On 2006-12-28, at 0936, Joshua Megerman wrote:

OK, I did some more testing with a test cdb and tcprulescheck, and got
some interesting results:

I thought that the daemontools documentation stated that it takes the
first match it finds period, but I misunderstood it slightly. It states
that it looks for a match of the exact IP first, and then shorter and
shorter prefixes, taking the first match. This is close to the exhibited behavior, but not quite. A rule that has all 4 octets listed, either a single IP (A.B.C.d) or an IP range within a single /24 block (A.B.C.D-E), will override any rule that is less specific (as documented). Therefore, even if a particular subnet is excluded (e.g., 127.0.0:deny), a single IP address updated by vpopmail (e.g.,,[...]) would be allowed
to connect (at least until the cdb was scrubbed).

However, if you have multiple rules with all 4 octets, it does take the first rule it finds. So the rule (e.g.) would override
the rule (e.g.), assuming that the deny rule appeared
first.  The same pattern holds true for shorter rules, where there are
multiple rules that could match with the same number of octets listed.
Thus, it may be possible that there are people denying entire netblocks and then using the pop-before-smtp (or maybe even imap-before-smtp, though I know there are problems with at least one major IMAP server out there)
to "poke holes" in their tcpserver cdb and allow connections from
otherwise denied addresses, and that one case would break with this patch.
 However, I have a possible idea for that - see below.

this is because a rule like this:

actually goes into the cdb file as eight rules, like so: -> allow -> allow -> allow -> allow -> allow -> allow -> allow -> allow

tcpserver actually checks four entries in the cdb file... for the IP address "a.b.c.d", it searches for the following keys, in this order:


it would be nice if the file format included the subnet mask as part of the key, it would allow for more granular searching, like so:


of course "?" represents the original octet, ANDed with the appropriate value to make it match the base address in a network (i.e. for a "/28" entry, the last octet would be one of 0, 16, 32, 48, 64, etc.)

I just came up with an option 4, which may well resolve the issue: 4)
modify the patch so that it looks for a specific comment line
("#UPDATESTATIC" perhaps - I'm open to suggestions) at the beginning of the static cdb file. Lines starting with '#' characters are ignored by tcprules, but I can easily modify my patch to check for them, especially on the first line, and short-circuit the search. Then all that is needed
is to document the effects of the patch, and state that in order to
continue updating the CDB file with addresses that have static matches you
have to insert that comment on the first line of the static CDB.  This
changes it from a compile-time configureation variable to a runtime one,
and has the benefit of not requiring additional configuration files.

Thoughts? (I'll go ahead and make a new patch anyway, just because it's
simple and I like the idea :))

i don't know enough about how the patch works to comment directly on this... from rick's one-line description at the beginning of the thread i gather the patch keeps statically-entered /etc/tcp/smtp entries from having dynamic lines created for them when they authenticate via POP3 or IMAP. if this is not the problem you're trying to solve, then ignore the rest of this message.

but here's another idea:

- when a user authenticates via POP3/IMAP, the code "touches" a file in a specific directory, whose name is the client's IP address. the directory would be set via a ./configure option, and if the option is not there, the code would be disabled entirely.

- vpopmail's "make" procedure would also build a program called "check-relay", which can be called from the "tcpserver ... qmail- smtpd" command line. it would work something like this (quick and dirty pseudo-C)...

        int main(int argc, char **argv, char **envp)

        #ifdef RELAY_DIR
                char *filename;
                char *ip ;

                ip = env_get("TCPREMOTEIP") ;
                if ( ip )
                        filename = malloc ( sizeof(RELAY_DIR) + 17 ) ;
                        sprintf ( filename, "%s/%s", RELAY_DIR, ip ) ;
                        if ( ! access ( filename, F_OK ) )
                                env_add ( "RELAYCLIENT", "" ) ;

                execve ( argv[1] , &(argv[1]) , envp ) ;
                perror("execve()") ;
                return (1) ;

basically, this program would read $TCPREMOTEIP, see if a file with that name exists in the configured directory, and add RELAYCLIENT="" to the environment if so. regardless of what happened, it would then exec() the rest of its command line arguments.

this program could also be written with a command-line option to drop the connection if RELAYCLIENT wasn't already set and if the IP is not found in the directory, so that people (like myself) who currently have a ":deny" line in their qmail-smtpd access control file wouldn't have to give up that functionality.

- run a cron job which deletes any entries from this directory which haven't been "touched" in half an hour.

to me this seems to be a LOT easier to write than anything else. (and yes, the idea of using a directory with "IP as the filename" and using the file's timestamps to hold the timeout values did come from my greylisting program.)

| John M. Simpson    ---   KG4ZOW   ---    Programmer At Large |
| http://www.jms1.net/                         <[EMAIL PROTECTED]> |
| http://video.google.com/videoplay?docid=-4312730277175242198 |

Attachment: PGP.sig
Description: This is a digitally signed message part

Reply via email to