Mercurial > dnsbl
comparison src/dnsbl.cpp @ 89:946fc1bcfb2c stable-5-3
don't load null config pointer, keep the old one
author | carl |
---|---|
date | Sun, 07 Aug 2005 11:26:37 -0700 |
parents | c1280cd3e248 |
children | 962a1f8f1d9f |
comparison
equal
deleted
inserted
replaced
88:7245c45cef7a | 89:946fc1bcfb2c |
---|---|
3 Copyright (c) 2004, 2005 Carl Byington - 510 Software Group, released | 3 Copyright (c) 2004, 2005 Carl Byington - 510 Software Group, released |
4 under the GPL version 2 or any later version at your choice available at | 4 under the GPL version 2 or any later version at your choice available at |
5 http://www.fsf.org/licenses/gpl.txt | 5 http://www.fsf.org/licenses/gpl.txt |
6 | 6 |
7 Based on a sample milter Copyright (c) 2000-2003 Sendmail, Inc. and its | 7 Based on a sample milter Copyright (c) 2000-2003 Sendmail, Inc. and its |
8 suppliers. Inspired by the DCC by Rhyolite Software | 8 suppliers. Inspired by the DCC by Rhyolite Software |
9 | 9 |
10 -r port The port used to talk to our internal dns resolver processes | 10 -r port The port used to talk to our internal dns resolver processes |
11 -p port The port through which the MTA will connect to this milter. | 11 -p port The port through which the MTA will connect to this milter. |
12 -t sec The timeout value. | 12 -t sec The timeout value. |
13 -c Check the config, and print a copy to stdout. Don't start the | 13 -c Check the config, and print a copy to stdout. Don't start the |
14 milter or do anything with the socket. | 14 milter or do anything with the socket. |
15 -s Stress test by loading and deleting the current config in a loop. | 15 -s Stress test by loading and deleting the current config in a loop. |
16 -d increase debug level | 16 -d increase debug level |
17 -e f|t Print the results of looking up from address f and to address | 17 -e f|t Print the results of looking up from address f and to address |
18 t in the current config | 18 t in the current config |
19 | 19 |
20 | 20 |
21 TODO: | 21 TODO: |
22 | 22 |
23 1) Add option for using smtp connections to verify addresses from backup | 23 1) Add option for using smtp connections to verify addresses from backup |
59 | 59 |
60 // misc stuff needed here | 60 // misc stuff needed here |
61 #include <ctype.h> | 61 #include <ctype.h> |
62 #include <syslog.h> | 62 #include <syslog.h> |
63 #include <pwd.h> | 63 #include <pwd.h> |
64 #include <sys/wait.h> /* header for waitpid() and various macros */ | 64 #include <sys/wait.h> /* header for waitpid() and various macros */ |
65 #include <signal.h> /* header for signal functions */ | 65 #include <signal.h> /* header for signal functions */ |
66 | 66 |
67 #include "includes.h" | 67 #include "includes.h" |
68 | 68 |
69 static char* dnsbl_version="$Id$"; | 69 static char* dnsbl_version="$Id$"; |
70 | 70 |
71 | 71 |
72 extern "C" { | 72 extern "C" { |
73 #include "libmilter/mfapi.h" | 73 #include "libmilter/mfapi.h" |
74 sfsistat mlfi_connect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr); | 74 sfsistat mlfi_connect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr); |
75 sfsistat mlfi_envfrom(SMFICTX *ctx, char **argv); | 75 sfsistat mlfi_envfrom(SMFICTX *ctx, char **argv); |
76 sfsistat mlfi_envrcpt(SMFICTX *ctx, char **argv); | 76 sfsistat mlfi_envrcpt(SMFICTX *ctx, char **argv); |
77 sfsistat mlfi_body(SMFICTX *ctx, u_char *data, size_t len); | 77 sfsistat mlfi_body(SMFICTX *ctx, u_char *data, size_t len); |
78 sfsistat mlfi_eom(SMFICTX *ctx); | 78 sfsistat mlfi_eom(SMFICTX *ctx); |
79 sfsistat mlfi_abort(SMFICTX *ctx); | 79 sfsistat mlfi_abort(SMFICTX *ctx); |
80 sfsistat mlfi_close(SMFICTX *ctx); | 80 sfsistat mlfi_close(SMFICTX *ctx); |
81 void sig_chld(int signo); | 81 void sig_chld(int signo); |
82 } | 82 } |
83 | 83 |
84 int debug_syslog = 0; | 84 int debug_syslog = 0; |
85 bool syslog_opened = false; | 85 bool syslog_opened = false; |
86 bool use_syslog = true; // false to printf | 86 bool use_syslog = true; // false to printf |
87 bool loader_run = true; // used to stop the config loader thread | 87 bool loader_run = true; // used to stop the config loader thread |
88 CONFIG *config = NULL; // protected by the config_mutex | 88 CONFIG *config = NULL; // protected by the config_mutex |
89 int generation = 0; // protected by the config_mutex | 89 int generation = 0; // protected by the config_mutex |
90 const int maxlen = 1000; // used for snprintf buffers | 90 const int maxlen = 1000; // used for snprintf buffers |
91 | 91 |
92 pthread_mutex_t config_mutex; | 92 pthread_mutex_t config_mutex; |
93 pthread_mutex_t syslog_mutex; | 93 pthread_mutex_t syslog_mutex; |
94 pthread_mutex_t resolve_mutex; | 94 pthread_mutex_t resolve_mutex; |
95 pthread_mutex_t fd_pool_mutex; | 95 pthread_mutex_t fd_pool_mutex; |
96 | 96 |
97 std::set<int> fd_pool; | 97 std::set<int> fd_pool; |
98 int NULL_SOCKET = -1; | 98 int NULL_SOCKET = -1; |
99 char *resolver_port = NULL; // unix domain socket to talk to the dns resolver process | 99 char *resolver_port = NULL; // unix domain socket to talk to the dns resolver process |
100 int resolver_socket = NULL_SOCKET; // socket used to listen for resolver requests | 100 int resolver_socket = NULL_SOCKET; // socket used to listen for resolver requests |
101 time_t ERROR_SOCKET_TIME = 60; // number of seconds between attempts to open the spam filter socket | 101 time_t ERROR_SOCKET_TIME = 60; // number of seconds between attempts to open the spam filter socket |
102 time_t last_error_time; | 102 time_t last_error_time; |
103 int resolver_sock_count = 0; // protected with fd_pool_mutex | 103 int resolver_sock_count = 0; // protected with fd_pool_mutex |
104 int resolver_pool_size = 0; // protected with fd_pool_mutex | 104 int resolver_pool_size = 0; // protected with fd_pool_mutex |
105 | 105 |
106 | 106 |
107 struct ns_map { | 107 struct ns_map { |
108 // all the strings are owned by the keys/values in the ns_host string map | 108 // all the strings are owned by the keys/values in the ns_host string map |
109 string_map ns_host; // nameserver name -> host name that uses this name server | 109 string_map ns_host; // nameserver name -> host name that uses this name server |
110 ns_mapper ns_ip; // nameserver name -> ip address of the name server | 110 ns_mapper ns_ip; // nameserver name -> ip address of the name server |
111 ~ns_map(); | 111 ~ns_map(); |
112 void add(char *name, char *refer); | 112 void add(char *name, char *refer); |
113 }; | 113 }; |
114 | 114 |
115 | 115 |
116 ns_map::~ns_map() { | 116 ns_map::~ns_map() { |
117 for (string_map::iterator i=ns_host.begin(); i!=ns_host.end(); i++) { | 117 for (string_map::iterator i=ns_host.begin(); i!=ns_host.end(); i++) { |
118 char *x = (*i).first; | 118 char *x = (*i).first; |
119 char *y = (*i).second; | 119 char *y = (*i).second; |
120 free(x); | 120 free(x); |
121 free(y); | 121 free(y); |
122 } | 122 } |
123 ns_ip.clear(); | 123 ns_ip.clear(); |
124 ns_host.clear(); | 124 ns_host.clear(); |
125 } | 125 } |
126 | 126 |
127 | 127 |
128 void ns_map::add(char *name, char *refer) { | 128 void ns_map::add(char *name, char *refer) { |
129 string_map::iterator i = ns_host.find(name); | 129 string_map::iterator i = ns_host.find(name); |
130 if (i != ns_host.end()) return; | 130 if (i != ns_host.end()) return; |
131 char *x = strdup(name); | 131 char *x = strdup(name); |
132 char *y = strdup(refer); | 132 char *y = strdup(refer); |
133 ns_ip[x] = 0; | 133 ns_ip[x] = 0; |
134 ns_host[x] = y; | 134 ns_host[x] = y; |
135 | 135 |
136 } | 136 } |
137 | 137 |
138 // packed structure to allow a single socket write to dump the | 138 // packed structure to allow a single socket write to dump the |
139 // length and the following answer. The packing attribute is gcc specific. | 139 // length and the following answer. The packing attribute is gcc specific. |
140 struct glommer { | 140 struct glommer { |
141 int length; | 141 int length; |
142 #ifdef NS_PACKETSZ | 142 #ifdef NS_PACKETSZ |
143 u_char answer[NS_PACKETSZ]; // with a resolver, we return resolver answers | 143 u_char answer[NS_PACKETSZ]; // with a resolver, we return resolver answers |
144 #else | 144 #else |
145 int answer; // without a resolver, we return a single ip4 address, 0 == no answer | 145 int answer; // without a resolver, we return a single ip4 address, 0 == no answer |
146 #endif | 146 #endif |
147 } __attribute__ ((packed)); | 147 } __attribute__ ((packed)); |
148 | 148 |
149 | 149 |
150 //////////////////////////////////////////////// | 150 //////////////////////////////////////////////// |
151 // helper to discard the strings held by a context_map | 151 // helper to discard the strings held by a context_map |
152 // | 152 // |
153 void discard(context_map &cm); | 153 void discard(context_map &cm); |
154 void discard(context_map &cm) { | 154 void discard(context_map &cm) { |
155 for (context_map::iterator i=cm.begin(); i!=cm.end(); i++) { | 155 for (context_map::iterator i=cm.begin(); i!=cm.end(); i++) { |
156 char *x = (*i).first; | 156 char *x = (*i).first; |
157 free(x); | 157 free(x); |
158 } | 158 } |
159 cm.clear(); | 159 cm.clear(); |
160 } | 160 } |
161 | 161 |
162 | 162 |
163 //////////////////////////////////////////////// | 163 //////////////////////////////////////////////// |
164 // helper to register a string in a context_map | 164 // helper to register a string in a context_map |
165 // | 165 // |
166 void register_string(context_map &cm, char *name, CONTEXT *con); | 166 void register_string(context_map &cm, char *name, CONTEXT *con); |
167 void register_string(context_map &cm, char *name, CONTEXT *con) { | 167 void register_string(context_map &cm, char *name, CONTEXT *con) { |
168 context_map::iterator i = cm.find(name); | 168 context_map::iterator i = cm.find(name); |
169 if (i != cm.end()) return; | 169 if (i != cm.end()) return; |
170 char *x = strdup(name); | 170 char *x = strdup(name); |
171 cm[x] = con; | 171 cm[x] = con; |
172 } | 172 } |
173 | 173 |
174 | 174 |
175 //////////////////////////////////////////////// | 175 //////////////////////////////////////////////// |
176 // disconnect the fd from the dns resolver process | 176 // disconnect the fd from the dns resolver process |
177 // | 177 // |
178 void my_disconnect(int sock, bool decrement = true); | 178 void my_disconnect(int sock, bool decrement = true); |
179 void my_disconnect(int sock, bool decrement) { | 179 void my_disconnect(int sock, bool decrement) { |
180 if (sock != NULL_SOCKET) { | 180 if (sock != NULL_SOCKET) { |
181 if (decrement) { | 181 if (decrement) { |
182 pthread_mutex_lock(&fd_pool_mutex); | 182 pthread_mutex_lock(&fd_pool_mutex); |
183 resolver_sock_count--; | 183 resolver_sock_count--; |
184 pthread_mutex_unlock(&fd_pool_mutex); | 184 pthread_mutex_unlock(&fd_pool_mutex); |
185 } | 185 } |
186 shutdown(sock, SHUT_RDWR); | 186 shutdown(sock, SHUT_RDWR); |
187 close(sock); | 187 close(sock); |
188 } | 188 } |
189 } | 189 } |
190 | 190 |
191 | 191 |
192 //////////////////////////////////////////////// | 192 //////////////////////////////////////////////// |
193 // return fd connected to the dns resolver process | 193 // return fd connected to the dns resolver process |
194 // | 194 // |
195 int my_connect(); | 195 int my_connect(); |
196 int my_connect() { | 196 int my_connect() { |
197 // if we have had recent errors, don't even try to open the socket | 197 // if we have had recent errors, don't even try to open the socket |
198 time_t now = time(NULL); | 198 time_t now = time(NULL); |
199 if ((now - last_error_time) < ERROR_SOCKET_TIME) return NULL_SOCKET; | 199 if ((now - last_error_time) < ERROR_SOCKET_TIME) return NULL_SOCKET; |
200 | 200 |
201 // nothing recent, maybe this time it will work | 201 // nothing recent, maybe this time it will work |
202 int sock = NULL_SOCKET; | 202 int sock = NULL_SOCKET; |
203 sockaddr_un server; | 203 sockaddr_un server; |
204 memset(&server, '\0', sizeof(server)); | 204 memset(&server, '\0', sizeof(server)); |
205 server.sun_family = AF_UNIX; | 205 server.sun_family = AF_UNIX; |
206 strncpy(server.sun_path, resolver_port, sizeof(server.sun_path)-1); | 206 strncpy(server.sun_path, resolver_port, sizeof(server.sun_path)-1); |
207 sock = socket(AF_UNIX, SOCK_STREAM, 0); | 207 sock = socket(AF_UNIX, SOCK_STREAM, 0); |
208 if (sock != NULL_SOCKET) { | 208 if (sock != NULL_SOCKET) { |
209 bool rc = (connect(sock, (sockaddr *)&server, sizeof(server)) == 0); | 209 bool rc = (connect(sock, (sockaddr *)&server, sizeof(server)) == 0); |
210 if (!rc) { | 210 if (!rc) { |
211 my_disconnect(sock, false); | 211 my_disconnect(sock, false); |
212 sock = NULL_SOCKET; | 212 sock = NULL_SOCKET; |
213 last_error_time = now; | 213 last_error_time = now; |
214 } | 214 } |
215 } | 215 } |
216 else last_error_time = now; | 216 else last_error_time = now; |
217 if (sock != NULL_SOCKET) { | 217 if (sock != NULL_SOCKET) { |
218 pthread_mutex_lock(&fd_pool_mutex); | 218 pthread_mutex_lock(&fd_pool_mutex); |
219 resolver_sock_count++; | 219 resolver_sock_count++; |
220 pthread_mutex_unlock(&fd_pool_mutex); | 220 pthread_mutex_unlock(&fd_pool_mutex); |
221 } | 221 } |
222 return sock; | 222 return sock; |
223 } | 223 } |
224 | 224 |
225 | 225 |
226 mlfiPriv::mlfiPriv() { | 226 mlfiPriv::mlfiPriv() { |
227 pthread_mutex_lock(&config_mutex); | 227 pthread_mutex_lock(&config_mutex); |
228 pc = config; | 228 pc = config; |
229 pc->reference_count++; | 229 pc->reference_count++; |
230 pthread_mutex_unlock(&config_mutex); | 230 pthread_mutex_unlock(&config_mutex); |
231 get_fd(); | 231 get_fd(); |
232 ip = 0; | 232 ip = 0; |
233 mailaddr = NULL; | 233 mailaddr = NULL; |
234 queueid = NULL; | 234 queueid = NULL; |
235 authenticated = false; | 235 authenticated = false; |
236 have_whites = false; | 236 have_whites = false; |
237 only_whites = true; | 237 only_whites = true; |
238 memory = NULL; | 238 memory = NULL; |
239 scanner = NULL; | 239 scanner = NULL; |
240 content_suffix = NULL; | 240 content_suffix = NULL; |
241 content_message = NULL; | 241 content_message = NULL; |
242 content_host_ignore = NULL; | 242 content_host_ignore = NULL; |
243 } | 243 } |
244 | 244 |
245 mlfiPriv::~mlfiPriv() { | 245 mlfiPriv::~mlfiPriv() { |
246 return_fd(); | 246 return_fd(); |
247 pthread_mutex_lock(&config_mutex); | 247 pthread_mutex_lock(&config_mutex); |
248 pc->reference_count--; | 248 pc->reference_count--; |
249 pthread_mutex_unlock(&config_mutex); | 249 pthread_mutex_unlock(&config_mutex); |
250 reset(true); | 250 reset(true); |
251 } | 251 } |
252 | 252 |
253 void mlfiPriv::reset(bool final) { | 253 void mlfiPriv::reset(bool final) { |
254 if (mailaddr) free(mailaddr); | 254 if (mailaddr) free(mailaddr); |
255 if (queueid) free(queueid); | 255 if (queueid) free(queueid); |
256 discard(env_to); | 256 discard(env_to); |
257 if (memory) delete memory; | 257 if (memory) delete memory; |
258 if (scanner) delete scanner; | 258 if (scanner) delete scanner; |
259 if (!final) { | 259 if (!final) { |
260 mailaddr = NULL; | 260 mailaddr = NULL; |
261 queueid = NULL; | 261 queueid = NULL; |
262 authenticated = false; | 262 authenticated = false; |
263 have_whites = false; | 263 have_whites = false; |
264 only_whites = true; | 264 only_whites = true; |
265 memory = NULL; | 265 memory = NULL; |
266 scanner = NULL; | 266 scanner = NULL; |
267 content_suffix = NULL; | 267 content_suffix = NULL; |
268 content_message = NULL; | 268 content_message = NULL; |
269 content_host_ignore = NULL; | 269 content_host_ignore = NULL; |
270 } | 270 } |
271 } | 271 } |
272 | 272 |
273 void mlfiPriv::get_fd() { | 273 void mlfiPriv::get_fd() { |
274 err = true; | 274 err = true; |
275 fd = NULL_SOCKET; | 275 fd = NULL_SOCKET; |
276 int result = pthread_mutex_lock(&fd_pool_mutex); | 276 int result = pthread_mutex_lock(&fd_pool_mutex); |
277 if (!result) { | 277 if (!result) { |
278 std::set<int>::iterator i; | 278 std::set<int>::iterator i; |
279 i = fd_pool.begin(); | 279 i = fd_pool.begin(); |
280 if (i != fd_pool.end()) { | 280 if (i != fd_pool.end()) { |
281 // have at least one fd in the pool | 281 // have at least one fd in the pool |
282 err = false; | 282 err = false; |
283 fd = *i; | 283 fd = *i; |
284 fd_pool.erase(fd); | 284 fd_pool.erase(fd); |
285 resolver_pool_size--; | 285 resolver_pool_size--; |
286 pthread_mutex_unlock(&fd_pool_mutex); | 286 pthread_mutex_unlock(&fd_pool_mutex); |
287 } | 287 } |
288 else { | 288 else { |
289 // pool is empty, get a new fd | 289 // pool is empty, get a new fd |
290 pthread_mutex_unlock(&fd_pool_mutex); | 290 pthread_mutex_unlock(&fd_pool_mutex); |
291 fd = my_connect(); | 291 fd = my_connect(); |
292 err = (fd == NULL_SOCKET); | 292 err = (fd == NULL_SOCKET); |
293 } | 293 } |
294 } | 294 } |
295 else { | 295 else { |
296 // cannot lock the pool, just get a new fd | 296 // cannot lock the pool, just get a new fd |
297 fd = my_connect(); | 297 fd = my_connect(); |
298 err = (fd == NULL_SOCKET); | 298 err = (fd == NULL_SOCKET); |
299 } | 299 } |
300 } | 300 } |
301 | 301 |
302 void mlfiPriv::return_fd() { | 302 void mlfiPriv::return_fd() { |
303 if (err) { | 303 if (err) { |
304 // this fd got a socket error, so close it, rather than returning it to the pool | 304 // this fd got a socket error, so close it, rather than returning it to the pool |
305 my_disconnect(fd); | 305 my_disconnect(fd); |
306 } | 306 } |
307 else { | 307 else { |
308 int result = pthread_mutex_lock(&fd_pool_mutex); | 308 int result = pthread_mutex_lock(&fd_pool_mutex); |
309 if (!result) { | 309 if (!result) { |
310 if ((resolver_sock_count > resolver_pool_size*5) || (resolver_pool_size < 5)) { | 310 if ((resolver_sock_count > resolver_pool_size*5) || (resolver_pool_size < 5)) { |
311 // return the fd to the pool | 311 // return the fd to the pool |
312 fd_pool.insert(fd); | 312 fd_pool.insert(fd); |
313 resolver_pool_size++; | 313 resolver_pool_size++; |
314 pthread_mutex_unlock(&fd_pool_mutex); | 314 pthread_mutex_unlock(&fd_pool_mutex); |
315 } | 315 } |
316 else { | 316 else { |
317 // more than 20% of the open resolver sockets are in the pool, and the | 317 // more than 20% of the open resolver sockets are in the pool, and the |
318 // pool as at least 5 sockets. that is enough, so just close this one. | 318 // pool as at least 5 sockets. that is enough, so just close this one. |
319 pthread_mutex_unlock(&fd_pool_mutex); | 319 pthread_mutex_unlock(&fd_pool_mutex); |
320 my_disconnect(fd); | 320 my_disconnect(fd); |
321 } | 321 } |
322 } | 322 } |
323 else { | 323 else { |
324 // could not lock the pool, so just close the fd | 324 // could not lock the pool, so just close the fd |
325 my_disconnect(fd); | 325 my_disconnect(fd); |
326 } | 326 } |
327 } | 327 } |
328 } | 328 } |
329 | 329 |
330 int mlfiPriv::my_write(char *buf, int len) { | 330 int mlfiPriv::my_write(char *buf, int len) { |
331 if (err) return 0; | 331 if (err) return 0; |
332 int rs = 0; | 332 int rs = 0; |
333 while (len) { | 333 while (len) { |
334 int ws = write(fd, buf, len); | 334 int ws = write(fd, buf, len); |
335 if (ws > 0) { | 335 if (ws > 0) { |
336 rs += ws; | 336 rs += ws; |
337 len -= ws; | 337 len -= ws; |
338 buf += ws; | 338 buf += ws; |
339 } | 339 } |
340 else { | 340 else { |
341 // peer closed the socket! | 341 // peer closed the socket! |
342 rs = 0; | 342 rs = 0; |
343 err = true; | 343 err = true; |
344 break; | 344 break; |
345 } | 345 } |
346 } | 346 } |
347 return rs; | 347 return rs; |
348 } | 348 } |
349 | 349 |
350 int mlfiPriv::my_read(char *buf, int len) { | 350 int mlfiPriv::my_read(char *buf, int len) { |
351 if (err) return 0; | 351 if (err) return 0; |
352 int rs = 0; | 352 int rs = 0; |
353 while (len > 1) { | 353 while (len > 1) { |
354 int ws = read(fd, buf, len); | 354 int ws = read(fd, buf, len); |
355 if (ws > 0) { | 355 if (ws > 0) { |
356 rs += ws; | 356 rs += ws; |
357 len -= ws; | 357 len -= ws; |
358 buf += ws; | 358 buf += ws; |
359 } | 359 } |
360 else { | 360 else { |
361 // peer closed the socket! | 361 // peer closed the socket! |
362 rs = 0; | 362 rs = 0; |
363 err = true; | 363 err = true; |
364 break; | 364 break; |
365 } | 365 } |
366 } | 366 } |
367 return rs; | 367 return rs; |
368 } | 368 } |
369 | 369 |
370 void mlfiPriv::need_content_filter(char *rcpt, CONTEXT &con) { | 370 void mlfiPriv::need_content_filter(char *rcpt, CONTEXT &con) { |
371 register_string(env_to, rcpt, &con); | 371 register_string(env_to, rcpt, &con); |
372 if (!memory) { | 372 if (!memory) { |
373 // first recipient that needs content filtering sets all | 373 // first recipient that needs content filtering sets all |
374 // the content filtering parameters | 374 // the content filtering parameters |
375 memory = new recorder(this, con.get_html_tags(), con.get_content_tlds()); | 375 memory = new recorder(this, con.get_html_tags(), con.get_content_tlds()); |
376 scanner = new url_scanner(memory); | 376 scanner = new url_scanner(memory); |
377 content_suffix = con.get_content_suffix(); | 377 content_suffix = con.get_content_suffix(); |
378 content_message = con.get_content_message(); | 378 content_message = con.get_content_message(); |
379 content_host_ignore = &con.get_content_host_ignore(); | 379 content_host_ignore = &con.get_content_host_ignore(); |
380 } | 380 } |
381 } | 381 } |
382 | 382 |
383 #define MLFIPRIV ((struct mlfiPriv *) smfi_getpriv(ctx)) | 383 #define MLFIPRIV ((struct mlfiPriv *) smfi_getpriv(ctx)) |
384 | 384 |
385 | 385 |
386 //////////////////////////////////////////////// | 386 //////////////////////////////////////////////// |
387 // syslog a message | 387 // syslog a message |
388 // | 388 // |
389 void my_syslog(mlfiPriv *priv, char *text) { | 389 void my_syslog(mlfiPriv *priv, char *text) { |
390 char buf[maxlen]; | 390 char buf[maxlen]; |
391 if (priv) { | 391 if (priv) { |
392 snprintf(buf, sizeof(buf), "%s: %s", priv->queueid, text); | 392 snprintf(buf, sizeof(buf), "%s: %s", priv->queueid, text); |
393 text = buf; | 393 text = buf; |
394 } | 394 } |
395 if (use_syslog) { | 395 if (use_syslog) { |
396 pthread_mutex_lock(&syslog_mutex); | 396 pthread_mutex_lock(&syslog_mutex); |
397 if (!syslog_opened) { | 397 if (!syslog_opened) { |
398 openlog("dnsbl", LOG_PID, LOG_MAIL); | 398 openlog("dnsbl", LOG_PID, LOG_MAIL); |
399 syslog_opened = true; | 399 syslog_opened = true; |
400 } | 400 } |
401 syslog(LOG_NOTICE, "%s", text); | 401 syslog(LOG_NOTICE, "%s", text); |
402 // closelog(); | 402 // closelog(); |
403 // syslog_opened = false; | 403 // syslog_opened = false; |
404 pthread_mutex_unlock(&syslog_mutex); | 404 pthread_mutex_unlock(&syslog_mutex); |
405 } | 405 } |
406 else { | 406 else { |
407 printf("%s \n", text); | 407 printf("%s \n", text); |
408 } | 408 } |
409 } | 409 } |
410 | 410 |
411 void my_syslog(char *text) { | 411 void my_syslog(char *text) { |
412 my_syslog(NULL, text); | 412 my_syslog(NULL, text); |
413 } | 413 } |
414 | 414 |
415 | 415 |
416 //////////////////////////////////////////////// | 416 //////////////////////////////////////////////// |
417 // read a resolver request from the socket, process it, and | 417 // read a resolver request from the socket, process it, and |
418 // write the result back to the socket. | 418 // write the result back to the socket. |
419 | 419 |
420 void process_resolver_requests(int socket); | 420 void process_resolver_requests(int socket); |
421 void process_resolver_requests(int socket) { | 421 void process_resolver_requests(int socket) { |
422 #ifdef NS_MAXDNAME | 422 #ifdef NS_MAXDNAME |
423 char question[NS_MAXDNAME]; | 423 char question[NS_MAXDNAME]; |
424 #else | 424 #else |
425 char question[1000]; | 425 char question[1000]; |
426 #endif | 426 #endif |
427 glommer glom; | 427 glommer glom; |
428 | 428 |
429 int maxq = sizeof(question); | 429 int maxq = sizeof(question); |
430 while (true) { | 430 while (true) { |
431 // read a question | 431 // read a question |
432 int rs = 0; | 432 int rs = 0; |
433 while (true) { | 433 while (true) { |
434 int ns = read(socket, question+rs, maxq-rs); | 434 int ns = read(socket, question+rs, maxq-rs); |
435 if (ns > 0) { | 435 if (ns > 0) { |
436 rs += ns; | 436 rs += ns; |
437 if (question[rs-1] == '\0') { | 437 if (question[rs-1] == '\0') { |
438 // last byte read was the null terminator, we are done | 438 // last byte read was the null terminator, we are done |
439 break; | 439 break; |
440 } | 440 } |
441 } | 441 } |
442 else { | 442 else { |
443 // peer closed the socket | 443 // peer closed the socket |
444 //my_syslog("!!child worker process, peer closed socket while reading question"); | 444 //my_syslog("!!child worker process, peer closed socket while reading question"); |
445 shutdown(socket, SHUT_RDWR); | 445 shutdown(socket, SHUT_RDWR); |
446 close(socket); | 446 close(socket); |
447 return; | 447 return; |
448 } | 448 } |
449 } | 449 } |
450 | 450 |
451 // find the answer | 451 // find the answer |
452 #ifdef NS_PACKETSZ | 452 #ifdef NS_PACKETSZ |
453 //char text[1000]; | 453 //char text[1000]; |
454 //snprintf(text, sizeof(text), "!!child worker process has a question %s", question); | 454 //snprintf(text, sizeof(text), "!!child worker process has a question %s", question); |
455 //my_syslog(text); | 455 //my_syslog(text); |
456 glom.length = res_search(question, ns_c_in, ns_t_a, glom.answer, sizeof(glom.answer)); | 456 glom.length = res_search(question, ns_c_in, ns_t_a, glom.answer, sizeof(glom.answer)); |
457 if (glom.length < 0) glom.length = 0; // represent all errors as zero length answers | 457 if (glom.length < 0) glom.length = 0; // represent all errors as zero length answers |
458 #else | 458 #else |
459 glom.length = sizeof(glom.answer); | 459 glom.length = sizeof(glom.answer); |
460 glom.answer = 0; | 460 glom.answer = 0; |
461 struct hostent *host = gethostbyname(question); | 461 struct hostent *host = gethostbyname(question); |
462 if (host && (host->h_addrtype == AF_INET)) { | 462 if (host && (host->h_addrtype == AF_INET)) { |
463 memcpy(&glom.answer, host->h_addr, sizeof(glom.answer)); | 463 memcpy(&glom.answer, host->h_addr, sizeof(glom.answer)); |
464 } | 464 } |
465 #endif | 465 #endif |
466 | 466 |
467 // write the answer | 467 // write the answer |
468 char *buf = (char *)&glom; | 468 char *buf = (char *)&glom; |
469 int len = glom.length + sizeof(glom.length); | 469 int len = glom.length + sizeof(glom.length); |
470 //snprintf(text, sizeof(text), "!!child worker process writing answer length %d for total %d", glom.length, len); | 470 //snprintf(text, sizeof(text), "!!child worker process writing answer length %d for total %d", glom.length, len); |
471 //my_syslog(text); | 471 //my_syslog(text); |
472 int ws = 0; | 472 int ws = 0; |
473 while (len > ws) { | 473 while (len > ws) { |
474 int ns = write(socket, buf+ws, len-ws); | 474 int ns = write(socket, buf+ws, len-ws); |
475 if (ns > 0) { | 475 if (ns > 0) { |
476 ws += ns; | 476 ws += ns; |
477 } | 477 } |
478 else { | 478 else { |
479 // peer closed the socket! | 479 // peer closed the socket! |
480 //my_syslog("!!child worker process, peer closed socket while writing answer"); | 480 //my_syslog("!!child worker process, peer closed socket while writing answer"); |
481 shutdown(socket, SHUT_RDWR); | 481 shutdown(socket, SHUT_RDWR); |
482 close(socket); | 482 close(socket); |
483 return; | 483 return; |
484 } | 484 } |
485 } | 485 } |
486 } | 486 } |
487 } | 487 } |
488 | 488 |
489 | 489 |
490 //////////////////////////////////////////////// | 490 //////////////////////////////////////////////// |
491 // ask a dns question and get an A record answer - we don't try | 491 // ask a dns question and get an A record answer - we don't try |
492 // very hard, just using the default resolver retry settings. | 492 // very hard, just using the default resolver retry settings. |
493 // If we cannot get an answer, we just accept the mail. | 493 // If we cannot get an answer, we just accept the mail. |
494 // | 494 // |
495 // | 495 // |
496 int dns_interface(mlfiPriv &priv, char *question, bool maybe_ip, ns_map *nameservers); | 496 int dns_interface(mlfiPriv &priv, char *question, bool maybe_ip, ns_map *nameservers); |
497 int dns_interface(mlfiPriv &priv, char *question, bool maybe_ip, ns_map *nameservers) { | 497 int dns_interface(mlfiPriv &priv, char *question, bool maybe_ip, ns_map *nameservers) { |
498 // this part can be done without locking the resolver mutex. Each | 498 // this part can be done without locking the resolver mutex. Each |
499 // milter thread is talking over its own socket to a separate resolver | 499 // milter thread is talking over its own socket to a separate resolver |
500 // process, which does the actual dns resolution. | 500 // process, which does the actual dns resolution. |
501 if (priv.err) return 0; // cannot ask more questions on this socket. | 501 if (priv.err) return 0; // cannot ask more questions on this socket. |
502 priv.my_write(question, strlen(question)+1); // write the question including the null terminator | 502 priv.my_write(question, strlen(question)+1); // write the question including the null terminator |
503 glommer glom; | 503 glommer glom; |
504 char *buf = (char *)&glom; | 504 char *buf = (char *)&glom; |
505 priv.my_read(buf, sizeof(glom.length)); | 505 priv.my_read(buf, sizeof(glom.length)); |
506 buf += sizeof(glom.length); | 506 buf += sizeof(glom.length); |
507 ///char text[1000]; | 507 ///char text[1000]; |
508 ///snprintf(text, sizeof(text), "!!milter thread wrote question %s and has answer length %d", question, glom.length); | 508 ///snprintf(text, sizeof(text), "!!milter thread wrote question %s and has answer length %d", question, glom.length); |
509 ///my_syslog(text); | 509 ///my_syslog(text); |
510 if ((glom.length < 0) || (glom.length > sizeof(glom.answer))) { | 510 if ((glom.length < 0) || (glom.length > sizeof(glom.answer))) { |
511 priv.err = true; | 511 priv.err = true; |
512 return 0; // cannot process overlarge answers | 512 return 0; // cannot process overlarge answers |
513 } | 513 } |
514 priv.my_read(buf, glom.length); | 514 priv.my_read(buf, glom.length); |
515 | 515 |
516 #ifdef NS_PACKETSZ | 516 #ifdef NS_PACKETSZ |
517 // now we need to lock the resolver mutex to keep the milter threads from | 517 // now we need to lock the resolver mutex to keep the milter threads from |
518 // stepping on each other while parsing the dns answer. | 518 // stepping on each other while parsing the dns answer. |
519 int ret_address = 0; | 519 int ret_address = 0; |
520 pthread_mutex_lock(&resolve_mutex); | 520 pthread_mutex_lock(&resolve_mutex); |
521 if (glom.length > 0) { | 521 if (glom.length > 0) { |
522 // parse the answer | 522 // parse the answer |
523 ns_msg handle; | 523 ns_msg handle; |
524 ns_rr rr; | 524 ns_rr rr; |
525 if (ns_initparse(glom.answer, glom.length, &handle) == 0) { | 525 if (ns_initparse(glom.answer, glom.length, &handle) == 0) { |
526 // look for ns names | 526 // look for ns names |
527 if (nameservers) { | 527 if (nameservers) { |
528 ns_map &ns = *nameservers; | 528 ns_map &ns = *nameservers; |
529 int rrnum = 0; | 529 int rrnum = 0; |
530 while (ns_parserr(&handle, ns_s_ns, rrnum++, &rr) == 0) { | 530 while (ns_parserr(&handle, ns_s_ns, rrnum++, &rr) == 0) { |
531 if (ns_rr_type(rr) == ns_t_ns) { | 531 if (ns_rr_type(rr) == ns_t_ns) { |
532 char nam[NS_MAXDNAME+1]; | 532 char nam[NS_MAXDNAME+1]; |
533 char *n = nam; | 533 char *n = nam; |
534 const u_char *p = ns_rr_rdata(rr); | 534 const u_char *p = ns_rr_rdata(rr); |
535 while (((n-nam) < NS_MAXDNAME) && ((p-glom.answer) < glom.length) && *p) { | 535 while (((n-nam) < NS_MAXDNAME) && ((p-glom.answer) < glom.length) && *p) { |
536 size_t s = *(p++); | 536 size_t s = *(p++); |
537 if (s > 191) { | 537 if (s > 191) { |
538 // compression pointer | 538 // compression pointer |
539 s = (s-192)*256 + *(p++); | 539 s = (s-192)*256 + *(p++); |
540 if (s >= glom.length) break; // pointer outside bounds of answer | 540 if (s >= glom.length) break; // pointer outside bounds of answer |
541 p = glom.answer + s; | 541 p = glom.answer + s; |
542 s = *(p++); | 542 s = *(p++); |
543 } | 543 } |
544 if (s > 0) { | 544 if (s > 0) { |
545 if ((n-nam) >= (NS_MAXDNAME-s)) break; // destination would overflow name buffer | 545 if ((n-nam) >= (NS_MAXDNAME-s)) break; // destination would overflow name buffer |
546 if ((p-glom.answer) >= (glom.length-s)) break; // source outside bounds of answer | 546 if ((p-glom.answer) >= (glom.length-s)) break; // source outside bounds of answer |
547 memcpy(n, p, s); | 547 memcpy(n, p, s); |
548 n += s; | 548 n += s; |
549 p += s; | 549 p += s; |
550 *(n++) = '.'; | 550 *(n++) = '.'; |
551 } | 551 } |
552 } | 552 } |
553 if (n-nam) n--; // remove trailing . | 553 if (n-nam) n--; // remove trailing . |
554 *n = '\0'; // null terminate it | 554 *n = '\0'; // null terminate it |
555 ns.add(nam, question); // ns host to lookup later | 555 ns.add(nam, question); // ns host to lookup later |
556 } | 556 } |
557 } | 557 } |
558 rrnum = 0; | 558 rrnum = 0; |
559 while (ns_parserr(&handle, ns_s_ar, rrnum++, &rr) == 0) { | 559 while (ns_parserr(&handle, ns_s_ar, rrnum++, &rr) == 0) { |
560 if (ns_rr_type(rr) == ns_t_a) { | 560 if (ns_rr_type(rr) == ns_t_a) { |
561 char* nam = (char*)ns_rr_name(rr); | 561 char* nam = (char*)ns_rr_name(rr); |
562 ns_mapper::iterator i = ns.ns_ip.find(nam); | 562 ns_mapper::iterator i = ns.ns_ip.find(nam); |
563 if (i != ns.ns_ip.end()) { | 563 if (i != ns.ns_ip.end()) { |
564 // we want this ip address | 564 // we want this ip address |
565 int address; | 565 int address; |
566 memcpy(&address, ns_rr_rdata(rr), sizeof(address)); | 566 memcpy(&address, ns_rr_rdata(rr), sizeof(address)); |
567 ns.ns_ip[nam] = address; | 567 ns.ns_ip[nam] = address; |
568 } | 568 } |
569 } | 569 } |
570 } | 570 } |
571 } | 571 } |
572 int rrnum = 0; | 572 int rrnum = 0; |
573 while (ns_parserr(&handle, ns_s_an, rrnum++, &rr) == 0) { | 573 while (ns_parserr(&handle, ns_s_an, rrnum++, &rr) == 0) { |
574 if (ns_rr_type(rr) == ns_t_a) { | 574 if (ns_rr_type(rr) == ns_t_a) { |
575 int address; | 575 int address; |
576 memcpy(&address, ns_rr_rdata(rr), sizeof(address)); | 576 memcpy(&address, ns_rr_rdata(rr), sizeof(address)); |
577 ret_address = address; | 577 ret_address = address; |
578 } | 578 } |
579 } | 579 } |
580 } | 580 } |
581 } | 581 } |
582 if (maybe_ip && !ret_address) { | 582 if (maybe_ip && !ret_address) { |
583 // might be a bare ip address | 583 // might be a bare ip address |
584 in_addr ip; | 584 in_addr ip; |
585 if (inet_aton(question, &ip)) { | 585 if (inet_aton(question, &ip)) { |
586 ret_address = ip.s_addr; | 586 ret_address = ip.s_addr; |
587 } | 587 } |
588 } | 588 } |
589 pthread_mutex_unlock(&resolve_mutex); | 589 pthread_mutex_unlock(&resolve_mutex); |
590 return ret_address; | 590 return ret_address; |
591 #else | 591 #else |
592 return glom.answer; | 592 return glom.answer; |
593 #endif | 593 #endif |
594 } | 594 } |
595 | 595 |
596 | 596 |
597 //////////////////////////////////////////////// | 597 //////////////////////////////////////////////// |
598 // check a single dnsbl | 598 // check a single dnsbl |
599 // | 599 // |
600 bool check_single(mlfiPriv &priv, int ip, char *suffix); | 600 bool check_single(mlfiPriv &priv, int ip, char *suffix); |
601 bool check_single(mlfiPriv &priv, int ip, char *suffix) { | 601 bool check_single(mlfiPriv &priv, int ip, char *suffix) { |
602 // make a dns question | 602 // make a dns question |
603 const u_char *src = (const u_char *)&ip; | 603 const u_char *src = (const u_char *)&ip; |
604 if (src[0] == 127) return false; // don't do dns lookups on localhost | 604 if (src[0] == 127) return false; // don't do dns lookups on localhost |
605 #ifdef NS_MAXDNAME | 605 #ifdef NS_MAXDNAME |
606 char question[NS_MAXDNAME]; | 606 char question[NS_MAXDNAME]; |
607 #else | 607 #else |
608 char question[1000]; | 608 char question[1000]; |
609 #endif | 609 #endif |
610 snprintf(question, sizeof(question), "%u.%u.%u.%u.%s.", src[3], src[2], src[1], src[0], suffix); | 610 snprintf(question, sizeof(question), "%u.%u.%u.%u.%s.", src[3], src[2], src[1], src[0], suffix); |
611 // ask the question, if we get an A record it implies a blacklisted ip address | 611 // ask the question, if we get an A record it implies a blacklisted ip address |
612 return dns_interface(priv, question, false, NULL); | 612 return dns_interface(priv, question, false, NULL); |
613 } | 613 } |
614 | 614 |
615 | 615 |
616 //////////////////////////////////////////////// | 616 //////////////////////////////////////////////// |
617 // check a single dnsbl | 617 // check a single dnsbl |
618 // | 618 // |
619 bool check_single(mlfiPriv &priv, int ip, DNSBL &bl); | 619 bool check_single(mlfiPriv &priv, int ip, DNSBL &bl); |
620 bool check_single(mlfiPriv &priv, int ip, DNSBL &bl) { | 620 bool check_single(mlfiPriv &priv, int ip, DNSBL &bl) { |
621 return check_single(priv, ip, bl.suffix); | 621 return check_single(priv, ip, bl.suffix); |
622 } | 622 } |
623 | 623 |
624 | 624 |
625 //////////////////////////////////////////////// | 625 //////////////////////////////////////////////// |
626 // check the dnsbls specified for this recipient | 626 // check the dnsbls specified for this recipient |
627 // | 627 // |
628 bool check_dnsbl(mlfiPriv &priv, dnsblp_list &dnsbll, DNSBLP &rejectlist); | 628 bool check_dnsbl(mlfiPriv &priv, dnsblp_list &dnsbll, DNSBLP &rejectlist); |
629 bool check_dnsbl(mlfiPriv &priv, dnsblp_list &dnsbll, DNSBLP &rejectlist) { | 629 bool check_dnsbl(mlfiPriv &priv, dnsblp_list &dnsbll, DNSBLP &rejectlist) { |
630 if (priv.authenticated) return false; | 630 if (priv.authenticated) return false; |
631 for (dnsblp_list::iterator i=dnsbll.begin(); i!=dnsbll.end(); i++) { | 631 for (dnsblp_list::iterator i=dnsbll.begin(); i!=dnsbll.end(); i++) { |
632 DNSBLP dp = *i; // non null by construction | 632 DNSBLP dp = *i; // non null by construction |
633 bool st; | 633 bool st; |
634 map<DNSBLP, bool>::iterator f = priv.checked.find(dp); | 634 map<DNSBLP, bool>::iterator f = priv.checked.find(dp); |
635 if (f == priv.checked.end()) { | 635 if (f == priv.checked.end()) { |
636 // have not checked this list yet | 636 // have not checked this list yet |
637 st = check_single(priv, priv.ip, *dp); | 637 st = check_single(priv, priv.ip, *dp); |
638 rejectlist = dp; | 638 rejectlist = dp; |
639 priv.checked[dp] = st; | 639 priv.checked[dp] = st; |
640 } | 640 } |
641 else { | 641 else { |
642 st = (*f).second; | 642 st = (*f).second; |
643 rejectlist = (*f).first; | 643 rejectlist = (*f).first; |
644 } | 644 } |
645 if (st) return st; | 645 if (st) return st; |
646 } | 646 } |
647 return false; | 647 return false; |
648 } | 648 } |
649 | 649 |
650 | 650 |
651 //////////////////////////////////////////////// | 651 //////////////////////////////////////////////// |
652 // check the hosts from the body against the content dnsbl | 652 // check the hosts from the body against the content dnsbl |
653 // | 653 // |
654 bool check_hosts(mlfiPriv &priv, bool random, int limit, char *&host, int &ip); | 654 bool check_hosts(mlfiPriv &priv, bool random, int limit, char *&host, int &ip); |
655 bool check_hosts(mlfiPriv &priv, bool random, int limit, char *&host, int &ip) { | 655 bool check_hosts(mlfiPriv &priv, bool random, int limit, char *&host, int &ip) { |
656 CONFIG &dc = *priv.pc; | 656 CONFIG &dc = *priv.pc; |
657 string_set &hosts = priv.memory->get_hosts(); | 657 string_set &hosts = priv.memory->get_hosts(); |
658 string_set &ignore = *priv.content_host_ignore; | 658 string_set &ignore = *priv.content_host_ignore; |
659 char *suffix = priv.content_suffix; | 659 char *suffix = priv.content_suffix; |
660 | 660 |
661 int count = 0; | 661 int count = 0; |
662 int cnt = hosts.size(); // number of hosts we could look at | 662 int cnt = hosts.size(); // number of hosts we could look at |
663 int_set ips; | 663 int_set ips; |
664 ns_map nameservers; | 664 ns_map nameservers; |
665 for (string_set::iterator i=hosts.begin(); i!=hosts.end(); i++) { | 665 for (string_set::iterator i=hosts.begin(); i!=hosts.end(); i++) { |
666 host = *i; // a reference into hosts, which will live until this smtp transaction is closed | 666 host = *i; // a reference into hosts, which will live until this smtp transaction is closed |
667 | 667 |
668 // don't bother looking up hosts on the ignore list | 668 // don't bother looking up hosts on the ignore list |
669 string_set::iterator j = ignore.find(host); | 669 string_set::iterator j = ignore.find(host); |
670 if (j != ignore.end()) continue; | 670 if (j != ignore.end()) continue; |
671 | 671 |
672 // try to only look at limit/cnt fraction of the available cnt host names in random mode | 672 // try to only look at limit/cnt fraction of the available cnt host names in random mode |
673 if ((cnt > limit) && (limit > 0) && random) { | 673 if ((cnt > limit) && (limit > 0) && random) { |
674 int r = rand() % cnt; | 674 int r = rand() % cnt; |
675 if (r >= limit) { | 675 if (r >= limit) { |
676 if (debug_syslog > 2) { | 676 if (debug_syslog > 2) { |
677 char buf[maxlen]; | 677 char buf[maxlen]; |
678 snprintf(buf, sizeof(buf), "host %s skipped", host); | 678 snprintf(buf, sizeof(buf), "host %s skipped", host); |
679 my_syslog(&priv, buf); | 679 my_syslog(&priv, buf); |
680 } | 680 } |
681 continue; | 681 continue; |
682 } | 682 } |
683 } | 683 } |
684 count++; | 684 count++; |
685 ip = dns_interface(priv, host, true, &nameservers); | 685 ip = dns_interface(priv, host, true, &nameservers); |
686 if (debug_syslog > 2) { | 686 if (debug_syslog > 2) { |
687 char buf[maxlen]; | 687 char buf[maxlen]; |
688 if (ip) { | 688 if (ip) { |
689 char adr[sizeof "255.255.255.255"]; | 689 char adr[sizeof "255.255.255.255"]; |
690 adr[0] = '\0'; | 690 adr[0] = '\0'; |
691 inet_ntop(AF_INET, (const u_char *)&ip, adr, sizeof(adr)); | 691 inet_ntop(AF_INET, (const u_char *)&ip, adr, sizeof(adr)); |
692 snprintf(buf, sizeof(buf), "host %s found at %s", host, adr); | 692 snprintf(buf, sizeof(buf), "host %s found at %s", host, adr); |
693 } | 693 } |
694 else { | 694 else { |
695 snprintf(buf, sizeof(buf), "host %s not found", host); | 695 snprintf(buf, sizeof(buf), "host %s not found", host); |
696 } | 696 } |
697 my_syslog(&priv, buf); | 697 my_syslog(&priv, buf); |
698 } | 698 } |
699 if (ip) { | 699 if (ip) { |
700 int_set::iterator i = ips.find(ip); | 700 int_set::iterator i = ips.find(ip); |
701 if (i == ips.end()) { | 701 if (i == ips.end()) { |
702 ips.insert(ip); | 702 ips.insert(ip); |
703 if (check_single(priv, ip, suffix)) { | 703 if (check_single(priv, ip, suffix)) { |
704 return true; | 704 return true; |
705 } | 705 } |
706 } | 706 } |
707 } | 707 } |
708 } | 708 } |
709 limit *= 4; // allow average of 3 ns per host name | 709 limit *= 4; // allow average of 3 ns per host name |
710 for (ns_mapper::iterator i=nameservers.ns_ip.begin(); i!=nameservers.ns_ip.end(); i++) { | 710 for (ns_mapper::iterator i=nameservers.ns_ip.begin(); i!=nameservers.ns_ip.end(); i++) { |
711 count++; | 711 count++; |
712 if ((count > limit) && (limit > 0)) { | 712 if ((count > limit) && (limit > 0)) { |
713 if (random) continue; // don't complain | 713 if (random) continue; // don't complain |
714 return true; | 714 return true; |
715 } | 715 } |
716 host = (*i).first; // a transient reference that needs to be replaced before we return it | 716 host = (*i).first; // a transient reference that needs to be replaced before we return it |
717 ip = (*i).second; | 717 ip = (*i).second; |
718 if (!ip) ip = dns_interface(priv, host, false, NULL); | 718 if (!ip) ip = dns_interface(priv, host, false, NULL); |
719 if (debug_syslog > 2) { | 719 if (debug_syslog > 2) { |
720 char buf[maxlen]; | 720 char buf[maxlen]; |
721 if (ip) { | 721 if (ip) { |
722 char adr[sizeof "255.255.255.255"]; | 722 char adr[sizeof "255.255.255.255"]; |
723 adr[0] = '\0'; | 723 adr[0] = '\0'; |
724 inet_ntop(AF_INET, (const u_char *)&ip, adr, sizeof(adr)); | 724 inet_ntop(AF_INET, (const u_char *)&ip, adr, sizeof(adr)); |
725 snprintf(buf, sizeof(buf), "ns %s found at %s", host, adr); | 725 snprintf(buf, sizeof(buf), "ns %s found at %s", host, adr); |
726 } | 726 } |
727 else { | 727 else { |
728 snprintf(buf, sizeof(buf), "ns %s not found", host); | 728 snprintf(buf, sizeof(buf), "ns %s not found", host); |
729 } | 729 } |
730 my_syslog(&priv, buf); | 730 my_syslog(&priv, buf); |
731 } | 731 } |
732 if (ip) { | 732 if (ip) { |
733 int_set::iterator i = ips.find(ip); | 733 int_set::iterator i = ips.find(ip); |
734 if (i == ips.end()) { | 734 if (i == ips.end()) { |
735 ips.insert(ip); | 735 ips.insert(ip); |
736 if (check_single(priv, ip, suffix)) { | 736 if (check_single(priv, ip, suffix)) { |
737 string_map::iterator j = nameservers.ns_host.find(host); | 737 string_map::iterator j = nameservers.ns_host.find(host); |
738 if (j != nameservers.ns_host.end()) { | 738 if (j != nameservers.ns_host.end()) { |
739 char *refer = (*j).second; | 739 char *refer = (*j).second; |
740 char buf[maxlen]; | 740 char buf[maxlen]; |
741 snprintf(buf, sizeof(buf), "%s with nameserver %s", refer, host); | 741 snprintf(buf, sizeof(buf), "%s with nameserver %s", refer, host); |
742 host = register_string(hosts, buf); // put a copy into hosts, and return that reference | 742 host = register_string(hosts, buf); // put a copy into hosts, and return that reference |
743 } | 743 } |
744 else { | 744 else { |
745 host = register_string(hosts, host); // put a copy into hosts, and return that reference | 745 host = register_string(hosts, host); // put a copy into hosts, and return that reference |
746 } | 746 } |
747 return true; | 747 return true; |
748 } | 748 } |
749 } | 749 } |
750 } | 750 } |
751 } | 751 } |
752 return false; | 752 return false; |
753 } | 753 } |
754 | 754 |
755 | 755 |
756 //////////////////////////////////////////////// | 756 //////////////////////////////////////////////// |
757 // this email address is passed in from sendmail, and will | 757 // this email address is passed in from sendmail, and will |
759 // as the mail client sent it. We dup the string and convert | 759 // as the mail client sent it. We dup the string and convert |
760 // the duplicate to lower case. | 760 // the duplicate to lower case. |
761 // | 761 // |
762 char *to_lower_string(char *email); | 762 char *to_lower_string(char *email); |
763 char *to_lower_string(char *email) { | 763 char *to_lower_string(char *email) { |
764 int n = strlen(email)-2; | 764 int n = strlen(email)-2; |
765 if (n < 1) return strdup(email); | 765 if (n < 1) return strdup(email); |
766 char *key = strdup(email+1); | 766 char *key = strdup(email+1); |
767 key[n] = '\0'; | 767 key[n] = '\0'; |
768 for (int i=0; i<n; i++) key[i] = tolower(key[i]); | 768 for (int i=0; i<n; i++) key[i] = tolower(key[i]); |
769 return key; | 769 return key; |
770 } | 770 } |
771 | 771 |
772 | 772 |
773 //////////////////////////////////////////////// | 773 //////////////////////////////////////////////// |
774 // start of sendmail milter interfaces | 774 // start of sendmail milter interfaces |
775 // | 775 // |
776 sfsistat mlfi_connect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr) | 776 sfsistat mlfi_connect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr) |
777 { | 777 { |
778 // allocate some private memory | 778 // allocate some private memory |
779 mlfiPriv *priv = new mlfiPriv; | 779 mlfiPriv *priv = new mlfiPriv; |
780 if (hostaddr->sa_family == AF_INET) { | 780 if (hostaddr->sa_family == AF_INET) { |
781 priv->ip = ((struct sockaddr_in *)hostaddr)->sin_addr.s_addr; | 781 priv->ip = ((struct sockaddr_in *)hostaddr)->sin_addr.s_addr; |
782 } | 782 } |
783 | 783 |
784 // save the private data | 784 // save the private data |
785 smfi_setpriv(ctx, (void*)priv); | 785 smfi_setpriv(ctx, (void*)priv); |
786 | 786 |
787 // continue processing | 787 // continue processing |
788 return SMFIS_CONTINUE; | 788 return SMFIS_CONTINUE; |
789 } | 789 } |
790 | 790 |
791 sfsistat mlfi_envfrom(SMFICTX *ctx, char **from) | 791 sfsistat mlfi_envfrom(SMFICTX *ctx, char **from) |
792 { | 792 { |
793 mlfiPriv &priv = *MLFIPRIV; | 793 mlfiPriv &priv = *MLFIPRIV; |
794 priv.mailaddr = to_lower_string(from[0]); | 794 priv.mailaddr = to_lower_string(from[0]); |
795 priv.authenticated = (smfi_getsymval(ctx, "{auth_authen}") != NULL); | 795 priv.authenticated = (smfi_getsymval(ctx, "{auth_authen}") != NULL); |
796 return SMFIS_CONTINUE; | 796 return SMFIS_CONTINUE; |
797 } | 797 } |
798 | 798 |
799 sfsistat mlfi_envrcpt(SMFICTX *ctx, char **rcpt) | 799 sfsistat mlfi_envrcpt(SMFICTX *ctx, char **rcpt) |
800 { | 800 { |
801 DNSBLP rejectlist = NULL; // list that caused the reject | 801 DNSBLP rejectlist = NULL; // list that caused the reject |
802 mlfiPriv &priv = *MLFIPRIV; | 802 mlfiPriv &priv = *MLFIPRIV; |
803 CONFIG &dc = *priv.pc; | 803 CONFIG &dc = *priv.pc; |
804 if (!priv.queueid) priv.queueid = strdup(smfi_getsymval(ctx, "i")); | 804 if (!priv.queueid) priv.queueid = strdup(smfi_getsymval(ctx, "i")); |
805 char *rcptaddr = rcpt[0]; | 805 char *rcptaddr = rcpt[0]; |
806 char *loto = to_lower_string(rcptaddr); | 806 char *loto = to_lower_string(rcptaddr); |
807 CONTEXT &con = *(dc.find_context(loto)->find_context(priv.mailaddr)); | 807 CONTEXT &con = *(dc.find_context(loto)->find_context(priv.mailaddr)); |
808 if (debug_syslog > 1) { | 808 if (debug_syslog > 1) { |
809 char buf[maxlen]; | 809 char buf[maxlen]; |
810 char msg[maxlen]; | 810 char msg[maxlen]; |
811 snprintf(msg, sizeof(msg), "from <%s> to <%s> using context %s", priv.mailaddr, loto, con.get_full_name(buf,maxlen)); | 811 snprintf(msg, sizeof(msg), "from <%s> to <%s> using context %s", priv.mailaddr, loto, con.get_full_name(buf,maxlen)); |
812 my_syslog(&priv, msg); | 812 my_syslog(&priv, msg); |
813 } | 813 } |
814 char *fromvalue = con.find_from(priv.mailaddr); | 814 char *fromvalue = con.find_from(priv.mailaddr); |
815 free(loto); | 815 free(loto); |
816 status st; | 816 status st; |
817 if (fromvalue == token_black) { | 817 if (fromvalue == token_black) { |
818 st = black; | 818 st = black; |
819 } | 819 } |
820 else if (fromvalue == token_white) { | 820 else if (fromvalue == token_white) { |
821 st = white; | 821 st = white; |
822 } | 822 } |
823 else { | 823 else { |
824 // check the dns based lists | 824 // check the dns based lists |
825 st = (check_dnsbl(priv, con.get_dnsbl_list(), rejectlist)) ? reject : oksofar; | 825 st = (check_dnsbl(priv, con.get_dnsbl_list(), rejectlist)) ? reject : oksofar; |
826 } | 826 } |
827 if (st == reject) { | 827 if (st == reject) { |
828 // reject the recipient based on some dnsbl | 828 // reject the recipient based on some dnsbl |
829 char adr[sizeof "255.255.255.255"]; | 829 char adr[sizeof "255.255.255.255"]; |
830 adr[0] = '\0'; | 830 adr[0] = '\0'; |
831 inet_ntop(AF_INET, (const u_char *)&priv.ip, adr, sizeof(adr)); | 831 inet_ntop(AF_INET, (const u_char *)&priv.ip, adr, sizeof(adr)); |
832 char buf[maxlen]; | 832 char buf[maxlen]; |
833 snprintf(buf, sizeof(buf), rejectlist->message, adr, adr); | 833 snprintf(buf, sizeof(buf), rejectlist->message, adr, adr); |
834 smfi_setreply(ctx, "550", "5.7.1", buf); | 834 smfi_setreply(ctx, "550", "5.7.1", buf); |
835 return SMFIS_REJECT; | 835 return SMFIS_REJECT; |
836 } | 836 } |
837 else if (st == black) { | 837 else if (st == black) { |
838 // reject the recipient based on blacklisting either from or to | 838 // reject the recipient based on blacklisting either from or to |
839 smfi_setreply(ctx, "550", "5.7.1", "no such user"); | 839 smfi_setreply(ctx, "550", "5.7.1", "no such user"); |
840 return SMFIS_REJECT; | 840 return SMFIS_REJECT; |
841 } | 841 } |
842 else { | 842 else { |
843 // accept the recipient | 843 // accept the recipient |
844 if (!con.get_content_filtering()) st = white; | 844 if (!con.get_content_filtering()) st = white; |
845 if (st == oksofar) { | 845 if (st == oksofar) { |
846 // but remember the non-whites | 846 // but remember the non-whites |
847 priv.need_content_filter(rcptaddr, con); | 847 priv.need_content_filter(rcptaddr, con); |
848 priv.only_whites = false; | 848 priv.only_whites = false; |
849 } | 849 } |
850 if (st == white) { | 850 if (st == white) { |
851 priv.have_whites = true; | 851 priv.have_whites = true; |
852 } | 852 } |
853 return SMFIS_CONTINUE; | 853 return SMFIS_CONTINUE; |
854 } | 854 } |
855 } | 855 } |
856 | 856 |
857 sfsistat mlfi_body(SMFICTX *ctx, u_char *data, size_t len) | 857 sfsistat mlfi_body(SMFICTX *ctx, u_char *data, size_t len) |
858 { | 858 { |
859 mlfiPriv &priv = *MLFIPRIV; | 859 mlfiPriv &priv = *MLFIPRIV; |
860 if (priv.authenticated) return SMFIS_CONTINUE; | 860 if (priv.authenticated) return SMFIS_CONTINUE; |
861 if (priv.only_whites) return SMFIS_CONTINUE; | 861 if (priv.only_whites) return SMFIS_CONTINUE; |
862 priv.scanner->scan(data, len); | 862 priv.scanner->scan(data, len); |
863 return SMFIS_CONTINUE; | 863 return SMFIS_CONTINUE; |
864 } | 864 } |
865 | 865 |
866 sfsistat mlfi_eom(SMFICTX *ctx) | 866 sfsistat mlfi_eom(SMFICTX *ctx) |
867 { | 867 { |
868 sfsistat rc; | 868 sfsistat rc; |
869 mlfiPriv &priv = *MLFIPRIV; | 869 mlfiPriv &priv = *MLFIPRIV; |
870 CONFIG &dc = *priv.pc; | 870 CONFIG &dc = *priv.pc; |
871 char *host = NULL; | 871 char *host = NULL; |
872 int ip; | 872 int ip; |
873 status st; | 873 status st; |
874 // process end of message | 874 // process end of message |
875 if (priv.authenticated || priv.only_whites) rc = SMFIS_CONTINUE; | 875 if (priv.authenticated || priv.only_whites) rc = SMFIS_CONTINUE; |
876 else { | 876 else { |
877 // assert env_to not empty | 877 // assert env_to not empty |
878 char buf[maxlen]; | 878 char buf[maxlen]; |
879 char *msg = NULL; | 879 char *msg = NULL; |
880 string_set alive; | 880 string_set alive; |
881 bool random = false; | 881 bool random = false; |
882 int limit = 0; | 882 int limit = 0; |
883 for (context_map::iterator i=priv.env_to.begin(); i!=priv.env_to.end(); i++) { | 883 for (context_map::iterator i=priv.env_to.begin(); i!=priv.env_to.end(); i++) { |
884 char *rcpt = (*i).first; | 884 char *rcpt = (*i).first; |
885 CONTEXT &con = *((*i).second); | 885 CONTEXT &con = *((*i).second); |
886 if (!con.acceptable_content(*priv.memory, msg)) { | 886 if (!con.acceptable_content(*priv.memory, msg)) { |
887 // bad html tags or excessive hosts | 887 // bad html tags or excessive hosts |
888 smfi_delrcpt(ctx, rcpt); | 888 smfi_delrcpt(ctx, rcpt); |
889 } | 889 } |
890 else { | 890 else { |
891 alive.insert(rcpt); | 891 alive.insert(rcpt); |
892 random |= con.get_host_random(); | 892 random |= con.get_host_random(); |
893 limit = max(limit, con.get_host_limit()); | 893 limit = max(limit, con.get_host_limit()); |
894 } | 894 } |
895 } | 895 } |
896 bool rejecting = alive.empty(); // if alive is empty, we must have set msg above in acceptable_content() | 896 bool rejecting = alive.empty(); // if alive is empty, we must have set msg above in acceptable_content() |
897 if (!rejecting) { | 897 if (!rejecting) { |
898 if (check_hosts(priv, random, limit, host, ip)) { | 898 if (check_hosts(priv, random, limit, host, ip)) { |
899 char adr[sizeof "255.255.255.255"]; | 899 char adr[sizeof "255.255.255.255"]; |
900 adr[0] = '\0'; | 900 adr[0] = '\0'; |
901 inet_ntop(AF_INET, (const u_char *)&ip, adr, sizeof(adr)); | 901 inet_ntop(AF_INET, (const u_char *)&ip, adr, sizeof(adr)); |
902 snprintf(buf, sizeof(buf), priv.content_message, host, adr); | 902 snprintf(buf, sizeof(buf), priv.content_message, host, adr); |
903 msg = buf; | 903 msg = buf; |
904 rejecting = true; | 904 rejecting = true; |
905 } | 905 } |
906 } | 906 } |
907 if (!rejecting) { | 907 if (!rejecting) { |
908 rc = SMFIS_CONTINUE; | 908 rc = SMFIS_CONTINUE; |
909 } | 909 } |
910 else if (!priv.have_whites) { | 910 else if (!priv.have_whites) { |
911 // can reject the entire message | 911 // can reject the entire message |
912 smfi_setreply(ctx, "550", "5.7.1", msg); | 912 smfi_setreply(ctx, "550", "5.7.1", msg); |
913 rc = SMFIS_REJECT; | 913 rc = SMFIS_REJECT; |
914 } | 914 } |
915 else { | 915 else { |
916 // need to accept it but remove the recipients that don't want it | 916 // need to accept it but remove the recipients that don't want it |
917 for (string_set::iterator i=alive.begin(); i!=alive.end(); i++) { | 917 for (string_set::iterator i=alive.begin(); i!=alive.end(); i++) { |
918 char *rcpt = *i; | 918 char *rcpt = *i; |
919 smfi_delrcpt(ctx, rcpt); | 919 smfi_delrcpt(ctx, rcpt); |
920 } | 920 } |
921 rc = SMFIS_CONTINUE; | 921 rc = SMFIS_CONTINUE; |
922 } | 922 } |
923 } | 923 } |
924 // reset for a new message on the same connection | 924 // reset for a new message on the same connection |
925 mlfi_abort(ctx); | 925 mlfi_abort(ctx); |
926 return rc; | 926 return rc; |
927 } | 927 } |
928 | 928 |
929 sfsistat mlfi_abort(SMFICTX *ctx) | 929 sfsistat mlfi_abort(SMFICTX *ctx) |
930 { | 930 { |
931 mlfiPriv &priv = *MLFIPRIV; | 931 mlfiPriv &priv = *MLFIPRIV; |
932 priv.reset(); | 932 priv.reset(); |
933 return SMFIS_CONTINUE; | 933 return SMFIS_CONTINUE; |
934 } | 934 } |
935 | 935 |
936 sfsistat mlfi_close(SMFICTX *ctx) | 936 sfsistat mlfi_close(SMFICTX *ctx) |
937 { | 937 { |
938 mlfiPriv *priv = MLFIPRIV; | 938 mlfiPriv *priv = MLFIPRIV; |
939 if (!priv) return SMFIS_CONTINUE; | 939 if (!priv) return SMFIS_CONTINUE; |
940 delete priv; | 940 delete priv; |
941 smfi_setpriv(ctx, NULL); | 941 smfi_setpriv(ctx, NULL); |
942 return SMFIS_CONTINUE; | 942 return SMFIS_CONTINUE; |
943 } | 943 } |
944 | 944 |
945 struct smfiDesc smfilter = | 945 struct smfiDesc smfilter = |
946 { | 946 { |
947 "DNSBL", // filter name | 947 "DNSBL", // filter name |
948 SMFI_VERSION, // version code -- do not change | 948 SMFI_VERSION, // version code -- do not change |
949 SMFIF_DELRCPT, // flags | 949 SMFIF_DELRCPT, // flags |
950 mlfi_connect, // connection info filter | 950 mlfi_connect, // connection info filter |
951 NULL, // SMTP HELO command filter | 951 NULL, // SMTP HELO command filter |
952 mlfi_envfrom, // envelope sender filter | 952 mlfi_envfrom, // envelope sender filter |
953 mlfi_envrcpt, // envelope recipient filter | 953 mlfi_envrcpt, // envelope recipient filter |
954 NULL, // header filter | 954 NULL, // header filter |
955 NULL, // end of header | 955 NULL, // end of header |
956 mlfi_body, // body block filter | 956 mlfi_body, // body block filter |
957 mlfi_eom, // end of message | 957 mlfi_eom, // end of message |
958 mlfi_abort, // message aborted | 958 mlfi_abort, // message aborted |
959 mlfi_close, // connection cleanup | 959 mlfi_close, // connection cleanup |
960 }; | 960 }; |
961 | 961 |
962 | 962 |
963 //////////////////////////////////////////////// | 963 //////////////////////////////////////////////// |
964 // reload the config | 964 // reload the config |
965 // | 965 // |
966 CONFIG* new_conf(); | 966 CONFIG* new_conf(); |
967 CONFIG* new_conf() { | 967 CONFIG* new_conf() { |
968 CONFIG *newc = new CONFIG; | 968 CONFIG *newc = new CONFIG; |
969 pthread_mutex_lock(&config_mutex); | 969 pthread_mutex_lock(&config_mutex); |
970 newc->generation = generation++; | 970 newc->generation = generation++; |
971 pthread_mutex_unlock(&config_mutex); | 971 pthread_mutex_unlock(&config_mutex); |
972 if (debug_syslog) { | 972 if (debug_syslog) { |
973 char buf[maxlen]; | 973 char buf[maxlen]; |
974 snprintf(buf, sizeof(buf), "loading configuration generation %d", newc->generation); | 974 snprintf(buf, sizeof(buf), "loading configuration generation %d", newc->generation); |
975 my_syslog(buf); | 975 my_syslog(buf); |
976 } | 976 } |
977 if (load_conf(*newc, "dnsbl.conf")) { | 977 if (load_conf(*newc, "dnsbl.conf")) { |
978 newc->load_time = time(NULL); | 978 newc->load_time = time(NULL); |
979 return newc; | 979 return newc; |
980 } | 980 } |
981 delete newc; | 981 delete newc; |
982 return NULL; | 982 return NULL; |
983 } | 983 } |
984 | 984 |
985 | 985 |
986 //////////////////////////////////////////////// | 986 //////////////////////////////////////////////// |
987 // thread to watch the old config files for changes | 987 // thread to watch the old config files for changes |
988 // and reload when needed. we also cleanup old | 988 // and reload when needed. we also cleanup old |
989 // configs whose reference count has gone to zero. | 989 // configs whose reference count has gone to zero. |
990 // | 990 // |
991 void* config_loader(void *arg); | 991 void* config_loader(void *arg); |
992 void* config_loader(void *arg) { | 992 void* config_loader(void *arg) { |
993 typedef set<CONFIG *> configp_set; | 993 typedef set<CONFIG *> configp_set; |
994 configp_set old_configs; | 994 configp_set old_configs; |
995 while (loader_run) { | 995 while (loader_run) { |
996 sleep(180); // look for modifications every 3 minutes | 996 sleep(180); // look for modifications every 3 minutes |
997 if (!loader_run) break; | 997 if (!loader_run) break; |
998 CONFIG &dc = *config; | 998 CONFIG &dc = *config; |
999 time_t then = dc.load_time; | 999 time_t then = dc.load_time; |
1000 struct stat st; | 1000 struct stat st; |
1001 bool reload = false; | 1001 bool reload = false; |
1002 for (string_set::iterator i=dc.config_files.begin(); i!=dc.config_files.end(); i++) { | 1002 for (string_set::iterator i=dc.config_files.begin(); i!=dc.config_files.end(); i++) { |
1003 char *fn = *i; | 1003 char *fn = *i; |
1004 if (stat(fn, &st)) reload = true; // file disappeared | 1004 if (stat(fn, &st)) reload = true; // file disappeared |
1005 else if (st.st_mtime > then) reload = true; // file modified | 1005 else if (st.st_mtime > then) reload = true; // file modified |
1006 if (reload) break; | 1006 if (reload) break; |
1007 } | 1007 } |
1008 if (reload) { | 1008 if (reload) { |
1009 CONFIG *newc = new_conf(); | 1009 CONFIG *newc = new_conf(); |
1010 // replace the global config pointer | 1010 if (newc) { |
1011 pthread_mutex_lock(&config_mutex); | 1011 // replace the global config pointer |
1012 CONFIG *old = config; | 1012 pthread_mutex_lock(&config_mutex); |
1013 config = newc; | 1013 CONFIG *old = config; |
1014 pthread_mutex_unlock(&config_mutex); | 1014 config = newc; |
1015 if (old) old_configs.insert(old); | 1015 pthread_mutex_unlock(&config_mutex); |
1016 } | 1016 if (old) old_configs.insert(old); |
1017 // now look for old configs with zero ref counts | 1017 } |
1018 for (configp_set::iterator i=old_configs.begin(); i!=old_configs.end(); ) { | 1018 else { |
1019 CONFIG *old = *i; | 1019 // failed to load new config |
1020 if (!old->reference_count) { | 1020 my_syslog("failed to load new configuration"); |
1021 if (debug_syslog) { | 1021 system("echo 'failed to load new dnsbl configuration from /etc/dnsbl' | mail -s 'error in /etc/dnsbl configuration' root"); |
1022 char buf[maxlen]; | 1022 // update the load time on the current config to prevent complaining every 3 minutes |
1023 snprintf(buf, sizeof(buf), "freeing memory for old configuration generation %d", old->generation); | 1023 dc.load_time = time(NULL); |
1024 my_syslog(buf); | 1024 } |
1025 } | 1025 } |
1026 delete old; // destructor does all the work | 1026 // now look for old configs with zero ref counts |
1027 old_configs.erase(i++); | 1027 for (configp_set::iterator i=old_configs.begin(); i!=old_configs.end(); ) { |
1028 } | 1028 CONFIG *old = *i; |
1029 else i++; | 1029 if (!old->reference_count) { |
1030 } | 1030 if (debug_syslog) { |
1031 } | 1031 char buf[maxlen]; |
1032 return NULL; | 1032 snprintf(buf, sizeof(buf), "freeing memory for old configuration generation %d", old->generation); |
1033 my_syslog(buf); | |
1034 } | |
1035 delete old; // destructor does all the work | |
1036 old_configs.erase(i++); | |
1037 } | |
1038 else i++; | |
1039 } | |
1040 } | |
1041 return NULL; | |
1033 } | 1042 } |
1034 | 1043 |
1035 | 1044 |
1036 void usage(char *prog); | 1045 void usage(char *prog); |
1037 void usage(char *prog) | 1046 void usage(char *prog) |
1038 { | 1047 { |
1039 fprintf(stderr, "Usage: %s [-d [level]] [-c] [-s] [-e from|to] -r port -p sm-sock-addr [-t timeout]\n", prog); | 1048 fprintf(stderr, "Usage: %s [-d [level]] [-c] [-s] [-e from|to] -r port -p sm-sock-addr [-t timeout]\n", prog); |
1040 fprintf(stderr, "where port is for the connection to our own dns resolver processes\n"); | 1049 fprintf(stderr, "where port is for the connection to our own dns resolver processes\n"); |
1041 fprintf(stderr, " and should be local-domain-socket-file-name\n"); | 1050 fprintf(stderr, " and should be local-domain-socket-file-name\n"); |
1042 fprintf(stderr, "where sm-sock-addr is for the connection to sendmail\n"); | 1051 fprintf(stderr, "where sm-sock-addr is for the connection to sendmail\n"); |
1043 fprintf(stderr, " and should be one of\n"); | 1052 fprintf(stderr, " and should be one of\n"); |
1044 fprintf(stderr, " inet:port@ip-address\n"); | 1053 fprintf(stderr, " inet:port@ip-address\n"); |
1045 fprintf(stderr, " local:local-domain-socket-file-name\n"); | 1054 fprintf(stderr, " local:local-domain-socket-file-name\n"); |
1046 fprintf(stderr, "-c will load and dump the config to stdout\n"); | 1055 fprintf(stderr, "-c will load and dump the config to stdout\n"); |
1047 fprintf(stderr, "-s will stress test the config loading code by repeating the load/free cycle\n"); | 1056 fprintf(stderr, "-s will stress test the config loading code by repeating the load/free cycle\n"); |
1048 fprintf(stderr, " in an infinte loop.\n"); | 1057 fprintf(stderr, " in an infinte loop.\n"); |
1049 fprintf(stderr, "-d will set the syslog message level, currently 0 to 3"); | 1058 fprintf(stderr, "-d will set the syslog message level, currently 0 to 3"); |
1050 fprintf(stderr, "-e will print the results of looking up the from and to addresses in the\n"); | 1059 fprintf(stderr, "-e will print the results of looking up the from and to addresses in the\n"); |
1051 fprintf(stderr, " current config. The | character is used to separate the from and to\n"); | 1060 fprintf(stderr, " current config. The | character is used to separate the from and to\n"); |
1052 fprintf(stderr, " addresses in the argument to the -e switch\n"); | 1061 fprintf(stderr, " addresses in the argument to the -e switch\n"); |
1053 } | 1062 } |
1054 | 1063 |
1055 | 1064 |
1056 | 1065 |
1057 void setup_socket(char *sock); | 1066 void setup_socket(char *sock); |
1058 void setup_socket(char *sock) { | 1067 void setup_socket(char *sock) { |
1059 unlink(sock); | 1068 unlink(sock); |
1060 // sockaddr_un addr; | 1069 // sockaddr_un addr; |
1061 // memset(&addr, '\0', sizeof addr); | 1070 // memset(&addr, '\0', sizeof addr); |
1062 // addr.sun_family = AF_UNIX; | 1071 // addr.sun_family = AF_UNIX; |
1063 // strncpy(addr.sun_path, sock, sizeof(addr.sun_path)-1); | 1072 // strncpy(addr.sun_path, sock, sizeof(addr.sun_path)-1); |
1064 // int s = socket(AF_UNIX, SOCK_STREAM, 0); | 1073 // int s = socket(AF_UNIX, SOCK_STREAM, 0); |
1065 // bind(s, (sockaddr*)&addr, sizeof(addr)); | 1074 // bind(s, (sockaddr*)&addr, sizeof(addr)); |
1066 // close(s); | 1075 // close(s); |
1067 } | 1076 } |
1068 | 1077 |
1069 | 1078 |
1070 /* | 1079 /* |
1071 * The signal handler function -- only gets called when a SIGCHLD | 1080 * The signal handler function -- only gets called when a SIGCHLD |
1072 * is received, ie when a child terminates | 1081 * is received, ie when a child terminates |
1073 */ | 1082 */ |
1074 void sig_chld(int signo) | 1083 void sig_chld(int signo) |
1075 { | 1084 { |
1076 int status; | 1085 int status; |
1077 /* Wait for any child without blocking */ | 1086 /* Wait for any child without blocking */ |
1078 while (waitpid(-1, &status, WNOHANG) > 0) { | 1087 while (waitpid(-1, &status, WNOHANG) > 0) { |
1079 // ignore child exit status, we only do this to cleanup zombies | 1088 // ignore child exit status, we only do this to cleanup zombies |
1080 } | 1089 } |
1081 } | 1090 } |
1082 | 1091 |
1083 | 1092 |
1084 int main(int argc, char**argv) | 1093 int main(int argc, char**argv) |
1085 { | 1094 { |
1086 token_init(); | 1095 token_init(); |
1087 bool check = false; | 1096 bool check = false; |
1088 bool stress = false; | 1097 bool stress = false; |
1089 bool setconn = false; | 1098 bool setconn = false; |
1090 bool setreso = false; | 1099 bool setreso = false; |
1091 char *email = NULL; | 1100 char *email = NULL; |
1092 int c; | 1101 int c; |
1093 const char *args = "r:p:t:e:d:chs"; | 1102 const char *args = "r:p:t:e:d:chs"; |
1094 extern char *optarg; | 1103 extern char *optarg; |
1095 | 1104 |
1096 // Process command line options | 1105 // Process command line options |
1097 while ((c = getopt(argc, argv, args)) != -1) { | 1106 while ((c = getopt(argc, argv, args)) != -1) { |
1098 switch (c) { | 1107 switch (c) { |
1099 case 'r': | 1108 case 'r': |
1100 if (optarg == NULL || *optarg == '\0') { | 1109 if (optarg == NULL || *optarg == '\0') { |
1101 fprintf(stderr, "Illegal resolver socket: %s\n", optarg); | 1110 fprintf(stderr, "Illegal resolver socket: %s\n", optarg); |
1102 exit(EX_USAGE); | 1111 exit(EX_USAGE); |
1103 } | 1112 } |
1104 resolver_port = strdup(optarg); | 1113 resolver_port = strdup(optarg); |
1105 setup_socket(resolver_port); | 1114 setup_socket(resolver_port); |
1106 setreso = true; | 1115 setreso = true; |
1107 break; | 1116 break; |
1108 | 1117 |
1109 case 'p': | 1118 case 'p': |
1110 if (optarg == NULL || *optarg == '\0') { | 1119 if (optarg == NULL || *optarg == '\0') { |
1111 fprintf(stderr, "Illegal sendmail socket: %s\n", optarg); | 1120 fprintf(stderr, "Illegal sendmail socket: %s\n", optarg); |
1112 exit(EX_USAGE); | 1121 exit(EX_USAGE); |
1113 } | 1122 } |
1114 if (smfi_setconn(optarg) == MI_FAILURE) { | 1123 if (smfi_setconn(optarg) == MI_FAILURE) { |
1115 fprintf(stderr, "smfi_setconn failed\n"); | 1124 fprintf(stderr, "smfi_setconn failed\n"); |
1116 exit(EX_SOFTWARE); | 1125 exit(EX_SOFTWARE); |
1117 } | 1126 } |
1118 if (strncasecmp(optarg, "unix:", 5) == 0) setup_socket(optarg + 5); | 1127 if (strncasecmp(optarg, "unix:", 5) == 0) setup_socket(optarg + 5); |
1119 else if (strncasecmp(optarg, "local:", 6) == 0) setup_socket(optarg + 6); | 1128 else if (strncasecmp(optarg, "local:", 6) == 0) setup_socket(optarg + 6); |
1120 setconn = true; | 1129 setconn = true; |
1121 break; | 1130 break; |
1122 | 1131 |
1123 case 't': | 1132 case 't': |
1124 if (optarg == NULL || *optarg == '\0') { | 1133 if (optarg == NULL || *optarg == '\0') { |
1125 fprintf(stderr, "Illegal timeout: %s\n", optarg); | 1134 fprintf(stderr, "Illegal timeout: %s\n", optarg); |
1126 exit(EX_USAGE); | 1135 exit(EX_USAGE); |
1127 } | 1136 } |
1128 if (smfi_settimeout(atoi(optarg)) == MI_FAILURE) { | 1137 if (smfi_settimeout(atoi(optarg)) == MI_FAILURE) { |
1129 fprintf(stderr, "smfi_settimeout failed\n"); | 1138 fprintf(stderr, "smfi_settimeout failed\n"); |
1130 exit(EX_SOFTWARE); | 1139 exit(EX_SOFTWARE); |
1131 } | 1140 } |
1132 break; | 1141 break; |
1133 | 1142 |
1134 case 'e': | 1143 case 'e': |
1135 if (email) free(email); | 1144 if (email) free(email); |
1136 email = strdup(optarg); | 1145 email = strdup(optarg); |
1137 break; | 1146 break; |
1138 | 1147 |
1139 case 'c': | 1148 case 'c': |
1140 check = true; | 1149 check = true; |
1141 break; | 1150 break; |
1142 | 1151 |
1143 case 's': | 1152 case 's': |
1144 stress = true; | 1153 stress = true; |
1145 break; | 1154 break; |
1146 | 1155 |
1147 case 'd': | 1156 case 'd': |
1148 if (optarg == NULL || *optarg == '\0') debug_syslog = 1; | 1157 if (optarg == NULL || *optarg == '\0') debug_syslog = 1; |
1149 else debug_syslog = atoi(optarg); | 1158 else debug_syslog = atoi(optarg); |
1150 break; | 1159 break; |
1151 | 1160 |
1152 case 'h': | 1161 case 'h': |
1153 default: | 1162 default: |
1154 usage(argv[0]); | 1163 usage(argv[0]); |
1155 exit(EX_USAGE); | 1164 exit(EX_USAGE); |
1156 } | 1165 } |
1157 } | 1166 } |
1158 | 1167 |
1159 if (check) { | 1168 if (check) { |
1160 use_syslog = false; | 1169 use_syslog = false; |
1161 debug_syslog = 10; | 1170 debug_syslog = 10; |
1162 CONFIG *conf = new_conf(); | 1171 CONFIG *conf = new_conf(); |
1163 if (conf) { | 1172 if (conf) { |
1164 conf->dump(); | 1173 conf->dump(); |
1165 delete conf; | 1174 delete conf; |
1166 return 0; | 1175 return 0; |
1167 } | 1176 } |
1168 else { | 1177 else { |
1169 return 1; // config failed to load | 1178 return 1; // config failed to load |
1170 } | 1179 } |
1171 } | 1180 } |
1172 | 1181 |
1173 if (stress) { | 1182 if (stress) { |
1174 fprintf(stdout, "stress testing\n"); | 1183 fprintf(stdout, "stress testing\n"); |
1175 while (1) { | 1184 while (1) { |
1176 for (int i=0; i<10; i++) { | 1185 for (int i=0; i<10; i++) { |
1177 CONFIG *conf = new_conf(); | 1186 CONFIG *conf = new_conf(); |
1178 if (conf) delete conf; | 1187 if (conf) delete conf; |
1179 } | 1188 } |
1180 fprintf(stdout, "."); | 1189 fprintf(stdout, "."); |
1181 fflush(stdout); | 1190 fflush(stdout); |
1182 sleep(1); | 1191 sleep(1); |
1183 } | 1192 } |
1184 } | 1193 } |
1185 | 1194 |
1186 if (email) { | 1195 if (email) { |
1187 char *x = strchr(email, '|'); | 1196 char *x = strchr(email, '|'); |
1188 if (x) { | 1197 if (x) { |
1189 *x = '\0'; | 1198 *x = '\0'; |
1190 char *from = strdup(email); | 1199 char *from = strdup(email); |
1191 char *to = strdup(x+1); | 1200 char *to = strdup(x+1); |
1192 use_syslog = false; | 1201 use_syslog = false; |
1193 CONFIG *conf = new_conf(); | 1202 CONFIG *conf = new_conf(); |
1194 if (conf) { | 1203 if (conf) { |
1195 CONTEXTP con = conf->find_context(to); | 1204 CONTEXTP con = conf->find_context(to); |
1196 char buf[maxlen]; | 1205 char buf[maxlen]; |
1197 fprintf(stdout, "envelope to <%s> finds context %s\n", to, con->get_full_name(buf,maxlen)); | 1206 fprintf(stdout, "envelope to <%s> finds context %s\n", to, con->get_full_name(buf,maxlen)); |
1198 CONTEXTP fc = con->find_context(from); | 1207 CONTEXTP fc = con->find_context(from); |
1199 fprintf(stdout, "envelope from <%s> finds context %s\n", from, fc->get_full_name(buf,maxlen)); | 1208 fprintf(stdout, "envelope from <%s> finds context %s\n", from, fc->get_full_name(buf,maxlen)); |
1200 char *st = fc->find_from(from); | 1209 char *st = fc->find_from(from); |
1201 fprintf(stdout, "envelope from <%s> finds status %s\n", from, st); | 1210 fprintf(stdout, "envelope from <%s> finds status %s\n", from, st); |
1202 delete conf; | 1211 delete conf; |
1203 } | 1212 } |
1204 } | 1213 } |
1205 return 0; | 1214 return 0; |
1206 } | 1215 } |
1207 | 1216 |
1208 if (!setconn) { | 1217 if (!setconn) { |
1209 fprintf(stderr, "%s: Missing required -p argument\n", argv[0]); | 1218 fprintf(stderr, "%s: Missing required -p argument\n", argv[0]); |
1210 usage(argv[0]); | 1219 usage(argv[0]); |
1211 exit(EX_USAGE); | 1220 exit(EX_USAGE); |
1212 } | 1221 } |
1213 | 1222 |
1214 if (!setreso) { | 1223 if (!setreso) { |
1215 fprintf(stderr, "%s: Missing required -r argument\n", argv[0]); | 1224 fprintf(stderr, "%s: Missing required -r argument\n", argv[0]); |
1216 usage(argv[0]); | 1225 usage(argv[0]); |
1217 exit(EX_USAGE); | 1226 exit(EX_USAGE); |
1218 } | 1227 } |
1219 | 1228 |
1220 if (smfi_register(smfilter) == MI_FAILURE) { | 1229 if (smfi_register(smfilter) == MI_FAILURE) { |
1221 fprintf(stderr, "smfi_register failed\n"); | 1230 fprintf(stderr, "smfi_register failed\n"); |
1222 exit(EX_UNAVAILABLE); | 1231 exit(EX_UNAVAILABLE); |
1223 } | 1232 } |
1224 | 1233 |
1225 // switch to background mode | 1234 // switch to background mode |
1226 if (daemon(1,0) < 0) { | 1235 if (daemon(1,0) < 0) { |
1227 fprintf(stderr, "daemon() call failed\n"); | 1236 fprintf(stderr, "daemon() call failed\n"); |
1228 exit(EX_UNAVAILABLE); | 1237 exit(EX_UNAVAILABLE); |
1229 } | 1238 } |
1230 | 1239 |
1231 // write the pid | 1240 // write the pid |
1232 const char *pidpath = "/var/run/dnsbl.pid"; | 1241 const char *pidpath = "/var/run/dnsbl.pid"; |
1233 unlink(pidpath); | 1242 unlink(pidpath); |
1234 FILE *f = fopen(pidpath, "w"); | 1243 FILE *f = fopen(pidpath, "w"); |
1235 if (f) { | 1244 if (f) { |
1236 #ifdef linux | 1245 #ifdef linux |
1237 // from a comment in the DCC source code: | 1246 // from a comment in the DCC source code: |
1238 // Linux threads are broken. Signals given the | 1247 // Linux threads are broken. Signals given the |
1239 // original process are delivered to only the | 1248 // original process are delivered to only the |
1240 // thread that happens to have that PID. The | 1249 // thread that happens to have that PID. The |
1241 // sendmail libmilter thread that needs to hear | 1250 // sendmail libmilter thread that needs to hear |
1242 // SIGINT and other signals does not, and that breaks | 1251 // SIGINT and other signals does not, and that breaks |
1243 // scripts that need to stop milters. | 1252 // scripts that need to stop milters. |
1244 // However, signaling the process group works. | 1253 // However, signaling the process group works. |
1245 fprintf(f, "-%d\n", (u_int)getpgrp()); | 1254 fprintf(f, "-%d\n", (u_int)getpgrp()); |
1246 #else | 1255 #else |
1247 fprintf(f, "%d\n", (u_int)getpid()); | 1256 fprintf(f, "%d\n", (u_int)getpid()); |
1248 #endif | 1257 #endif |
1249 fclose(f); | 1258 fclose(f); |
1250 } | 1259 } |
1251 | 1260 |
1252 // initialize the thread sync objects | 1261 // initialize the thread sync objects |
1253 pthread_mutex_init(&config_mutex, 0); | 1262 pthread_mutex_init(&config_mutex, 0); |
1254 pthread_mutex_init(&syslog_mutex, 0); | 1263 pthread_mutex_init(&syslog_mutex, 0); |
1255 pthread_mutex_init(&resolve_mutex, 0); | 1264 pthread_mutex_init(&resolve_mutex, 0); |
1256 pthread_mutex_init(&fd_pool_mutex, 0); | 1265 pthread_mutex_init(&fd_pool_mutex, 0); |
1257 | 1266 |
1258 // drop root privs | 1267 // drop root privs |
1259 struct passwd *pw = getpwnam("dnsbl"); | 1268 struct passwd *pw = getpwnam("dnsbl"); |
1260 if (pw) { | 1269 if (pw) { |
1261 if (setgid(pw->pw_gid) == -1) { | 1270 if (setgid(pw->pw_gid) == -1) { |
1262 my_syslog("failed to switch to group dnsbl"); | 1271 my_syslog("failed to switch to group dnsbl"); |
1263 } | 1272 } |
1264 if (setuid(pw->pw_uid) == -1) { | 1273 if (setuid(pw->pw_uid) == -1) { |
1265 my_syslog("failed to switch to user dnsbl"); | 1274 my_syslog("failed to switch to user dnsbl"); |
1266 } | 1275 } |
1267 } | 1276 } |
1268 | 1277 |
1269 // fork off the resolver listener process | 1278 // load the initial config |
1270 pid_t child = fork(); | 1279 config = new_conf(); |
1271 if (child < 0) { | 1280 if (!config) { |
1272 my_syslog("failed to create resolver listener process"); | 1281 my_syslog("failed to load initial configuration, quitting"); |
1273 exit(0); | 1282 exit(1); |
1274 } | 1283 } |
1275 if (child == 0) { | 1284 |
1276 // we are the child - dns resolver listener process | 1285 // fork off the resolver listener process |
1277 resolver_socket = socket(AF_UNIX, SOCK_STREAM, 0); | 1286 pid_t child = fork(); |
1278 if (resolver_socket < 0) { | 1287 if (child < 0) { |
1279 my_syslog("child failed to create resolver socket"); | 1288 my_syslog("failed to create resolver listener process"); |
1280 exit(0); // failed | 1289 exit(0); |
1281 } | 1290 } |
1282 sockaddr_un server; | 1291 if (child == 0) { |
1283 memset(&server, '\0', sizeof(server)); | 1292 // we are the child - dns resolver listener process |
1284 server.sun_family = AF_UNIX; | 1293 resolver_socket = socket(AF_UNIX, SOCK_STREAM, 0); |
1285 strncpy(server.sun_path, resolver_port, sizeof(server.sun_path)-1); | 1294 if (resolver_socket < 0) { |
1286 //try to bind the address to the socket. | 1295 my_syslog("child failed to create resolver socket"); |
1287 if (bind(resolver_socket, (sockaddr *)&server, sizeof(server)) < 0) { | 1296 exit(0); // failed |
1288 // bind failed | 1297 } |
1289 shutdown(resolver_socket, SHUT_RDWR); | 1298 sockaddr_un server; |
1290 close(resolver_socket); | 1299 memset(&server, '\0', sizeof(server)); |
1291 my_syslog("child failed to bind resolver socket"); | 1300 server.sun_family = AF_UNIX; |
1292 exit(0); // failed | 1301 strncpy(server.sun_path, resolver_port, sizeof(server.sun_path)-1); |
1293 } | 1302 //try to bind the address to the socket. |
1294 //listen on the socket. | 1303 if (bind(resolver_socket, (sockaddr *)&server, sizeof(server)) < 0) { |
1295 if (listen(resolver_socket, 10) < 0) { | 1304 // bind failed |
1296 // listen failed | 1305 shutdown(resolver_socket, SHUT_RDWR); |
1297 shutdown(resolver_socket, SHUT_RDWR); | 1306 close(resolver_socket); |
1298 close(resolver_socket); | 1307 my_syslog("child failed to bind resolver socket"); |
1299 my_syslog("child failed to listen to resolver socket"); | 1308 exit(0); // failed |
1300 exit(0); // failed | 1309 } |
1301 } | 1310 //listen on the socket. |
1302 // setup sigchld handler to prevent zombies | 1311 if (listen(resolver_socket, 10) < 0) { |
1303 struct sigaction act; | 1312 // listen failed |
1304 act.sa_handler = sig_chld; // Assign sig_chld as our SIGCHLD handler | 1313 shutdown(resolver_socket, SHUT_RDWR); |
1305 sigemptyset(&act.sa_mask); // We don't want to block any other signals in this example | 1314 close(resolver_socket); |
1306 act.sa_flags = SA_NOCLDSTOP; // only want children that have terminated | 1315 my_syslog("child failed to listen to resolver socket"); |
1307 if (sigaction(SIGCHLD, &act, NULL) < 0) { | 1316 exit(0); // failed |
1308 my_syslog("child failed to setup SIGCHLD handler"); | 1317 } |
1309 exit(0); // failed | 1318 // setup sigchld handler to prevent zombies |
1310 } | 1319 struct sigaction act; |
1311 while (true) { | 1320 act.sa_handler = sig_chld; // Assign sig_chld as our SIGCHLD handler |
1312 sockaddr_un client; | 1321 sigemptyset(&act.sa_mask); // We don't want to block any other signals in this example |
1313 socklen_t clientlen = sizeof(client); | 1322 act.sa_flags = SA_NOCLDSTOP; // only want children that have terminated |
1314 int s = accept(resolver_socket, (sockaddr *)&client, &clientlen); | 1323 if (sigaction(SIGCHLD, &act, NULL) < 0) { |
1315 if (s > 0) { | 1324 my_syslog("child failed to setup SIGCHLD handler"); |
1316 // accept worked, it did not get cancelled before we could accept it | 1325 exit(0); // failed |
1317 // fork off a process to handle this connection | 1326 } |
1318 int newchild = fork(); | 1327 while (true) { |
1319 if (newchild == 0) { | 1328 sockaddr_un client; |
1320 // this is the worker process | 1329 socklen_t clientlen = sizeof(client); |
1321 // child does not need the listening socket | 1330 int s = accept(resolver_socket, (sockaddr *)&client, &clientlen); |
1322 close(resolver_socket); | 1331 if (s > 0) { |
1323 process_resolver_requests(s); | 1332 // accept worked, it did not get cancelled before we could accept it |
1324 exit(0); | 1333 // fork off a process to handle this connection |
1325 } | 1334 int newchild = fork(); |
1326 else { | 1335 if (newchild == 0) { |
1327 // this is the parent | 1336 // this is the worker process |
1328 // parent does not need the accepted socket | 1337 // child does not need the listening socket |
1329 close(s); | 1338 close(resolver_socket); |
1330 } | 1339 process_resolver_requests(s); |
1331 } | 1340 exit(0); |
1332 } | 1341 } |
1333 exit(0); // make sure we don't fall thru. | 1342 else { |
1334 } | 1343 // this is the parent |
1335 else { | 1344 // parent does not need the accepted socket |
1336 sleep(2); // allow child to get started | 1345 close(s); |
1337 } | 1346 } |
1338 | 1347 } |
1339 // load the initial config | 1348 } |
1340 config = new_conf(); | 1349 exit(0); // make sure we don't fall thru. |
1341 | 1350 } |
1342 // only create threads after the fork() in daemon | 1351 else { |
1343 pthread_t tid; | 1352 sleep(2); // allow child to get started |
1344 if (pthread_create(&tid, 0, config_loader, 0)) | 1353 } |
1345 my_syslog("failed to create config loader thread"); | 1354 |
1346 if (pthread_detach(tid)) | 1355 // only create threads after the fork() in daemon |
1347 my_syslog("failed to detach config loader thread"); | 1356 pthread_t tid; |
1348 | 1357 if (pthread_create(&tid, 0, config_loader, 0)) |
1349 time_t starting = time(NULL); | 1358 my_syslog("failed to create config loader thread"); |
1350 int rc = smfi_main(); | 1359 if (pthread_detach(tid)) |
1351 if ((rc != MI_SUCCESS) && (time(NULL) > starting+5*60)) { | 1360 my_syslog("failed to detach config loader thread"); |
1352 my_syslog("trying to restart after smfi_main()"); | 1361 |
1353 loader_run = false; // eventually the config loader thread will terminate | 1362 time_t starting = time(NULL); |
1354 execvp(argv[0], argv); | 1363 int rc = smfi_main(); |
1355 } | 1364 if ((rc != MI_SUCCESS) && (time(NULL) > starting+5*60)) { |
1356 exit((rc == MI_SUCCESS) ? 0 : EX_UNAVAILABLE); | 1365 my_syslog("trying to restart after smfi_main()"); |
1357 } | 1366 loader_run = false; // eventually the config loader thread will terminate |
1358 | 1367 execvp(argv[0], argv); |
1368 } | |
1369 exit((rc == MI_SUCCESS) ? 0 : EX_UNAVAILABLE); | |
1370 } | |
1371 |