comparison src/dnsbl.cpp @ 34:fc7f8f3ea90f

look for NS records on the SBL also
author carl
date Sun, 30 May 2004 16:17:44 -0700
parents 4dfdf33f1db0
children d718dca81bc9
comparison
equal deleted inserted replaced
33:ce229348cdbe 34:fc7f8f3ea90f
20 rejected if it is sent. 20 rejected if it is sent.
21 21
22 2) Add config for poison addresses. If any recipient is poison, all 22 2) Add config for poison addresses. If any recipient is poison, all
23 recipients are rejected even if they would be whitelisted, and the 23 recipients are rejected even if they would be whitelisted, and the
24 data is rejected if sent. 24 data is rejected if sent.
25
26 3) Add option to only allow one recipient if the return path is empty.
25 27
26 */ 28 */
27 29
28 30
29 // from sendmail sample 31 // from sendmail sample
111 typedef map<char *, string_map *, ltstr> from_map; 113 typedef map<char *, string_map *, ltstr> from_map;
112 typedef map<char *, DNSBLP, ltstr> dnsblp_map; 114 typedef map<char *, DNSBLP, ltstr> dnsblp_map;
113 typedef map<char *, DNSBLLP, ltstr> dnsbllp_map; 115 typedef map<char *, DNSBLLP, ltstr> dnsbllp_map;
114 typedef set<char *, ltstr> string_set; 116 typedef set<char *, ltstr> string_set;
115 typedef list<char *> string_list; 117 typedef list<char *> string_list;
118 typedef map<char *, int, ltstr> ns_map;
116 119
117 struct CONFIG { 120 struct CONFIG {
118 // the only mutable stuff once it has been loaded from the config file 121 // the only mutable stuff once it has been loaded from the config file
119 int reference_count; // protected by the global config_mutex 122 int reference_count; // protected by the global config_mutex
120 // all the rest is constant after loading from the config file 123 // all the rest is constant after loading from the config file
176 static pthread_mutex_t syslog_mutex; 179 static pthread_mutex_t syslog_mutex;
177 static pthread_mutex_t resolve_mutex; 180 static pthread_mutex_t resolve_mutex;
178 181
179 182
180 //////////////////////////////////////////////// 183 ////////////////////////////////////////////////
184 // helper to discard the strings and objects held by an ns_map
185 //
186 static void discard(ns_map &s);
187 static void discard(ns_map &s) {
188 for (ns_map::iterator i=s.begin(); i!=s.end(); i++) {
189 char *x = (*i).first;
190 free(x);
191 }
192 s.clear();
193 }
194
195 ////////////////////////////////////////////////
196 // helper to register a string in an ns_map
197 //
198 static void register_string(ns_map &s, char *name);
199 static void register_string(ns_map &s, char *name) {
200 ns_map::iterator i = s.find(name);
201 if (i != s.end()) return;
202 char *x = strdup(name);
203 s[x] = 0;
204 }
205
206 ////////////////////////////////////////////////
181 // helper to discard the strings held by a string_set 207 // helper to discard the strings held by a string_set
182 // 208 //
183 static void discard(string_set &s); 209 static void discard(string_set &s);
184 static void discard(string_set &s) { 210 static void discard(string_set &s) {
185 for (string_set::iterator i=s.begin(); i!=s.end(); i++) { 211 for (string_set::iterator i=s.begin(); i!=s.end(); i++) {
377 // very hard, just using the default resolver retry settings. 403 // very hard, just using the default resolver retry settings.
378 // If we cannot get an answer, we just accept the mail. The 404 // If we cannot get an answer, we just accept the mail. The
379 // caller must ensure thread safety. 405 // caller must ensure thread safety.
380 // 406 //
381 // 407 //
382 static int dns_interface(char *question, bool maybe_ip); 408 static int dns_interface(char *question, bool maybe_ip, ns_map *nameservers);
383 static int dns_interface(char *question, bool maybe_ip) { 409 static int dns_interface(char *question, bool maybe_ip, ns_map *nameservers) {
384 #ifdef NS_PACKETSZ 410 #ifdef NS_PACKETSZ
385 u_char answer[NS_PACKETSZ]; 411 u_char answer[NS_PACKETSZ];
386 int length = res_search(question, ns_c_in, ns_t_a, answer, sizeof(answer)); 412 int length = res_search(question, ns_c_in, ns_t_a, answer, sizeof(answer));
387 if (length >= 0) { // no error yet 413 if (length >= 0) { // no error yet
388 // parse the answer 414 // parse the answer
389 ns_msg handle; 415 ns_msg handle;
390 ns_rr rr; 416 ns_rr rr;
391 if (ns_initparse(answer, length, &handle) == 0) { 417 if (ns_initparse(answer, length, &handle) == 0) {
418 // look for ns names
419 if (nameservers) {
420 ns_map &ns = *nameservers;
421 int rrnum = 0;
422 while (ns_parserr(&handle, ns_s_ns, rrnum++, &rr) == 0) {
423 if (ns_rr_type(rr) == ns_t_ns) {
424 char nam[NS_MAXDNAME+1];
425 char *n = nam;
426 const u_char *p = ns_rr_rdata(rr);
427 while (((n-nam) < NS_MAXDNAME) && ((p-answer) < length) && *p) {
428 size_t s = *(p++);
429 if (s > 191) {
430 // compression pointer
431 s = (s-192)*256 + *(p++);
432 if (s >= length) break; // pointer outside bounds of answer
433 p = answer + s;
434 s = *(p++);
435 }
436 if (s > 0) {
437 if ((n-nam) >= (NS_MAXDNAME-s)) break; // destination would overflow name buffer
438 if ((p-answer) >= (length-s)) break; // source outside bounds of answer
439 memcpy(n, p, s);
440 n += s;
441 p += s;
442 *(n++) = '.';
443 }
444 }
445 *(--n) = '\0'; // remove trailing .
446 register_string(ns, nam); // ns host to lookup later
447 }
448 }
449 rrnum = 0;
450 while (ns_parserr(&handle, ns_s_ar, rrnum++, &rr) == 0) {
451 if (ns_rr_type(rr) == ns_t_a) {
452 char* nam = (char*)ns_rr_name(rr);
453 ns_map::iterator i = ns.find(nam);
454 if (i != ns.end()) {
455 // we want this ip address
456 int address;
457 memcpy(&address, ns_rr_rdata(rr), sizeof(address));
458 ns[nam] = address;
459 }
460 }
461 }
462 }
392 int rrnum = 0; 463 int rrnum = 0;
393 while (ns_parserr(&handle, ns_s_an, rrnum++, &rr) == 0) { 464 while (ns_parserr(&handle, ns_s_an, rrnum++, &rr) == 0) {
394 if (ns_rr_type(rr) == ns_t_a) { 465 if (ns_rr_type(rr) == ns_t_a) {
395 int address; 466 int address;
396 memcpy(&address, ns_rr_rdata(rr), sizeof(address)); 467 memcpy(&address, ns_rr_rdata(rr), sizeof(address));
415 memcpy(&address, host->h_addr, sizeof(address)); 486 memcpy(&address, host->h_addr, sizeof(address));
416 return address; 487 return address;
417 #endif 488 #endif
418 } 489 }
419 490
420 static int protected_dns_interface(char *question, bool maybe_ip); 491 static int protected_dns_interface(char *question, bool maybe_ip, ns_map *nameservers);
421 static int protected_dns_interface(char *question, bool maybe_ip) { 492 static int protected_dns_interface(char *question, bool maybe_ip, ns_map *nameservers) {
422 int ans; 493 int ans;
423 pthread_mutex_lock(&resolve_mutex); 494 pthread_mutex_lock(&resolve_mutex);
424 ans = dns_interface(question, maybe_ip); 495 ans = dns_interface(question, maybe_ip, nameservers);
425 pthread_mutex_unlock(&resolve_mutex); 496 pthread_mutex_unlock(&resolve_mutex);
426 return ans; 497 return ans;
427 498
428 } 499 }
429 500
440 #else 511 #else
441 char question[1000]; 512 char question[1000];
442 #endif 513 #endif
443 snprintf(question, sizeof(question), "%u.%u.%u.%u.%s.", src[3], src[2], src[1], src[0], suffix); 514 snprintf(question, sizeof(question), "%u.%u.%u.%u.%s.", src[3], src[2], src[1], src[0], suffix);
444 // ask the question, if we get an A record it implies a blacklisted ip address 515 // ask the question, if we get an A record it implies a blacklisted ip address
445 return (protected_dns_interface(question, false)) ? reject : oksofar; 516 return (protected_dns_interface(question, false, NULL)) ? reject : oksofar;
446 } 517 }
447 518
448 519
449 //////////////////////////////////////////////// 520 ////////////////////////////////////////////////
450 // check a single dnsbl 521 // check a single dnsbl
489 static status check_hosts(mlfiPriv &priv, char *&host, int &ip); 560 static status check_hosts(mlfiPriv &priv, char *&host, int &ip);
490 static status check_hosts(mlfiPriv &priv, char *&host, int &ip) { 561 static status check_hosts(mlfiPriv &priv, char *&host, int &ip) {
491 CONFIG &dc = *priv.pc; 562 CONFIG &dc = *priv.pc;
492 if (!dc.content_suffix) return oksofar; 563 if (!dc.content_suffix) return oksofar;
493 int count = 0; 564 int count = 0;
565 ns_map nameservers;
566 int lim = priv.pc->host_limit;
494 for (string_set::iterator i=priv.memory->hosts.begin(); i!=priv.memory->hosts.end(); i++) { 567 for (string_set::iterator i=priv.memory->hosts.begin(); i!=priv.memory->hosts.end(); i++) {
495 count++; 568 count++;
496 int lim = priv.pc->host_limit; 569 if ((count > lim) && (lim > 0)) {
497 if ((count > lim) && (lim > 0)) return reject_host; 570 discard(nameservers);
571 return reject_host;
572 }
498 host = *i; 573 host = *i;
499 ip = protected_dns_interface(host, true); 574 ip = protected_dns_interface(host, true, &nameservers);
500 if (debug_syslog) { 575 if (debug_syslog) {
501 char buf[200]; 576 char buf[200];
502 if (ip) { 577 if (ip) {
503 char adr[sizeof "255.255.255.255"]; 578 char adr[sizeof "255.255.255.255"];
504 adr[0] = '\0'; 579 adr[0] = '\0';
510 } 585 }
511 my_syslog(buf); 586 my_syslog(buf);
512 } 587 }
513 if (ip) { 588 if (ip) {
514 status st = check_single(ip, dc.content_suffix); 589 status st = check_single(ip, dc.content_suffix);
515 if (st == reject) return st; 590 if (st == reject) {
516 } 591 discard(nameservers);
517 } 592 return st;
593 }
594 }
595 }
596 lim *= 4; // allow average of 3 ns per host name
597 for (ns_map::iterator i=nameservers.begin(); i!=nameservers.end(); i++) {
598 count++;
599 if ((count > lim) && (lim > 0)) {
600 discard(nameservers);
601 return reject_host;
602 }
603 host = (*i).first;
604 ip = (*i).second;
605 if (!ip) ip = protected_dns_interface(host, false, NULL);
606 if (debug_syslog) {
607 char buf[200];
608 if (ip) {
609 char adr[sizeof "255.255.255.255"];
610 adr[0] = '\0';
611 inet_ntop(AF_INET, (const u_char *)&ip, adr, sizeof(adr));
612 snprintf(buf, sizeof(buf), "ns %s found at %s", host, adr);
613 }
614 else {
615 snprintf(buf, sizeof(buf), "ns %s not found", host);
616 }
617 my_syslog(buf);
618 }
619 if (ip) {
620 status st = check_single(ip, dc.content_suffix);
621 if (st == reject) {
622 discard(nameservers);
623 return st;
624 }
625 }
626 }
627 discard(nameservers);
518 host = NULL; 628 host = NULL;
519 int bin = priv.memory->binary_tags; 629 int bin = priv.memory->binary_tags;
520 int bad = priv.memory->bad_html_tags; 630 int bad = priv.memory->bad_html_tags;
521 int lim = priv.pc->tag_limit; 631 lim = priv.pc->tag_limit;
522 if (bin > bad) return oksofar; // probably .zip or .tar.gz with random content 632 if (bin > bad) return oksofar; // probably .zip or .tar.gz with random content
523 if ((bad > lim) && (lim > 0)) return reject_tag; 633 if ((bad > lim) && (lim > 0)) return reject_tag;
524 return oksofar; 634 return oksofar;
525 } 635 }
526 636