Postfix3.3.1
postscreen_dnsbl.c
[詳解]
1 /*++
2 /* NAME
3 /* postscreen_dnsbl 3
4 /* SUMMARY
5 /* postscreen DNSBL support
6 /* SYNOPSIS
7 /* #include <postscreen.h>
8 /*
9 /* void psc_dnsbl_init(void)
10 /*
11 /* int psc_dnsbl_request(client_addr, callback, context)
12 /* char *client_addr;
13 /* void (*callback)(int, char *);
14 /* char *context;
15 /*
16 /* int psc_dnsbl_retrieve(client_addr, dnsbl_name, dnsbl_index,
17 /* dnsbl_ttl)
18 /* char *client_addr;
19 /* const char **dnsbl_name;
20 /* int dnsbl_index;
21 /* int *dnsbl_ttl;
22 /* DESCRIPTION
23 /* This module implements preliminary support for DNSBL lookups.
24 /* Multiple requests for the same information are handled with
25 /* reference counts.
26 /*
27 /* psc_dnsbl_init() initializes this module, and must be called
28 /* once before any of the other functions in this module.
29 /*
30 /* psc_dnsbl_request() requests a blocklist score for the
31 /* specified client IP address and increments the reference
32 /* count. The request completes in the background. The client
33 /* IP address must be in inet_ntop(3) output format. The
34 /* callback argument specifies a function that is called when
35 /* the requested result is available. The context is passed
36 /* on to the callback function. The callback should ignore its
37 /* first argument (it exists for compatibility with Postfix
38 /* generic event infrastructure).
39 /* The result value is the index for the psc_dnsbl_retrieve()
40 /* call.
41 /*
42 /* psc_dnsbl_retrieve() retrieves the result score and reply
43 /* TTL requested with psc_dnsbl_request(), and decrements the
44 /* reference count. The reply TTL value is clamped to
45 /* postscreen_dnsbl_min_ttl and postscreen_dnsbl_max_ttl. It
46 /* is an error to retrieve a score without requesting it first.
47 /* LICENSE
48 /* .ad
49 /* .fi
50 /* The Secure Mailer license must be distributed with this software.
51 /* AUTHOR(S)
52 /* Wietse Venema
53 /* IBM T.J. Watson Research
54 /* P.O. Box 704
55 /* Yorktown Heights, NY 10598, USA
56 /*
57 /* Wietse Venema
58 /* Google, Inc.
59 /* 111 8th Avenue
60 /* New York, NY 10011, USA
61 /*--*/
62 
63 /* System library. */
64 
65 #include <sys_defs.h>
66 #include <sys/socket.h> /* AF_INET */
67 #include <netinet/in.h> /* inet_pton() */
68 #include <arpa/inet.h> /* inet_pton() */
69 #include <stdio.h> /* sscanf */
70 #include <limits.h>
71 
72 /* Utility library. */
73 
74 #include <msg.h>
75 #include <mymalloc.h>
76 #include <argv.h>
77 #include <htable.h>
78 #include <events.h>
79 #include <vstream.h>
80 #include <connect.h>
81 #include <split_at.h>
82 #include <valid_hostname.h>
83 #include <ip_match.h>
84 #include <myaddrinfo.h>
85 #include <stringops.h>
86 
87 /* Global library. */
88 
89 #include <mail_params.h>
90 #include <mail_proto.h>
91 
92 /* Application-specific. */
93 
94 #include <postscreen.h>
95 
96  /*
97  * Talking to the DNSBLOG service.
98  */
99 static char *psc_dnsbl_service;
100 
101  /*
102  * Per-DNSBL filters and weights.
103  *
104  * The postscreen_dnsbl_sites parameter specifies zero or more DNSBL domains.
105  * We provide multiple access methods, one for quick iteration when sending
106  * queries to all DNSBL servers, and one for quick location when receiving a
107  * reply from one DNSBL server.
108  *
109  * Each DNSBL domain can be specified more than once, each time with a
110  * different (filter, weight) pair. We group (filter, weight) pairs in a
111  * linked list under their DNSBL domain name. The list head has a reference
112  * to a "safe name" for the DNSBL, in case the name includes a password.
113  */
114 static HTABLE *dnsbl_site_cache; /* indexed by DNSBNL domain */
115 static HTABLE_INFO **dnsbl_site_list; /* flattened cache */
116 
117 typedef struct {
118  const char *safe_dnsbl; /* from postscreen_dnsbl_reply_map */
119  struct PSC_DNSBL_SITE *first; /* list of (filter, weight) tuples */
121 
122 typedef struct PSC_DNSBL_SITE {
123  char *filter; /* printable filter (default: null) */
124  char *byte_codes; /* encoded filter (default: null) */
125  int weight; /* reply weight (default: 1) */
126  struct PSC_DNSBL_SITE *next; /* linked list */
128 
129  /*
130  * Per-client DNSBL scores.
131  *
132  * Some SMTP clients make parallel connections. This can trigger parallel
133  * blocklist score requests when the pre-handshake delays of the connections
134  * overlap.
135  *
136  * We combine requests for the same score under the client IP address in a
137  * single reference-counted entry. The reference count goes up with each
138  * request for a score, and it goes down with each score retrieval. Each
139  * score has one or more requestors that need to be notified when the result
140  * is ready, so that postscreen can terminate a pre-handshake delay when all
141  * pre-handshake tests are completed.
142  */
143 static HTABLE *dnsbl_score_cache; /* indexed by client address */
144 
145 typedef struct {
146  void (*callback) (int, void *); /* generic call-back routine */
147  void *context; /* generic call-back argument */
149 
150 typedef struct {
151  const char *dnsbl_name; /* DNSBL with largest contribution */
152  int dnsbl_weight; /* weight of largest contribution */
153  int total; /* combined white+blocklist score */
154  int fail_ttl; /* combined reply TTL */
155  int pass_ttl; /* combined reply TTL */
156  int refcount; /* score reference count */
157  int pending_lookups; /* nr of DNS requests in flight */
158  int request_id; /* duplicate suppression */
159  /* Call-back table support. */
160  int index; /* next table index */
161  int limit; /* last valid index */
162  PSC_CALL_BACK_ENTRY table[1]; /* actually a bunch */
164 
165 #define PSC_CALL_BACK_INIT(sp) do { \
166  (sp)->limit = 0; \
167  (sp)->index = 0; \
168  } while (0)
169 
170 #define PSC_CALL_BACK_INDEX_OF_LAST(sp) ((sp)->index - 1)
171 
172 #define PSC_CALL_BACK_CANCEL(sp, idx) do { \
173  PSC_CALL_BACK_ENTRY *_cb_; \
174  if ((idx) < 0 || (idx) >= (sp)->index) \
175  msg_panic("%s: index %d must be >= 0 and < %d", \
176  myname, (idx), (sp)->index); \
177  _cb_ = (sp)->table + (idx); \
178  event_cancel_timer(_cb_->callback, _cb_->context); \
179  _cb_->callback = 0; \
180  _cb_->context = 0; \
181  } while (0)
182 
183 #define PSC_CALL_BACK_EXTEND(hp, sp) do { \
184  if ((sp)->index >= (sp)->limit) { \
185  int _count_ = ((sp)->limit ? (sp)->limit * 2 : 5); \
186  (hp)->value = myrealloc((void *) (sp), sizeof(*(sp)) + \
187  _count_ * sizeof((sp)->table)); \
188  (sp) = (PSC_DNSBL_SCORE *) (hp)->value; \
189  (sp)->limit = _count_; \
190  } \
191  } while (0)
192 
193 #define PSC_CALL_BACK_ENTER(sp, fn, ctx) do { \
194  PSC_CALL_BACK_ENTRY *_cb_ = (sp)->table + (sp)->index++; \
195  _cb_->callback = (fn); \
196  _cb_->context = (ctx); \
197  } while (0)
198 
199 #define PSC_CALL_BACK_NOTIFY(sp, ev) do { \
200  PSC_CALL_BACK_ENTRY *_cb_; \
201  for (_cb_ = (sp)->table; _cb_ < (sp)->table + (sp)->index; _cb_++) \
202  if (_cb_->callback != 0) \
203  _cb_->callback((ev), _cb_->context); \
204  } while (0)
205 
206 #define PSC_NULL_EVENT (0)
207 
208  /*
209  * Per-request state.
210  *
211  * This implementation stores the client IP address and DNSBL domain in the
212  * DNSBLOG query/reply stream. This simplifies code, and allows the DNSBLOG
213  * server to produce more informative logging.
214  */
215 static VSTRING *reply_client; /* client address in DNSBLOG reply */
216 static VSTRING *reply_dnsbl; /* domain in DNSBLOG reply */
217 static VSTRING *reply_addr; /* address list in DNSBLOG reply */
218 
219 /* psc_dnsbl_add_site - add DNSBL site information */
220 
221 static void psc_dnsbl_add_site(const char *site)
222 {
223  const char *myname = "psc_dnsbl_add_site";
224  char *saved_site = mystrdup(site);
225  VSTRING *byte_codes = 0;
226  PSC_DNSBL_HEAD *head;
227  PSC_DNSBL_SITE *new_site;
228  char junk;
229  const char *weight_text;
230  char *pattern_text;
231  int weight;
232  HTABLE_INFO *ht;
233  char *parse_err;
234 
235  /*
236  * Parse the required DNSBL domain name, the optional reply filter and
237  * the optional reply weight factor.
238  */
239 #define DO_GRIPE 1
240 
241  /* Negative weight means whitelist. */
242  if ((weight_text = split_at(saved_site, '*')) != 0) {
243  if (sscanf(weight_text, "%d%c", &weight, &junk) != 1)
244  msg_fatal("bad DNSBL weight factor \"%s\" in \"%s\"",
245  weight_text, site);
246  } else {
247  weight = 1;
248  }
249  /* Reply filter. */
250  if ((pattern_text = split_at(saved_site, '=')) != 0) {
251  byte_codes = vstring_alloc(100);
252  if ((parse_err = ip_match_parse(byte_codes, pattern_text)) != 0)
253  msg_fatal("bad DNSBL filter syntax: %s", parse_err);
254  }
255  if (valid_hostname(saved_site, DO_GRIPE) == 0)
256  msg_fatal("bad DNSBL domain name \"%s\" in \"%s\"",
257  saved_site, site);
258 
259  if (msg_verbose > 1)
260  msg_info("%s: \"%s\" -> domain=\"%s\" pattern=\"%s\" weight=%d",
261  myname, site, saved_site, pattern_text ? pattern_text :
262  "null", weight);
263 
264  /*
265  * Look up or create the (filter, weight) list head for this DNSBL domain
266  * name.
267  */
268  if ((head = (PSC_DNSBL_HEAD *)
269  htable_find(dnsbl_site_cache, saved_site)) == 0) {
270  head = (PSC_DNSBL_HEAD *) mymalloc(sizeof(*head));
271  ht = htable_enter(dnsbl_site_cache, saved_site, (void *) head);
272  /* Translate the DNSBL name into a safe name if available. */
273  if (psc_dnsbl_reply == 0
274  || (head->safe_dnsbl = dict_get(psc_dnsbl_reply, saved_site)) == 0)
275  head->safe_dnsbl = ht->key;
277  msg_fatal("%s:%s lookup error", psc_dnsbl_reply->type,
279  head->first = 0;
280  }
281 
282  /*
283  * Append the new (filter, weight) node to the list for this DNSBL domain
284  * name.
285  */
286  new_site = (PSC_DNSBL_SITE *) mymalloc(sizeof(*new_site));
287  new_site->filter = (pattern_text ? mystrdup(pattern_text) : 0);
288  new_site->byte_codes = (byte_codes ? ip_match_save(byte_codes) : 0);
289  new_site->weight = weight;
290  new_site->next = head->first;
291  head->first = new_site;
292 
293  myfree(saved_site);
294  if (byte_codes)
295  vstring_free(byte_codes);
296 }
297 
298 /* psc_dnsbl_match - match DNSBL reply filter */
299 
300 static int psc_dnsbl_match(const char *filter, ARGV *reply)
301 {
302  char addr_buf[MAI_HOSTADDR_STRSIZE];
303  char **cpp;
304 
305  /*
306  * Run the replies through the pattern-matching engine.
307  */
308  for (cpp = reply->argv; *cpp != 0; cpp++) {
309  if (inet_pton(AF_INET, *cpp, addr_buf) != 1)
310  msg_warn("address conversion error for %s -- ignoring this reply",
311  *cpp);
312  if (ip_match_execute(filter, addr_buf))
313  return (1);
314  }
315  return (0);
316 }
317 
318 /* psc_dnsbl_retrieve - retrieve blocklist score, decrement reference count */
319 
320 int psc_dnsbl_retrieve(const char *client_addr, const char **dnsbl_name,
321  int dnsbl_index, int *dnsbl_ttl)
322 {
323  const char *myname = "psc_dnsbl_retrieve";
324  PSC_DNSBL_SCORE *score;
325  int result_score;
326  int result_ttl;
327 
328  /*
329  * Sanity check.
330  */
331  if ((score = (PSC_DNSBL_SCORE *)
332  htable_find(dnsbl_score_cache, client_addr)) == 0)
333  msg_panic("%s: no blocklist score for %s", myname, client_addr);
334 
335  /*
336  * Disable callbacks.
337  */
338  PSC_CALL_BACK_CANCEL(score, dnsbl_index);
339 
340  /*
341  * Reads are destructive.
342  */
343  result_score = score->total;
344  *dnsbl_name = score->dnsbl_name;
345  result_ttl = (result_score > 0) ? score->fail_ttl : score->pass_ttl;
346  /* As with dnsblog(8), a value < 0 means no reply TTL. */
347  if (result_ttl < var_psc_dnsbl_min_ttl)
348  result_ttl = var_psc_dnsbl_min_ttl;
349  if (result_ttl > var_psc_dnsbl_max_ttl)
350  result_ttl = var_psc_dnsbl_max_ttl;
351  *dnsbl_ttl = result_ttl;
352  if (msg_verbose)
353  msg_info("%s: addr=%s score=%d ttl=%d",
354  myname, client_addr, result_score, result_ttl);
355  score->refcount -= 1;
356  if (score->refcount < 1) {
357  if (msg_verbose > 1)
358  msg_info("%s: delete blocklist score for %s", myname, client_addr);
359  htable_delete(dnsbl_score_cache, client_addr, myfree);
360  }
361  return (result_score);
362 }
363 
364 /* psc_dnsbl_receive - receive DNSBL reply, update blocklist score */
365 
366 static void psc_dnsbl_receive(int event, void *context)
367 {
368  const char *myname = "psc_dnsbl_receive";
369  VSTREAM *stream = (VSTREAM *) context;
370  PSC_DNSBL_SCORE *score;
371  PSC_DNSBL_HEAD *head;
372  PSC_DNSBL_SITE *site;
373  ARGV *reply_argv;
374  int request_id;
375  int dnsbl_ttl;
376 
377  PSC_CLEAR_EVENT_REQUEST(vstream_fileno(stream), psc_dnsbl_receive, context);
378 
379  /*
380  * Receive the DNSBL lookup result.
381  *
382  * This is preliminary code to explore the field. Later, DNSBL lookup will
383  * be handled by an UDP-based DNS client that is built directly into some
384  * Postfix daemon.
385  *
386  * Don't bother looking up the blocklist score when the client IP address is
387  * not listed at the DNSBL.
388  *
389  * Don't panic when the blocklist score no longer exists. It may be deleted
390  * when the client triggers a "drop" action after pregreet, when the
391  * client does not pregreet and the DNSBL reply arrives late, or when the
392  * client triggers a "drop" action after hanging up.
393  */
394  if (event == EVENT_READ
395  && attr_scan(stream,
397  RECV_ATTR_STR(MAIL_ATTR_RBL_DOMAIN, reply_dnsbl),
399  RECV_ATTR_INT(MAIL_ATTR_LABEL, &request_id),
400  RECV_ATTR_STR(MAIL_ATTR_RBL_ADDR, reply_addr),
401  RECV_ATTR_INT(MAIL_ATTR_TTL, &dnsbl_ttl),
402  ATTR_TYPE_END) == 5
403  && (score = (PSC_DNSBL_SCORE *)
404  htable_find(dnsbl_score_cache, STR(reply_client))) != 0
405  && score->request_id == request_id) {
406 
407  /*
408  * Run this response past all applicable DNSBL filters and update the
409  * blocklist score for this client IP address.
410  *
411  * Don't panic when the DNSBL domain name is not found. The DNSBLOG
412  * server may be messed up.
413  */
414  if (msg_verbose > 1)
415  msg_info("%s: client=\"%s\" score=%d domain=\"%s\" reply=\"%d %s\"",
416  myname, STR(reply_client), score->total,
417  STR(reply_dnsbl), dnsbl_ttl, STR(reply_addr));
418  head = (PSC_DNSBL_HEAD *)
419  htable_find(dnsbl_site_cache, STR(reply_dnsbl));
420  if (head == 0) {
421  /* Bogus domain. Do nothing. */
422  } else if (*STR(reply_addr) != 0) {
423  /* DNS reputation record(s) found. */
424  reply_argv = 0;
425  for (site = head->first; site != 0; site = site->next) {
426  if (site->byte_codes == 0
427  || psc_dnsbl_match(site->byte_codes, reply_argv ? reply_argv :
428  (reply_argv = argv_split(STR(reply_addr), " ")))) {
429  if (score->dnsbl_name == 0
430  || score->dnsbl_weight < site->weight) {
431  score->dnsbl_name = head->safe_dnsbl;
432  score->dnsbl_weight = site->weight;
433  }
434  score->total += site->weight;
435  if (msg_verbose > 1)
436  msg_info("%s: filter=\"%s\" weight=%d score=%d",
437  myname, site->filter ? site->filter : "null",
438  site->weight, score->total);
439  }
440  /* As with dnsblog(8), a value < 0 means no reply TTL. */
441  if (site->weight > 0) {
442  if (score->fail_ttl < 0 || score->fail_ttl > dnsbl_ttl)
443  score->fail_ttl = dnsbl_ttl;
444  } else {
445  if (score->pass_ttl < 0 || score->pass_ttl > dnsbl_ttl)
446  score->pass_ttl = dnsbl_ttl;
447  }
448  }
449  if (reply_argv != 0)
450  argv_free(reply_argv);
451  } else {
452  /* No DNS reputation record found. */
453  for (site = head->first; site != 0; site = site->next) {
454  /* As with dnsblog(8), a value < 0 means no reply TTL. */
455  if (site->weight > 0) {
456  if (score->pass_ttl < 0 || score->pass_ttl > dnsbl_ttl)
457  score->pass_ttl = dnsbl_ttl;
458  } else {
459  if (score->fail_ttl < 0 || score->fail_ttl > dnsbl_ttl)
460  score->fail_ttl = dnsbl_ttl;
461  }
462  }
463  }
464 
465  /*
466  * Notify the requestor(s) that the result is ready to be picked up.
467  * If this call isn't made, clients have to sit out the entire
468  * pre-handshake delay.
469  */
470  score->pending_lookups -= 1;
471  if (score->pending_lookups == 0)
473  } else if (event == EVENT_TIME) {
474  msg_warn("dnsblog reply timeout %ds for %s",
475  var_psc_dnsbl_tmout, (char *) vstream_context(stream));
476  }
477  /* Here, score may be a null pointer. */
478  vstream_fclose(stream);
479 }
480 
481 /* psc_dnsbl_request - send dnsbl query, increment reference count */
482 
483 int psc_dnsbl_request(const char *client_addr,
484  void (*callback) (int, void *),
485  void *context)
486 {
487  const char *myname = "psc_dnsbl_request";
488  int fd;
489  VSTREAM *stream;
490  HTABLE_INFO **ht;
491  PSC_DNSBL_SCORE *score;
492  HTABLE_INFO *hash_node;
493  static int request_count;
494 
495  /*
496  * Some spambots make several connections at nearly the same time,
497  * causing their pregreet delays to overlap. Such connections can share
498  * the efforts of DNSBL lookup.
499  *
500  * We store a reference-counted DNSBL score under its client IP address. We
501  * increment the reference count with each score request, and decrement
502  * the reference count with each score retrieval.
503  *
504  * Do not notify the requestor NOW when the DNS replies are already in.
505  * Reason: we must not make a backwards call while we are still in the
506  * middle of executing the corresponding forward call. Instead we create
507  * a zero-delay timer request and call the notification function from
508  * there.
509  *
510  * psc_dnsbl_request() could instead return a result value to indicate that
511  * the DNSBL score is already available, but that would complicate the
512  * caller with two different notification code paths: one asynchronous
513  * code path via the callback invocation, and one synchronous code path
514  * via the psc_dnsbl_request() result value. That would be a source of
515  * future bugs.
516  */
517  if ((hash_node = htable_locate(dnsbl_score_cache, client_addr)) != 0) {
518  score = (PSC_DNSBL_SCORE *) hash_node->value;
519  score->refcount += 1;
520  PSC_CALL_BACK_EXTEND(hash_node, score);
521  PSC_CALL_BACK_ENTER(score, callback, context);
522  if (msg_verbose > 1)
523  msg_info("%s: reuse blocklist score for %s refcount=%d pending=%d",
524  myname, client_addr, score->refcount,
525  score->pending_lookups);
526  if (score->pending_lookups == 0)
527  event_request_timer(callback, context, EVENT_NULL_DELAY);
528  return (PSC_CALL_BACK_INDEX_OF_LAST(score));
529  }
530  if (msg_verbose > 1)
531  msg_info("%s: create blocklist score for %s", myname, client_addr);
532  score = (PSC_DNSBL_SCORE *) mymalloc(sizeof(*score));
533  score->request_id = request_count++;
534  score->dnsbl_name = 0;
535  score->dnsbl_weight = 0;
536  /* As with dnsblog(8), a value < 0 means no reply TTL. */
537  score->pass_ttl = -1;
538  score->fail_ttl = -1;
539  score->total = 0;
540  score->refcount = 1;
541  score->pending_lookups = 0;
542  PSC_CALL_BACK_INIT(score);
543  PSC_CALL_BACK_ENTER(score, callback, context);
544  (void) htable_enter(dnsbl_score_cache, client_addr, (void *) score);
545 
546  /*
547  * Send a query to all DNSBL servers. Later, DNSBL lookup will be done
548  * with an UDP-based DNS client that is built directly into Postfix code.
549  * We therefore do not optimize the maximum out of this temporary
550  * implementation.
551  */
552  for (ht = dnsbl_site_list; *ht; ht++) {
553  if ((fd = LOCAL_CONNECT(psc_dnsbl_service, NON_BLOCKING, 1)) < 0) {
554  msg_warn("%s: connect to %s service: %m",
555  myname, psc_dnsbl_service);
556  continue;
557  }
558  stream = vstream_fdopen(fd, O_RDWR);
559  vstream_control(stream,
560  CA_VSTREAM_CTL_CONTEXT(ht[0]->key),
562  attr_print(stream, ATTR_FLAG_NONE,
563  SEND_ATTR_STR(MAIL_ATTR_RBL_DOMAIN, ht[0]->key),
566  ATTR_TYPE_END);
567  if (vstream_fflush(stream) != 0) {
568  msg_warn("%s: error sending to %s service: %m",
569  myname, psc_dnsbl_service);
570  vstream_fclose(stream);
571  continue;
572  }
573  PSC_READ_EVENT_REQUEST(vstream_fileno(stream), psc_dnsbl_receive,
574  (void *) stream, var_psc_dnsbl_tmout);
575  score->pending_lookups += 1;
576  }
577  return (PSC_CALL_BACK_INDEX_OF_LAST(score));
578 }
579 
580 /* psc_dnsbl_init - initialize */
581 
582 void psc_dnsbl_init(void)
583 {
584  const char *myname = "psc_dnsbl_init";
586  char **cpp;
587 
588  /*
589  * Sanity check.
590  */
591  if (dnsbl_site_cache != 0)
592  msg_panic("%s: called more than once", myname);
593 
594  /*
595  * pre-compute the DNSBLOG socket name.
596  */
597  psc_dnsbl_service = concatenate(MAIL_CLASS_PRIVATE, "/",
598  var_dnsblog_service, (char *) 0);
599 
600  /*
601  * Prepare for quick iteration when sending out queries to all DNSBL
602  * servers, and for quick lookup when a reply arrives from a specific
603  * DNSBL server.
604  */
605  dnsbl_site_cache = htable_create(13);
606  for (cpp = dnsbl_site->argv; *cpp; cpp++)
607  psc_dnsbl_add_site(*cpp);
608  argv_free(dnsbl_site);
609  dnsbl_site_list = htable_list(dnsbl_site_cache);
610 
611  /*
612  * The per-client blocklist score.
613  */
614  dnsbl_score_cache = htable_create(13);
615 
616  /*
617  * Space for ad-hoc DNSBLOG server request/reply parameters.
618  */
619  reply_client = vstring_alloc(100);
620  reply_dnsbl = vstring_alloc(100);
621  reply_addr = vstring_alloc(100);
622 }
int msg_verbose
Definition: msg.c:177
#define PSC_CALL_BACK_CANCEL(sp, idx)
#define MAIL_ATTR_RBL_ADDR
Definition: mail_proto.h:196
void * value
Definition: htable.h:18
const char * safe_dnsbl
#define PSC_CALL_BACK_EXTEND(hp, sp)
struct PSC_DNSBL_SITE * next
#define ATTR_FLAG_NONE
Definition: attr.h:98
void myfree(void *ptr)
Definition: mymalloc.c:207
HTABLE_INFO * htable_locate(HTABLE *table, const char *key)
Definition: htable.c:242
char * mystrdup(const char *str)
Definition: mymalloc.c:225
#define PSC_CALL_BACK_INIT(sp)
ARGV * argv_free(ARGV *argvp)
Definition: argv.c:136
Definition: argv.h:17
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
#define PSC_CLEAR_EVENT_REQUEST(fd, time_act, context)
Definition: postscreen.h:341
char * name
Definition: dict.h:80
struct PSC_DNSBL_SITE PSC_DNSBL_SITE
char ** argv
Definition: argv.h:20
#define CA_VSTREAM_CTL_CONTEXT(v)
Definition: vstream.h:165
#define RECV_ATTR_INT(name, val)
Definition: attr.h:71
#define ATTR_TYPE_END
Definition: attr.h:39
#define MAIL_ATTR_ACT_CLIENT_ADDR
Definition: mail_proto.h:216
int ip_match_execute(const char *byte_codes, const char *addr_bytes)
Definition: ip_match.c:272
int var_psc_dnsbl_max_ttl
Definition: postscreen.c:490
Definition: htable.h:25
struct PSC_DNSBL_SITE * first
#define vstream_context(vp)
Definition: vstream.h:117
#define LOCAL_CONNECT
Definition: sys_defs.h:1424
HTABLE * htable_create(ssize_t size)
Definition: htable.c:179
int valid_hostname(const char *name, int gripe)
char * ip_match_save(const VSTRING *byte_codes)
Definition: ip_match.c:142
char * type
Definition: dict.h:79
#define attr_print
Definition: attr.h:109
HTABLE_INFO ** htable_list(HTABLE *table)
Definition: htable.c:330
#define PSC_READ_EVENT_REQUEST(fd, action, context, timeout)
Definition: postscreen.h:325
#define dict_get(dp, key)
Definition: dict.h:236
int vstream_fclose(VSTREAM *stream)
Definition: vstream.c:1268
void psc_dnsbl_init(void)
#define STR(x)
Definition: anvil.c:518
void msg_warn(const char *fmt,...)
Definition: msg.c:215
char * key
Definition: htable.h:17
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
#define MAIL_ATTR_TTL
Definition: mail_proto.h:169
int inet_pton(int af, const char *src, void *dst)
Definition: sys_compat.c:368
void * htable_find(HTABLE *table, const char *key)
Definition: htable.c:227
#define MAIL_ATTR_LABEL
Definition: mail_proto.h:170
int error
Definition: dict.h:94
#define EVENT_READ
Definition: events.h:40
int var_psc_dnsbl_tmout
Definition: postscreen.c:491
#define SEND_ATTR_INT(name, val)
Definition: attr.h:63
int var_psc_dnsbl_min_ttl
Definition: postscreen.c:489
#define DO_GRIPE
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
const char * dnsbl_name
DICT * psc_dnsbl_reply
Definition: postscreen.c:546
#define CHARS_COMMA_SP
Definition: sys_defs.h:1761
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
int psc_dnsbl_retrieve(const char *client_addr, const char **dnsbl_name, int dnsbl_index, int *dnsbl_ttl)
char * concatenate(const char *arg0,...)
Definition: concatenate.c:42
ARGV * argv_split(const char *, const char *)
Definition: argv_split.c:63
char * var_dnsblog_service
Definition: postscreen.c:508
#define EVENT_TIME
Definition: events.h:43
#define NON_BLOCKING
Definition: iostuff.h:49
int int
Definition: smtpd_proxy.h:21
char * ip_match_parse(VSTRING *byte_codes, char *pattern)
Definition: ip_match.c:434
#define MAIL_ATTR_RBL_DOMAIN
Definition: mail_proto.h:191
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
time_t event_request_timer(EVENT_NOTIFY_TIME_FN callback, void *context, int delay)
Definition: events.c:894
#define PSC_CALL_BACK_INDEX_OF_LAST(sp)
char * split_at(char *string, int delimiter)
Definition: split_at.c:53
#define vstream_fileno(vp)
Definition: vstream.h:115
#define CA_VSTREAM_CTL_END
Definition: vstream.h:155
#define PSC_CALL_BACK_ENTER(sp, fn, ctx)
#define PSC_CALL_BACK_NOTIFY(sp, ev)
int psc_dnsbl_request(const char *client_addr, void(*callback)(int, void *), void *context)
void vstream_control(VSTREAM *stream, int name,...)
Definition: vstream.c:1372
void htable_delete(HTABLE *table, const char *key, void(*free_fn)(void *))
Definition: htable.c:257
#define attr_scan
Definition: attr.h:111
char * var_psc_dnsbl_sites
Definition: postscreen.c:484
#define SEND_ATTR_STR(name, val)
Definition: attr.h:64
#define PSC_NULL_EVENT
#define MAIL_CLASS_PRIVATE
Definition: mail_proto.h:96
VSTREAM * vstream_fdopen(int fd, int flags)
Definition: vstream.c:1204
#define EVENT_NULL_DELAY
Definition: events.h:52
#define RECV_ATTR_STR(name, val)
Definition: attr.h:72
void * mymalloc(ssize_t len)
Definition: mymalloc.c:150
#define ATTR_FLAG_STRICT
Definition: attr.h:103
#define MAI_HOSTADDR_STRSIZE
Definition: myaddrinfo.h:117
HTABLE_INFO * htable_enter(HTABLE *table, const char *key, void *value)
Definition: htable.c:212
void msg_info(const char *fmt,...)
Definition: msg.c:199