While sending individual messages with qmail consumes very little CPU, sending multiple large messages in parallel can effectively DoS a sender due to inefficiencies in qmail-remote's "blast" function. In its original form, this function scans the message one byte at a time to escape leading periods and newlines, as required by SMTP. This patch modifies blast to scan the message in larger chunks. I have benchmarked before and after, and the change reduced the CPU time consumed by qmail-remote by a factor of 10. The original version of this patch had two bugs that would corrupt data for any message larger than 4kB. -- Bruce Guenter http://untroubled.org/ diff -u qmail-1.03/qmail-remote.c qmail-1.03-fastremote/qmail-remote.c --- qmail-1.03/qmail-remote.c 1998-06-15 04:53:16.000000000 -0600 +++ qmail-1.03-fastremote/qmail-remote.c 2005-08-26 10:28:45.000000000 -0600 @@ -192,23 +192,38 @@ void blast() { int r; + int i; + int o; char ch; + char in[4096]; + char out[4096*2+1]; + int sol; - for (;;) { - r = substdio_get(&ssin,&ch,1); + for (sol = 1;;) { + r = substdio_get(&ssin,in,sizeof in); if (r == 0) break; if (r == -1) temp_read(); - if (ch == '.') - substdio_put(&smtpto,".",1); - while (ch != '\n') { - substdio_put(&smtpto,&ch,1); - r = substdio_get(&ssin,&ch,1); - if (r == 0) perm_partialline(); - if (r == -1) temp_read(); + for (i = o = 0; i < r; ) { + if (sol && in[i] == '.') { + out[o++] = '.'; + out[o++] = in[i++]; + } + sol = 0; + while (i < r) { + if (in[i] == '\n') { + sol = 1; + ++i; + out[o++] = '\r'; + out[o++] = '\n'; + break; + } + out[o++] = in[i++]; + } } - substdio_put(&smtpto,"\r\n",2); + substdio_put(&smtpto,out,o); } + if (!sol) perm_partialline(); flagcritical = 1; substdio_put(&smtpto,".\r\n",3); substdio_flush(&smtpto);