1 /*
2 Copyright (c) 2006 Morettoni Luca <luca@morettoni.net>
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8 1. Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13
14 THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 SUCH DAMAGE.
25
26 $Id: qmail-rblchk.c,v 1.8 2006/01/24 08:17:24 luca Exp $
27
28 NOTE: functions ``buffer_copy, maildir_child and wait_pid'' plus all external
29 file (like dns.h and more) are developed by Dr. Dan Bernstein and are
30 free to use in the public domain.
31 */
32
33 #include <unistd.h>
34 #include <signal.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <sys/wait.h>
38 #include "alloc.h"
39 #include "dns.h"
40 #include "str.h"
41 #include "stralloc.h"
42 #include "buffer.h"
43 #include "ip4.h"
44 #include "byte.h"
45 #include "strerr.h"
46 #include "error.h"
47 #include "sgetopt.h"
48 #include "fmt.h"
49 #include "open.h"
50 #include "scan.h"
51 #include "timestamp.h"
52 #include "cdb.h"
53
54 static char seed[128];
55 struct rbl_entry {
56 char *server;
57 int txt;
58 int rev;
59 int otc;
60 } rbl[32];
61
62 char skipip[64];
63 int iptoskip = 0;
64 unsigned long ignore = 0;
65 int rblnum = 0;
66 int scan_all = 0;
67 int cond_redir = 0;
68 int verbose = 0;
69 int quiet = 0;
70 int tagspam = 0;
71 char *delivery = NULL;
72 char *cdbrules = NULL;
73 stralloc why = {0};
74 buffer *buffer_log;
75
76 char fntmptph[80 + FMT_ULONG * 2];
77 char fnnewtph[80 + FMT_ULONG * 2];
tryunlinktmp()78 void tryunlinktmp() { unlink (fntmptph); }
sigalrm()79 void sigalrm() { tryunlinktmp (); _exit(3); }
80
81 #define TEMP_FAIL 111
82 #define EXIT_OK (cond_redir ? 1 : 0)
83 #define EXIT_SPAM (cond_redir ? 0 : (delivery ? 99 : 100))
84 #define FATAL "qmail-rblchk: fatal: "
85 #define BUF_LEN 1024
86 #define VERSION "qmail-rblchk 2.4.1"
87 #define AUTHOR "Luca Morettoni <luca@morettoni.net>"
88
do_log(void)89 void do_log (void)
90 {
91 char ts[TIMESTAMP];
92 char s[FMT_ULONG];
93 static pid_t pid = 0;
94
95 if (!pid) pid = getpid();
96
97 timestamp (ts);
98 buffer_put (buffer_log, ts, TIMESTAMP);
99 buffer_puts (buffer_log, " ");
100 buffer_put (buffer_log, s, fmt_ulong (s,pid));
101 buffer_puts (buffer_log, " ");
102 }
103
nomem(void)104 void nomem (void)
105 {
106 strerr_die2x(111,FATAL,"out of memory");
107 }
108
nocdb(void)109 void nocdb (void)
110 {
111 strerr_die4sys(111,FATAL,"unable to read ",cdbrules,": ");
112 }
113
usage(void)114 void usage (void)
115 {
116 buffer_puts (buffer_2, "qmail-rblchk: usage: qmail-rblchk [opz] [dir]\n\n");
117 buffer_puts (buffer_2, " options may be:\n");
118 buffer_puts (buffer_2, " -h this screen\n");
119 buffer_puts (buffer_2, " -s add X-Spam header into the incoming mail (work only with delivery ``dir'')\n");
120 buffer_puts (buffer_2, " -c turn on condredirect compatibility mode\n");
121 buffer_puts (buffer_2, " -i NUM ignore first ``NUM'' IPs found in the header\n");
122 buffer_puts (buffer_2, " -x IP do not check ``IP'', try to find other address in header\n");
123 buffer_puts (buffer_2, " -v verbose (debug) mode\n");
124 buffer_puts (buffer_2, " -V show program version\n");
125 buffer_puts (buffer_2, " -q quiet mode (suppress any output)\n");
126 buffer_puts (buffer_2, " -p don't check private IP class:\n");
127 buffer_puts (buffer_2, " 127.0.0.0 - 127.255.255.255\n");
128 buffer_puts (buffer_2, " 10.0.0.0 - 10.255.255.255\n");
129 buffer_puts (buffer_2, " 172.16.0.0 - 172.31.255.255\n");
130 buffer_puts (buffer_2, " 192.168.0.0 - 192.168.255.255\n");
131 buffer_puts (buffer_2, " -m check all IPs in email (default: check only first IP)\n");
132 buffer_puts (buffer_2, " -l log write program action to ``log'' file\n");
133 buffer_puts (buffer_2, " -L data write blocked IP to ``data'' file\n");
134 buffer_puts (buffer_2, " -r addr use ``addr'' for RBL checking (if TXT record exist block mail)\n");
135 buffer_puts (buffer_2, " -R addr use ``addr'' for RBL reverted checking (if TXT record NOT exist block mail)\n");
136 buffer_puts (buffer_2, " -C addr use ``addr'' for one time RBL checking (if TXT or A record exist don't block mail)\n");
137 buffer_puts (buffer_2, " -a addr use ``addr'' for anti-RBL checking (if A record NOT exist block mail)\n");
138 buffer_puts (buffer_2, " -A addr use ``addr'' for anti-RBL reverted checking (if A record exist block mail)\n");
139 buffer_puts (buffer_2, " -X cdb check IP from tcpserver-style ``cdb'' file (IP:deny block mail from that IP)\n");
140
141 buffer_puts (buffer_2, "\nYou must specify one or more (max 32) RBL address, example:\n");
142 buffer_puts (buffer_2, " qmail-rblchk -r dnsbl.sorbs.net -r sbl-xbl.spamhaus.org -r relays.ordb.org\n\n");
143 buffer_puts (buffer_2, "You can ignore (-x option) no more than 16 IP address\n\n");
144 buffer_puts (buffer_2, "If ``dir'' is given in command line and it exist all blocked mails are delivered\n");
145 buffer_puts (buffer_2, "into Maildir ``dir'' (dir must start with a / or a . and end with a /);\n");
146 buffer_puts (buffer_2, "the program run in ``delivery mode''.\n");
147
148 buffer_puts (buffer_2, "\nThe program exit status may be (normal mode):\n");
149 buffer_puts (buffer_2, " 0 when the message is not blocked\n");
150 buffer_puts (buffer_2, " 100 when the message is blocked\n");
151 buffer_puts (buffer_2, " 111 when fails or no checking options was given\n");
152 buffer_puts (buffer_2, "In ``delivery mode'':\n");
153 buffer_puts (buffer_2, " 0 the message is not blocked (continue .qmail checking)\n");
154 buffer_puts (buffer_2, " 99 the blocked message has been wrote to ``dir'' Maildir\n");
155 buffer_puts (buffer_2, " 111 same as above\n");
156 buffer_puts (buffer_2, "In ``condredirect compatibility mode'':\n");
157 buffer_puts (buffer_2, " 0 when the message is blocked\n");
158 buffer_puts (buffer_2, " 1 when the message is not blocked\n");
159 buffer_puts (buffer_2, " 111 same as above\n");
160
161 buffer_flush (buffer_2);
162
163 _exit (TEMP_FAIL);
164 }
165
docheck(struct cdb * c,stralloc * ip)166 int docheck (struct cdb *c, stralloc *ip)
167 {
168 char *data;
169 unsigned int datalen;
170 int ret = -1; /* not found, try again! */
171
172 switch (cdb_find (c, ip->s, ip->len)) {
173 case -1: nocdb ();
174 case 0: return -1;
175 }
176
177 datalen = cdb_datalen(c);
178 data = alloc(datalen);
179 if (!data) nomem ();
180 if (cdb_read (c,data,datalen,cdb_datapos (c)) == -1) {
181 alloc_free(data);
182 nocdb ();
183 }
184
185 switch (data[0]) {
186 case 'D': ret = 1; break; /* deny */
187 default: ret = 0; break; /* allow */
188 }
189
190 alloc_free(data);
191
192 return ret;
193 }
194
check_cdb(char ip[4])195 int check_cdb (char ip[4])
196 {
197 int fd;
198 struct cdb c;
199 char ip_fmt[IP4_FMT];
200 stralloc ipcdb = {0};
201 int ret = -1; /* default: NOT found in CDB file */
202
203 ip4_fmt (ip_fmt, ip);
204
205 fd = open_read (cdbrules);
206 if (fd == -1)
207 nocdb ();
208 else {
209 cdb_init(&c,fd);
210 if (!stralloc_copyb (&ipcdb, ip_fmt, ip4_fmt (ip_fmt, ip))) nomem ();
211
212 if (verbose) {
213 do_log ();
214 buffer_puts (buffer_log, "checking: ");
215 buffer_put (buffer_log, ipcdb.s, ipcdb.len);
216 buffer_puts (buffer_log, " into ");
217 buffer_puts (buffer_log, cdbrules);
218 buffer_puts (buffer_log, "\n");
219 buffer_flush (buffer_log);
220 }
221
222 /* check all octets */
223 ret = docheck (&c, &ipcdb);
224 while (ipcdb.len > 0 && ret == -1) {
225 /* delete right octect and try again */
226 if (ip_fmt[ipcdb.len - 1] == '.')
227 ret = docheck (&c, &ipcdb);
228 --ipcdb.len;
229 }
230 /* if no match, we see the defaul rule in the file */
231 if (ret == -1) ret = docheck (&c, &ipcdb);
232
233 cdb_free(&c);
234 close (fd);
235
236 if (verbose) {
237 do_log ();
238 stralloc_copyb (&ipcdb, ip_fmt, ip4_fmt (ip_fmt, ip));
239 buffer_put (buffer_log, ipcdb.s, ipcdb.len);
240 switch (ret) {
241 case -1: buffer_puts (buffer_log, " not listed"); break;
242 case 0: buffer_puts (buffer_log, " allowed"); break;
243 case 1: buffer_puts (buffer_log, " blocked"); break;
244 }
245 buffer_puts (buffer_log, "\n");
246 buffer_flush (buffer_log);
247 }
248
249 if (ret == 1) {
250 stralloc_copyb (&why, ip_fmt, ip4_fmt (ip_fmt, ip));
251 stralloc_cats (&why, " is blocked (deny) in ");
252 stralloc_cats (&why, cdbrules);
253 }
254 }
255
256 return ret;
257 }
258
check_ip(char ip[4])259 int check_ip (char ip[4])
260 {
261 stralloc check = {0};
262 stralloc out = {0};
263 char ip_fmt[IP4_FMT];
264 char rev[4];
265 int i;
266 char s[FMT_ULONG];
267
268 for (i = 0; i < 4; i++) rev[i] = ip[3-i];
269
270 for (i = 0; i < rblnum; i++) {
271 stralloc_copyb (&check,ip_fmt, ip4_fmt (ip_fmt, rev));
272 stralloc_cats (&check, ".");
273 stralloc_cats (&check, rbl[i].server);
274
275 if (verbose) {
276 do_log ();
277 if (rbl[i].otc) buffer_puts (buffer_log, "one time ");
278 buffer_puts (buffer_log, "checking: ");
279 buffer_put (buffer_log, check.s, check.len);
280 buffer_puts (buffer_log, "\n");
281 buffer_flush (buffer_log);
282 }
283
284 if ((!rbl[i].txt || rbl[i].otc) && dns_ip4 (&out, &check) != -1) {
285 if (verbose) {
286 do_log ();
287 if (out.len) {
288 buffer_puts (buffer_log, "list #");
289 buffer_put (buffer_log, s, fmt_ulong (s,i+1));
290 buffer_puts (buffer_log, ", A record: ");
291 buffer_put (buffer_log, ip_fmt, ip4_fmt (ip_fmt, out.s));
292 buffer_puts (buffer_log, "\n");
293 } else {
294 buffer_put (buffer_log, ip_fmt, ip4_fmt (ip_fmt, ip));
295 buffer_puts (buffer_log, " no A record\n");
296 }
297 buffer_flush (buffer_log);
298 }
299
300 if (out.len && !rbl[i].rev) {
301 stralloc_copyb (&why, ip_fmt, ip4_fmt (ip_fmt, ip));
302 stralloc_cats (&why, " is listed in ");
303 stralloc_cats (&why, rbl[i].server);
304 return (rbl[i].otc ? 0 : 1);
305 }
306
307 if (!out.len && rbl[i].rev && !rbl[i].otc) {
308 stralloc_copyb (&why, ip_fmt, ip4_fmt (ip_fmt, ip));
309 stralloc_cats (&why, " is NOT listed in ");
310 stralloc_cats (&why, rbl[i].server);
311 return 1;
312 }
313 }
314
315 if ((rbl[i].txt || rbl[i].otc) && dns_txt (&out, &check) != -1) {
316 if (verbose) {
317 do_log ();
318 if (out.len) {
319 buffer_puts (buffer_log, "list #");
320 buffer_put (buffer_log, s, fmt_ulong (s,i+1));
321 buffer_puts (buffer_log, ", TXT record: ");
322 buffer_put (buffer_log, out.s, out.len);
323 buffer_puts (buffer_log, "\n");
324 } else {
325 buffer_put (buffer_log, ip_fmt, ip4_fmt (ip_fmt, ip));
326 buffer_puts (buffer_log, " no TXT record\n");
327 }
328 buffer_flush (buffer_log);
329 }
330
331 if (out.len && !rbl[i].rev) {
332 stralloc_copy (&why, &out);
333 return (rbl[i].otc ? 0 : 1);
334 }
335
336 if (!out.len && rbl[i].rev) {
337 stralloc_copys (&why, "No TXTs for ");
338 stralloc_catb (&why, ip_fmt, ip4_fmt (ip_fmt, ip));
339 return 1;
340 }
341 }
342 }
343
344 return 0;
345 }
346
347 /* child process */
buffer_copy(ssout,ssin)348 int buffer_copy(ssout,ssin)
349 register buffer *ssout;
350 register buffer *ssin;
351 {
352 register int n;
353 register char *x;
354 stralloc tag = {0};
355
356 if (tagspam) {
357 stralloc_copys (&tag, "X-Spam: yes\n");
358 if (buffer_put(ssout,tag.s,tag.len) == -1) return -3;
359
360 stralloc_copys (&tag, "X-Spam-Status: ");
361 stralloc_cat (&tag, &why);
362 stralloc_cats (&tag, "\n");
363 if (buffer_put(ssout,tag.s,tag.len) == -1) return -3;
364
365 stralloc_copys (&tag, "X-Spam-Version: ");
366 stralloc_cats (&tag, VERSION);
367 stralloc_cats (&tag, "\n");
368 if (buffer_put(ssout,tag.s,tag.len) == -1) return -3;
369 }
370
371 for (;;) {
372 n = buffer_feed(ssin);
373 if (n < 0) return -2;
374 if (!n) return 0;
375 x = buffer_PEEK(ssin);
376 if (buffer_put(ssout,x,n) == -1) return -3;
377 buffer_SEEK(ssin,n);
378 }
379 }
380
maildir_child(dir)381 void maildir_child(dir)
382 char *dir;
383 {
384 unsigned long pid;
385 unsigned long now;
386 char host[64];
387 char *s;
388 int loop;
389 struct stat st;
390 int fd;
391 char buf[BUF_LEN];
392 char outbuf[BUF_LEN];
393 buffer ss;
394 buffer ssout;
395
396 signal (SIGALRM,sigalrm);
397 if (chdir(dir) == -1) { if (error_temp(errno)) _exit(1); _exit(2); }
398 pid = getpid();
399 host[0] = 0;
400 gethostname(host,sizeof(host));
401 for (loop = 0;;++loop)
402 {
403 now = time(0);
404 s = fntmptph;
405 s += fmt_str(s,"tmp/");
406 s += fmt_ulong(s,now); *s++ = '.';
407 s += fmt_ulong(s,pid); *s++ = '.';
408 s += fmt_strn(s,host,sizeof(host)); *s++ = 0;
409 if (stat(fntmptph,&st) == -1) if (errno == error_noent) break;
410 /* really should never get to this point */
411 if (loop == 2) _exit(1);
412 sleep(2);
413 }
414 str_copy(fnnewtph,fntmptph);
415 byte_copy(fnnewtph,3,"new");
416
417 alarm(86400);
418 fd = open_excl(fntmptph);
419 if (fd == -1) _exit(1);
420
421 buffer_init (&ss,read,0,buf,sizeof(buf));
422 buffer_init (&ssout,write,fd,outbuf,sizeof(outbuf));
423
424 switch(buffer_copy(&ssout,&ss))
425 {
426 case -2: tryunlinktmp(); _exit(4);
427 case -3: goto fail;
428 }
429
430 if (buffer_flush(&ssout) == -1) goto fail;
431 if (fsync(fd) == -1) goto fail;
432 if (close(fd) == -1) goto fail; /* NFS dorks */
433
434 if (link(fntmptph,fnnewtph) == -1) goto fail;
435 /* if it was error_exist, almost certainly successful; i hate NFS */
436 tryunlinktmp(); _exit(0);
437
438 fail: tryunlinktmp(); _exit(1);
439 }
440
441 /* end child process */
wait_pid(wstat,pid)442 int wait_pid(wstat,pid) int *wstat; int pid;
443 {
444 int r;
445
446 do
447 r = waitpid(pid,wstat,0);
448 while ((r == -1) && (errno == error_intr));
449 return r;
450 }
451
ip4_equal(const char * ip1,const char * ip2)452 int ip4_equal (const char *ip1, const char *ip2)
453 {
454 register char i;
455
456 for (i = 0; i < 4; i++)
457 if (*(ip1+i) != *(ip2+i)) return 0;
458
459 return 1;
460 }
461
ip4_isprivate(const unsigned char * ip)462 int ip4_isprivate (const unsigned char *ip)
463 {
464 /* 127.0.0.0 - 127.255.255.255 */
465 if (*ip == 127) return 1;
466
467 /* 10.0.0.0 - 10.255.255.255 */
468 if (*ip == 10) return 1;
469
470 /* 172.16.0.0 - 172.31.255.255 */
471 if (*ip == 172 && (*(ip+1) >> 4 == 1)) return 1;
472
473 /* 192.168.0.0 - 192.168.255.255 */
474 if (*ip == 192 && *(ip+1) == 168) return 1;
475
476 return 0;
477 }
478
main(int argc,char * argv[])479 int main (int argc, char* argv[])
480 {
481 char ip[4];
482 stralloc partial = {0};
483 stralloc out = {0};
484 char ip_fmt[IP4_FMT];
485 char line[BUF_LEN];
486 char s[FMT_ULONG];
487 int r, i, j;
488 int inbuflen = 0;
489 int flag0 = 1;
490 int opt;
491 int block = 0;
492 int skip_priv = 0;
493 int list = 0;
494 int child;
495 int wstat;
496 buffer ssout;
497 buffer sslist;
498 int fd = 0;
499 int fdlist = 0;
500 char outbuf[BUF_LEN];
501 char outlist[BUF_LEN];
502
503 buffer_log = buffer_2;
504
505 while ((opt = getopt (argc, argv, "a:A:cC:hi:l:L:mpqr:R:svVx:X:")) != opteof)
506 switch(opt) {
507 case 'a':
508 case 'A':
509 case 'C':
510 rbl[rblnum].server = optarg;
511 rbl[rblnum].txt = 0;
512 rbl[rblnum].rev = (opt == 'a');
513 rbl[rblnum].otc = (opt == 'C');
514
515 if (rblnum < 32-1) rblnum++;
516 break;
517 case 'c':
518 cond_redir = 1;
519 break;
520 case 'i':
521 scan_ulong (optarg, &ignore);
522 if (ignore < 1) ignore = 1;
523 if (ignore > 10) ignore = 10;
524 scan_all = 1;
525 break;
526 case 'l':
527 verbose = 1;
528 fd = open_append(optarg);
529 if (fd == -1)
530 strerr_die4sys (111,FATAL,"unable to write ",optarg,": ");
531 buffer_init (&ssout,write,fd,outbuf,sizeof(outbuf));
532 buffer_log = &ssout;
533 break;
534 case 'L':
535 list = 1;
536 fdlist = open_append(optarg);
537 if (fdlist == -1)
538 strerr_die4sys (111,FATAL,"unable to write ",optarg,": ");
539 buffer_init (&sslist,write,fdlist,outlist,sizeof(outlist));
540 break;
541 case 'm':
542 scan_all = 1;
543 break;
544 case 'p':
545 skip_priv = 1;
546 break;
547 case 'q':
548 quiet = 1;
549 verbose = 0;
550 break;
551 case 'r':
552 case 'R':
553 rbl[rblnum].server = optarg;
554 rbl[rblnum].txt = 1;
555 rbl[rblnum].rev = (opt == 'R');
556 rbl[rblnum].otc = 0;
557
558 if (rblnum < 32-1) rblnum++;
559 break;
560 case 's':
561 tagspam = 1;
562 break;
563 case 'v':
564 verbose = 1;
565 break;
566 case 'V':
567 buffer_puts (buffer_2, VERSION); buffer_puts (buffer_2, " - ");
568 buffer_puts (buffer_2, AUTHOR); buffer_puts (buffer_2, "\n");
569 buffer_flush (buffer_2);
570 _exit (TEMP_FAIL);
571 break;
572 case 'x':
573 if (iptoskip < 16)
574 if (ip4_scan (optarg, skipip+(iptoskip*4)))
575 iptoskip++;
576 else
577 strerr_die3x (111, FATAL, "unable to parse IP ", optarg);
578 break;
579 case 'X':
580 cdbrules = optarg;
581 break;
582 case 'h':
583 default:
584 usage ();
585 }
586
587 argc -= optind;
588 argv += optind;
589
590 /* set verbose mode if we want to log */
591 if (fd) verbose = 1;
592
593 if (!rblnum && !cdbrules)
594 strerr_die2x (111, FATAL, "you must supply one or more RLB list address or a CDB rule file");
595
596 /* check if a delivery dir was given */
597 if (argc > 0) {
598 cond_redir = 0;
599 delivery = argv[0];
600
601 if ((*delivery != '.' && *delivery != '/') || *(delivery+str_len (delivery)-1) != '/')
602 strerr_die2x (111, FATAL, "spam delivery path must start with . or / and end with /.");
603 }
604
605 dns_random_init(seed);
606
607 if (!stralloc_copys (&partial, "")) nomem ();
608
609 while (flag0 || inbuflen || partial.len) {
610 if (flag0)
611 if (inbuflen < sizeof line) {
612 r = read (0, line+inbuflen, sizeof line-inbuflen);
613
614 if (r <= 0)
615 flag0 = 0;
616 else
617 inbuflen += r;
618 }
619
620 while (flag0) {
621 i = byte_chr (line, inbuflen, '\n');
622 if (inbuflen && (i == inbuflen)) {
623 if (!stralloc_catb (&partial, line, inbuflen)) nomem ();
624 inbuflen = 0;
625 continue;
626 }
627
628 if ((i < inbuflen) || (!flag0 && partial.len)) {
629 if (i < inbuflen) ++i;
630 if (!stralloc_catb (&partial, line, i)) nomem ();
631
632 inbuflen -= i;
633 for (j = 0; j < inbuflen; ++j) line[j] = line[j + i];
634
635 /* end of header */
636 if (partial.len == 1) {
637 inbuflen = partial.len = flag0 = 0;
638 break;
639 }
640
641 if (partial.len && flag0) {
642 if (verbose) {
643 do_log ();
644 buffer_puts (buffer_log, "header: ");
645 buffer_put (buffer_log, partial.s, partial.len);
646 buffer_flush (buffer_log);
647 }
648
649 if (str_start (partial.s, "Received: from ")) {
650 /* OLD SCAN MODE
651 for (j = 15; flag0 && j < partial.len-8; j++) {
652 OLD SCAN MODE */
653 for (j = str_rchr (partial.s, '(')+1; flag0 && j; j--) {
654 i = ip4_scan (partial.s+j, ip);
655 if (i) {
656 /* skip listed IP */
657 for (r = 0; r < iptoskip; r++)
658 if (ip4_equal(ip, skipip+r*4)) {
659 j += i-1;
660 i = 0;
661
662 if (verbose) {
663 do_log ();
664 buffer_puts (buffer_log, "skip IP: ");
665 stralloc_copyb (&out,ip_fmt, ip4_fmt (ip_fmt, ip));
666 buffer_put (buffer_log, out.s, out.len);
667 buffer_puts (buffer_log, "\n");
668 }
669 }
670
671 /* skip private IP */
672 if (skip_priv && ip4_isprivate (ip)) {
673 j += i-1;
674 i = 0;
675 if (verbose) {
676 do_log ();
677 buffer_puts (buffer_log, "skip private IP: ");
678 stralloc_copyb (&out,ip_fmt, ip4_fmt (ip_fmt, ip));
679 buffer_put (buffer_log, out.s, out.len);
680 buffer_puts (buffer_log, "\n");
681 }
682 }
683
684 /* now we can check... */
685 if (i) {
686 if (!ignore) {
687 if (cdbrules) {
688 block = check_cdb (ip);
689 if (block == -1) block = check_ip (ip);
690 } else
691 block = check_ip (ip);
692 } else
693 ignore--;
694
695 j += i-1;
696
697 if (!scan_all)
698 flag0 = 0;
699 else if (block)
700 flag0 = 0;
701
702 if (!flag0) inbuflen = 0;
703 }
704 }
705 }
706 }
707 }
708
709 partial.len = 0;
710 continue;
711 }
712
713 break;
714 }
715 }
716
717 if (block) {
718 /* append blocked IP to the list */
719 if (list) {
720 stralloc_copyb (&out,ip_fmt, ip4_fmt (ip_fmt, ip));
721 buffer_put (&sslist, out.s, out.len);
722 buffer_puts (&sslist, "\n");
723 buffer_flush (&sslist);
724 }
725
726 /* report why we block into qmail-send logs */
727 if (!quiet) {
728 if (delivery) {
729 buffer_puts (buffer_2, "qmail-rblchk[spam]: writing to ");
730 buffer_puts (buffer_2, delivery);
731 buffer_puts (buffer_2, "\n");
732 } else {
733 buffer_puts (buffer_2, "qmail-rblchk[spam]: ");
734 buffer_put (buffer_2, why.s, why.len);
735 buffer_puts (buffer_2, "\n");
736 }
737 buffer_flush (buffer_2);
738 }
739
740 if (delivery) {
741 if (verbose) {
742 do_log ();
743 buffer_puts (buffer_log, "spam, writing to ");
744 buffer_puts (buffer_log, delivery);
745 buffer_puts (buffer_log, "\n");
746 buffer_flush (buffer_log);
747 }
748
749 /* write spam to spam maildir */
750 if (lseek (0, 0, SEEK_SET) == -1)
751 strerr_die1x (111, "Unable to rewind message. (#4.3.0)");
752
753 switch (child = fork ()) {
754 case -1:
755 break;
756 case 0:
757 maildir_child (delivery);
758 _exit(111);
759 }
760
761 wait_pid (&wstat, child);
762 if (wstat & 127)
763 strerr_die1x(111,"Aack, child crashed. (#4.3.0)");
764
765 switch ((wstat >> 8)) {
766 case 0: break;
767 case 2: strerr_die1x(111,"Unable to chdir to maildir. (#4.2.1)");
768 case 3: strerr_die1x(111,"Timeout on maildir delivery. (#4.3.0)");
769 case 4: strerr_die1x(111,"Unable to read message. (#4.3.0)");
770 default: strerr_die1x(111,"Temporary error on maildir delivery. (#4.3.0)");
771 }
772 } else {
773 if (verbose) {
774 do_log ();
775 buffer_puts (buffer_log, "spam, exit code: ");
776 buffer_put (buffer_log, s, fmt_ulong (s,(block ? EXIT_SPAM : EXIT_OK)));
777 buffer_puts (buffer_log, "\n");
778 buffer_flush (buffer_log);
779 }
780 }
781 } else {
782 if (verbose) {
783 do_log ();
784 buffer_puts (buffer_log, "ok, default delivery\n");
785 }
786 }
787
788 buffer_flush (buffer_log);
789 if (fd) {
790 fsync(fd);
791 close(fd);
792 }
793
794 if (fdlist) {
795 fsync(fdlist);
796 close(fdlist);
797 }
798
799 _exit (block ? EXIT_SPAM : EXIT_OK);
800 }
801