Mercurial > dnsbl
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 |