Postfix3.3.1
smtp_addr.c
[詳解]
1 /*++
2 /* NAME
3 /* smtp_addr 3
4 /* SUMMARY
5 /* SMTP server address lookup
6 /* SYNOPSIS
7 /* #include "smtp_addr.h"
8 /*
9 /* DNS_RR *smtp_domain_addr(name, mxrr, misc_flags, why, found_myself)
10 /* char *name;
11 /* DNS_RR **mxrr;
12 /* int misc_flags;
13 /* DSN_BUF *why;
14 /* int *found_myself;
15 /*
16 /* DNS_RR *smtp_host_addr(name, misc_flags, why)
17 /* char *name;
18 /* int misc_flags;
19 /* DSN_BUF *why;
20 /* DESCRIPTION
21 /* This module implements Internet address lookups. By default,
22 /* lookups are done via the Internet domain name service (DNS).
23 /* A reasonable number of CNAME indirections is permitted. When
24 /* DNS lookups are disabled, host address lookup is done with
25 /* getnameinfo() or gethostbyname().
26 /*
27 /* smtp_domain_addr() looks up the network addresses for mail
28 /* exchanger hosts listed for the named domain. Addresses are
29 /* returned in most-preferred first order. The result is truncated
30 /* so that it contains only hosts that are more preferred than the
31 /* local mail server itself. The found_myself result parameter
32 /* is updated when the local MTA is MX host for the specified
33 /* destination. If MX records were found, the rname, qname,
34 /* and dnssec validation status of the MX RRset are returned
35 /* via mxrr, which the caller must free with dns_rr_free().
36 /*
37 /* When no mail exchanger is listed in the DNS for \fIname\fR, the
38 /* request is passed to smtp_host_addr().
39 /*
40 /* It is an error to call smtp_domain_addr() when DNS lookups are
41 /* disabled.
42 /*
43 /* smtp_host_addr() looks up all addresses listed for the named
44 /* host. The host can be specified as a numerical Internet network
45 /* address, or as a symbolic host name.
46 /*
47 /* Results from smtp_domain_addr() or smtp_host_addr() are
48 /* destroyed by dns_rr_free(), including null lists.
49 /* DIAGNOSTICS
50 /* Panics: interface violations. For example, calling smtp_domain_addr()
51 /* when DNS lookups are explicitly disabled.
52 /*
53 /* All routines either return a DNS_RR pointer, or return a null
54 /* pointer and update the \fIwhy\fR argument accordingly.
55 /* LICENSE
56 /* .ad
57 /* .fi
58 /* The Secure Mailer license must be distributed with this software.
59 /* AUTHOR(S)
60 /* Wietse Venema
61 /* IBM T.J. Watson Research
62 /* P.O. Box 704
63 /* Yorktown Heights, NY 10598, USA
64 /*
65 /* Wietse Venema
66 /* Google, Inc.
67 /* 111 8th Avenue
68 /* New York, NY 10011, USA
69 /*--*/
70 
71 /* System library. */
72 
73 #include <sys_defs.h>
74 #include <sys/socket.h>
75 #include <netinet/in.h>
76 #include <arpa/inet.h>
77 #include <stdlib.h>
78 #include <netdb.h>
79 #include <ctype.h>
80 #include <string.h>
81 #include <unistd.h>
82 #include <errno.h>
83 
84 /* Utility library. */
85 
86 #include <msg.h>
87 #include <vstring.h>
88 #include <mymalloc.h>
89 #include <inet_addr_list.h>
90 #include <stringops.h>
91 #include <myaddrinfo.h>
92 #include <inet_proto.h>
93 #include <midna_domain.h>
94 
95 /* Global library. */
96 
97 #include <mail_params.h>
98 #include <own_inet_addr.h>
99 #include <dsn_buf.h>
100 
101 /* DNS library. */
102 
103 #include <dns.h>
104 
105 /* Application-specific. */
106 
107 #include "smtp.h"
108 #include "smtp_addr.h"
109 
110 /* smtp_print_addr - print address list */
111 
112 static void smtp_print_addr(const char *what, DNS_RR *addr_list)
113 {
114  DNS_RR *addr;
115  MAI_HOSTADDR_STR hostaddr;
116 
117  msg_info("begin %s address list", what);
118  for (addr = addr_list; addr; addr = addr->next) {
119  if (dns_rr_to_pa(addr, &hostaddr) == 0) {
120  msg_warn("skipping record type %s: %m", dns_strtype(addr->type));
121  } else {
122  msg_info("pref %4d host %s/%s",
123  addr->pref, SMTP_HNAME(addr),
124  hostaddr.buf);
125  }
126  }
127  msg_info("end %s address list", what);
128 }
129 
130 /* smtp_addr_one - address lookup for one host name */
131 
132 static DNS_RR *smtp_addr_one(DNS_RR *addr_list, const char *host, int res_opt,
133  unsigned pref, DSN_BUF *why)
134 {
135  const char *myname = "smtp_addr_one";
136  DNS_RR *addr = 0;
137  DNS_RR *rr;
138  int aierr;
139  struct addrinfo *res0;
140  struct addrinfo *res;
141  INET_PROTO_INFO *proto_info = inet_proto_info();
142  unsigned char *proto_family_list = proto_info->sa_family_list;
143  int found;
144 
145  if (msg_verbose)
146  msg_info("%s: host %s", myname, host);
147 
148  /*
149  * Interpret a numerical name as an address.
150  */
151  if (hostaddr_to_sockaddr(host, (char *) 0, 0, &res0) == 0) {
152  if (strchr((char *) proto_family_list, res0->ai_family) != 0) {
153  if ((addr = dns_sa_to_rr(host, pref, res0->ai_addr)) == 0)
154  msg_fatal("host %s: conversion error for address family "
155  "%d: %m", host, res0->ai_addr->sa_family);
156  addr_list = dns_rr_append(addr_list, addr);
157  freeaddrinfo(res0);
158  return (addr_list);
159  }
160  freeaddrinfo(res0);
161  }
162 
163  /*
164  * Use DNS lookup, but keep the option open to use native name service.
165  *
166  * XXX A soft error dominates past and future hard errors. Therefore we
167  * should not clobber a soft error text and status code.
168  */
170  res_opt |= smtp_dns_res_opt;
171  switch (dns_lookup_v(host, res_opt, &addr, (VSTRING *) 0,
173  proto_info->dns_atype_list)) {
174  case DNS_OK:
175  for (rr = addr; rr; rr = rr->next)
176  rr->pref = pref;
177  addr_list = dns_rr_append(addr_list, addr);
178  return (addr_list);
179  default:
180  dsb_status(why, "4.4.3");
181  return (addr_list);
182  case DNS_FAIL:
183  dsb_status(why, SMTP_HAS_SOFT_DSN(why) ? "4.4.3" : "5.4.3");
184  return (addr_list);
185  case DNS_INVAL:
186  dsb_status(why, SMTP_HAS_SOFT_DSN(why) ? "4.4.4" : "5.4.4");
187  return (addr_list);
188  case DNS_POLICY:
189  dsb_status(why, "4.7.0");
190  return (addr_list);
191  case DNS_NOTFOUND:
192  dsb_status(why, SMTP_HAS_SOFT_DSN(why) ? "4.4.4" : "5.4.4");
193  /* maybe native naming service will succeed */
194  break;
195  }
196  }
197 
198  /*
199  * Use the native name service which also looks in /etc/hosts.
200  *
201  * XXX A soft error dominates past and future hard errors. Therefore we
202  * should not clobber a soft error text and status code.
203  */
204 #define RETRY_AI_ERROR(e) \
205  ((e) == EAI_AGAIN || (e) == EAI_MEMORY || (e) == EAI_SYSTEM)
206 #ifdef EAI_NODATA
207 #define DSN_NOHOST(e) \
208  ((e) == EAI_AGAIN || (e) == EAI_NODATA || (e) == EAI_NONAME)
209 #else
210 #define DSN_NOHOST(e) \
211  ((e) == EAI_AGAIN || (e) == EAI_NONAME)
212 #endif
213 
215  if ((aierr = hostname_to_sockaddr(host, (char *) 0, 0, &res0)) != 0) {
216  dsb_simple(why, (SMTP_HAS_SOFT_DSN(why) || RETRY_AI_ERROR(aierr)) ?
217  (DSN_NOHOST(aierr) ? "4.4.4" : "4.3.0") :
218  (DSN_NOHOST(aierr) ? "5.4.4" : "5.3.0"),
219  "unable to look up host %s: %s",
220  host, MAI_STRERROR(aierr));
221  } else {
222  for (found = 0, res = res0; res != 0; res = res->ai_next) {
223  if (strchr((char *) proto_family_list, res->ai_family) == 0) {
224  msg_info("skipping address family %d for host %s",
225  res->ai_family, host);
226  continue;
227  }
228  found++;
229  if ((addr = dns_sa_to_rr(host, pref, res->ai_addr)) == 0)
230  msg_fatal("host %s: conversion error for address family "
231  "%d: %m", host, res0->ai_addr->sa_family);
232  addr_list = dns_rr_append(addr_list, addr);
233  }
234  freeaddrinfo(res0);
235  if (found == 0) {
236  dsb_simple(why, SMTP_HAS_SOFT_DSN(why) ? "4.4.4" : "5.4.4",
237  "%s: host not found", host);
238  }
239  return (addr_list);
240  }
241  }
242 
243  /*
244  * No further alternatives for host lookup.
245  */
246  return (addr_list);
247 }
248 
249 /* smtp_addr_list - address lookup for a list of mail exchangers */
250 
251 static DNS_RR *smtp_addr_list(DNS_RR *mx_names, DSN_BUF *why)
252 {
253  DNS_RR *addr_list = 0;
254  DNS_RR *rr;
255  int res_opt = 0;
256 
257  if (mx_names->dnssec_valid)
258  res_opt = RES_USE_DNSSEC;
259 #ifdef USE_TLS
260  else if (smtp_tls_insecure_mx_policy > TLS_LEV_MAY)
261  res_opt = RES_USE_DNSSEC;
262 #endif
263 
264  /*
265  * As long as we are able to look up any host address, we ignore problems
266  * with DNS lookups (except if we're backup MX, and all the better MX
267  * hosts can't be found).
268  *
269  * XXX 2821: update the error status (0->FAIL upon unrecoverable lookup
270  * error, any->RETRY upon temporary lookup error) so that we can
271  * correctly handle the case of no resolvable MX host. Currently this is
272  * always treated as a soft error. RFC 2821 wants a more precise
273  * response.
274  *
275  * XXX dns_lookup() enables RES_DEFNAMES. This is wrong for names found in
276  * MX records - we should not append the local domain to dot-less names.
277  *
278  * XXX However, this is not the only problem. If we use the native name
279  * service for host lookup, then it will usually enable RES_DNSRCH which
280  * appends local domain information to all lookups. In particular,
281  * getaddrinfo() may invoke a resolver that runs in a different process
282  * (NIS server, nscd), so we can't even reliably turn this off by
283  * tweaking the in-process resolver flags.
284  */
285  for (rr = mx_names; rr; rr = rr->next) {
286  if (rr->type != T_MX)
287  msg_panic("smtp_addr_list: bad resource type: %d", rr->type);
288  addr_list = smtp_addr_one(addr_list, (char *) rr->data, res_opt,
289  rr->pref, why);
290  }
291  return (addr_list);
292 }
293 
294 /* smtp_find_self - spot myself in a crowd of mail exchangers */
295 
296 static DNS_RR *smtp_find_self(DNS_RR *addr_list)
297 {
298  const char *myname = "smtp_find_self";
299  INET_ADDR_LIST *self;
300  INET_ADDR_LIST *proxy;
301  DNS_RR *addr;
302  int i;
303 
304  self = own_inet_addr_list();
305  proxy = proxy_inet_addr_list();
306 
307  for (addr = addr_list; addr; addr = addr->next) {
308 
309  /*
310  * Find out if this mail system is listening on this address.
311  */
312  for (i = 0; i < self->used; i++)
313  if (DNS_RR_EQ_SA(addr, (struct sockaddr *) (self->addrs + i))) {
314  if (msg_verbose)
315  msg_info("%s: found self at pref %d", myname, addr->pref);
316  return (addr);
317  }
318 
319  /*
320  * Find out if this mail system has a proxy listening on this
321  * address.
322  */
323  for (i = 0; i < proxy->used; i++)
324  if (DNS_RR_EQ_SA(addr, (struct sockaddr *) (proxy->addrs + i))) {
325  if (msg_verbose)
326  msg_info("%s: found proxy at pref %d", myname, addr->pref);
327  return (addr);
328  }
329  }
330 
331  /*
332  * Didn't find myself, or my proxy.
333  */
334  if (msg_verbose)
335  msg_info("%s: not found", myname);
336  return (0);
337 }
338 
339 /* smtp_truncate_self - truncate address list at self and equivalents */
340 
341 static DNS_RR *smtp_truncate_self(DNS_RR *addr_list, unsigned pref)
342 {
343  DNS_RR *addr;
344  DNS_RR *last;
345 
346  for (last = 0, addr = addr_list; addr; last = addr, addr = addr->next) {
347  if (pref == addr->pref) {
348  if (msg_verbose)
349  smtp_print_addr("truncated", addr);
350  dns_rr_free(addr);
351  if (last == 0) {
352  addr_list = 0;
353  } else {
354  last->next = 0;
355  }
356  break;
357  }
358  }
359  return (addr_list);
360 }
361 
362 /* smtp_balance_inet_proto - balance IPv4/6 protocols within address limit */
363 
364 static DNS_RR *smtp_balance_inet_proto(DNS_RR *addr_list, int misc_flags,
365  int addr_limit)
366 {
367  const char myname[] = "smtp_balance_inet_proto";
368  DNS_RR *rr;
369  DNS_RR *stripped_list;
370  DNS_RR *next;
371  int v6_count;
372  int v4_count;
373  int v6_target,
374  v4_target;
375  int *p;
376 
377  /*
378  * Precondition: the input is sorted by MX preference (not necessarily IP
379  * address family preference), and addresses with the same or worse
380  * preference than 'myself' have been eliminated. Postcondition: the
381  * relative list order is unchanged, but some elements are removed.
382  */
383 
384  /*
385  * Count the number of IPv6 and IPv4 addresses.
386  */
387  for (v4_count = v6_count = 0, rr = addr_list; rr != 0; rr = rr->next) {
388  if (rr->type == T_A) {
389  v4_count++;
390  } else if (rr->type == T_AAAA) {
391  v6_count++;
392  } else {
393  msg_panic("%s: unexpected record type: %s",
394  myname, dns_strtype(rr->type));
395  }
396  }
397 
398  /*
399  * Ensure that one address type will not out-crowd the other, while
400  * enforcing the address count limit. This works around a current problem
401  * where some destination announces primarily IPv6 MX addresses, the
402  * smtp_address_limit eliminates most or all IPv4 addresses, and the
403  * destination is not reachable over IPv6.
404  *
405  * Maybe: do all smtp_mx_address_limit enforcement here, and remove
406  * pre-existing enforcement elsewhere. That would obsolete the
407  * smtp_balance_inet_protocols configuration parameter.
408  */
409  if (v4_count > 0 && v6_count > 0 && v4_count + v6_count > addr_limit) {
410 
411  /*-
412  * Decide how many IPv6 and IPv4 addresses to keep. The code below
413  * has three branches, corresponding to the regions R1, R2 and R3
414  * in the figure.
415  *
416  * L = addr_limit
417  * X = excluded by condition (v4_count + v6_count > addr_limit)
418  *
419  * v4_count
420  * ^
421  * |
422  * L \ R1
423  * |X\ |
424  * |XXX\ |
425  * |XXXXX\ | R2
426  * L/2 +-------\-------
427  * |XXXXXXX|X\
428  * |XXXXXXX|XXX\ R3
429  * |XXXXXXX|XXXXX\
430  * 0 +-------+-------\--> v6_count
431  * 0 L/2 L
432  */
433  if (v6_count <= addr_limit / 2) { /* Region R1 */
434  v6_target = v6_count;
435  v4_target = addr_limit - v6_target;
436  } else if (v4_count <= addr_limit / 2) {/* Region R3 */
437  v4_target = v4_count;
438  v6_target = addr_limit - v4_target;
439  } else { /* Region R2 */
440  /* v4_count > addr_limit / 2 && v6_count > addr_limit / 2 */
441  v4_target = (addr_limit + (addr_list->type == T_A)) / 2;
442  v6_target = addr_limit - v4_target;
443  }
444  if (msg_verbose)
445  msg_info("v6_target=%d, v4_target=%d", v6_target, v4_target);
446 
447  /* Enforce the address count targets. */
448  stripped_list = 0;
449  for (rr = addr_list; rr != 0; rr = next) {
450  next = rr->next;
451  rr->next = 0;
452  if (rr->type == T_A) {
453  p = &v4_target;
454  } else if (rr->type == T_AAAA) {
455  p = &v6_target;
456  } else {
457  msg_panic("%s: unexpected record type: %s",
458  myname, dns_strtype(rr->type));
459  }
460  if (*p > 0) {
461  stripped_list = dns_rr_append(stripped_list, rr);
462  *p -= 1;
463  } else {
464  dns_rr_free(rr);
465  }
466  }
467  if (v4_target > 0 || v6_target > 0)
468  msg_panic("%s: bad target count: v4_target=%d, v6_target=%d",
469  myname, v4_target, v6_target);
470  if (msg_verbose)
471  smtp_print_addr("smtp_balance_inet_proto result", stripped_list);
472  return (stripped_list);
473  } else {
474  return (addr_list);
475  }
476 }
477 
478 /* smtp_domain_addr - mail exchanger address lookup */
479 
480 DNS_RR *smtp_domain_addr(const char *name, DNS_RR **mxrr, int misc_flags,
481  DSN_BUF *why, int *found_myself)
482 {
483  DNS_RR *mx_names;
484  DNS_RR *addr_list = 0;
485  DNS_RR *self = 0;
486  unsigned best_pref;
487  unsigned best_found;
488  int r = 0; /* Resolver flags */
489  const char *aname;
490 
491  dsb_reset(why); /* Paranoia */
492 
493  /*
494  * Preferences from DNS use 0..32767, fall-backs use 32768+.
495  */
496 #define IMPOSSIBLE_PREFERENCE (~0)
497 
498  /*
499  * Sanity check.
500  */
502  msg_panic("smtp_domain_addr: DNS lookup is disabled");
504  r |= RES_USE_DNSSEC;
505 
506  /*
507  * IDNA support.
508  */
509 #ifndef NO_EAI
510  if (!allascii(name) && (aname = midna_domain_to_ascii(name)) != 0) {
511  if (msg_verbose)
512  msg_info("%s asciified to %s", name, aname);
513  } else
514 #endif
515  aname = name;
516 
517  /*
518  * Look up the mail exchanger hosts listed for this name. Sort the
519  * results by preference. Look up the corresponding host addresses, and
520  * truncate the list so that it contains only hosts that are more
521  * preferred than myself. When no MX resource records exist, look up the
522  * addresses listed for this name.
523  *
524  * According to RFC 974: "It is possible that the list of MXs in the
525  * response to the query will be empty. This is a special case. If the
526  * list is empty, mailers should treat it as if it contained one RR, an
527  * MX RR with a preference value of 0, and a host name of REMOTE. (I.e.,
528  * REMOTE is its only MX). In addition, the mailer should do no further
529  * processing on the list, but should attempt to deliver the message to
530  * REMOTE."
531  *
532  * Normally it is OK if an MX host cannot be found in the DNS; we'll just
533  * use a backup one, and silently ignore the better MX host. However, if
534  * the best backup that we can find in the DNS is the local machine, then
535  * we must remember that the local machine is not the primary MX host, or
536  * else we will claim that mail loops back.
537  *
538  * XXX Optionally do A lookups even when the MX lookup didn't complete.
539  * Unfortunately with some DNS servers this is not a transient problem.
540  *
541  * XXX Ideally we would perform A lookups only as far as needed. But as long
542  * as we're looking up all the hosts, it would be better to look up the
543  * least preferred host first, so that DNS lookup error messages make
544  * more sense.
545  *
546  * XXX 2821: RFC 2821 says that the sender must shuffle equal-preference MX
547  * hosts, whereas multiple A records per hostname must be used in the
548  * order as received. They make the bogus assumption that a hostname with
549  * multiple A records corresponds to one machine with multiple network
550  * interfaces.
551  *
552  * XXX 2821: Postfix recognizes the local machine by looking for its own IP
553  * address in the list of mail exchangers. RFC 2821 says one has to look
554  * at the mail exchanger hostname as well, making the bogus assumption
555  * that an IP address is listed only under one hostname. However, looking
556  * at hostnames provides a partial solution for MX hosts behind a NAT
557  * gateway.
558  */
559  switch (dns_lookup(aname, T_MX, r, &mx_names, (VSTRING *) 0, why->reason)) {
560  default:
561  dsb_status(why, "4.4.3");
563  addr_list = smtp_host_addr(aname, misc_flags, why);
564  break;
565  case DNS_INVAL:
566  dsb_status(why, "5.4.4");
568  addr_list = smtp_host_addr(aname, misc_flags, why);
569  break;
570  case DNS_NULLMX:
571  dsb_status(why, "5.1.0");
572  break;
573  case DNS_POLICY:
574  dsb_status(why, "4.7.0");
575  break;
576  case DNS_FAIL:
577  dsb_status(why, "5.4.3");
579  addr_list = smtp_host_addr(aname, misc_flags, why);
580  break;
581  case DNS_OK:
582  mx_names = dns_rr_sort(mx_names, dns_rr_compare_pref_any);
583  best_pref = (mx_names ? mx_names->pref : IMPOSSIBLE_PREFERENCE);
584  addr_list = smtp_addr_list(mx_names, why);
585  if (mxrr)
586  *mxrr = dns_rr_copy(mx_names); /* copies one record! */
587  dns_rr_free(mx_names);
588  if (addr_list == 0) {
589  /* Text does not change. */
590  if (var_smtp_defer_mxaddr) {
591  /* Don't clobber the null terminator. */
592  if (SMTP_HAS_HARD_DSN(why))
593  SMTP_SET_SOFT_DSN(why); /* XXX */
594  /* Require some error status. */
595  else if (!SMTP_HAS_SOFT_DSN(why))
596  msg_panic("smtp_domain_addr: bad status");
597  }
598  msg_warn("no MX host for %s has a valid address record", name);
599  break;
600  }
601  best_found = (addr_list ? addr_list->pref : IMPOSSIBLE_PREFERENCE);
602  if (msg_verbose)
603  smtp_print_addr(name, addr_list);
604  if ((misc_flags & SMTP_MISC_FLAG_LOOP_DETECT)
605  && (self = smtp_find_self(addr_list)) != 0) {
606  addr_list = smtp_truncate_self(addr_list, self->pref);
607  if (addr_list == 0) {
608  if (best_pref != best_found) {
609  dsb_simple(why, "4.4.4",
610  "unable to find primary relay for %s", name);
611  } else {
612  dsb_simple(why, "5.4.6", "mail for %s loops back to myself",
613  name);
614  }
615  }
616  }
617 #define SMTP_COMPARE_ADDR(flags) \
618  (((flags) & SMTP_MISC_FLAG_PREF_IPV6) ? dns_rr_compare_pref_ipv6 : \
619  ((flags) & SMTP_MISC_FLAG_PREF_IPV4) ? dns_rr_compare_pref_ipv4 : \
620  dns_rr_compare_pref_any)
621 
622  if (addr_list && addr_list->next) {
623  if (var_smtp_rand_addr)
624  addr_list = dns_rr_shuffle(addr_list);
625  addr_list = dns_rr_sort(addr_list, SMTP_COMPARE_ADDR(misc_flags));
627  addr_list = smtp_balance_inet_proto(addr_list, misc_flags,
629  }
630  break;
631  case DNS_NOTFOUND:
632  addr_list = smtp_host_addr(aname, misc_flags, why);
633  break;
634  }
635 
636  /*
637  * Clean up.
638  */
639  *found_myself |= (self != 0);
640  return (addr_list);
641 }
642 
643 /* smtp_host_addr - direct host lookup */
644 
645 DNS_RR *smtp_host_addr(const char *host, int misc_flags, DSN_BUF *why)
646 {
647  DNS_RR *addr_list;
648  int res_opt = 0;
649  const char *ahost;
650 
651  dsb_reset(why); /* Paranoia */
652 
654  res_opt |= RES_USE_DNSSEC;
655 
656  /*
657  * IDNA support.
658  */
659 #ifndef NO_EAI
660  if (!allascii(host) && (ahost = midna_domain_to_ascii(host)) != 0) {
661  if (msg_verbose)
662  msg_info("%s asciified to %s", host, ahost);
663  } else
664 #endif
665  ahost = host;
666 
667  /*
668  * If the host is specified by numerical address, just convert the
669  * address to internal form. Otherwise, the host is specified by name.
670  */
671 #define PREF0 0
672  addr_list = smtp_addr_one((DNS_RR *) 0, ahost, res_opt, PREF0, why);
673  if (addr_list
674  && (misc_flags & SMTP_MISC_FLAG_LOOP_DETECT)
675  && smtp_find_self(addr_list) != 0) {
676  dns_rr_free(addr_list);
677  dsb_simple(why, "5.4.6", "mail for %s loops back to myself", host);
678  return (0);
679  }
680  if (addr_list && addr_list->next) {
681  if (var_smtp_rand_addr)
682  addr_list = dns_rr_shuffle(addr_list);
683  /* The following changes the order of equal-preference hosts. */
684  if (inet_proto_info()->ai_family_list[1] != 0)
685  addr_list = dns_rr_sort(addr_list, SMTP_COMPARE_ADDR(misc_flags));
687  addr_list = smtp_balance_inet_proto(addr_list, misc_flags,
689  }
690  if (msg_verbose)
691  smtp_print_addr(host, addr_list);
692  return (addr_list);
693 }
int msg_verbose
Definition: msg.c:177
unsigned short pref
Definition: dns.h:146
const char * dns_strtype(unsigned)
Definition: dns_strtype.c:187
#define SMTP_HAS_SOFT_DSN(why)
Definition: smtp.h:259
void freeaddrinfo(struct addrinfo *ai)
Definition: myaddrinfo.c:742
#define SMTP_SET_SOFT_DSN(why)
Definition: smtp.h:264
bool var_smtp_defer_mxaddr
Definition: smtp.c:878
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
bool var_ign_mx_lookup_err
Definition: smtp.c:853
#define inet_proto_info()
Definition: inet_proto.h:29
#define DNS_NOTFOUND
Definition: dns.h:278
#define hostname_to_sockaddr(host, serv, sock, res)
Definition: myaddrinfo.h:171
struct sockaddr_storage * addrs
char data[1]
Definition: dns.h:149
void dsb_reset(DSN_BUF *dsb)
Definition: dsn_buf.c:333
int smtp_host_lookup_mask
Definition: smtp.c:964
#define DSN_NOHOST(e)
#define SMTP_HNAME(rr)
Definition: smtp.h:359
int hostaddr_to_sockaddr(const char *hostaddr, const char *service, int socktype, struct addrinfo **res)
Definition: myaddrinfo.c:464
#define SMTP_HOST_FLAG_DNS
Definition: smtp.h:269
#define dns_lookup_v(name, rflags, list, fqdn, why, lflags, ltype)
Definition: dns.h:238
const char * dns_rr_to_pa(DNS_RR *, MAI_HOSTADDR_STR *)
Definition: dns_rr_to_pa.c:53
int smtp_dns_support
Definition: smtp.c:965
#define DNS_NULLMX
Definition: dns.h:279
bool var_smtp_rand_addr
Definition: smtp.c:869
char buf[MAI_HOSTADDR_STRSIZE]
Definition: myaddrinfo.h:146
#define PREF0
#define DNS_FAIL
Definition: dns.h:280
INET_ADDR_LIST * proxy_inet_addr_list(void)
int var_smtp_mxaddr_limit
Definition: smtp.c:880
#define SMTP_HAS_HARD_DSN(why)
Definition: smtp.h:260
#define DNS_OK
Definition: dns.h:284
void msg_warn(const char *fmt,...)
Definition: msg.c:215
#define SMTP_HOST_FLAG_NATIVE
Definition: smtp.h:270
DNS_RR * smtp_domain_addr(const char *name, DNS_RR **mxrr, int misc_flags, DSN_BUF *why, int *found_myself)
Definition: smtp_addr.c:480
DNS_RR * dns_rr_shuffle(DNS_RR *)
Definition: dns_rr.c:288
#define DNS_INVAL
Definition: dns.h:281
DNS_RR * dns_rr_copy(DNS_RR *)
Definition: dns_rr.c:150
unsigned char * sa_family_list
Definition: inet_proto.h:21
DNS_RR * dns_sa_to_rr(const char *, unsigned, struct sockaddr *)
Definition: dns_sa_to_rr.c:53
struct DNS_RR * next
Definition: dns.h:147
unsigned smtp_dns_res_opt
Definition: smtp.c:971
DSN_BUF * dsb_simple(DSN_BUF *dsb, const char *status, const char *format,...)
Definition: dsn_buf.c:275
#define RES_USE_DNSSEC
Definition: dns.h:68
#define allascii(s)
Definition: stringops.h:66
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
#define IMPOSSIBLE_PREFERENCE
int dns_rr_compare_pref_any(DNS_RR *, DNS_RR *)
Definition: dns_rr.c:214
DNS_RR * dns_rr_append(DNS_RR *, DNS_RR *)
Definition: dns_rr.c:168
DNS_RR * smtp_host_addr(const char *host, int misc_flags, DSN_BUF *why)
Definition: smtp_addr.c:645
VSTRING * reason
Definition: dsn_buf.h:37
DSN_BUF * dsb_status(DSN_BUF *dsb, const char *status)
Definition: dsn_buf.c:320
INET_ADDR_LIST * own_inet_addr_list(void)
const char * midna_domain_to_ascii(const char *name)
Definition: midna_domain.c:261
#define SMTP_DNS_DISABLED
Definition: smtp.h:275
unsigned int dnssec_valid
Definition: dns.h:145
#define SMTP_DNS_DNSSEC
Definition: smtp.h:277
bool var_smtp_balance_inet_proto
Definition: smtp.c:953
#define MAI_STRERROR(e)
Definition: myaddrinfo.h:169
#define TLS_LEV_MAY
Definition: tls.h:44
DNS_RR * dns_rr_sort(DNS_RR *, int(*)(DNS_RR *, DNS_RR *))
Definition: dns_rr.c:242
#define SMTP_MISC_FLAG_LOOP_DETECT
Definition: smtp.h:241
#define DNS_REQ_FLAG_NONE
Definition: dns.h:250
#define RETRY_AI_ERROR(e)
unsigned short type
Definition: dns.h:142
void dns_rr_free(DNS_RR *)
Definition: dns_rr.c:137
Definition: dns.h:139
#define dns_lookup(name, type, rflags, list, fqdn, why)
Definition: dns.h:229
#define DNS_RR_EQ_SA(rr, sa)
Definition: dns.h:214
#define DNS_POLICY
Definition: dns.h:283
unsigned int * dns_atype_list
Definition: inet_proto.h:20
#define SMTP_COMPARE_ADDR(flags)
void msg_info(const char *fmt,...)
Definition: msg.c:199