Forum Discussion

xxkozxx's avatar
xxkozxx
Icon for Nimbostratus rankNimbostratus
Jun 15, 2020

SMTP Proxy Not receiving Client Quit...

I recently ran into a situation where legacy devices are sending emails for alerting. However, the firmware uses AUTH PLAIN as the security mechanism which is no longer supported in the new 0365 code revision. So I decided to attempt to proxy SMTP for these devices, so that I could deal with the auth mechanism.

 

I have everything working. However, it seems as though once the mail is queued the Client QUIT is not processed or isn't seen so the connections go into a stale state. The servers then send a 451 response and the client connection eventually closes. I believe this is causing a problem with e-mails sent in succession. If the legacy devices send 3 emails in succession (alerts). Two may be delivered.

 

In testing this against a POSTFIX server this is not an issue. I can clearly see the Client send a QUIT to the POSTFIX server when it is not running across the F5 VIP.

 

Here is my code, so far. I am wondering if there is something that is missing or miscoded that might be causing this problem.

 

# GATHER PAYLOAD VARIABLES AND STORE FOR LATER.

when CLIENT_ACCEPTED {
    set chelo ""
    set cfrom ""
    set crcpt ""
    set cauth ""
    set cquit ""
    TCP::respond "220\r\n"
    log local0. "GenMail: Client [IP::client_addr] accepted"
    TCP::collect
}

# GATHER PAYLOAD AND PROXY SMPT RESPONSES

when CLIENT_DATA {
    set cdata [TCP::payload]
    log local0. "GenMail: Empty Payload. Resuming..."
    if { [ string length $cdata ] <= 0 } {
        return
    }
    # CONTINUE GATHERING PAYLOAD UNTIL A CARRIAGE RETURN IS FOUND
    if { not ( $cdata contains "\r\n" ) } {
        log local0. "Genmail: Gathering Payload <$cdata>"
        return
    }
    # TRAP HELO/EHLO and set chelo for payload rebuild.  Clear payload so it doesn't get forwarded to server.
    if { $cdata starts_with "HELO" } {
        set chelo [TCP::payload]
        log local0. "Genmail: Gathering HELO/EHLO <$cdata>"
        TCP::respond "250 OK\r\n"
        TCP::payload replace 0 [string length $chelo] ""
        return
    }
    
    if { $cdata starts_with "EHLO" } {
        set chelo [TCP::payload]
        log local0. "Genmail: Gathering HELO/EHLO <$cdata>"
        TCP::respond "250 OK\r\n"
        TCP::payload replace 0 [string length $chelo] ""
        return
    }
    
    # TRAP for Client QUIT
    if { $cdata starts_with "QUIT" } {
        set cquit [TCP::payload]
        log local0. "GenMail: Client [IP::client_addr] issued QUIT."
        TCP::respond "221 Bye.\r\n"
        TCP::payload replace 0 [string length $cquit] ""
        TCP::close
    }
    
    # SPOOF AUTH SUCCESS FOR AUTH PLAIN.  Clear payload so it doesn't get forwarded to server.
    if { $cdata starts_with "AUTH" } {
        set cauth [TCP::payload]
        log local0. "GenMail: Spoofing Auth Success for <$cauth>"
        TCP::respond "235 2.7.0 Authentication successful\r\n"
        TCP::payload replace 0 [string length $cauth] ""
        return
    }
    
    # TRAP SENDER and set cfrom for payload rebuild. Clear payload so it doesn't get forwarded to server.
    if { $cdata starts_with "MAIL" } {
        set cfrom [TCP::payload]
        log local0. "Genmail: Getting Sender - <$cfrom>"
        TCP::respond "250 OK\r\n"
        TCP::payload replace 0 [string length $cfrom] ""
        return
    }
    
    # TRAP RECIPIENT and set cfrom for payload rebuild. Clear payload so it doesn't get forwarded to server.
    if { $cdata starts_with "RCPT" } {
        set crcpt [TCP::payload]
        log local0. "Genmail: Getting Recipient - <$crcpt>"
        TCP::respond "250 OK\r\n"
        TCP::payload replace 0 [string length $crcpt] ""
        return
    }
    # TRAP DATA and Respond with 354.
    if { $cdata starts_with "DATA" } {
        log local0. "GenMail: Getting Message Data - <$cdata>"
        TCP::respond "354 End data with <CR><LF>.<CR><LF>\r\n"
        
        #  Reconstruct TCP Payload without Auth Plain to server.
        log local0. "GenMail: Reconstructed TCP Payload [TCP::payload]"
        TCP::payload replace 0 0 $chelo$cfrom$crcpt
    }
    
   
    # RELEASE PAYLOAD TO SERVER AND COLLECT NEXT PAYLOAD
    log local0. "GenMail: <CLIENT PAYLOAD> [TCP::payload]"
    
    TCP::release
    TCP::collect
}


# SERVER SIDE CONNECTION HANDLING


when SERVER_CONNECTED {
    log "GenMail: Server [IP::server_addr] connected"
    TCP::collect
    }

when SERVER_DATA {
    set sdata [TCP::payload]

    # STRIP 220 Responses. Already sent to client.
    if { $sdata starts_with "220" } {
        log local0. "GenMail: Stripping Server 220 Response <$sdata>"
        TCP::payload replace 0 [string length $sdata] ""
        return
    }
    
    #SEND QUEUED 250 RESPONSE BACK TO CLIENT
    if { $sdata contains "Queued" } {
        log local0. "GenMail: Server Queued Response <$sdata>"
        return
    }
        
    # STRIP 250 Responses already sent to client.
    if { $sdata starts_with "250" } {
        log local0. "GenMail: Stripping Server 250 OK Response <$sdata>"
        TCP::payload replace 0 [string length $sdata] ""
        return
    }
    
    # STRIP 354 response already sent to client.
    if { $sdata contains "354" } {
        log local0. "GenMail: Stripping Server 354 Response <$sdata>"
        TCP::payload replace 0 [string length $sdata] ""
    }
    # STRIP 221 Response already sent to client.
    if { $sdata contains "221" } {
        log local0. "GenMail: Stripping Server 221 Response <$sdata>"
        TCP::payload replace 0 [string length $sdata] ""
        TCP::close
    }
   
    if { [ string length $sdata ] <= 0 } {
        return
    }
    
    # RELEASE PAYLOAD TO CLIENT AND COLLECT NEXT PAYLOAD
    log local0. "GenMail: <SERVER PAYLOAD> [TCP::payload]"
    
    TCP::release
    TCP::collect

}

when CLIENT_CLOSED {
    log local0. "GenMail: Client [IP::client_addr] closed the connection."
}

 

Any help would be appreciated. Thanks.

  • xxkozxx,

    If you add a TCP::release statement in your SERVER_DATA (QUEUED) section it shoud resolve your issue.

        #SEND QUEUED 250 RESPONSE BACK TO CLIENT
    if { $sdata contains "Queued" } {
    log local0. "GenMail: Server Queued Response <$sdata>"
    TCP::release
    return
    }