Tag Archives: Qmail

Qmail per domain concurrency

Problem

In my last post about qmail I said that once you solve the big concurrency problem you'll end up with another problem because your mail server would create too many outgoing connections to some domains and you risk having your ips banned by those servers.

Solution

The solution is to have a way of limiting the maximum concurrency rate by domains. To do that you'll need the   qmail channels patch or write your own patch like I did ( mostly because I was unaware of the existence of the qmail channels patch )

The home page of the qmail channels patch will explain how to setup and configure qmail to limit the concurrency by a domain or group of domains.

What I like about this patch is that it allows you to set a concurrency limit for a group of domains like set 100 for all yahoo.com, yahoo.co.uk, yahoo.ca, etc .

What I don't like is that it doesn't seem to be able to set a default concurrency level for any domain. If I'm wrong please correct me, but if I'm right then this seems like a major problem for an email server that sends to a large number of addresses distributed over a large number of domains because you would have to configure concurrency limits for a lot of domains.

The ideal solution would allow you to specify a default per domain concurrency and this would apply to any domain that doesn't have a specific concurrency. For example most email servers would be ok with 5 concurrency connections from the same ip but no way for AOL (unless you're white listed and maybe not even then ) .

Another feature I would like is to be able to specify concurrency by domain's MX records or ips/group of ips assigned to the MX servers instead of the actual domain. This would ease the configuration for ISPs that host a lot of domains like rr or yahoo.

Qmail Big concurrency

Wanna send messages faster with your qmail server? Everyone will tell you to increase the remote concurrency. Till you find out that it can only go as high as 255. If you want more then that you have to apply the big concurrency patch

The Problem

Applying the patch and setting concurrency ( conf-spawn ) bigger then 509 will break the compilation. I was hoping to get at least 1000 on that new quad core 🙁

Why 509? It seems the number depends on the maximum size of the FD_SET array used for "monitoring" ( using select ) the file descriptors ( connection sockets or opened files ) . This limit is set in FD_SETSIZE constant to 1024. In case you're wondering ... the formula that gets you from 1024 to 509 is (FD_SETSIZE-5)/2 ( from chkspawn.c )

Trying to define FD_SETSIZE to a higher value in conf-cc like this -DFD_SETSIZE=4096 doesn't work because FD_SETSIZE is redefined in sys/select.h like this

  1. #define FD_SETSIZE __FD_SETSIZE

__FD_SETSIZE is defined somewhere in /usr/include/bits/types.h ( actually typesizes.h ) to 1024. Defining -D__FD_SETSIZE doesn't work either...I even tried both and still no luck.

The Solution

After hours of digging through mail archives and sites I found this mailing list post that really helped:
Re: fd_setsize

If you just want to get it working just download my patch qmail Big Concurrency fix-1.0 (898 bytes) , apply it ( after you apply the big concurrency patch ) , set conf-spawn to something big ( but less then 65000 ) and then you should be able to compile qmail.

If you want to know how it's done, read bellow...

