Mercurial > dnsbl
comparison src/context.cpp @ 90:962a1f8f1d9f stable-5-4
add verify statement to verify addresses with better mx host
author | carl |
---|---|
date | Sun, 18 Sep 2005 10:19:58 -0700 |
parents | 7245c45cef7a |
children | ca46fafc6621 |
comparison
equal
deleted
inserted
replaced
89:946fc1bcfb2c | 90:962a1f8f1d9f |
---|---|
5 http://www.fsf.org/licenses/gpl.txt | 5 http://www.fsf.org/licenses/gpl.txt |
6 | 6 |
7 */ | 7 */ |
8 | 8 |
9 #include "includes.h" | 9 #include "includes.h" |
10 | |
11 // needed for socket io | |
12 #include <sys/ioctl.h> | |
13 #include <net/if.h> | |
14 #include <arpa/inet.h> | |
15 #include <netinet/in.h> | |
16 #include <netinet/tcp.h> | |
17 #include <netdb.h> | |
18 #include <sys/socket.h> | |
19 #include <sys/un.h> | |
10 | 20 |
11 static char* context_version="$Id$"; | 21 static char* context_version="$Id$"; |
12 | 22 |
13 char *token_black; | 23 char *token_black; |
14 char *token_content; | 24 char *token_content; |
38 char *token_semi; | 48 char *token_semi; |
39 char *token_soft; | 49 char *token_soft; |
40 char *token_substitute; | 50 char *token_substitute; |
41 char *token_tld; | 51 char *token_tld; |
42 char *token_unknown; | 52 char *token_unknown; |
53 char *token_verify; | |
43 char *token_white; | 54 char *token_white; |
44 | 55 |
45 string_set all_strings; // owns all the strings, only modified by the config loader thread | 56 char *token_myhostname; |
46 const int maxlen = 1000; | 57 char myhostname[HOST_NAME_MAX+1]; |
58 | |
59 verify_map verifiers; | |
60 string_set all_strings; // owns all the strings, only modified by the config loader thread | |
61 const int maxlen = 1000; // used for snprintf buffers | |
62 const int maxage = 120; // smtp verify sockets older than this are ancient | |
63 extern int NULL_SOCKET; | |
64 extern time_t ERROR_SOCKET_TIME; // number of seconds between attempts to open a socket an smtp host for address verification | |
65 | |
66 | |
67 int SMTP::writer() { | |
68 // log("writer() sees buffer with %s", buffer); | |
69 // log("writer() sees error %d", (int)error); | |
70 int rs = 0; | |
71 if (!error) { | |
72 int len = strlen(buffer); | |
73 while (rs < len) { | |
74 int ws = write(fd, buffer+rs, len-rs); | |
75 if (ws > 0) { | |
76 rs += ws; | |
77 } | |
78 else { | |
79 // peer closed the socket! | |
80 rs = 0; | |
81 error = true; | |
82 break; | |
83 } | |
84 } | |
85 } | |
86 return rs; | |
87 } | |
88 | |
89 | |
90 int SMTP::reader() { | |
91 // read some bytes terminated by lf or end of buffer. | |
92 // we may have a multi line response or part thereof in the buffer. | |
93 // log("reader() sees error %d", (int)error); | |
94 if (error) return 0; | |
95 int len = maxlen-1; // room for null terminator | |
96 while (pending < len) { | |
97 int ws = read(fd, buffer+pending, len-pending); | |
98 if (ws > 0) { | |
99 pending += ws; | |
100 if (buffer[pending-1] == '\n') break; | |
101 } | |
102 else { | |
103 // peer closed the socket! | |
104 pending = 0; | |
105 error = true; | |
106 break; | |
107 } | |
108 } | |
109 buffer[pending] = '\0'; | |
110 // log("reader() sees buffer with %s", buffer); | |
111 return pending; | |
112 } | |
113 | |
114 | |
115 int SMTP::read_line() { | |
116 char *lf = strchr(buffer, '\n'); | |
117 if (!lf) { | |
118 reader(); // get a lf | |
119 lf = strchr(buffer, '\n'); | |
120 if (!lf) lf = buffer + pending - 1; | |
121 } | |
122 return (lf-buffer)+1; // number of bytes in this line | |
123 } | |
124 | |
125 | |
126 int SMTP::flush_line(int r) { | |
127 if (pending > r) memmove(buffer, buffer+r, pending-r); | |
128 pending -= r; | |
129 } | |
130 | |
131 | |
132 int SMTP::read_response() { | |
133 pending = 0; | |
134 buffer[pending] = '\0'; | |
135 while (true) { | |
136 int r = read_line(); | |
137 // log("read_response() sees line with %s", buffer); | |
138 // log("read_response() sees line length %d", r); | |
139 if (r == 0) return 0; // failed to read any bytes | |
140 if ((r > 4) && (buffer[3] == '-')) { | |
141 flush_line(r); | |
142 continue; | |
143 } | |
144 return atoi(buffer); | |
145 } | |
146 return 0; | |
147 } | |
148 | |
149 | |
150 int SMTP::cmd(char *c) { | |
151 if (c) { | |
152 init(); | |
153 append(c); | |
154 } | |
155 append("\r\n"); | |
156 writer(); | |
157 return read_response(); | |
158 } | |
159 | |
160 | |
161 int SMTP::helo() { | |
162 if (read_response() != 220) return 0; | |
163 init(); | |
164 append("HELO "); | |
165 append(token_myhostname); | |
166 return cmd(NULL); | |
167 } | |
168 | |
169 | |
170 int SMTP::rset() { | |
171 return cmd("RSET"); | |
172 } | |
173 | |
174 | |
175 int SMTP::from(char *f) { | |
176 init(); | |
177 append("MAIL FROM:<"); | |
178 append(f); | |
179 append(">"); | |
180 return cmd(NULL); | |
181 } | |
182 | |
183 | |
184 int SMTP::rcpt(char *t) { | |
185 init(); | |
186 append("RCPT TO:<"); | |
187 append(t); | |
188 append(">"); | |
189 return cmd(NULL); | |
190 } | |
191 | |
192 | |
193 int SMTP::quit() { | |
194 int rc = cmd("QUIT"); | |
195 shutdown(fd, SHUT_RDWR); | |
196 close(fd); | |
197 return rc; | |
198 } | |
199 | |
200 | |
201 // void SMTP::log(char *m, int v) { | |
202 // char buf[maxlen]; | |
203 // snprintf(buf, maxlen, m, v); | |
204 // my_syslog(buf); | |
205 // } | |
206 // | |
207 // | |
208 // void SMTP::log(char *m, char *v) { | |
209 // char buf[maxlen]; | |
210 // snprintf(buf, maxlen, m, v); | |
211 // my_syslog(buf); | |
212 // } | |
213 // | |
214 // | |
215 VERIFY::VERIFY(char *h) { | |
216 host = h; | |
217 last_err = 0; | |
218 pthread_mutex_init(&mutex, 0); | |
219 } | |
220 | |
221 | |
222 void VERIFY::closer() { | |
223 bool ok = true; | |
224 while (ok) { | |
225 int fd = 0; | |
226 pthread_mutex_lock(&mutex); | |
227 if (sockets.empty()) { | |
228 ok = false; | |
229 } | |
230 else { | |
231 time_t t = times.front(); | |
232 time_t now = time(NULL); | |
233 if ((now - t) > maxage) { | |
234 // this socket is ancient, remove it | |
235 fd = sockets.front(); | |
236 times.pop_front(); | |
237 sockets.pop_front(); | |
238 } | |
239 else { | |
240 ok = false; | |
241 } | |
242 } | |
243 pthread_mutex_unlock(&mutex); | |
244 if (fd) { | |
245 SMTP s(fd); | |
246 s.quit(); // closes the fd | |
247 // s.log("closer() closes ancient %d", fd); | |
248 } | |
249 } | |
250 } | |
251 | |
252 | |
253 int VERIFY::get_socket() { | |
254 int sock = NULL_SOCKET; | |
255 pthread_mutex_lock(&mutex); | |
256 if (!sockets.empty()) { | |
257 sock = sockets.front(); | |
258 times.pop_front(); | |
259 sockets.pop_front(); | |
260 // SMTP::log("get_socket() %d from cache", sock); | |
261 } | |
262 pthread_mutex_unlock(&mutex); | |
263 | |
264 if (sock == NULL_SOCKET) { | |
265 time_t now = time(NULL); | |
266 if ((now - last_err) > ERROR_SOCKET_TIME) { | |
267 // nothing recent, maybe this time it will work | |
268 hostent *h = gethostbyname(host); | |
269 if (h) { | |
270 sockaddr_in server; | |
271 server.sin_family = h->h_addrtype; | |
272 server.sin_port = htons(25); | |
273 memcpy(&server.sin_addr, h->h_addr_list[0], h->h_length); | |
274 sock = socket(PF_INET, SOCK_STREAM, 0); | |
275 if (sock != NULL_SOCKET) { | |
276 bool rc = (connect(sock, (sockaddr *)&server, sizeof(server)) == 0); | |
277 if (!rc) { | |
278 shutdown(sock, SHUT_RDWR); | |
279 close(sock); | |
280 sock = NULL_SOCKET; | |
281 last_err = now; | |
282 } | |
283 } | |
284 else last_err = now; | |
285 } | |
286 else last_err = now; | |
287 } | |
288 if (sock != NULL_SOCKET) { | |
289 SMTP s(sock); | |
290 if (s.helo() != 250) { | |
291 put_socket(sock, true); | |
292 sock = NULL_SOCKET; | |
293 } | |
294 } | |
295 } | |
296 return sock; | |
297 } | |
298 | |
299 | |
300 void VERIFY::put_socket(int fd, bool err) { | |
301 if (err) { | |
302 // SMTP::log("put_socket() %d with error, close it", fd); | |
303 shutdown(fd, SHUT_RDWR); | |
304 close(fd); | |
305 last_err = time(NULL); | |
306 } | |
307 else { | |
308 // SMTP::log("put_socket() %d", fd); | |
309 pthread_mutex_lock(&mutex); | |
310 time_t now = time(NULL); | |
311 times.push_back(now); | |
312 sockets.push_back(fd); | |
313 pthread_mutex_unlock(&mutex); | |
314 } | |
315 } | |
316 | |
317 | |
318 bool VERIFY::ok(char *from, char *to) { | |
319 if (host == token_myhostname) return true; | |
320 int fd = get_socket(); | |
321 if (fd == NULL_SOCKET) return true; // cannot verify right now, we have socket errors | |
322 SMTP s(fd); | |
323 s.rset(); | |
324 int rc; | |
325 rc = s.from(from); | |
326 // s.log("verify::ok from sees %d", rc); | |
327 if (rc != 250) { | |
328 put_socket(fd, s.err()); | |
329 return (rc >= 500) ? false : true; | |
330 } | |
331 rc = s.rcpt(to); | |
332 // s.log("verify::ok rcpt sees %d", rc); | |
333 put_socket(fd, s.err()); | |
334 return (rc >= 500) ? false : true; | |
335 } | |
336 | |
47 | 337 |
48 DNSBL::DNSBL(char *n, char *s, char *m) { | 338 DNSBL::DNSBL(char *n, char *s, char *m) { |
49 name = n; | 339 name = n; |
50 suffix = s; | 340 suffix = s; |
51 message = m; | 341 message = m; |
153 | 443 |
154 | 444 |
155 CONTEXT::CONTEXT(CONTEXTP parent_, char *name_) { | 445 CONTEXT::CONTEXT(CONTEXTP parent_, char *name_) { |
156 parent = parent_; | 446 parent = parent_; |
157 name = name_; | 447 name = name_; |
448 verify_host = NULL; | |
158 env_from_default = (parent) ? token_inherit : token_unknown; | 449 env_from_default = (parent) ? token_inherit : token_unknown; |
159 content_filtering = (parent) ? parent->content_filtering : false; | 450 content_filtering = (parent) ? parent->content_filtering : false; |
160 content_suffix = NULL; | 451 content_suffix = NULL; |
161 content_message = NULL; | 452 content_message = NULL; |
162 host_limit = (parent) ? parent->host_limit : 0; | 453 host_limit = (parent) ? parent->host_limit : 0; |
198 else x = to; | 489 else x = to; |
199 if (*x == '\0') return true; // always allow covering addresses with no domain name, eg abuse@ | 490 if (*x == '\0') return true; // always allow covering addresses with no domain name, eg abuse@ |
200 string_set::iterator i = env_to.find(x); | 491 string_set::iterator i = env_to.find(x); |
201 if (i != env_to.end()) return true; | 492 if (i != env_to.end()) return true; |
202 return false; | 493 return false; |
494 } | |
495 | |
496 | |
497 VERIFYP CONTEXT::find_verify(char *to) { | |
498 if (verify_host && (verify_host != token_myhostname) && cover_env_to(to)) { | |
499 verify_map::iterator i = verifiers.find(verify_host); | |
500 if (i == verifiers.end()) { | |
501 if (debug_syslog) { | |
502 char buf[maxlen]; | |
503 snprintf(buf, maxlen, "cannot find struc for %s", verify_host); | |
504 my_syslog(buf); | |
505 } | |
506 return NULL; | |
507 } | |
508 VERIFYP v = (*i).second; | |
509 | |
510 return v; | |
511 } | |
512 else if (parent) return parent->find_verify(to); | |
513 else return NULL; | |
203 } | 514 } |
204 | 515 |
205 | 516 |
206 char *CONTEXT::find_from(char *from) { | 517 char *CONTEXT::find_from(char *from) { |
207 char *rc = token_inherit; | 518 char *rc = token_inherit; |
387 for (string_set::iterator i=env_to.begin(); i!=env_to.end(); i++) { | 698 for (string_set::iterator i=env_to.begin(); i!=env_to.end(); i++) { |
388 printf("%s %s; \n", indent, *i); | 699 printf("%s %s; \n", indent, *i); |
389 } | 700 } |
390 printf("%s }; \n", indent); | 701 printf("%s }; \n", indent); |
391 | 702 |
703 if (verify_host) { | |
704 printf("%s verify %s; \n", indent, verify_host); | |
705 } | |
706 | |
392 for (context_map::iterator i=children.begin(); i!=children.end(); i++) { | 707 for (context_map::iterator i=children.begin(); i!=children.end(); i++) { |
393 CONTEXTP c = (*i).second; | 708 CONTEXTP c = (*i).second; |
394 c->dump(level+1); | 709 c->dump(level+1); |
395 } | 710 } |
396 | 711 |
680 } | 995 } |
681 | 996 |
682 | 997 |
683 //////////////////////////////////////////////// | 998 //////////////////////////////////////////////// |
684 // | 999 // |
1000 bool parse_verify(TOKEN &tok, CONFIG &dc, CONTEXT &me); | |
1001 bool parse_verify(TOKEN &tok, CONFIG &dc, CONTEXT &me) { | |
1002 char *host = tok.next(); | |
1003 if (!tsa(tok, token_semi)) return false; | |
1004 me.set_verify(host); | |
1005 add_verify_host(host); | |
1006 } | |
1007 | |
1008 | |
1009 //////////////////////////////////////////////// | |
1010 // | |
685 bool parse_envfrom(TOKEN &tok, CONFIG &dc, CONTEXT &me); | 1011 bool parse_envfrom(TOKEN &tok, CONFIG &dc, CONTEXT &me); |
686 bool parse_envfrom(TOKEN &tok, CONFIG &dc, CONTEXT &me) { | 1012 bool parse_envfrom(TOKEN &tok, CONFIG &dc, CONTEXT &me) { |
687 char *st = tok.next(); | 1013 char *st = tok.next(); |
688 if ((st == token_black) || (st == token_white) || (st == token_unknown) || (st == token_inherit)) { | 1014 if ((st == token_black) || (st == token_white) || (st == token_unknown) || (st == token_inherit)) { |
689 me.set_from_default(st); | 1015 me.set_from_default(st); |
780 if (!parse_content(tok, dc, *con)) return false; | 1106 if (!parse_content(tok, dc, *con)) return false; |
781 } | 1107 } |
782 else if (have == token_envto) { | 1108 else if (have == token_envto) { |
783 if (!parse_envto(tok, dc, *con)) return false; | 1109 if (!parse_envto(tok, dc, *con)) return false; |
784 } | 1110 } |
1111 else if (have == token_verify) { | |
1112 if (!parse_verify(tok, dc, *con)) return false; | |
1113 } | |
785 else if (have == token_envfrom) { | 1114 else if (have == token_envfrom) { |
786 if (!parse_envfrom(tok, dc, *con)) return false; | 1115 if (!parse_envfrom(tok, dc, *con)) return false; |
787 } | 1116 } |
788 else if (have == token_context) { | 1117 else if (have == token_context) { |
789 if (!parse_context(tok, dc, con)) return false; | 1118 if (!parse_context(tok, dc, con)) return false; |
821 tok.token_error(token_context, have); | 1150 tok.token_error(token_context, have); |
822 return false; | 1151 return false; |
823 } | 1152 } |
824 } | 1153 } |
825 return (dc.default_context) ? true : false; | 1154 return (dc.default_context) ? true : false; |
1155 } | |
1156 | |
1157 | |
1158 //////////////////////////////////////////////// | |
1159 // setup a new smtp verify host | |
1160 // | |
1161 void add_verify_host(char *host) { | |
1162 verify_map::iterator i = verifiers.find(host); | |
1163 if (i == verifiers.end()) { | |
1164 VERIFYP v = new VERIFY(host); | |
1165 verifiers[host] = v; | |
1166 } | |
1167 } | |
1168 | |
1169 | |
1170 //////////////////////////////////////////////// | |
1171 // thread to check for verify hosts with old sockets that we can close | |
1172 // | |
1173 void* verify_closer(void *arg) { | |
1174 while (true) { | |
1175 sleep(maxage); | |
1176 for (verify_map::iterator i=verifiers.begin(); i!=verifiers.end(); i++) { | |
1177 VERIFYP v = (*i).second; | |
1178 v->closer(); | |
1179 } | |
1180 } | |
1181 return NULL; | |
826 } | 1182 } |
827 | 1183 |
828 | 1184 |
829 //////////////////////////////////////////////// | 1185 //////////////////////////////////////////////// |
830 // init the tokens | 1186 // init the tokens |
858 token_semi = register_string(";"); | 1214 token_semi = register_string(";"); |
859 token_soft = register_string("soft"); | 1215 token_soft = register_string("soft"); |
860 token_substitute = register_string("substitute"); | 1216 token_substitute = register_string("substitute"); |
861 token_tld = register_string("tld"); | 1217 token_tld = register_string("tld"); |
862 token_unknown = register_string("unknown"); | 1218 token_unknown = register_string("unknown"); |
1219 token_verify = register_string("verify"); | |
863 token_white = register_string("white"); | 1220 token_white = register_string("white"); |
864 } | 1221 |
1222 if (gethostname(myhostname, HOST_NAME_MAX+1) != 0) { | |
1223 strncpy(myhostname, "localhost", HOST_NAME_MAX+1); | |
1224 } | |
1225 myhostname[HOST_NAME_MAX] = '\0'; // ensure null termination | |
1226 token_myhostname = register_string(myhostname); | |
1227 } |