smtp
41 TopicsSMTP Proxy
Problem this snippet solves: This iRule implements a simple SMTP proxy. This is just to show an idea to relay smtp message and to route mail traffic based on FROM or TO... this rule is tested and work with one default pool and basic smtp client. Code : when CLIENT_ACCEPTED { set chelo "" set cfrom "" set crcpt "" TCP::respond "220\r\n" log local0. "client accepted" 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" } { log local0. "get data <$cdata>" 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" }2.7KViews0likes2CommentsSTARTTLS Server SMTP with cleartext and STARTTLS client support
Problem this snippet solves: We were looking at our O365 security score and our SMTP scores were pretty sad, so I looked at how I could create a STARTTLS connection up to O365 regardless of the client support. Originally I just supported cleartext clients, but I was able to get it to support clients running STARTTLS too. Links in the iRule to some helpful threads I used while developing this. How to use this snippet: Attach this iRule to a SMTP VS with a clientssl, serverssl and a SMTP profile. Code : # This iRule allows dynamic cleartext and STARTTLS client connection with a STARTTLS connection to the upstream server # unfortunately, cleartext to server connections do not work with the iRule as-is when CLIENT_ACCEPTED { # No SSL client side, also check no SSL running already on server side # Debug mode set DEBUG 1 set SERVER_SSL 0 set CLIENT_SSL 0 set EHLO_Name "smtp.domain.com" if { $DEBUG } { log local0. "CLIENT_ACCEPTED" } SSL::disable serverside # Disable All TLS so we can dynamically enable it SSL::disable } when SERVER_CONNECTED { if { $DEBUG } { log local0. "SERVER_CONNECTED" } # Start collecting from the server because in SMTP the server responds first TCP::collect } when CLIENT_DATA { set lcpayload [string tolower [TCP::payload]] if { $DEBUG } { log local0.debug "CLIENT_DATA - PAYLOAD - $lcpayload" } if { $lcpayload starts_with "ehlo" } { if { $DEBUG } { log local0.debug "CLIENT_DATA - ehlo" } # https://devcentral.f5.com/s/articles/offload-smtp-encryption-via-irules # Spoof back STARTTLS headers to the client so they'll tell us if the support it or not TCP::respond "250-STARTTLS\r\n250 OK\r\n" TCP::payload replace 0 [TCP::payload length] "" TCP::release TCP::collect } elseif { $lcpayload starts_with "starttls" } { if { $DEBUG } { log local0.debug "CLIENT_DATA - Starttls" } # https://devcentral.f5.com/s/articles/smtp-start-tls # Spoof back the 'Ready to start TLS' header to the client so we can do client<->F5 SSL TCP::respond "220 Ready to start TLS\r\n" TCP::payload replace 0 [TCP::payload length] "" TCP::release clientside {SSL::enable} } elseif { $lcpayload starts_with "rset" and $SERVER_SSL == 1 } { if { $DEBUG } { log local0.debug "CLIENT_DATA - Client RSET" } # In situations where the client is not encrypting, but the server is, it appears nessecary to reset and re-EHLO to the SMTP server. # In this case, these are the advertisements from the O365 relay so you may have to adjust them according to your SMTP server responses. # This can be attained by setting DEBUG variable to '1' and watching /var/log/ltm when you send a message for the response returned from # the SMTP server for 'Hello'. # Example: Rule /Common/SMTP_STARTTLS : server SSL payload: 250-blah.mail.protection.outlook.com Hello [removed-IP] 250-SIZE 157286400 250-PIPELINING 250-DSN 250-ENHANCEDSTATUSCODES 250-8BITMIME 250-BINARYMIME 250-CHUNKING 250 SMTPUTF8 TCP::respond "250-STARTTLS 250-SIZE 157286400 250-PIPELINING 250-DSN 250-ENHANCEDSTATUSCODES 250-8BITMIME 250-BINARYMIME 250-CHUNKING 250 SMTPUTF8\r\n" TCP::payload replace 0 [TCP::payload length] "" TCP::release TCP::collect # /var/log/ltm complains about this, but it appears to work serverside { SSL::respond "EHLO $EHLO_Name\r\n" } } else { if { $DEBUG } { log local0.debug "CLIENT_DATA - Default release" } TCP::release } } when SERVER_DATA { # Most of thise was helpfully taken from https://devcentral.f5.com/s/questions/need-an-irule-for-starttls-for-smtps-server-side-only-not-client-side # Read in responses from remote server into a variable and log to /var/log/ltm set payload [string tolower [TCP::payload]] if { $DEBUG } { log local0. "SERVER_DATA - PAYLOAD - $payload" } if {$payload starts_with "220" and $payload contains "esmtp"} { # Listen for remote servers opening 220 and esmtp message # NOTE the ‘if’ statement above may need to be tweaked to except what message the other # side is actually sending in reply. Logs should show this. # Respond with a EHLO to server, most servers require a name after the EHLO as well. TCP::respond "EHLO $EHLO_Name\r\n" TCP::payload replace 0 [TCP::payload length] "" TCP::release if { $DEBUG } { log local0. "SERVER_DATA - Responded to server with EHLO" } serverside {TCP::collect} } elseif {$payload contains "250-starttls" } { # Check server responds with "250-starttls", if so, respond with a STARTTLS TCP::respond "STARTTLS\r\n" TCP::payload replace 0 [TCP::payload length] "" TCP::release if { $DEBUG } { log local0. "SERVER_DATA - Sent the server a STARTTLS" } serverside {TCP::collect} } elseif {$payload contains "220 ready for tls" or $payload contains "220 2.0.0 continue" or $payload contains "220 2.0.0 smtp server ready" } { # if server gives a 220 response, then start server side ssl profile # NOTE the ‘if’ statement above may need to be tweaked to except what message the other # side is actually sending in reply. Logs should show this. ###### # O365 Edit - O365 returns 220 2.0.0 smtp server ready after enabling TLS - Adjust as needed ###### if { $DEBUG } { log local0. "SERVER_DATA - server said he is ready for TLS, enable the SSL profile" } TCP::payload replace 0 [TCP::payload length] "" TCP::release serverside {SSL::enable} # TLS hanshake should now start, which is best seen in wireshark packet captures. } else { if { $DEBUG } { log local0.debug "SERVER_DATA - Default release" } TCP::release clientside { TCP::collect } } } when SERVERSSL_HANDSHAKE { # This will only trigger if that is completed successfully. # ServerSSL profile will need a certificate to match the outbound IP and DNS name, # and you may want to set the "Server certificate" setting to "require", # and the "Trusted Certificate Authorities" set to "ca-bundle". if { $DEBUG } { log local0. "SERVERSSL_HANDSHAKE - SSL handshake completed." } set SERVER_SSL 1 if { $CLIENT_SSL == 1 } { if { $DEBUG } { log local0.debug "SERVERSSL_HANDSHAKE - Client respond SSL" } clientside { SSL::respond "220 SMTP ESMTP Relay F5\r\n" } } else { if { $DEBUG } { log local0.debug "SERVERSSL_HANDSHAKE - Client respond TCP" } clientside { TCP::respond "220 SMTP ESMTP Relay F5\r\n" } # Give the client side a chance to STARTTLS clientside { TCP::collect } } if { $DEBUG } { log local0.debug "SERVERSSL_HANDSHAKE - SSL collect" } SSL::collect } when CLIENTSSL_HANDSHAKE { # This will only trigger if that is completed successfully. # ServerSSL profile will need a certificate to match the outbound IP and DNS name, # and you may want to set the "Server certificate" setting to "require", # and the "Trusted Certificate Authorities" set to "ca-bundle". if { $DEBUG } { log local0. "SSL handshake completed." } set CLIENT_SSL 1 SSL::collect } when SERVERSSL_DATA { # Log the SMTP responses to see any errors. if { $DEBUG } { log local0. "SERVERSSL_DATA - PAYLOAD - [SSL::payload]" } SSL::release if { $CLIENT_SSL == 0 } { if { $DEBUG } { log local0.debug "SERVERSSL_DATA - Client TCP Collect"} clientside { TCP::collect } } SSL::collect } when CLIENTSSL_DATA { # Log the SMTP responses to see any errors. if { $DEBUG } { log local0. "CLIENTSSL_DATA - PAYLOAD - [SSL::payload]" } #log local0.debug "Clientssl_data - release" SSL::release SSL::collect }2.6KViews0likes6CommentsSNMP Trap for Expired Certificates
Can anyone provide an example of the useralert.conf file displaying a trap for expired certificates on the Big IP? I have read the article below though it is still not clear to me on how to perform this function. Also, I have read several different methods for monitoring for expired or expiring SSL certificates though does anyone have a preference or recommendation? http://support.f5.com/kb/en-us/solutions/public/3000/700/sol3727.htmlSolved1.7KViews0likes11CommentsSMTP Start TLS
Problem this snippet solves: Summary: This iRule allows either clear text or TLS encrypted communication with the LTM initiating the encryption process if it sees the appropriate "starttls" command in the SMTP communication. Code : when CLIENT_ACCEPTED { set ehlo 0 SSL::disable } when SERVER_CONNECTED { TCP::collect } when CLIENT_DATA { set lcpayload [string tolower [TCP::payload]] if { $lcpayload starts_with "ehlo" } { set ehlo 1 serverside { TCP::collect } TCP::release TCP::collect } elseif { $lcpayload starts_with "starttls" } { TCP::respond "220 Ready to start TLS\r\n" TCP::payload replace 0 [TCP::payload length] "" TCP::release SSL::enable } else { TCP::release } } when SERVER_DATA { if { $ehlo == 1 and not([string tolower [TCP::payload]] contains "starttls") } { TCP::payload replace 0 0 "250-STARTTLS\r\n" } TCP::release clientside { TCP::collect } }1.3KViews0likes3CommentsFailure of SMTP health check
I've always received great help here and it's truly appreciated. Now I have another issue that requires some assistance. BTW, I have a support case with F5 regarding this and they have not been able to offer any solutions that have worked. I have a virtual server that uses a single member pool doing SMTP health checks. The health check is failing (showing the member down) but all logs show proper connectivity, proper smtp responses from the mail server, and communications working correctly, but the health check still shows down and the logs related to this traffic are displaying a "Sending data failed, errno 'EPIPE'" type error message. I can telnet from the F5 to the member server from a SSH console and run the same SMTP commands and all checks out. Simply not sure why the health check would fail is all appears to be talking properly.Solved1.2KViews0likes16CommentsSMTP Load Balancing without SNAT Outbound traffic problems
Hello, I’m sorry because this is an issue that it has been reviewed in the forum, but in our case it doesn’t work and we don`t know what is the problem. We have two STMP VLANs, internal (192.168.26.0/24) and external (192.168.227.0/24). In the external we have a standard virtual server (192.168.227.11) with a SMTP pool with two servers in the internal VLAN (192.168.26.11 and 192.168.26.12). We have SNAT Automap disable because we want to keep the original source IP, so SMTP servers have its default gateway on F5 (192.168.26.1). This works OK. The problem is about outbound traffic. For example, when SMTP server tries to send outbound traffic to Internet or Exchange servers, through F5, it doesn’t work. We know internal servers can reach F5 SMTP internal floating ip (192.168.26.1) by ping, but it seems it doesn´t know what to do with traffic originated on SMTP servers, or where to send it. It also happens with any connection started in the server. We have tried to configure a 0.0.0.0/0.0.0.0:any virtual server forwarding IP enabled on internal VLAN but it doesn’t work. Traffic reaches F5 (we show IN traffic statistics), but doesn’t continue to the external VLAN. We have also tried with a default route too (0.0.0.0/0 -> 192.168.227.1), but it doesn´t work. Could you help us? Thank you very much!1.1KViews0likes11CommentsSMTP filter and forward proxy
Problem this snippet solves: This iRule provides a forward proxy for SMTP messages; it also filters messages by limiting the maximum size of the DATA sent, and also limiting the amount of messages per TCP connection. The iRule is limited to a single RCPT at the moment... I'm not sure this could have multiple RCPTs as this would need support of multiple server connections, and a way to store the DATA which doesn't sound like a good thing to do. The other limitation is that it does not support pipelining; I think this is something that could be done in the next version, but will complicate the iRule somewhat. WARNING: This iRule has NOT been tested in earnest. Code : when RULE_INIT { # The following parameter enables local logging - 0=off, 1=on set static::SMTPfiltprxdebug 1 # Set maximum message size in bytes (21504000 is 21Mbyte) set static::maxMsgLen 21504000 # Set maximum number of messages in a single TCP connection (20) set static::maxNumMsgs 20 # # High speed logging setup - local7.info set static::bigip [info hostname] set static::facility <190> set static::hsl_prefix "$static::facility|host=$static::bigip" } when CLIENT_ACCEPTED { # Open a connection for high speed logging to hsl_syslog_pool & define log prefix set hsl [HSL::open -proto UDP -pool hsl_syslog_pool] set hsl_prefix "${static::hsl_prefix}|client=[IP::client_addr]:[TCP::client_port]" # Set up a variable to collect number of RCPTs set numRcpts 0 # Set up variables to collect length of email set dataFlag 0 set msgLen 0 # Set up variable to collect number of messages in TCP connection set numMsgs 0 # Set up other variables use to collect payload until we have a RCPT to act upon set heloCmd "" set mailCmd "" set rcptCmd "" set destIP "" set smtpSeq 0 # Send back a SMTP service ready and collect client data TCP::respond "220 Proxy Ready\r\n" TCP::collect } when CLIENT_DATA { if { [string length [TCP::payload]] <= 0 } { return } if { not ( [TCP::payload] contains "\r\n" ) } { return } switch -glob {[string tolower [TCP::payload]]} { rset* { # Blank out payload TCP::payload replace 0 [string length [TCP::payload]] "" # Send back an SMTP OK TCP::respond "250 OK\r\n" TCP::collect return } helo* { # Store the command set heloCmd [TCP::payload] # Blank out payload TCP::payload replace 0 [string length $heloCmd] "" # Send back an SMTP OK TCP::respond "250 Hello client at [IP::client_addr]\r\n" TCP::collect return } ehlo* { # Store the command set heloCmd [TCP::payload] # Blank out payload TCP::payload replace 0 [string length $heloCmd] "" # Send back an SMTP OK TCP::respond "250 Hello client at [IP::client_addr] \r\n" # Restart collection TCP::collect return } mail* { # Release any server connection if applicable LB::detach # MAIL FROM is first command of every message so this is a good place reset variables set numRcpts 0 set dataFlag 0 set msgLen 0 set smtpSeq 0 # Increment number of messages incr numMsgs 1 # Store the command set mailCmd [TCP::payload] # Blank out payload TCP::payload replace 0 [string length $mailCmd] "" # Send back an SMTP OK TCP::respond "250 sender ok\r\n" # Restart collection TCP::collect return } rcpt* { incr numRcpts 1 # Check to ensure the maximum number of recipients has not been breached if { $numRcpts > 1 } { # This session is going to be closed down as too many RCPTs have been detected set log_message "event=CLIENT_DATA|desc=Over $static::maxNumRcpts recipients detected - session aborted|\n" HSL::send $hsl "$hsl_prefix|$log_message" if { $static::SMTPfiltprxdebug ne "0" } { log local0. "$log_message" } reject return } # Store the command set rcptCmd [TCP::payload] # Need to get the RCPT domain and lookup onward host set rcptDomain [lindex [split [lindex [split [lindex [split [lindex [split $rcptCmd ":"] 1] "@"] 1] "\r\n"] 0] ">"] 0] # Use RCPT domain to find mail host set mailSrvs [RESOLV::lookup @/Common/dns -mx $rcptDomain] # NB: If there are multiple entries it could be a TCL list. # Check if the first list element was empty if { $mailSrvs equals "" } { reject set log_message "event=CLIENT_DATA|desc=DNS lookup (MX) failed for $rcptDomain|\n" HSL::send $hsl "$hsl_prefix|$log_message" if { $static::SMTPfiltprxdebug ne "0" } { log local0. "$log_message" } return } else { # Select the 1st returned mail server name and find IP address set destHost [lindex $mailSrvs 1] set ips [RESOLV::lookup @/Common/dns -a $destHost] # Again this could be a TCL list if { $ips equals "" } { reject set log_message "event=CLIENT_DATA|desc=DNS lookup (A) failed for $destHost|\n" HSL::send $hsl "$hsl_prefix|$log_message" if { $static::SMTPfiltprxdebug ne "0" } { log local0. "$log_message" } return } else { set destIP [lindex $ips 0] } } # Blank out payload TCP::payload replace 0 [string length $rcptCmd] "" # Connect to server and release stored SMTP messages set log_message "event=CLIENT_DATA|desc=Connection to server $destIP|\n" HSL::send $hsl "$hsl_prefix|$log_message" if { $static::SMTPfiltprxdebug ne "0" } { log local0. "$log_message" } node $destIP 25 } data* { set dataFlag 1 } } # Start counting payload lengths once the DATA command has been seen if { $dataFlag ne "0" } { incr msgLen [TCP::payload length] } # Check to ensure the maximum message size has not been breached if { $msgLen > $static::maxMsgLen } { # This session is going to be closed down as it is too big set log_message "event=CLIENT_DATA|desc=Over $static::maxMsgLen byte message size detected - session aborted|\n" HSL::send $hsl "$hsl_prefix|$log_message" if { $static::SMTPfiltprxdebug ne "0" } { log local0. "$log_message" } reject return } # Check to ensure the maximum number of messages has not been breached if { $numMsgs > $static::maxNumMsgs } { #This session is going to be closed down as too many messages have been attempted set log_message "event=CLIENT_DATA|desc=Over $static::maxNumMsgs messages detected - session aborted|\n" HSL::send $hsl "$hsl_prefix|$log_message" if { $static::SMTPfiltprxdebug ne "0" } { log local0. "$log_message" } reject return } TCP::release TCP::collect } when SERVER_CONNECTED { TCP::collect } when SERVER_DATA { switch -glob [string tolower [TCP::payload]] { 220* { # Suppress message to client TCP::payload replace 0 [string length [TCP::payload]] "" # Send stored HELO command to server TCP::respond $heloCmd # Restart collection TCP::collect return } 250* { incr smtpSeq 1 switch $smtpSeq { 1 { # Suppress message to client TCP::payload replace 0 [string length [TCP::payload]] "" # First time we see this we need to send MAIL command TCP::respond $mailCmd # Restart collection TCP::collect return } 2 { # Suppress message to client TCP::payload replace 0 [string length [TCP::payload]] "" # First time we see this we need to send MAIL command TCP::respond $rcptCmd # Restart collection TCP::collect return } } } } TCP::release }1.1KViews0likes0CommentsDifference between TCP monitor and SMTP monitor
Hi. Will anyone be able to explain to me the difference between the normal TCP monitor (Alias port 25) and a SMTP type monitor? For both type of monitor: 1. Will F5 close the connection gracefully (send a reset packet) or does it let the connection timeout/expire ? What exactly does the SMTP type monitor do? Does it sends a HELO to the email server?1.1KViews0likes3CommentsiRule to modify SMTP mail content
Hi, We have an requirement, where in we need to inspect the incoming SMTP message, look for a particular string and based on that modify the mail content. I have written the below iRule but this is not working. The CLIENT_DATA event is being triggered. I refered to the SMTP proxy iRule provided in this link(https://devcentral.f5.com/wiki/iRules.SMTPProxy.ashx?NS=iRules). I am not sure if i am missing anything here. when CLIENT_ACCEPTED { TCP::respond "220\r\n" TCP::collect 2000 } when CLIENT_DATA { set cdata [TCP::payload] if { $cdata starts_with "DATA" } { if { [string match "Exchange2010R2" $cdata ]} { string map {"Sent From:" "Sent From:\nExchange 2010 R2 Server\n"} TCP::payload } } TCP::release TCP::collect } Thanks in Advance. Ajay806Views0likes15CommentsInvalid response SMTP server
Hi, We are using 11.4.1 HF8 on a 4200 BIG-IP. I am trying to configure email alerts for snmp traps using user_alert.conf. When I am trying to send a test mail using echo "ssmtp test" | mail -vs "test mail" xxx@domain.com it is giving me Invalid response SMTP server. Please let me know if I am doing anything wrong and how can I fix this. Thanks, Sekhar745Views0likes3Comments