It seems like the solution is to include bits/types.h, undefine __FD_SETSIZE and then define it to a higher value. The author of that post says that this is not a good idea (from the portability point of view, but I don't care about that ) since programs should never directly include bits/types.h ( true ) but the alternative is to modify that system file, again not a good idea since it will be overwritten by a possible update.

My first idea was to just use that code from the mailing list post into the select.h2 , since this is the file used to generate select.h and select.h is included in spawn.c and ckhspawn.c but this didn't work because spawn.c was including "select.h" after "sys/types.h" so even if select.h would define __FD_SETSIZE it would be useless since FD_SETSIZE ( this is the one that really matters ) would have been already defined in sys/types.h .

The solution I found at the time was to just move "select.h" at the top of the file and remove "sys/types.h" since it was already included from select.h but now I realized I could have just as well undefined and defined FD_SETSIZE too inside select.h

And that's the story about how I got to run 1000 concurrent connection in qmail.

The real problem

Now that we can have so much concurrency we hit another wall. Qmail, as most other MTAs, doesn't have any way of controlling the remote concurrency per destination domain.

At 1000 simultaneous connections it's very likely that it would create a few tens or hundreds of connections simultaneously to the same domain.

When this happens that domain will just ban your ip.  So how do we fix this one?

PS: I have an answer but I want to see what you have for a solution 🙂 so hit the comments...

Ask me questions

Have a question about unix, linux, freebsd.  Or maybe you want some advice about configuring apache, mysql,an email server like exim, qmail, postfix, a proxy server like squid cache or antinat, dns or anything else similar. Want some help with php programming or maybe you want to create a wordpress plugin?

Feel free to ask and I'll do my best to answer it on this blog. I will publish a new blog post for each question and my answer.

You can use the contact form or ( if your question is short enough ) you can send it to me over twitter

You can follow me on twitter or subscribe to my RSS feeds if you want to be notified when I post the answer to your question.

Qmail TLS + SMTP Plugins on FreeBSD

Problem

One of the worst problems in qmail is that it accepts messages for non existent users and then sends back a bounce to the sender. This is the perfect setup to be exploited by a spammer. I'm using the qmail-tls port configured with vpopmail on FreeBSD.

Solution

There might be some patches that make qmail use the vpopmail command line tools directly to check if a user exists before accepting messages but I either didn't find them or thought that using the SMTP Plugins patch is more elegant and gives me more flexibility (It might be slower but this was not a high traffic server so I didn't care).

The SMTP plugins patch adds hooks at all STMP stages and the plugins can use those hooks to accept or reject a message based on the data in the smtp statements sent by the sender.
I used the Qmail-SPP - Vpopmail check user Script written by Werner Maier.

The only problem was that I had to patch the source code for qmail-tls with the qmail-spp patch and there were quite a few rejects because of the other patches applied by freebsd ports system.
I managed to adapt the code to make this patch work and here is how I did it...

First I built the original freebsd port:

  1. cd /usr/ports/mail/qmail-tls
  2. make config # pick up the options you want here ... I needed tls, smtpd-auth,vpopmail and a few others
  3. make
  4. make install

This will also install the files and then after we apply the spp plugin we just copy the modified file ( qmail-smtpd )
Next step if to download the qmail-spp plugin into /usr/ports/mail/qmail-tls/work and apply it.

  1. cd work
  2. tar -xzpf qmail-spp-0.42.tar.gz
  3. cd qmail-1.03
  4. patch -p1 < ../qmail-spp-0.42/qmail-spp-smtpauth-tls-20060105.diff

This will give you some rejects but don't worry because you'll fix them with my next patch : Qmail-tls-spp-FreeBSD patch-0.1 (4.73 KB)

  1. patch < qmail-tls-spp-freebsd.patch
  2. make
  3. /usr/local/etc/rc.d/svscan stop
  4. cp qmail-smtpd /var/qmail/bin
  5. /usr/local/etc/rc.d/svscan start

At this point qmail-smtpd should have smtp plugins working and we can set up the vpopmail user verifier script.

  1. cd /var/qmail
  2. mkdir plugins
  3. fetch http://www.maiers.de/qmail/vpopmail_check_recipient.sh
  4. chown root:qmail vpopmail_check_recipient.sh
  5. chmod 755 vpopmail_check_recipient.sh

Now edit vpopmail_check_recipient.sh and make sure the correct paths to vpopmail directory ( /home/vpopmail on freebsd ) are set in the script.

To test it, connect to smtp and try to send a message to an nonexistent account, you should see a reject message instead of the usual "ok".

Qmail Taps Extended

Problem

You're running qmail and you want to log as in "copy/archive/tap"  only the outgoing email messages.  Inter7, the creators of vpopmail have a nice solution in a patch named qmailtap.

This patch will actually give you the option to match a message's To and From addresses against a regexp and decide what to do with them, all in an easy to write configuration file but this solution will not differentiate between To and From so if any of them matches the regexp the messages will be copied.

If you would only want to log outgoing mail you could decide to log only the messages which have the From address set to a local account but since there's no way to know which of the From or To addresses  matched you can't do this.

