Forum Discussion

AnthicL's avatar
AnthicL
Icon for Nimbostratus rankNimbostratus
Oct 07, 2024

SMTP Proxy irule

I have configured the SMTP irule as below:

-----------------------------------------------------------------------

when CLIENT_ACCEPTED {
    set chelo ""
    set cfrom ""
    set crcpt ""    
    TCP::respond "220\r\n"
log local0. "client accepted on [virtual] - client ip=[IP::client_addr]:[TCP::client_port]"
    TCP::collect
}
 
when CLIENT_DATA {
 
    set cdata [TCP::payload]
    if { [ string length $cdata ] <= 0 } {
        return
    }
    if { not ( $cdata contains "\r\n" ) } {
        log local0. "get <$cdata> so far"
        return
    }
    if { $cdata starts_with "HELO" } {
        set chelo [TCP::payload]
        log local0. "get helo <$cdata>"
        TCP::respond "250 OK\r\n"
        TCP::payload replace 0 [string length $chelo] ""
        return
    }
    if { $cdata starts_with "MAIL FROM:" } {
        set cfrom [TCP::payload]
        log local0. "get from <$cfrom>"
        TCP::respond "250 OK\r\n"
        TCP::payload replace 0 [string length $cfrom] ""
        return
    }
    if { $cdata starts_with "RCPT TO:" } {
        set crcpt "$crcpt[TCP::payload]"
        log local0. "get rcpt <$crcpt>"
        TCP::respond "250 OK\r\n"
        TCP::payload replace 0 [string length [TCP::payload]] ""
        return
    }
    if { $cdata starts_with "DATA" } {
        set Cntnt [lsearch "$cdata[TCP::payload]" Content-Type*]
        log local0. "get data <$Cntnt>"
        TCP::payload replace 0 0 $chelo$cfrom$crcpt
    }
    log local0. "payload [TCP::payload]"
    TCP::release
    TCP::collect
}
 
when SERVER_CONNECTED {
    log "server connected"
    TCP::collect
}
 
when SERVER_DATA {
    set sdata [TCP::payload]
 
    if { $sdata starts_with "220" } {
        #log local0. "get data <$sdata>"
        TCP::payload replace 0 [string length $sdata] ""
        return
    }
    if { $sdata contains "\r\n354 " } {
        #log local0. "get data <$sdata>"
        TCP::payload replace 0 [string length $sdata] "354\r\n"
    }
    if { [ string length $sdata ] <= 0 } {
        return
    }
    #log local0. "payload <[TCP::payload]>"
    TCP::release
    TCP::collect
}
when CLIENT_CLOSED {
    log local0. "client closed"
}
---------------------------------------------------------------------------
On testing, this irule works for most clients, but few of them are unable to send emails while this irule is applied to the Virtual Server.
 
While doing a packet capture, we see client facing the interruption reply with a [FIN, ACK] for the response 220 domain service ready which comes from the F5. Ideally, it should start sending data which is not the case.
 
Attached is the packet capture snippet. Client IP: 192.168.44.37 F5 IP: 192.168.166.33
 
Any advise would be appreciated.
  • Maybe add the domain to the 220 response: https://en.wikipedia.org/wiki/List_of_SMTP_server_return_codes