Postfix3.3.1
dns_lookup.c
[詳解]
1 /*++
2 /* NAME
3 /* dns_lookup 3
4 /* SUMMARY
5 /* domain name service lookup
6 /* SYNOPSIS
7 /* #include <dns.h>
8 /*
9 /* int dns_lookup(name, type, rflags, list, fqdn, why)
10 /* const char *name;
11 /* unsigned type;
12 /* unsigned rflags;
13 /* DNS_RR **list;
14 /* VSTRING *fqdn;
15 /* VSTRING *why;
16 /*
17 /* int dns_lookup_l(name, rflags, list, fqdn, why, lflags, ltype, ...)
18 /* const char *name;
19 /* unsigned rflags;
20 /* DNS_RR **list;
21 /* VSTRING *fqdn;
22 /* VSTRING *why;
23 /* int lflags;
24 /* unsigned ltype;
25 /*
26 /* int dns_lookup_v(name, rflags, list, fqdn, why, lflags, ltype)
27 /* const char *name;
28 /* unsigned rflags;
29 /* DNS_RR **list;
30 /* VSTRING *fqdn;
31 /* VSTRING *why;
32 /* int lflags;
33 /* unsigned *ltype;
34 /* AUXILIARY FUNCTIONS
35 /* extern int var_dns_ncache_ttl_fix;
36 /*
37 /* int dns_lookup_r(name, type, rflags, list, fqdn, why, rcode)
38 /* const char *name;
39 /* unsigned type;
40 /* unsigned rflags;
41 /* DNS_RR **list;
42 /* VSTRING *fqdn;
43 /* VSTRING *why;
44 /* int *rcode;
45 /*
46 /* int dns_lookup_rl(name, rflags, list, fqdn, why, rcode, lflags,
47 /* ltype, ...)
48 /* const char *name;
49 /* unsigned rflags;
50 /* DNS_RR **list;
51 /* VSTRING *fqdn;
52 /* VSTRING *why;
53 /* int *rcode;
54 /* int lflags;
55 /* unsigned ltype;
56 /*
57 /* int dns_lookup_rv(name, rflags, list, fqdn, why, rcode, lflags,
58 /* ltype)
59 /* const char *name;
60 /* unsigned rflags;
61 /* DNS_RR **list;
62 /* VSTRING *fqdn;
63 /* VSTRING *why;
64 /* int *rcode;
65 /* int lflags;
66 /* unsigned *ltype;
67 /*
68 /* int dns_lookup_x(name, type, rflags, list, fqdn, why, rcode, lflags)
69 /* const char *name;
70 /* unsigned type;
71 /* unsigned rflags;
72 /* DNS_RR **list;
73 /* VSTRING *fqdn;
74 /* VSTRING *why;
75 /* int *rcode;
76 /* unsigned lflags;
77 /* DESCRIPTION
78 /* dns_lookup() looks up DNS resource records. When requested to
79 /* look up data other than type CNAME, it will follow a limited
80 /* number of CNAME indirections. All result names (including
81 /* null terminator) will fit a buffer of size DNS_NAME_LEN.
82 /* All name results are validated by \fIvalid_hostname\fR();
83 /* an invalid name is reported as a DNS_INVAL result, while
84 /* malformed replies are reported as transient errors.
85 /*
86 /* dns_lookup_l() and dns_lookup_v() allow the user to specify
87 /* a list of resource types.
88 /*
89 /* dns_lookup_x, dns_lookup_r(), dns_lookup_rl() and dns_lookup_rv()
90 /* accept or return additional information.
91 /*
92 /* The var_dns_ncache_ttl_fix variable controls a workaround
93 /* for res_search(3) implementations that break the
94 /* DNS_REQ_FLAG_NCACHE_TTL feature. The workaround does not
95 /* support EDNS0 or DNSSEC, but it should be sufficient for
96 /* DNSBL/DNSWL lookups.
97 /* INPUTS
98 /* .ad
99 /* .fi
100 /* .IP name
101 /* The name to be looked up in the domain name system.
102 /* This name must pass the valid_hostname() test; it
103 /* must not be an IP address.
104 /* .IP type
105 /* The resource record type to be looked up (T_A, T_MX etc.).
106 /* .IP rflags
107 /* Resolver flags. These are a bitwise OR of:
108 /* .RS
109 /* .IP RES_DEBUG
110 /* Print debugging information.
111 /* .IP RES_DNSRCH
112 /* Search local domain and parent domains.
113 /* .IP RES_DEFNAMES
114 /* Append local domain to unqualified names.
115 /* .IP RES_USE_DNSSEC
116 /* Request DNSSEC validation. This flag is silently ignored
117 /* when the system stub resolver API, resolver(3), does not
118 /* implement DNSSEC.
119 /* .RE
120 /* .IP lflags
121 /* Flags that control the operation of the dns_lookup*()
122 /* functions. DNS_REQ_FLAG_NONE requests no special processing.
123 /* Otherwise, specify one or more of the following:
124 /* .RS
125 /* .IP DNS_REQ_FLAG_STOP_INVAL
126 /* This flag is used by dns_lookup_l() and dns_lookup_v().
127 /* Invoke dns_lookup() for the resource types in the order as
128 /* specified, and return when dns_lookup() returns DNS_INVAL.
129 /* .IP DNS_REQ_FLAG_STOP_NULLMX
130 /* This flag is used by dns_lookup_l() and dns_lookup_v().
131 /* Invoke dns_lookup() for the resource types in the order as
132 /* specified, and return when dns_lookup() returns DNS_NULLMX.
133 /* .IP DNS_REQ_FLAG_STOP_MX_POLICY
134 /* This flag is used by dns_lookup_l() and dns_lookup_v().
135 /* Invoke dns_lookup() for the resource types in the order as
136 /* specified, and return when dns_lookup() returns DNS_POLICY
137 /* for an MX query.
138 /* .IP DNS_REQ_FLAG_STOP_OK
139 /* This flag is used by dns_lookup_l() and dns_lookup_v().
140 /* Invoke dns_lookup() for the resource types in the order as
141 /* specified, and return when dns_lookup() returns DNS_OK.
142 /* .IP DNS_REQ_FLAG_NCACHE_TTL
143 /* When the lookup result status is DNS_NOTFOUND, return the
144 /* SOA record(s) from the authority section in the reply, if
145 /* available. The per-record reply TTL specifies how long the
146 /* DNS_NOTFOUND answer is valid. The caller should pass the
147 /* record(s) to dns_rr_free().
148 /* .RE
149 /* .IP ltype
150 /* The resource record types to be looked up. In the case of
151 /* dns_lookup_l(), this is a null-terminated argument list.
152 /* In the case of dns_lookup_v(), this is a null-terminated
153 /* integer array.
154 /* OUTPUTS
155 /* .ad
156 /* .fi
157 /* .IP list
158 /* A null pointer, or a pointer to a variable that receives a
159 /* list of requested resource records.
160 /* .IP fqdn
161 /* A null pointer, or storage for the fully-qualified domain
162 /* name found for \fIname\fR.
163 /* .IP why
164 /* A null pointer, or storage for the reason for failure.
165 /* .IP rcode
166 /* Pointer to storage for the reply RCODE value. This gives
167 /* more detailed information than DNS_FAIL, DNS_RETRY, etc.
168 /* DIAGNOSTICS
169 /* dns_lookup() returns one of the following codes and sets the
170 /* \fIwhy\fR argument accordingly:
171 /* .IP DNS_OK
172 /* The DNS query succeeded.
173 /* .IP DNS_POLICY
174 /* The DNS query succeeded, but the answer did not pass the
175 /* policy filter.
176 /* .IP DNS_NOTFOUND
177 /* The DNS query succeeded; the requested information was not found.
178 /* .IP DNS_NULLMX
179 /* The DNS query succeeded; the requested service is unavailable.
180 /* This is returned when the list argument is not a null
181 /* pointer, and an MX lookup result contains a null server
182 /* name (so-called "nullmx" record).
183 /* .IP DNS_INVAL
184 /* The DNS query succeeded; the result failed the valid_hostname() test.
185 /*
186 /* NOTE: the valid_hostname() test is skipped for results that
187 /* the caller suppresses explicitly. For example, when the
188 /* caller requests MX record lookup but specifies a null
189 /* resource record list argument, no syntax check will be done
190 /* for MX server names.
191 /* .IP DNS_RETRY
192 /* The query failed, or the reply was malformed.
193 /* The problem is considered transient.
194 /* .IP DNS_FAIL
195 /* The query failed.
196 /* BUGS
197 /* dns_lookup() implements a subset of all possible resource types:
198 /* CNAME, MX, A, and some records with similar formatting requirements.
199 /* It is unwise to specify the T_ANY wildcard resource type.
200 /*
201 /* It takes a surprising amount of code to accomplish what appears
202 /* to be a simple task. Later versions of the mail system may implement
203 /* their own DNS client software.
204 /* SEE ALSO
205 /* dns_rr(3) resource record memory and list management
206 /* LICENSE
207 /* .ad
208 /* .fi
209 /* The Secure Mailer license must be distributed with this software.
210 /* AUTHOR(S)
211 /* Wietse Venema
212 /* IBM T.J. Watson Research
213 /* P.O. Box 704
214 /* Yorktown Heights, NY 10598, USA
215 /*
216 /* Wietse Venema
217 /* Google, Inc.
218 /* 111 8th Avenue
219 /* New York, NY 10011, USA
220 /*--*/
221 
222 /* System library. */
223 
224 #include <sys_defs.h>
225 #include <netdb.h>
226 #include <string.h>
227 #include <ctype.h>
228 
229 /* Utility library. */
230 
231 #include <mymalloc.h>
232 #include <vstring.h>
233 #include <msg.h>
234 #include <valid_hostname.h>
235 #include <stringops.h>
236 
237 /* Global library. */
238 
239 #include <mail_params.h>
240 
241 /* DNS library. */
242 
243 #define LIBDNS_INTERNAL
244 #include "dns.h"
245 
246 /* Local stuff. */
247 
248  /*
249  * Structure to keep track of things while decoding a name server reply.
250  */
251 #define DEF_DNS_REPLY_SIZE 4096 /* in case we're using TCP */
252 #define MAX_DNS_REPLY_SIZE 65536 /* in case we're using TCP */
253 #define MAX_DNS_QUERY_SIZE 2048 /* XXX */
254 
255 typedef struct DNS_REPLY {
256  unsigned char *buf; /* raw reply data */
257  size_t buf_len; /* reply buffer length */
258  int rcode; /* unfiltered reply code */
259  int dnssec_ad; /* DNSSEC AD bit */
260  int query_count; /* number of queries */
261  int answer_count; /* number of answers */
262  int auth_count; /* number of authority records */
263  unsigned char *query_start; /* start of query data */
264  unsigned char *answer_start; /* start of answer data */
265  unsigned char *end; /* first byte past reply */
266 } DNS_REPLY;
267 
268  /*
269  * Test/set primitives to determine if the reply buffer contains a server
270  * response. We use this when the caller requests DNS_REQ_FLAG_NCACHE_TTL,
271  * and the DNS server replies that the requested record does not exist.
272  */
273 #define TEST_HAVE_DNS_REPLY_PACKET(r) ((r)->end > (r)->buf)
274 #define SET_HAVE_DNS_REPLY_PACKET(r, l) ((r)->end = (r)->buf + (l))
275 #define SET_NO_DNS_REPLY_PACKET(r) ((r)->end = (r)->buf)
276 
277 #define INET_ADDR_LEN 4 /* XXX */
278 #define INET6_ADDR_LEN 16 /* XXX */
279 
280  /*
281  * To improve postscreen's whitelisting support, we need to know how long a
282  * DNSBL "not found" answer is valid. The 2010 implementation assumed it was
283  * valid for 3600 seconds. That is too long by 2015 standards.
284  *
285  * Instead of guessing, Postfix 3.1 and later implement RFC 2308 (DNS NCACHE),
286  * where a DNS server provides the TTL of a "not found" response as the TTL
287  * of an SOA record in the authority section.
288  *
289  * Unfortunately, the res_search() and res_query() API gets in the way. These
290  * functions overload their result value, the server reply length, and
291  * return -1 when the requested record does not exist. With libbind-based
292  * implementations, the server response is still available in an application
293  * buffer, thanks to the promise that res_query() and res_search() invoke
294  * res_send(), which returns the full server response even if the requested
295  * record does not exist.
296  *
297  * If this promise is broken (for example, res_search() does not call
298  * res_send(), but some non-libbind implementation that updates the
299  * application buffer only when the requested record exists), then we have a
300  * way out by setting the var_dns_ncache_ttl_fix variable. This enables a
301  * limited res_query() clone that should be sufficient for DNSBL / DNSWL
302  * lookups.
303  *
304  * The libunbound API does not comingle the reply length and reply status
305  * information, but that will have to wait until it is safe to make
306  * libunbound a mandatory dependency for Postfix.
307  */
308 
309 /* dns_res_query - a res_query() clone that can return negative replies */
310 
311 static int dns_res_query(const char *name, int class, int type,
312  unsigned char *answer, int anslen)
313 {
314  unsigned char msg_buf[MAX_DNS_QUERY_SIZE];
315  HEADER *reply_header = (HEADER *) answer;
316  int len;
317 
318  /*
319  * Differences with res_query() from libbind:
320  *
321  * - This function returns a positive server reply length not only in case
322  * of success, but in all cases where a server reply is available that
323  * passes the preliminary checks in res_send().
324  *
325  * - This function clears h_errno in case of success. The caller must use
326  * h_errno instead of the return value to decide if the lookup was
327  * successful.
328  *
329  * - No support for EDNS0 and DNSSEC (including turning off EDNS0 after
330  * error). That should be sufficient for DNS reputation lookups where the
331  * reply contains a small number of IP addresses. TXT records are out of
332  * scope for this workaround.
333  */
334  reply_header->rcode = NOERROR;
335 
336 #define NO_MKQUERY_DATA_BUF ((unsigned char *) 0)
337 #define NO_MKQUERY_DATA_LEN ((int) 0)
338 #define NO_MKQUERY_NEWRR ((unsigned char *) 0)
339 
340  if ((len = res_mkquery(QUERY, name, class, type, NO_MKQUERY_DATA_BUF,
342  msg_buf, sizeof(msg_buf))) < 0) {
343  SET_H_ERRNO(NO_RECOVERY);
344  if (msg_verbose)
345  msg_info("res_mkquery() failed");
346  return (len);
347  } else if ((len = res_send(msg_buf, len, answer, anslen)) < 0) {
348  SET_H_ERRNO(TRY_AGAIN);
349  if (msg_verbose)
350  msg_info("res_send() failed");
351  return (len);
352  } else {
353  switch (reply_header->rcode) {
354  case NXDOMAIN:
355  SET_H_ERRNO(HOST_NOT_FOUND);
356  break;
357  case NOERROR:
358  if (reply_header->ancount != 0)
359  SET_H_ERRNO(0);
360  else
361  SET_H_ERRNO(NO_DATA);
362  break;
363  case SERVFAIL:
364  SET_H_ERRNO(TRY_AGAIN);
365  break;
366  default:
367  SET_H_ERRNO(NO_RECOVERY);
368  break;
369  }
370  return (len);
371  }
372 }
373 
374 /* dns_res_search - res_search() that can return negative replies */
375 
376 static int dns_res_search(const char *name, int class, int type,
377  unsigned char *answer, int anslen, int keep_notfound)
378 {
379  int len;
380 
381  /*
382  * Differences with res_search() from libbind:
383  *
384  * - With a non-zero keep_notfound argument, this function returns a
385  * positive server reply length not only in case of success, but also in
386  * case of a "notfound" reply status. The keep_notfound argument is
387  * usually zero, which allows us to avoid an unnecessary memset() call in
388  * the most common use case.
389  *
390  * - This function clears h_errno in case of success. The caller must use
391  * h_errno instead of the return value to decide if a lookup was
392  * successful.
393  */
394 #define NOT_FOUND_H_ERRNO(he) ((he) == HOST_NOT_FOUND || (he) == NO_DATA)
395 
396  if (keep_notfound)
397  /* Prepare for returning a null-padded server reply. */
398  memset(answer, 0, anslen);
399  len = res_query(name, class, type, answer, anslen);
400  /* Begin API creep workaround. */
401  if (len < 0 && h_errno == 0) {
402  SET_H_ERRNO(TRY_AGAIN);
403  msg_warn("res_query(\"%s\", %d, %d, %p, %d) returns %d with h_errno==0"
404  " -- setting h_errno=TRY_AGAIN",
405  name, class, type, answer, anslen, len);
406  }
407  /* End API creep workaround. */
408  if (len > 0) {
409  SET_H_ERRNO(0);
410  } else if (keep_notfound && NOT_FOUND_H_ERRNO(h_errno)) {
411  /* Expect to return a null-padded server reply. */
412  len = anslen;
413  }
414  return (len);
415 }
416 
417 /* dns_query - query name server and pre-parse the reply */
418 
419 static int dns_query(const char *name, int type, unsigned flags,
420  DNS_REPLY *reply, VSTRING *why, unsigned lflags)
421 {
422  HEADER *reply_header;
423  int len;
424  unsigned long saved_options;
425  int keep_notfound = (lflags & DNS_REQ_FLAG_NCACHE_TTL);
426 
427  /*
428  * Initialize the reply buffer.
429  */
430  if (reply->buf == 0) {
431  reply->buf = (unsigned char *) mymalloc(DEF_DNS_REPLY_SIZE);
432  reply->buf_len = DEF_DNS_REPLY_SIZE;
433  }
434 
435  /*
436  * Initialize the name service.
437  */
438  if ((_res.options & RES_INIT) == 0 && res_init() < 0) {
439  if (why)
440  vstring_strcpy(why, "Name service initialization failure");
441  return (DNS_FAIL);
442  }
443 
444  /*
445  * Set search options: debugging, parent domain search, append local
446  * domain. Do not allow the user to control other features.
447  */
448 #define USER_FLAGS (RES_DEBUG | RES_DNSRCH | RES_DEFNAMES | RES_USE_DNSSEC)
449 
450  if ((flags & USER_FLAGS) != flags)
451  msg_panic("dns_query: bad flags: %d", flags);
452 
453  /*
454  * Set extra options that aren't exposed to the application.
455  */
456 #define XTRA_FLAGS (RES_USE_EDNS0)
457 
458  if (flags & RES_USE_DNSSEC)
459  flags |= RES_USE_EDNS0;
460 
461  /*
462  * Save and restore resolver options that we overwrite, to avoid
463  * surprising behavior in other code that also invokes the resolver.
464  */
465 #define SAVE_FLAGS (USER_FLAGS | XTRA_FLAGS)
466 
467  saved_options = (_res.options & SAVE_FLAGS);
468 
469  /*
470  * Perform the lookup. Claim that the information cannot be found if and
471  * only if the name server told us so.
472  */
473  for (;;) {
474  _res.options &= ~saved_options;
475  _res.options |= flags;
476  if (keep_notfound && var_dns_ncache_ttl_fix) {
477  len = dns_res_query((char *) name, C_IN, type, reply->buf,
478  reply->buf_len);
479  } else {
480  len = dns_res_search((char *) name, C_IN, type, reply->buf,
481  reply->buf_len, keep_notfound);
482  }
483  _res.options &= ~flags;
484  _res.options |= saved_options;
485  reply_header = (HEADER *) reply->buf;
486  reply->rcode = reply_header->rcode;
487  if (h_errno != 0) {
488  if (why)
489  vstring_sprintf(why, "Host or domain name not found. "
490  "Name service error for name=%s type=%s: %s",
491  name, dns_strtype(type), dns_strerror(h_errno));
492  if (msg_verbose)
493  msg_info("dns_query: %s (%s): %s",
494  name, dns_strtype(type), dns_strerror(h_errno));
495  switch (h_errno) {
496  case NO_RECOVERY:
497  return (DNS_FAIL);
498  case HOST_NOT_FOUND:
499  case NO_DATA:
500  if (keep_notfound)
501  break;
503  return (DNS_NOTFOUND);
504  default:
505  return (DNS_RETRY);
506  }
507  } else {
508  if (msg_verbose)
509  msg_info("dns_query: %s (%s): OK", name, dns_strtype(type));
510  }
511 
512  if (reply_header->tc == 0 || reply->buf_len >= MAX_DNS_REPLY_SIZE)
513  break;
514  reply->buf = (unsigned char *)
515  myrealloc((void *) reply->buf, 2 * reply->buf_len);
516  reply->buf_len *= 2;
517  }
518 
519  /*
520  * Future proofing. If this reaches the panic call, then some code change
521  * introduced a bug.
522  */
523  if (len < 0)
524  msg_panic("dns_query: bad length %d (h_errno=%s)",
525  len, dns_strerror(h_errno));
526 
527  /*
528  * Paranoia.
529  */
530  if (len > reply->buf_len) {
531  msg_warn("reply length %d > buffer length %d for name=%s type=%s",
532  len, (int) reply->buf_len, name, dns_strtype(type));
533  len = reply->buf_len;
534  }
535 
536  /*
537  * Initialize the reply structure. Some structure members are filled on
538  * the fly while the reply is being parsed. Coerce AD bit to boolean.
539  */
540 #if RES_USE_DNSSEC != 0
541  reply->dnssec_ad = (flags & RES_USE_DNSSEC) ? !!reply_header->ad : 0;
542 #else
543  reply->dnssec_ad = 0;
544 #endif
545  SET_HAVE_DNS_REPLY_PACKET(reply, len);
546  reply->query_start = reply->buf + sizeof(HEADER);
547  reply->answer_start = 0;
548  reply->query_count = ntohs(reply_header->qdcount);
549  reply->answer_count = ntohs(reply_header->ancount);
550  reply->auth_count = ntohs(reply_header->nscount);
551  if (msg_verbose > 1)
552  msg_info("dns_query: reply len=%d ancount=%d nscount=%d",
553  len, reply->answer_count, reply->auth_count);
554 
555  /*
556  * Future proofing. If this reaches the panic call, then some code change
557  * introduced a bug.
558  */
559  if (h_errno == 0) {
560  return (DNS_OK);
561  } else if (keep_notfound) {
562  return (DNS_NOTFOUND);
563  } else {
564  msg_panic("dns_query: unexpected reply status: %s",
565  dns_strerror(h_errno));
566  }
567 }
568 
569 /* dns_skip_query - skip query data in name server reply */
570 
571 static int dns_skip_query(DNS_REPLY *reply)
572 {
573  int query_count = reply->query_count;
574  unsigned char *pos = reply->query_start;
575  int len;
576 
577  /*
578  * For each query, skip over the domain name and over the fixed query
579  * data.
580  */
581  while (query_count-- > 0) {
582  if (pos >= reply->end)
583  return DNS_RETRY;
584  len = dn_skipname(pos, reply->end);
585  if (len < 0)
586  return (DNS_RETRY);
587  pos += len + QFIXEDSZ;
588  }
589  reply->answer_start = pos;
590  return (DNS_OK);
591 }
592 
593 /* dns_get_fixed - extract fixed data from resource record */
594 
595 static int dns_get_fixed(unsigned char *pos, DNS_FIXED *fixed)
596 {
597  GETSHORT(fixed->type, pos);
598  GETSHORT(fixed->class, pos);
599  GETLONG(fixed->ttl, pos);
600  GETSHORT(fixed->length, pos);
601 
602  if (fixed->class != C_IN) {
603  msg_warn("dns_get_fixed: bad class: %u", fixed->class);
604  return (DNS_RETRY);
605  }
606  return (DNS_OK);
607 }
608 
609 /* valid_rr_name - validate hostname in resource record */
610 
611 static int valid_rr_name(const char *name, const char *location,
612  unsigned type, DNS_REPLY *reply)
613 {
614  char temp[DNS_NAME_LEN];
615  char *query_name;
616  int len;
617  char *gripe;
618  int result;
619 
620  /*
621  * People aren't supposed to specify numeric names where domain names are
622  * required, but it "works" with some mailers anyway, so people complain
623  * when software doesn't bend over backwards.
624  */
625 #define PASS_NAME 1
626 #define REJECT_NAME 0
627 
628  if (valid_hostaddr(name, DONT_GRIPE)) {
629  result = PASS_NAME;
630  gripe = "numeric domain name";
631  } else if (!valid_hostname(name, DO_GRIPE)) {
632  result = REJECT_NAME;
633  gripe = "malformed domain name";
634  } else {
635  result = PASS_NAME;
636  gripe = 0;
637  }
638 
639  /*
640  * If we have a gripe, show some context, including the name used in the
641  * query and the type of reply that we're looking at.
642  */
643  if (gripe) {
644  len = dn_expand(reply->buf, reply->end, reply->query_start,
645  temp, DNS_NAME_LEN);
646  query_name = (len < 0 ? "*unparsable*" : temp);
647  msg_warn("%s in %s of %s record for %s: %.100s",
648  gripe, location, dns_strtype(type), query_name, name);
649  }
650  return (result);
651 }
652 
653 /* dns_get_rr - extract resource record from name server reply */
654 
655 static int dns_get_rr(DNS_RR **list, const char *orig_name, DNS_REPLY *reply,
656  unsigned char *pos, char *rr_name,
657  DNS_FIXED *fixed)
658 {
659  char temp[DNS_NAME_LEN];
660  char *tempbuf = temp;
661  UINT32_TYPE soa_buf[5];
662  int comp_len;
663  ssize_t data_len;
664  unsigned pref = 0;
665  unsigned char *src;
666  unsigned char *dst;
667  int ch;
668 
669 #define MIN2(a, b) ((unsigned)(a) < (unsigned)(b) ? (a) : (b))
670 
671  *list = 0;
672 
673  switch (fixed->type) {
674  default:
675  msg_panic("dns_get_rr: don't know how to extract resource type %s",
676  dns_strtype(fixed->type));
677  case T_CNAME:
678  case T_DNAME:
679  case T_MB:
680  case T_MG:
681  case T_MR:
682  case T_NS:
683  case T_PTR:
684  if (dn_expand(reply->buf, reply->end, pos, temp, sizeof(temp)) < 0)
685  return (DNS_RETRY);
686  if (!valid_rr_name(temp, "resource data", fixed->type, reply))
687  return (DNS_INVAL);
688  data_len = strlen(temp) + 1;
689  break;
690  case T_MX:
691  GETSHORT(pref, pos);
692  if (dn_expand(reply->buf, reply->end, pos, temp, sizeof(temp)) < 0)
693  return (DNS_RETRY);
694  /* Don't even think of returning an invalid hostname to the caller. */
695  if (*temp == 0)
696  return (DNS_NULLMX); /* TODO: descriptive text */
697  if (!valid_rr_name(temp, "resource data", fixed->type, reply))
698  return (DNS_INVAL);
699  data_len = strlen(temp) + 1;
700  break;
701  case T_A:
702  if (fixed->length != INET_ADDR_LEN) {
703  msg_warn("extract_answer: bad address length: %d", fixed->length);
704  return (DNS_RETRY);
705  }
706  if (fixed->length > sizeof(temp))
707  msg_panic("dns_get_rr: length %d > DNS_NAME_LEN",
708  fixed->length);
709  memcpy(temp, pos, fixed->length);
710  data_len = fixed->length;
711  break;
712 #ifdef T_AAAA
713  case T_AAAA:
714  if (fixed->length != INET6_ADDR_LEN) {
715  msg_warn("extract_answer: bad address length: %d", fixed->length);
716  return (DNS_RETRY);
717  }
718  if (fixed->length > sizeof(temp))
719  msg_panic("dns_get_rr: length %d > DNS_NAME_LEN",
720  fixed->length);
721  memcpy(temp, pos, fixed->length);
722  data_len = fixed->length;
723  break;
724 #endif
725 
726  /*
727  * We impose the same length limit here as for DNS names. However,
728  * see T_TLSA discussion below.
729  */
730  case T_TXT:
731  data_len = MIN2(pos[0] + 1, MIN2(fixed->length + 1, sizeof(temp)));
732  for (src = pos + 1, dst = (unsigned char *) (temp);
733  dst < (unsigned char *) (temp) + data_len - 1; /* */ ) {
734  ch = *src++;
735  *dst++ = (ISPRINT(ch) ? ch : ' ');
736  }
737  *dst = 0;
738  break;
739 
740  /*
741  * For a full certificate, fixed->length may be longer than
742  * sizeof(tmpbuf) == DNS_NAME_LEN. Since we don't need a decode
743  * buffer, just copy the raw data into the rr.
744  *
745  * XXX Reject replies with bogus length < 3.
746  *
747  * XXX What about enforcing a sane upper bound? The RFC 1035 hard
748  * protocol limit is the RRDATA length limit of 65535.
749  */
750  case T_TLSA:
751  data_len = fixed->length;
752  tempbuf = (char *) pos;
753  break;
754 
755  /*
756  * We use the SOA record TTL to determine the negative reply TTL. We
757  * save the time fields in the SOA record for debugging, but for now
758  * we don't bother saving the source host and mailbox information, as
759  * that would require changes to the DNS_RR structure and APIs. See
760  * also code in dns_strrecord().
761  */
762  case T_SOA:
763  comp_len = dn_skipname(pos, reply->end);
764  if (comp_len < 0)
765  return (DNS_RETRY);
766  pos += comp_len;
767  comp_len = dn_skipname(pos, reply->end);
768  if (comp_len < 0)
769  return (DNS_RETRY);
770  pos += comp_len;
771  if (reply->end - pos < sizeof(soa_buf)) {
772  msg_warn("extract_answer: bad SOA length: %d", fixed->length);
773  return (DNS_RETRY);
774  }
775  GETLONG(soa_buf[0], pos); /* Serial */
776  GETLONG(soa_buf[1], pos); /* Refresh */
777  GETLONG(soa_buf[2], pos); /* Retry */
778  GETLONG(soa_buf[3], pos); /* Expire */
779  GETLONG(soa_buf[4], pos); /* Ncache TTL */
780  tempbuf = (char *) soa_buf;
781  data_len = sizeof(soa_buf);
782  break;
783  }
784  *list = dns_rr_create(orig_name, rr_name, fixed->type, fixed->class,
785  fixed->ttl, pref, tempbuf, data_len);
786  return (DNS_OK);
787 }
788 
789 /* dns_get_alias - extract CNAME from name server reply */
790 
791 static int dns_get_alias(DNS_REPLY *reply, unsigned char *pos,
792  DNS_FIXED *fixed, char *cname, int c_len)
793 {
794  if (fixed->type != T_CNAME)
795  msg_panic("dns_get_alias: bad type %s", dns_strtype(fixed->type));
796  if (dn_expand(reply->buf, reply->end, pos, cname, c_len) < 0)
797  return (DNS_RETRY);
798  if (!valid_rr_name(cname, "resource data", fixed->type, reply))
799  return (DNS_INVAL);
800  return (DNS_OK);
801 }
802 
803 /* dns_get_answer - extract answers from name server reply */
804 
805 static int dns_get_answer(const char *orig_name, DNS_REPLY *reply, int type,
806  DNS_RR **rrlist, VSTRING *fqdn, char *cname, int c_len,
807  int *maybe_secure)
808 {
809  char rr_name[DNS_NAME_LEN];
810  unsigned char *pos;
811  int answer_count = reply->answer_count;
812  int len;
813  DNS_FIXED fixed;
814  DNS_RR *rr;
815  int resource_found = 0;
816  int cname_found = 0;
817  int not_found_status = DNS_NOTFOUND; /* can't happen */
818  int status;
819 
820  /*
821  * Initialize. Skip over the name server query if we haven't yet.
822  */
823  if (reply->answer_start == 0)
824  if ((status = dns_skip_query(reply)) < 0)
825  return (status);
826  pos = reply->answer_start;
827 
828  /*
829  * Either this, or use a GOTO for emergency exits. The purpose is to
830  * prevent incomplete answers from being passed back to the caller.
831  */
832 #define CORRUPT(status) { \
833  if (rrlist && *rrlist) { \
834  dns_rr_free(*rrlist); \
835  *rrlist = 0; \
836  } \
837  return (status); \
838  }
839 
840  /*
841  * Iterate over all answers.
842  */
843  while (answer_count-- > 0) {
844 
845  /*
846  * Optionally extract the fully-qualified domain name.
847  */
848  if (pos >= reply->end)
850  len = dn_expand(reply->buf, reply->end, pos, rr_name, DNS_NAME_LEN);
851  if (len < 0)
853  pos += len;
854 
855  /*
856  * Extract the fixed reply data: type, class, ttl, length.
857  */
858  if (pos + RRFIXEDSZ > reply->end)
860  if ((status = dns_get_fixed(pos, &fixed)) != DNS_OK)
861  CORRUPT(status);
862  if (!valid_rr_name(rr_name, "resource name", fixed.type, reply))
864  if (fqdn)
865  vstring_strcpy(fqdn, rr_name);
866  if (msg_verbose)
867  msg_info("dns_get_answer: type %s for %s",
868  dns_strtype(fixed.type), rr_name);
869  pos += RRFIXEDSZ;
870 
871  /*
872  * Optionally extract the requested resource or CNAME data.
873  */
874  if (pos + fixed.length > reply->end)
876  if (type == fixed.type || type == T_ANY) { /* requested type */
877  if (rrlist) {
878  if ((status = dns_get_rr(&rr, orig_name, reply, pos, rr_name,
879  &fixed)) == DNS_OK) {
880  resource_found++;
881  rr->dnssec_valid = *maybe_secure ? reply->dnssec_ad : 0;
882  *rrlist = dns_rr_append(*rrlist, rr);
883  } else if (status == DNS_NULLMX) {
884  CORRUPT(status); /* TODO: use better name */
885  } else if (not_found_status != DNS_RETRY)
886  not_found_status = status;
887  } else
888  resource_found++;
889  } else if (fixed.type == T_CNAME) { /* cname resource */
890  cname_found++;
891  if (cname && c_len > 0)
892  if ((status = dns_get_alias(reply, pos, &fixed, cname, c_len)) != DNS_OK)
893  CORRUPT(status);
894  if (!reply->dnssec_ad)
895  *maybe_secure = 0;
896  }
897  pos += fixed.length;
898  }
899 
900  /*
901  * See what answer we came up with. Report success when the requested
902  * information was found. Otherwise, when a CNAME was found, report that
903  * more recursion is needed. Otherwise report failure.
904  */
905  if (resource_found)
906  return (DNS_OK);
907  if (cname_found)
908  return (DNS_RECURSE);
909  return (not_found_status);
910 }
911 
912 /* dns_lookup_x - DNS lookup user interface */
913 
914 int dns_lookup_x(const char *name, unsigned type, unsigned flags,
915  DNS_RR **rrlist, VSTRING *fqdn, VSTRING *why,
916  int *rcode, unsigned lflags)
917 {
918  char cname[DNS_NAME_LEN];
919  int c_len = sizeof(cname);
920  static DNS_REPLY reply;
921  int count;
922  int status;
923  int maybe_secure = 1; /* Query name presumed secure */
924  const char *orig_name = name;
925 
926  /*
927  * Reset results early. DNS_OK is not the only status that returns
928  * resource records; DNS_NOTFOUND will do that too, if requested.
929  */
930  if (rrlist)
931  *rrlist = 0;
932 
933  /*
934  * DJBDNS produces a bogus A record when given a numerical hostname.
935  */
936  if (valid_hostaddr(name, DONT_GRIPE)) {
937  if (why)
938  vstring_sprintf(why,
939  "Name service error for %s: invalid host or domain name",
940  name);
941  if (rcode)
942  *rcode = NXDOMAIN;
943  SET_H_ERRNO(HOST_NOT_FOUND);
944  return (DNS_NOTFOUND);
945  }
946 
947  /*
948  * The Linux resolver misbehaves when given an invalid domain name.
949  */
950  if (!valid_hostname(name, DONT_GRIPE)) {
951  if (why)
952  vstring_sprintf(why,
953  "Name service error for %s: invalid host or domain name",
954  name);
955  if (rcode)
956  *rcode = NXDOMAIN;
957  SET_H_ERRNO(HOST_NOT_FOUND);
958  return (DNS_NOTFOUND);
959  }
960 
961  /*
962  * Perform the lookup. Follow CNAME chains, but only up to a
963  * pre-determined maximum.
964  */
965  for (count = 0; count < 10; count++) {
966 
967  /*
968  * Perform the DNS lookup, and pre-parse the name server reply.
969  */
970  status = dns_query(name, type, flags, &reply, why, lflags);
971  if (rcode)
972  *rcode = reply.rcode;
973  if (status != DNS_OK) {
974 
975  /*
976  * If the record does not exist, and we have a copy of the server
977  * response, try to extract the negative caching TTL for the SOA
978  * record in the authority section. DO NOT return an error if an
979  * SOA record is malformed.
980  */
981  if (status == DNS_NOTFOUND && TEST_HAVE_DNS_REPLY_PACKET(&reply)
982  && reply.auth_count > 0) {
983  reply.answer_count = reply.auth_count; /* XXX TODO: Fix API */
984  (void) dns_get_answer(orig_name, &reply, T_SOA, rrlist, fqdn,
985  cname, c_len, &maybe_secure);
986  }
987  return (status);
988  }
989 
990  /*
991  * Extract resource records of the requested type. Pick up CNAME
992  * information just in case the requested data is not found.
993  */
994  status = dns_get_answer(orig_name, &reply, type, rrlist, fqdn,
995  cname, c_len, &maybe_secure);
996  switch (status) {
997  default:
998  if (why)
999  vstring_sprintf(why, "Name service error for name=%s type=%s: "
1000  "Malformed or unexpected name server reply",
1001  name, dns_strtype(type));
1002  return (status);
1003  case DNS_NULLMX:
1004  if (why)
1005  vstring_sprintf(why, "Domain %s does not accept mail (nullMX)",
1006  name);
1007  SET_H_ERRNO(NO_DATA);
1008  return (status);
1009  case DNS_OK:
1010  if (rrlist && dns_rr_filter_maps) {
1011  if (dns_rr_filter_execute(rrlist) < 0) {
1012  if (why)
1013  vstring_sprintf(why,
1014  "Error looking up name=%s type=%s: "
1015  "Invalid DNS reply filter syntax",
1016  name, dns_strtype(type));
1017  dns_rr_free(*rrlist);
1018  *rrlist = 0;
1019  status = DNS_RETRY;
1020  } else if (*rrlist == 0) {
1021  if (why)
1022  vstring_sprintf(why,
1023  "Error looking up name=%s type=%s: "
1024  "DNS reply filter drops all results",
1025  name, dns_strtype(type));
1026  status = DNS_POLICY;
1027  }
1028  }
1029  return (status);
1030  case DNS_RECURSE:
1031  if (msg_verbose)
1032  msg_info("dns_lookup: %s aliased to %s", name, cname);
1033 #if RES_USE_DNSSEC
1034 
1035  /*
1036  * Once an intermediate CNAME reply is not validated, all
1037  * consequent RRs are deemed not validated, so we don't ask for
1038  * further DNSSEC replies.
1039  */
1040  if (maybe_secure == 0)
1041  flags &= ~RES_USE_DNSSEC;
1042 #endif
1043  name = cname;
1044  }
1045  }
1046  if (why)
1047  vstring_sprintf(why, "Name server loop for %s", name);
1048  msg_warn("dns_lookup: Name server loop for %s", name);
1049  return (DNS_NOTFOUND);
1050 }
1051 
1052 /* dns_lookup_rl - DNS lookup interface with types list */
1053 
1054 int dns_lookup_rl(const char *name, unsigned flags, DNS_RR **rrlist,
1055  VSTRING *fqdn, VSTRING *why, int *rcode,
1056  int lflags,...)
1057 {
1058  va_list ap;
1059  unsigned type, next;
1060  int status = DNS_NOTFOUND;
1061  int hpref_status = INT_MIN;
1062  VSTRING *hpref_rtext = 0;
1063  int hpref_rcode;
1064  int hpref_h_errno;
1065  DNS_RR *rr;
1066 
1067  /* Save intermediate highest-priority result. */
1068 #define SAVE_HPREF_STATUS() do { \
1069  hpref_status = status; \
1070  if (rcode) \
1071  hpref_rcode = *rcode; \
1072  if (why && status != DNS_OK) \
1073  vstring_strcpy(hpref_rtext ? hpref_rtext : \
1074  (hpref_rtext = vstring_alloc(VSTRING_LEN(why))), \
1075  vstring_str(why)); \
1076  hpref_h_errno = h_errno; \
1077  } while (0)
1078 
1079  /* Restore intermediate highest-priority result. */
1080 #define RESTORE_HPREF_STATUS() do { \
1081  status = hpref_status; \
1082  if (rcode) \
1083  *rcode = hpref_rcode; \
1084  if (why && status != DNS_OK) \
1085  vstring_strcpy(why, vstring_str(hpref_rtext)); \
1086  SET_H_ERRNO(hpref_h_errno); \
1087  } while (0)
1088 
1089  if (rrlist)
1090  *rrlist = 0;
1091  va_start(ap, lflags);
1092  for (type = va_arg(ap, unsigned); type != 0; type = next) {
1093  next = va_arg(ap, unsigned);
1094  if (msg_verbose)
1095  msg_info("lookup %s type %s flags %s",
1096  name, dns_strtype(type), dns_str_resflags(flags));
1097  status = dns_lookup_x(name, type, flags, rrlist ? &rr : (DNS_RR **) 0,
1098  fqdn, why, rcode, lflags);
1099  if (rrlist && rr)
1100  *rrlist = dns_rr_append(*rrlist, rr);
1101  if (status == DNS_OK) {
1102  if (lflags & DNS_REQ_FLAG_STOP_OK)
1103  break;
1104  } else if (status == DNS_INVAL) {
1105  if (lflags & DNS_REQ_FLAG_STOP_INVAL)
1106  break;
1107  } else if (status == DNS_POLICY) {
1108  if (type == T_MX && (lflags & DNS_REQ_FLAG_STOP_MX_POLICY))
1109  break;
1110  } else if (status == DNS_NULLMX) {
1111  if (lflags & DNS_REQ_FLAG_STOP_NULLMX)
1112  break;
1113  }
1114  /* XXX Stop after NXDOMAIN error. */
1115  if (next == 0)
1116  break;
1117  if (status >= hpref_status)
1118  SAVE_HPREF_STATUS(); /* save last info */
1119  }
1120  va_end(ap);
1121  if (status < hpref_status)
1122  RESTORE_HPREF_STATUS(); /* else report last info */
1123  if (hpref_rtext)
1124  vstring_free(hpref_rtext);
1125  return (status);
1126 }
1127 
1128 /* dns_lookup_rv - DNS lookup interface with types vector */
1129 
1130 int dns_lookup_rv(const char *name, unsigned flags, DNS_RR **rrlist,
1131  VSTRING *fqdn, VSTRING *why, int *rcode,
1132  int lflags, unsigned *types)
1133 {
1134  unsigned type, next;
1135  int status = DNS_NOTFOUND;
1136  int hpref_status = INT_MIN;
1137  VSTRING *hpref_rtext = 0;
1138  int hpref_rcode;
1139  int hpref_h_errno;
1140  DNS_RR *rr;
1141 
1142  if (rrlist)
1143  *rrlist = 0;
1144  for (type = *types++; type != 0; type = next) {
1145  next = *types++;
1146  if (msg_verbose)
1147  msg_info("lookup %s type %s flags %s",
1148  name, dns_strtype(type), dns_str_resflags(flags));
1149  status = dns_lookup_x(name, type, flags, rrlist ? &rr : (DNS_RR **) 0,
1150  fqdn, why, rcode, lflags);
1151  if (rrlist && rr)
1152  *rrlist = dns_rr_append(*rrlist, rr);
1153  if (status == DNS_OK) {
1154  if (lflags & DNS_REQ_FLAG_STOP_OK)
1155  break;
1156  } else if (status == DNS_INVAL) {
1157  if (lflags & DNS_REQ_FLAG_STOP_INVAL)
1158  break;
1159  } else if (status == DNS_POLICY) {
1160  if (type == T_MX && (lflags & DNS_REQ_FLAG_STOP_MX_POLICY))
1161  break;
1162  } else if (status == DNS_NULLMX) {
1163  if (lflags & DNS_REQ_FLAG_STOP_NULLMX)
1164  break;
1165  }
1166  /* XXX Stop after NXDOMAIN error. */
1167  if (next == 0)
1168  break;
1169  if (status >= hpref_status)
1170  SAVE_HPREF_STATUS(); /* save last info */
1171  }
1172  if (status < hpref_status)
1173  RESTORE_HPREF_STATUS(); /* else report last info */
1174  if (hpref_rtext)
1175  vstring_free(hpref_rtext);
1176  return (status);
1177 }
int msg_verbose
Definition: msg.c:177
#define DNS_REQ_FLAG_NCACHE_TTL
Definition: dns.h:249
int valid_hostaddr(const char *addr, int gripe)
#define RES_USE_EDNS0
Definition: dns.h:71
#define UINT32_TYPE
Definition: sys_defs.h:1720
struct DNS_REPLY DNS_REPLY
const char * dns_strtype(unsigned)
Definition: dns_strtype.c:187
#define RESTORE_HPREF_STATUS()
size_t buf_len
Definition: dns_lookup.c:257
const char * dns_str_resflags(unsigned long)
unsigned int ttl
Definition: dns.h:131
#define NO_MKQUERY_NEWRR
int dnssec_ad
Definition: dns_lookup.c:259
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
unsigned char * end
Definition: dns_lookup.c:265
void * myrealloc(void *ptr, ssize_t len)
Definition: mymalloc.c:175
#define MAX_DNS_REPLY_SIZE
Definition: dns_lookup.c:252
#define DEF_DNS_REPLY_SIZE
Definition: dns_lookup.c:251
#define DNS_RETRY
Definition: dns.h:282
#define DNS_NOTFOUND
Definition: dns.h:278
#define SAVE_FLAGS
unsigned length
Definition: dns.h:132
unsigned short type
Definition: dns.h:129
#define USER_FLAGS
#define GETLONG(l, cp)
Definition: dns.h:45
#define T_DNAME
Definition: dns.h:87
#define T_TXT
Definition: dns.h:115
int dns_lookup_rl(const char *name, unsigned flags, DNS_RR **rrlist, VSTRING *fqdn, VSTRING *why, int *rcode, int lflags,...)
Definition: dns_lookup.c:1054
#define DNS_RECURSE
Definition: dns.h:277
VSTRING * vstring_strcpy(VSTRING *vp, const char *src)
Definition: vstring.c:431
#define SET_HAVE_DNS_REPLY_PACKET(r, l)
Definition: dns_lookup.c:274
DNS_RR * dns_rr_create(const char *, const char *, ushort, ushort, unsigned, unsigned, const char *, size_t)
int valid_hostname(const char *name, int gripe)
#define DNS_NULLMX
Definition: dns.h:279
const char * dns_strerror(unsigned)
Definition: dns_strerror.c:57
int query_count
Definition: dns_lookup.c:260
#define TEST_HAVE_DNS_REPLY_PACKET(r)
Definition: dns_lookup.c:273
MAPS * dns_rr_filter_maps
Definition: dns_rr_filter.c:77
#define NO_MKQUERY_DATA_BUF
#define DNS_FAIL
Definition: dns.h:280
#define DNS_REQ_FLAG_STOP_OK
Definition: dns.h:245
Definition: dns.h:128
#define DNS_OK
Definition: dns.h:284
int answer_count
Definition: dns_lookup.c:261
void msg_warn(const char *fmt,...)
Definition: msg.c:215
#define INET6_ADDR_LEN
Definition: dns_lookup.c:278
#define SET_NO_DNS_REPLY_PACKET(r)
Definition: dns_lookup.c:275
#define DNS_INVAL
Definition: dns.h:281
#define MIN2(a, b)
#define NO_MKQUERY_DATA_LEN
VSTRING * vstring_sprintf(VSTRING *vp, const char *format,...)
Definition: vstring.c:602
#define T_TLSA
Definition: dns.h:81
#define RES_USE_DNSSEC
Definition: dns.h:68
#define DNS_NAME_LEN
Definition: dns.h:289
#define NOT_FOUND_H_ERRNO(he)
DNS_RR * dns_rr_append(DNS_RR *, DNS_RR *)
Definition: dns_rr.c:168
#define SAVE_HPREF_STATUS()
#define INET_ADDR_LEN
Definition: dns_lookup.c:277
int dns_lookup_rv(const char *name, unsigned flags, DNS_RR **rrlist, VSTRING *fqdn, VSTRING *why, int *rcode, int lflags, unsigned *types)
Definition: dns_lookup.c:1130
#define ISPRINT(c)
Definition: sys_defs.h:1751
int auth_count
Definition: dns_lookup.c:262
#define DNS_REQ_FLAG_STOP_INVAL
Definition: dns.h:246
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
unsigned int dnssec_valid
Definition: dns.h:145
#define DO_GRIPE
Definition: haproxy_srvr.h:30
#define MAX_DNS_QUERY_SIZE
Definition: dns_lookup.c:253
#define REJECT_NAME
int dns_rr_filter_execute(DNS_RR **rrlist)
#define SET_H_ERRNO(err)
Definition: sys_defs.h:1695
unsigned short class
Definition: dns.h:130
#define DNS_REQ_FLAG_STOP_MX_POLICY
Definition: dns.h:248
void dns_rr_free(DNS_RR *)
Definition: dns_rr.c:137
#define CORRUPT(status)
Definition: dns.h:139
unsigned char * answer_start
Definition: dns_lookup.c:264
int dns_lookup_x(const char *name, unsigned type, unsigned flags, DNS_RR **rrlist, VSTRING *fqdn, VSTRING *why, int *rcode, unsigned lflags)
Definition: dns_lookup.c:914
#define DNS_POLICY
Definition: dns.h:283
unsigned char * query_start
Definition: dns_lookup.c:263
#define PASS_NAME
#define DNS_REQ_FLAG_STOP_NULLMX
Definition: dns.h:247
void * mymalloc(ssize_t len)
Definition: mymalloc.c:150
#define DONT_GRIPE
Definition: haproxy_srvr.h:31
unsigned char * buf
Definition: dns_lookup.c:256
#define GETSHORT(s, cp)
Definition: dns.h:37
void msg_info(const char *fmt,...)
Definition: msg.c:199
bool var_dns_ncache_ttl_fix
Definition: mail_params.c:341