Solution

I created another patch that would allow you to specify which address you want to match.

With the original patch to match everything To or From @domain.com and copy to copy@example.com  you would need a line like this in the configuration:

.*@domain.com:copy@example.com

With the new patch if you only want to log the messages with the From address @domain.com you would set the configuration like this:

F:.*@domain.com:copy@example.com

If you want to log only those with the To address @domain.com

T:.*@domain.com:copy@example.com

if you want the same behavior as the original patch:

A:.*@domain.com:copy@example.com

Note: When writing multiple rules you have to consider how qmail-queue works after this patch
For each message qmail-queue looks at the From address first and tries to match it against the lines
starting with F: or A:.   When it finds a match it copies the message and stops.
If it didn't find a match in the F: or A: lines  it will try to match the To address against
the T: and A: lines.

Download

If you have not applied qmailtap patch yet here is the new full patch:

Qmail taps Extended-full (10.46 KB)

If you have already applied the qmailtap patch here is a patch you have to apply to obtain the new functionality:

Qmail taps Extended-diff (3.54 KB)

Got any questions ? Or maybe you have other solutions... hit the comments!

Core dumps

I was working on qmail (patching it heavily ) and at one point I was getting a segmentation fault. Trying to trace it in a busy environment is hard, especially in qmail that is very modular and processes come and go away all the time.

So I thought a core dump could be the answer.The only problem was my system wouldn't dump the core of the processes where the 'segmentation fault' occurred. I have set the core size file high enough ( ulimit -c 10000000 ) in the qmail start script but still not core dump so I decided to do some research.

From core man page it seems like a core could not be dumped for a number of reasons:

  1. the process owner doesn't have write permission to the directory where the core file should be written.
  2. the core file size limits ( RLIMIT_CORE , RLIMIT_FSIZE ) are less then the size of the core that would be dumped
  3. the process was setuid and in this case dumping the core would depend on the setting in /proc/sys/fs/suid_dumpable ( proc(5) )
  4. the file being executed doesn't have read permission

In my case #2 and #4 were not an issue so it must have been #1 and/or #3 .

To make sure #1 was not an issue I created a directory /tmp/cores, made it 777 to make sure any process can write to it ( not safe in a multiuser environment but works ) and then set /proc/sys/kernel/core_pattern to /tmp/cores/core so now all core files would be in /tmp/cores instead of the process working directory as it is by default. It's also a good idea to make sure /proc/sys/kernel/core_uses_pid is set to 1 so the pid of the process will be appended to the core file name.

To fix #3 I set /proc/sys/fs/suid_dumpable to 2 . I restarted qmail and there I had the core in /tmp/cores .

qmail and DKIM

DomainKeys Identified Mail (DKIM) is a method for validating the identity associated with a message using using public-key cryptography and key server technology. DKIM is an enhanced version of Yahoo's Domain Keys and Cisco's Identified Internet Mail methods. As of February 2007 an IETF draft was accepted as "Proposed standard", it may take some more time till this will be a standard but the current version is stable ( according to dkim.org ).

Implementations of DKIM in email servers is not available as much as DomainKeys.
For qmail there is a patch that uses libdomainkeys to implement a replacement for qmail-queue that will verify and sign messages but this only works for DomainKeys not DKIM. I have developed a solution for qmail to be able to verify and sign messages with DKIM. Continue reading

Qmail with smtp-auth and DomainKeys on FreeBSD

I tried to set up qmail with tls and smtp auth on freebsd. I have configured my server with SMTP-AUTH so that I can use it to relay messages for me and other authenticated users. I would like qmail to sign the messages that the authenticated users send through my server.

I compiled qmail-tls from ports, checked the smtp-auth and qmailqueue options, then I compiled qmail-dk and selected the SMTP-AUTH patch. I set up my private and public keys, I set up bin/qmail-dk for qmailqueue as described on this page : http://jeremy.kister.net/howto/dk.htm but still not results. It just does not want to add the DomainKeys signature but instead it tries to verify the messages. Continue reading