Mercurial > dnsbl
comparison src/dnsbl.cpp @ 382:c378e9d03f37
start parsing spf txt records
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Mon, 06 Mar 2017 12:21:05 -0800 |
parents | 879a470c6ac3 |
children | 7b7066a51c33 |
comparison
equal
deleted
inserted
replaced
381:879a470c6ac3 | 382:c378e9d03f37 |
---|---|
121 rates rcpt_daily_counts; // protected with rate_mutex | 121 rates rcpt_daily_counts; // protected with rate_mutex |
122 auth_addresses auth_hourly_addresses; // protected with rate_mutex | 122 auth_addresses auth_hourly_addresses; // protected with rate_mutex |
123 auth_addresses auth_daily_addresses; // protected with rate_mutex | 123 auth_addresses auth_daily_addresses; // protected with rate_mutex |
124 | 124 |
125 | 125 |
126 struct ns_map { | |
127 // all the strings are owned by the keys/values in the ns_host string map | |
128 string_map ns_host; // nameserver name -> host name that uses this name server | |
129 ns_mapper ns_ip; // nameserver name -> ipv4 address of the name server | |
130 ~ns_map(); | |
131 void add(const char *name, const char *refer); | |
132 }; | |
133 | |
134 | 126 |
135 ns_map::~ns_map() { | 127 ns_map::~ns_map() { |
136 for (string_map::iterator i=ns_host.begin(); i!=ns_host.end(); i++) { | 128 for (string_map::iterator i=ns_host.begin(); i!=ns_host.end(); i++) { |
137 const char *x = (*i).first; | 129 const char *x = (*i).first; |
138 const char *y = (*i).second; | 130 const char *y = (*i).second; |
193 } | 185 } |
194 pthread_mutex_unlock(&rate_mutex); | 186 pthread_mutex_unlock(&rate_mutex); |
195 } | 187 } |
196 | 188 |
197 | 189 |
198 void add_auth_address(const char *user, int &hourly, int &daily, int32_t ip); | 190 void add_auth_address(const char *user, int &hourly, int &daily, uint32_t ip); |
199 void add_auth_address(const char *user, int &hourly, int &daily, int32_t ip) { | 191 void add_auth_address(const char *user, int &hourly, int &daily, uint32_t ip) { |
200 pthread_mutex_lock(&rate_mutex); | 192 pthread_mutex_lock(&rate_mutex); |
201 auth_addresses::iterator i = auth_hourly_addresses.find(user); | 193 auth_addresses::iterator i = auth_hourly_addresses.find(user); |
202 if (i == auth_hourly_addresses.end()) { | 194 if (i == auth_hourly_addresses.end()) { |
203 user = strdup(user); | 195 user = strdup(user); |
204 auth_hourly_addresses[user] = new int32_t_set; | 196 auth_hourly_addresses[user] = new uint32_t_set; |
205 auth_hourly_addresses[user]->insert(ip); | 197 auth_hourly_addresses[user]->insert(ip); |
206 hourly = 1; | 198 hourly = 1; |
207 } | 199 } |
208 else { | 200 else { |
209 int32_t_set::iterator k = ((*i).second)->find(ip); | 201 uint32_t_set::iterator k = ((*i).second)->find(ip); |
210 if (k == ((*i).second)->end()) ((*i).second)->insert(ip); | 202 if (k == ((*i).second)->end()) ((*i).second)->insert(ip); |
211 hourly = ((*i).second)->size(); | 203 hourly = ((*i).second)->size(); |
212 } | 204 } |
213 | 205 |
214 auth_addresses::iterator j = auth_daily_addresses.find(user); | 206 auth_addresses::iterator j = auth_daily_addresses.find(user); |
215 if (j == auth_daily_addresses.end()) { | 207 if (j == auth_daily_addresses.end()) { |
216 user = strdup(user); | 208 user = strdup(user); |
217 auth_daily_addresses[user] = new int32_t_set; | 209 auth_daily_addresses[user] = new uint32_t_set; |
218 auth_daily_addresses[user]->insert(ip); | 210 auth_daily_addresses[user]->insert(ip); |
219 daily = 1; | 211 daily = 1; |
220 } | 212 } |
221 else { | 213 else { |
222 int32_t_set::iterator k = ((*j).second)->find(ip); | 214 uint32_t_set::iterator k = ((*j).second)->find(ip); |
223 if (k == ((*j).second)->end()) ((*j).second)->insert(ip); | 215 if (k == ((*j).second)->end()) ((*j).second)->insert(ip); |
224 daily = ((*j).second)->size(); | 216 daily = ((*j).second)->size(); |
225 } | 217 } |
226 pthread_mutex_unlock(&rate_mutex); | 218 pthread_mutex_unlock(&rate_mutex); |
227 } | 219 } |
305 // Ask a dns question and get an A record answer in network byte order. | 297 // Ask a dns question and get an A record answer in network byte order. |
306 // We don't try very hard, just using the default resolver retry settings. | 298 // We don't try very hard, just using the default resolver retry settings. |
307 // If we cannot get an answer, we just accept the mail. | 299 // If we cannot get an answer, we just accept the mail. |
308 // If the qtype is ns_t_txt, the answer is placed in txt_answer which | 300 // If the qtype is ns_t_txt, the answer is placed in txt_answer which |
309 // must be non-null, and the return value can be ignored. | 301 // must be non-null, and the return value can be ignored. |
302 // A null string is returned in txt_answer in the case of errors. | |
310 // If the qtype is ns_t_a, the ip address is returned in network byte order. | 303 // If the qtype is ns_t_a, the ip address is returned in network byte order. |
304 // IP address 0 is returned in case of errors. | |
311 // | 305 // |
312 uint32_t dns_interface(mlfiPriv &priv, const char *question, int qtype, bool maybe_ip = false, ns_map *nameservers = NULL, char *txt_answer = NULL, size_t txt_size = 0); | |
313 uint32_t dns_interface(mlfiPriv &priv, const char *question, int qtype, bool maybe_ip, ns_map *nameservers, char *txt_answer, size_t txt_size) { | 306 uint32_t dns_interface(mlfiPriv &priv, const char *question, int qtype, bool maybe_ip, ns_map *nameservers, char *txt_answer, size_t txt_size) { |
307 if (txt_answer) txt_answer[0] = '\0'; // return null string if there are no txt answers | |
308 | |
314 // tell sendmail we are still working | 309 // tell sendmail we are still working |
315 #if _FFR_SMFI_PROGRESS | 310 #if _FFR_SMFI_PROGRESS |
316 if (priv.eom) smfi_progress(priv.ctx); | 311 if (priv.eom) smfi_progress(priv.ctx); |
317 #endif | 312 #endif |
318 | 313 |
417 memcpy(&address, ns_rr_rdata(rr), sizeof(address)); | 412 memcpy(&address, ns_rr_rdata(rr), sizeof(address)); |
418 ret_address = address; | 413 ret_address = address; |
419 } | 414 } |
420 } | 415 } |
421 } | 416 } |
422 if ((qtype == ns_t_txt) && (txt_answer) && (txt_size > 5)) { | 417 if ((qtype == ns_t_txt) && (txt_answer) && (txt_size > 7)) { |
418 txt_answer[0] = '\0'; // return null string if there are no txt answers | |
423 txt_size--; // allow room for terminating null; | 419 txt_size--; // allow room for terminating null; |
424 txt_answer[0] = '\0'; // return null string if there are no answers | |
425 while (ns_parserr(&handle, ns_s_an, rrnum++, &rr) == 0) { | 420 while (ns_parserr(&handle, ns_s_an, rrnum++, &rr) == 0) { |
426 size_t offset = 0; | 421 size_t offset = 0; |
427 if (ns_rr_type(rr) == qtype) { | 422 if (ns_rr_type(rr) == qtype) { |
428 size_t rdlen = ns_rr_rdlen(rr); | 423 size_t rdlen = ns_rr_rdlen(rr); |
429 const unsigned char *rdata = ns_rr_rdata(rr); | 424 const unsigned char *rdata = ns_rr_rdata(rr); |
437 rdata += m; | 432 rdata += m; |
438 rdlen -= m; | 433 rdlen -= m; |
439 } | 434 } |
440 } | 435 } |
441 txt_answer[offset] = '\0'; // trailing null | 436 txt_answer[offset] = '\0'; // trailing null |
442 if (strcasecmp(txt_answer, "v=spf1 ") == 0) break; | 437 if (strncasecmp(txt_answer, "v=spf1 ", 7) == 0) break; |
438 } | |
439 if (strncasecmp(txt_answer, "v=spf1 ", 7) != 0) { | |
440 txt_answer[0] = '\0'; // return null string if there are no spf1 txt answers | |
443 } | 441 } |
444 } | 442 } |
445 } | 443 } |
446 pthread_mutex_unlock(&resolve_mutex); | 444 pthread_mutex_unlock(&resolve_mutex); |
447 #ifdef RESOLVER_DEBUG | 445 #ifdef RESOLVER_DEBUG |
889 if (res_result < 0) glom.length = 0; // represent all errors as zero length answers | 887 if (res_result < 0) glom.length = 0; // represent all errors as zero length answers |
890 else glom.length = (size_t)res_result; | 888 else glom.length = (size_t)res_result; |
891 #else | 889 #else |
892 glom.length = sizeof(glom.answer); | 890 glom.length = sizeof(glom.answer); |
893 glom.answer = 0; | 891 glom.answer = 0; |
894 struct hostent *host = gethostbyname(question+1); | 892 int t = int8_t(question[0]); |
895 if (host && (host->h_addrtype == AF_INET)) { | 893 if (t != ns_t_a) { |
896 memcpy(&glom.answer, host->h_addr, sizeof(glom.answer)); | 894 glom.length = 0; |
895 } | |
896 else { | |
897 struct hostent *host = gethostbyname(question+1); | |
898 if (host && (host->h_addrtype == AF_INET)) { | |
899 memcpy(&glom.answer, host->h_addr, sizeof(glom.answer)); | |
900 } | |
897 } | 901 } |
898 #endif | 902 #endif |
899 | 903 |
900 // write the answer | 904 // write the answer |
901 char *buf = (char *)&glom; | 905 char *buf = (char *)&glom; |
925 | 929 |
926 | 930 |
927 //////////////////////////////////////////////// | 931 //////////////////////////////////////////////// |
928 // check a single dns list, return ip address in network byte order | 932 // check a single dns list, return ip address in network byte order |
929 // | 933 // |
930 uint32_t check_single(mlfiPriv &priv, int32_t ip, const char *suffix); | 934 uint32_t check_single(mlfiPriv &priv, uint32_t ip, const char *suffix); |
931 uint32_t check_single(mlfiPriv &priv, int32_t ip, const char *suffix) { | 935 uint32_t check_single(mlfiPriv &priv, uint32_t ip, const char *suffix) { |
932 // make a dns question | 936 // make a dns question |
933 const u_char *src = (const u_char *)&ip; | 937 const u_char *src = (const u_char *)&ip; |
934 if (src[0] == 127) return 0; // don't do dns lookups on localhost | 938 if (src[0] == 127) return 0; // don't do dns lookups on localhost |
935 if (src[0] == 10) return 0; // don't do dns lookups on rfc1918 space | 939 if (src[0] == 10) return 0; // don't do dns lookups on rfc1918 space |
936 if ((src[0] == 192) && (src[1] == 168)) return 0; | 940 if ((src[0] == 192) && (src[1] == 168)) return 0; |
947 | 951 |
948 | 952 |
949 //////////////////////////////////////////////// | 953 //////////////////////////////////////////////// |
950 // check a single dnsbl | 954 // check a single dnsbl |
951 // | 955 // |
952 bool check_single(mlfiPriv &priv, int32_t ip, DNSBL &bl); | 956 bool check_single(mlfiPriv &priv, uint32_t ip, DNSBL &bl); |
953 bool check_single(mlfiPriv &priv, int32_t ip, DNSBL &bl) { | 957 bool check_single(mlfiPriv &priv, uint32_t ip, DNSBL &bl) { |
954 return check_single(priv, ip, bl.suffix); | 958 return check_single(priv, ip, bl.suffix); |
955 } | 959 } |
956 | 960 |
957 | 961 |
958 //////////////////////////////////////////////// | 962 //////////////////////////////////////////////// |
959 // check a single dnswl | 963 // check a single dnswl |
960 // | 964 // |
961 bool check_single(mlfiPriv &priv, int32_t ip, DNSWL &wl); | 965 bool check_single(mlfiPriv &priv, uint32_t ip, DNSWL &wl); |
962 bool check_single(mlfiPriv &priv, int32_t ip, DNSWL &wl) { | 966 bool check_single(mlfiPriv &priv, uint32_t ip, DNSWL &wl) { |
963 uint32_t r = ntohl(check_single(priv, ip, wl.suffix)); | 967 uint32_t r = ntohl(check_single(priv, ip, wl.suffix)); |
964 uint32_t v = (uint32_t)0x7f000000; | 968 uint32_t v = (uint32_t)0x7f000000; |
965 uint32_t m = (uint32_t)0xffff0000; | 969 uint32_t m = (uint32_t)0xffff0000; |
966 uint32_t m2 = (uint32_t)0x000000ff; | 970 uint32_t m2 = (uint32_t)0x000000ff; |
967 if ((r & m) == v) { | 971 if ((r & m) == v) { |
1024 | 1028 |
1025 //////////////////////////////////////////////// | 1029 //////////////////////////////////////////////// |
1026 // check the hosts from the body against the content filter and uribl dnsbls | 1030 // check the hosts from the body against the content filter and uribl dnsbls |
1027 // | 1031 // |
1028 // | 1032 // |
1029 bool check_hosts(mlfiPriv &priv, bool random, int limit, const char *&msg, const char *&host, int32_t &ip, const char *&found); | 1033 bool check_hosts(mlfiPriv &priv, bool random, int limit, const char *&msg, const char *&host, uint32_t &ip, const char *&found); |
1030 bool check_hosts(mlfiPriv &priv, bool random, int limit, const char *&msg, const char *&host, int32_t &ip, const char *&found) { | 1034 bool check_hosts(mlfiPriv &priv, bool random, int limit, const char *&msg, const char *&host, uint32_t &ip, const char *&found) { |
1031 found = NULL; // normally ip address style | 1035 found = NULL; // normally ip address style |
1032 if (!priv.content_suffix && !priv.uribl_suffix) return false; // nothing to check | 1036 if (!priv.content_suffix && !priv.uribl_suffix) return false; // nothing to check |
1033 string_set &hosts = priv.memory->get_hosts(); | 1037 string_set &hosts = priv.memory->get_hosts(); |
1034 string_set &ignore = *priv.content_host_ignore; | 1038 string_set &ignore = *priv.content_host_ignore; |
1035 | 1039 |
1036 int count = 0; | 1040 int count = 0; |
1037 int cnt = hosts.size(); // number of hosts we could look at | 1041 int cnt = hosts.size(); // number of hosts we could look at |
1038 int32_t_set ips; | 1042 uint32_t_set ips; |
1039 ns_map nameservers; | 1043 ns_map nameservers; |
1040 for (string_set::iterator i=hosts.begin(); i!=hosts.end(); i++) { | 1044 for (string_set::iterator i=hosts.begin(); i!=hosts.end(); i++) { |
1041 host = *i; // a reference into hosts, which will live until this smtp transaction is closed | 1045 host = *i; // a reference into hosts, which will live until this smtp transaction is closed |
1042 | 1046 |
1043 // don't bother looking up hosts on the ignore list | 1047 // don't bother looking up hosts on the ignore list |
1070 snprintf(buf, sizeof(buf), "host %s not found", host); | 1074 snprintf(buf, sizeof(buf), "host %s not found", host); |
1071 } | 1075 } |
1072 my_syslog(&priv, buf); | 1076 my_syslog(&priv, buf); |
1073 } | 1077 } |
1074 if (ip) { | 1078 if (ip) { |
1075 int32_t_set::iterator i = ips.find(ip); | 1079 uint32_t_set::iterator i = ips.find(ip); |
1076 if (i == ips.end()) { | 1080 if (i == ips.end()) { |
1077 // we haven't looked this up yet | 1081 // we haven't looked this up yet |
1078 ips.insert(ip); | 1082 ips.insert(ip); |
1079 // check dnsbl style list | 1083 // check dnsbl style list |
1080 if (priv.content_suffix && check_single(priv, ip, priv.content_suffix)) { | 1084 if (priv.content_suffix && check_single(priv, ip, priv.content_suffix)) { |
1108 snprintf(buf, sizeof(buf), "ns %s not found", host); | 1112 snprintf(buf, sizeof(buf), "ns %s not found", host); |
1109 } | 1113 } |
1110 my_syslog(&priv, buf); | 1114 my_syslog(&priv, buf); |
1111 } | 1115 } |
1112 if (ip) { | 1116 if (ip) { |
1113 int32_t_set::iterator i = ips.find(ip); | 1117 uint32_t_set::iterator i = ips.find(ip); |
1114 if (i == ips.end()) { | 1118 if (i == ips.end()) { |
1115 ips.insert(ip); | 1119 ips.insert(ip); |
1116 if (check_single(priv, ip, priv.content_suffix)) { | 1120 if (check_single(priv, ip, priv.content_suffix)) { |
1117 msg = priv.content_message; | 1121 msg = priv.content_message; |
1118 string_map::iterator j = nameservers.ns_host.find(host); | 1122 string_map::iterator j = nameservers.ns_host.find(host); |
1647 sfsistat mlfi_eom(SMFICTX *ctx) | 1651 sfsistat mlfi_eom(SMFICTX *ctx) |
1648 { | 1652 { |
1649 sfsistat rc; | 1653 sfsistat rc; |
1650 mlfiPriv &priv = *MLFIPRIV; | 1654 mlfiPriv &priv = *MLFIPRIV; |
1651 const char *host = NULL; | 1655 const char *host = NULL; |
1652 int32_t ip; | 1656 uint32_t ip; |
1653 // process end of message | 1657 // process end of message |
1654 priv.eom = true; | 1658 priv.eom = true; |
1655 if (priv.authenticated || priv.only_whites) rc = SMFIS_CONTINUE; | 1659 if (priv.authenticated || priv.only_whites) rc = SMFIS_CONTINUE; |
1656 else { | 1660 else { |
1657 // assert env_to not empty, it contains the | 1661 // assert env_to not empty, it contains the |
1845 for (rates::iterator i=rcpt_hourly_counts.begin(); i!=rcpt_hourly_counts.end(); i++) { | 1849 for (rates::iterator i=rcpt_hourly_counts.begin(); i!=rcpt_hourly_counts.end(); i++) { |
1846 (*i).second = 0; | 1850 (*i).second = 0; |
1847 } | 1851 } |
1848 for (auth_addresses::iterator j=auth_hourly_addresses.begin(); j!=auth_hourly_addresses.end(); j++) { | 1852 for (auth_addresses::iterator j=auth_hourly_addresses.begin(); j!=auth_hourly_addresses.end(); j++) { |
1849 delete (*j).second; | 1853 delete (*j).second; |
1850 (*j).second = new int32_t_set; | 1854 (*j).second = new uint32_t_set; |
1851 } | 1855 } |
1852 pthread_mutex_unlock(&rate_mutex); | 1856 pthread_mutex_unlock(&rate_mutex); |
1853 loop1 = 0; | 1857 loop1 = 0; |
1854 } | 1858 } |
1855 if (loop2 == 480) { | 1859 if (loop2 == 480) { |
1859 for (rates::iterator i=rcpt_daily_counts.begin(); i!=rcpt_daily_counts.end(); i++) { | 1863 for (rates::iterator i=rcpt_daily_counts.begin(); i!=rcpt_daily_counts.end(); i++) { |
1860 (*i).second = 0; | 1864 (*i).second = 0; |
1861 } | 1865 } |
1862 for (auth_addresses::iterator j=auth_daily_addresses.begin(); j!=auth_daily_addresses.end(); j++) { | 1866 for (auth_addresses::iterator j=auth_daily_addresses.begin(); j!=auth_daily_addresses.end(); j++) { |
1863 delete (*j).second; | 1867 delete (*j).second; |
1864 (*j).second = new int32_t_set; | 1868 (*j).second = new uint32_t_set; |
1865 } | 1869 } |
1866 pthread_mutex_unlock(&rate_mutex); | 1870 pthread_mutex_unlock(&rate_mutex); |
1867 loop2 = 0; | 1871 loop2 = 0; |
1868 } | 1872 } |
1869 CONFIG &dc = *config; | 1873 CONFIG &dc = *config; |