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