Synchronizing SMTPIf you wish to use ZXTM to inspect or modify the headers or body of SMTP messages, you need to write some TrafficScript™ to synchronize the two halves of the conversation, to ensure that the connection doesn't stall. This article explains how to do this, and presents an example TrafficScript rule that can be used as the basis of more advanced SMTP rules. Background - salient details of SMTPSMTP is a server first TCP protocol, usually run on port 25. Lines are terminated by carriage return and line feed (CRLF). A typical SMTP conversation proceeds as follows:
It's important to note the following:
Synchronizing SMTP with TrafficScriptTo handle SMTP, we need a TrafficScript rule that creates a state-machine with two states:
Since our TrafficScript rule is going to be executed every time a new line of data is received from the client, not just once per email sent, we need to keep track of the state between invocations of the rule. TrafficScript provides connection.data.set() and connection.data.get() to set flags that will let us keep track of which state we are in. As their names suggest, these commands allow you to set and read variables that persist as long as the TCP connection they are associated with. Multiple lines might arrive in the same packet from the client, even though we only wish to pass them to the server one at a time. We therefore need to indicate to ZXTM how to split the data into individual lines. We can do this using request.endsWith(), which takes a single argument, a regular expression that defines the end of the current request. Any data that comes after this will be kept for the next time the request rule is run. Putting this together, the following is a request rule that will synchronise SMTP. There are three places in it from which you could hook in code to inspect/modify the headers and body on the way through.
You should note the difference in behavior of request.endsWith() and request.getline(). Whilst they both return some data from the request, request.endsWith() tells ZXTM that this is the end of this request, and no more data should be read from the client until after the request has been sent to the server and a response received. request.getline(), on the other hand, merely reads some data from the client without ending the request, and so can be called multiple times within the same invocation of a request rule. If no data is available when request.getline() is called, processing will pause until the client sends some. We can thus use it to read and buffer the body. If we tried to use request.endsWith() instead, then the connection would stall. ZXTM would read the first line of the body, send it to the server, then pause waiting for a response from the server, which would never come. The condensed versionIf you don't want to perform line by line inspection or modification of the body, you can condense the above rule into the more elegant one below. This uses request.endswith() to read both the headers and the body, with only a single connection.data variable that both tracks the state and supplies the appropriate regular expression to request.endswith().
|
Recently...
Other Resources
|





