domain.c (302408) | domain.c (38032) |
---|---|
1/* | 1/* |
2 * Copyright (c) 1998-2004, 2006, 2010 Proofpoint, Inc. and its suppliers. 3 * All rights reserved. | 2 * Copyright (c) 1998 Sendmail, Inc. All rights reserved. |
4 * Copyright (c) 1986, 1995-1997 Eric P. Allman. All rights reserved. 5 * Copyright (c) 1988, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * By using this file, you agree to the terms and conditions set 9 * forth in the LICENSE file which can be found at the top level of 10 * the sendmail distribution. 11 * 12 */ 13 | 3 * Copyright (c) 1986, 1995-1997 Eric P. Allman. All rights reserved. 4 * Copyright (c) 1988, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * By using this file, you agree to the terms and conditions set 8 * forth in the LICENSE file which can be found at the top level of 9 * the sendmail distribution. 10 * 11 */ 12 |
14#include <sendmail.h> 15#include "map.h" | 13#include "sendmail.h" |
16 | 14 |
15#ifndef lint |
|
17#if NAMED_BIND | 16#if NAMED_BIND |
18SM_RCSID("@(#)$Id: domain.c,v 8.205 2013-11-22 20:51:55 ca Exp $ (with name server)") 19#else /* NAMED_BIND */ 20SM_RCSID("@(#)$Id: domain.c,v 8.205 2013-11-22 20:51:55 ca Exp $ (without name server)") 21#endif /* NAMED_BIND */ | 17static char sccsid[] = "@(#)domain.c 8.77 (Berkeley) 6/4/98 (with name server)"; 18#else 19static char sccsid[] = "@(#)domain.c 8.77 (Berkeley) 6/4/98 (without name server)"; 20#endif 21#endif /* not lint */ |
22 23#if NAMED_BIND 24 | 22 23#if NAMED_BIND 24 |
25# include <arpa/inet.h> | 25#include <errno.h> 26#include <resolv.h> 27#include <arpa/inet.h> |
26 | 28 |
27 28# ifndef MXHOSTBUFSIZE 29# define MXHOSTBUFSIZE (128 * MAXMXHOSTS) 30# endif /* ! MXHOSTBUFSIZE */ 31 32static char MXHostBuf[MXHOSTBUFSIZE]; 33#if (MXHOSTBUFSIZE < 2) || (MXHOSTBUFSIZE >= INT_MAX/2) 34 ERROR: _MXHOSTBUFSIZE is out of range 35#endif /* (MXHOSTBUFSIZE < 2) || (MXHOSTBUFSIZE >= INT_MAX/2) */ 36 37# ifndef MAXDNSRCH 38# define MAXDNSRCH 6 /* number of possible domains to search */ 39# endif /* ! MAXDNSRCH */ 40 41# ifndef RES_DNSRCH_VARIABLE 42# define RES_DNSRCH_VARIABLE _res.dnsrch 43# endif /* ! RES_DNSRCH_VARIABLE */ 44 45# ifndef NO_DATA 46# define NO_DATA NO_ADDRESS 47# endif /* ! NO_DATA */ 48 49# ifndef HFIXEDSZ 50# define HFIXEDSZ 12 /* sizeof(HEADER) */ 51# endif /* ! HFIXEDSZ */ 52 53# define MAXCNAMEDEPTH 10 /* maximum depth of CNAME recursion */ 54 55# if defined(__RES) && (__RES >= 19940415) 56# define RES_UNC_T char * 57# else /* defined(__RES) && (__RES >= 19940415) */ 58# define RES_UNC_T unsigned char * 59# endif /* defined(__RES) && (__RES >= 19940415) */ 60 61static int mxrand __P((char *)); 62static int fallbackmxrr __P((int, unsigned short *, char **)); 63 | |
64/* | 29/* |
65** GETFALLBACKMXRR -- get MX resource records for fallback MX host. 66** 67** We have to initialize this once before doing anything else. 68** Moreover, we have to repeat this from time to time to avoid 69** stale data, e.g., in persistent queue runners. 70** This should be done in a parent process so the child 71** processes have the right data. 72** 73** Parameters: 74** host -- the name of the fallback MX host. 75** 76** Returns: 77** number of MX records. 78** 79** Side Effects: 80** Populates NumFallbackMXHosts and fbhosts. 81** Sets renewal time (based on TTL). | 30** The standard udp packet size PACKETSZ (512) is not sufficient for some 31** nameserver answers containing very many resource records. The resolver 32** may switch to tcp and retry if it detects udp packet overflow. 33** Also note that the resolver routines res_query and res_search return 34** the size of the *un*truncated answer in case the supplied answer buffer 35** it not big enough to accommodate the entire answer. |
82*/ 83 | 36*/ 37 |
84int NumFallbackMXHosts = 0; /* Number of fallback MX hosts (after MX expansion) */ 85static char *fbhosts[MAXMXHOSTS + 1]; | 38#ifndef MAXPACKET 39# define MAXPACKET 8192 /* max packet size used internally by BIND */ 40#endif |
86 | 41 |
87int 88getfallbackmxrr(host) 89 char *host; | 42typedef union |
90{ | 43{ |
91 int i, rcode; 92 int ttl; 93 static time_t renew = 0; | 44 HEADER qb1; 45 u_char qb2[MAXPACKET]; 46} querybuf; |
94 | 47 |
95#if 0 96 /* This is currently done before this function is called. */ 97 if (host == NULL || *host == '\0') 98 return 0; 99#endif /* 0 */ 100 if (NumFallbackMXHosts > 0 && renew > curtime()) 101 return NumFallbackMXHosts; 102 if (host[0] == '[') 103 { 104 fbhosts[0] = host; 105 NumFallbackMXHosts = 1; 106 } 107 else 108 { 109 /* free old data */ 110 for (i = 0; i < NumFallbackMXHosts; i++) 111 sm_free(fbhosts[i]); | 48#ifndef MXHOSTBUFSIZE 49# define MXHOSTBUFSIZE (128 * MAXMXHOSTS) 50#endif |
112 | 51 |
113 /* get new data */ 114 NumFallbackMXHosts = getmxrr(host, fbhosts, NULL, false, 115 &rcode, false, &ttl); 116 renew = curtime() + ttl; 117 for (i = 0; i < NumFallbackMXHosts; i++) 118 fbhosts[i] = newstr(fbhosts[i]); 119 } 120 return NumFallbackMXHosts; 121} | 52static char MXHostBuf[MXHOSTBUFSIZE]; |
122 | 53 |
123/* 124** FALLBACKMXRR -- add MX resource records for fallback MX host to list. 125** 126** Parameters: 127** nmx -- current number of MX records. 128** prefs -- array of preferences. 129** mxhosts -- array of MX hosts (maximum size: MAXMXHOSTS) 130** 131** Returns: 132** new number of MX records. 133** 134** Side Effects: 135** If FallbackMX was set, it appends the MX records for 136** that host to mxhosts (and modifies prefs accordingly). 137*/ | 54#ifndef MAXDNSRCH 55# define MAXDNSRCH 6 /* number of possible domains to search */ 56#endif |
138 | 57 |
139static int 140fallbackmxrr(nmx, prefs, mxhosts) 141 int nmx; 142 unsigned short *prefs; 143 char **mxhosts; 144{ 145 int i; | 58#ifndef MAX 59# define MAX(a, b) ((a) > (b) ? (a) : (b)) 60#endif |
146 | 61 |
147 for (i = 0; i < NumFallbackMXHosts && nmx < MAXMXHOSTS; i++) 148 { 149 if (nmx > 0) 150 prefs[nmx] = prefs[nmx - 1] + 1; 151 else 152 prefs[nmx] = 0; 153 mxhosts[nmx++] = fbhosts[i]; 154 } 155 return nmx; 156} | 62#ifndef NO_DATA 63# define NO_DATA NO_ADDRESS 64#endif |
157 | 65 |
158/* | 66#ifndef HFIXEDSZ 67# define HFIXEDSZ 12 /* sizeof(HEADER) */ 68#endif 69 70#define MAXCNAMEDEPTH 10 /* maximum depth of CNAME recursion */ 71 72#if defined(__RES) && (__RES >= 19940415) 73# define RES_UNC_T char * 74#else 75# define RES_UNC_T u_char * 76#endif 77/* |
159** GETMXRR -- get MX resource records for a domain 160** 161** Parameters: 162** host -- the name of the host to MX. 163** mxhosts -- a pointer to a return buffer of MX records. | 78** GETMXRR -- get MX resource records for a domain 79** 80** Parameters: 81** host -- the name of the host to MX. 82** mxhosts -- a pointer to a return buffer of MX records. |
164** mxprefs -- a pointer to a return buffer of MX preferences. 165** If NULL, don't try to populate. 166** droplocalhost -- If true, all MX records less preferred | 83** droplocalhost -- If TRUE, all MX records less preferred |
167** than the local host (as determined by $=w) will 168** be discarded. 169** rcode -- a pointer to an EX_ status code. | 84** than the local host (as determined by $=w) will 85** be discarded. 86** rcode -- a pointer to an EX_ status code. |
170** tryfallback -- add also fallback MX host? 171** pttl -- pointer to return TTL (can be NULL). | |
172** 173** Returns: 174** The number of MX records found. 175** -1 if there is an internal failure. 176** If no MX records are found, mxhosts[0] is set to host 177** and 1 is returned. | 87** 88** Returns: 89** The number of MX records found. 90** -1 if there is an internal failure. 91** If no MX records are found, mxhosts[0] is set to host 92** and 1 is returned. |
178** 179** Side Effects: 180** The entries made for mxhosts point to a static array 181** MXHostBuf[MXHOSTBUFSIZE], so the data needs to be copied, 182** if it must be preserved across calls to this function. | |
183*/ 184 185int | 93*/ 94 95int |
186getmxrr(host, mxhosts, mxprefs, droplocalhost, rcode, tryfallback, pttl) | 96getmxrr(host, mxhosts, droplocalhost, rcode) |
187 char *host; 188 char **mxhosts; | 97 char *host; 98 char **mxhosts; |
189 unsigned short *mxprefs; | |
190 bool droplocalhost; 191 int *rcode; | 99 bool droplocalhost; 100 int *rcode; |
192 bool tryfallback; 193 int *pttl; | |
194{ | 101{ |
195 register unsigned char *eom, *cp; | 102 register u_char *eom, *cp; |
196 register int i, j, n; 197 int nmx = 0; 198 register char *bp; 199 HEADER *hp; 200 querybuf answer; 201 int ancount, qdcount, buflen; | 103 register int i, j, n; 104 int nmx = 0; 105 register char *bp; 106 HEADER *hp; 107 querybuf answer; 108 int ancount, qdcount, buflen; |
202 bool seenlocal = false; 203 unsigned short pref, type; 204 unsigned short localpref = 256; 205 char *fallbackMX = FallbackMX; 206 bool trycanon = false; 207 unsigned short *prefs; 208 int (*resfunc) __P((const char *, int, int, u_char *, int)); 209 unsigned short prefer[MAXMXHOSTS]; 210 int weight[MAXMXHOSTS]; 211 int ttl = 0; | 109 bool seenlocal = FALSE; 110 u_short pref, type; 111 u_short localpref = 256; 112 char *fallbackMX = FallBackMX; 113 bool trycanon = FALSE; 114 int (*resfunc)(); |
212 extern int res_query(), res_search(); | 115 extern int res_query(), res_search(); |
116 u_short prefer[MAXMXHOSTS]; 117 int weight[MAXMXHOSTS]; 118 extern int mxrand __P((char *)); |
|
213 214 if (tTd(8, 2)) | 119 120 if (tTd(8, 2)) |
215 sm_dprintf("getmxrr(%s, droplocalhost=%d)\n", 216 host, droplocalhost); 217 *rcode = EX_OK; 218 if (pttl != NULL) 219 *pttl = SM_DEFAULT_TTL; 220 if (*host == '\0') 221 return 0; | 121 printf("getmxrr(%s, droplocalhost=%d)\n", host, droplocalhost); |
222 | 122 |
223 if ((fallbackMX != NULL && droplocalhost && 224 wordinclass(fallbackMX, 'w')) || !tryfallback) | 123 if (fallbackMX != NULL && droplocalhost && 124 wordinclass(fallbackMX, 'w')) |
225 { 226 /* don't use fallback for this pass */ 227 fallbackMX = NULL; 228 } 229 | 125 { 126 /* don't use fallback for this pass */ 127 fallbackMX = NULL; 128 } 129 |
230 if (mxprefs != NULL) 231 prefs = mxprefs; 232 else 233 prefs = prefer; | 130 *rcode = EX_OK; |
234 235 /* efficiency hack -- numeric or non-MX lookups */ 236 if (host[0] == '[') 237 goto punt; 238 239 /* 240 ** If we don't have MX records in our host switch, don't 241 ** try for MX records. Note that this really isn't "right", --- 5 unchanged lines hidden (view full) --- 247 if (!UseNameServer) 248 goto punt; 249 if (HasWildcardMX && ConfigLevel >= 6) 250 resfunc = res_query; 251 else 252 resfunc = res_search; 253 254 errno = 0; | 131 132 /* efficiency hack -- numeric or non-MX lookups */ 133 if (host[0] == '[') 134 goto punt; 135 136 /* 137 ** If we don't have MX records in our host switch, don't 138 ** try for MX records. Note that this really isn't "right", --- 5 unchanged lines hidden (view full) --- 144 if (!UseNameServer) 145 goto punt; 146 if (HasWildcardMX && ConfigLevel >= 6) 147 resfunc = res_query; 148 else 149 resfunc = res_search; 150 151 errno = 0; |
255 n = (*resfunc)(host, C_IN, T_MX, (unsigned char *) &answer, 256 sizeof(answer)); | 152 n = (*resfunc)(host, C_IN, T_MX, (u_char *) &answer, sizeof(answer)); |
257 if (n < 0) 258 { 259 if (tTd(8, 1)) | 153 if (n < 0) 154 { 155 if (tTd(8, 1)) |
260 sm_dprintf("getmxrr: res_search(%s) failed (errno=%d, h_errno=%d)\n", 261 host, errno, h_errno); | 156 printf("getmxrr: res_search(%s) failed (errno=%d, h_errno=%d)\n", 157 (host == NULL) ? "<NULL>" : host, errno, h_errno); |
262 switch (h_errno) 263 { 264 case NO_DATA: | 158 switch (h_errno) 159 { 160 case NO_DATA: |
265 trycanon = true; 266 /* FALLTHROUGH */ | 161 trycanon = TRUE; 162 /* fall through */ |
267 268 case NO_RECOVERY: 269 /* no MX data on this host */ 270 goto punt; 271 272 case HOST_NOT_FOUND: | 163 164 case NO_RECOVERY: 165 /* no MX data on this host */ 166 goto punt; 167 168 case HOST_NOT_FOUND: |
273# if BROKEN_RES_SEARCH | 169#if BROKEN_RES_SEARCH |
274 case 0: /* Ultrix resolver retns failure w/ h_errno=0 */ | 170 case 0: /* Ultrix resolver retns failure w/ h_errno=0 */ |
275# endif /* BROKEN_RES_SEARCH */ | 171#endif |
276 /* host doesn't exist in DNS; might be in /etc/hosts */ | 172 /* host doesn't exist in DNS; might be in /etc/hosts */ |
277 trycanon = true; | 173 trycanon = TRUE; |
278 *rcode = EX_NOHOST; 279 goto punt; 280 281 case TRY_AGAIN: 282 case -1: 283 /* couldn't connect to the name server */ 284 if (fallbackMX != NULL) 285 { 286 /* name server is hosed -- push to fallback */ | 174 *rcode = EX_NOHOST; 175 goto punt; 176 177 case TRY_AGAIN: 178 case -1: 179 /* couldn't connect to the name server */ 180 if (fallbackMX != NULL) 181 { 182 /* name server is hosed -- push to fallback */ |
287 return fallbackmxrr(nmx, prefs, mxhosts); | 183 mxhosts[nmx++] = fallbackMX; 184 return nmx; |
288 } 289 /* it might come up later; better queue it up */ 290 *rcode = EX_TEMPFAIL; 291 break; 292 293 default: | 185 } 186 /* it might come up later; better queue it up */ 187 *rcode = EX_TEMPFAIL; 188 break; 189 190 default: |
294 syserr("getmxrr: res_search (%s) failed with impossible h_errno (%d)", | 191 syserr("getmxrr: res_search (%s) failed with impossible h_errno (%d)\n", |
295 host, h_errno); 296 *rcode = EX_OSERR; 297 break; 298 } 299 300 /* irreconcilable differences */ | 192 host, h_errno); 193 *rcode = EX_OSERR; 194 break; 195 } 196 197 /* irreconcilable differences */ |
301 return -1; | 198 return (-1); |
302 } 303 304 /* avoid problems after truncation in tcp packets */ 305 if (n > sizeof(answer)) 306 n = sizeof(answer); 307 308 /* find first satisfactory answer */ 309 hp = (HEADER *)&answer; | 199 } 200 201 /* avoid problems after truncation in tcp packets */ 202 if (n > sizeof(answer)) 203 n = sizeof(answer); 204 205 /* find first satisfactory answer */ 206 hp = (HEADER *)&answer; |
310 cp = (unsigned char *)&answer + HFIXEDSZ; 311 eom = (unsigned char *)&answer + n; 312 for (qdcount = ntohs((unsigned short) hp->qdcount); 313 qdcount--; 314 cp += n + QFIXEDSZ) 315 { | 207 cp = (u_char *)&answer + HFIXEDSZ; 208 eom = (u_char *)&answer + n; 209 for (qdcount = ntohs(hp->qdcount); qdcount--; cp += n + QFIXEDSZ) |
316 if ((n = dn_skipname(cp, eom)) < 0) 317 goto punt; | 210 if ((n = dn_skipname(cp, eom)) < 0) 211 goto punt; |
318 } 319 320 /* NOTE: see definition of MXHostBuf! */ | |
321 buflen = sizeof(MXHostBuf) - 1; | 212 buflen = sizeof(MXHostBuf) - 1; |
322 SM_ASSERT(buflen > 0); | |
323 bp = MXHostBuf; | 213 bp = MXHostBuf; |
324 ancount = ntohs((unsigned short) hp->ancount); 325 326 /* See RFC 1035 for layout of RRs. */ 327 /* XXX leave room for FallbackMX ? */ | 214 ancount = ntohs(hp->ancount); |
328 while (--ancount >= 0 && cp < eom && nmx < MAXMXHOSTS - 1) 329 { | 215 while (--ancount >= 0 && cp < eom && nmx < MAXMXHOSTS - 1) 216 { |
330 if ((n = dn_expand((unsigned char *)&answer, eom, cp, 331 (RES_UNC_T) bp, buflen)) < 0) | 217 if ((n = dn_expand((u_char *)&answer, 218 eom, cp, (RES_UNC_T) bp, buflen)) < 0) |
332 break; 333 cp += n; 334 GETSHORT(type, cp); | 219 break; 220 cp += n; 221 GETSHORT(type, cp); |
335 cp += INT16SZ; /* skip over class */ 336 GETLONG(ttl, cp); 337 GETSHORT(n, cp); /* rdlength */ | 222 cp += INT16SZ + INT32SZ; 223 GETSHORT(n, cp); |
338 if (type != T_MX) 339 { 340 if (tTd(8, 8) || _res.options & RES_DEBUG) | 224 if (type != T_MX) 225 { 226 if (tTd(8, 8) || _res.options & RES_DEBUG) |
341 sm_dprintf("unexpected answer type %d, size %d\n", 342 type, n); | 227 printf("unexpected answer type %d, size %d\n", 228 type, n); |
343 cp += n; 344 continue; 345 } 346 GETSHORT(pref, cp); | 229 cp += n; 230 continue; 231 } 232 GETSHORT(pref, cp); |
347 if ((n = dn_expand((unsigned char *)&answer, eom, cp, | 233 if ((n = dn_expand((u_char *)&answer, eom, cp, |
348 (RES_UNC_T) bp, buflen)) < 0) 349 break; 350 cp += n; | 234 (RES_UNC_T) bp, buflen)) < 0) 235 break; 236 cp += n; |
351 n = strlen(bp); 352# if 0 353 /* Can this happen? */ 354 if (n == 0) 355 { 356 if (LogLevel > 4) 357 sm_syslog(LOG_ERR, NOQID, 358 "MX records for %s contain empty string", 359 host); 360 continue; 361 } 362# endif /* 0 */ | |
363 if (wordinclass(bp, 'w')) 364 { 365 if (tTd(8, 3)) | 237 if (wordinclass(bp, 'w')) 238 { 239 if (tTd(8, 3)) |
366 sm_dprintf("found localhost (%s) in MX list, pref=%d\n", | 240 printf("found localhost (%s) in MX list, pref=%d\n", |
367 bp, pref); 368 if (droplocalhost) 369 { 370 if (!seenlocal || pref < localpref) 371 localpref = pref; | 241 bp, pref); 242 if (droplocalhost) 243 { 244 if (!seenlocal || pref < localpref) 245 localpref = pref; |
372 seenlocal = true; | 246 seenlocal = TRUE; |
373 continue; 374 } 375 weight[nmx] = 0; 376 } 377 else 378 weight[nmx] = mxrand(bp); | 247 continue; 248 } 249 weight[nmx] = 0; 250 } 251 else 252 weight[nmx] = mxrand(bp); |
379 prefs[nmx] = pref; | 253 prefer[nmx] = pref; |
380 mxhosts[nmx++] = bp; | 254 mxhosts[nmx++] = bp; |
255 n = strlen(bp); |
|
381 bp += n; 382 if (bp[-1] != '.') 383 { 384 *bp++ = '.'; 385 n++; 386 } 387 *bp++ = '\0'; | 256 bp += n; 257 if (bp[-1] != '.') 258 { 259 *bp++ = '.'; 260 n++; 261 } 262 *bp++ = '\0'; |
388 if (buflen < n + 1) 389 { 390 /* don't want to wrap buflen */ 391 break; 392 } | |
393 buflen -= n + 1; 394 } 395 | 263 buflen -= n + 1; 264 } 265 |
396 /* return only one TTL entry, that should be sufficient */ 397 if (ttl > 0 && pttl != NULL) 398 *pttl = ttl; 399 | |
400 /* sort the records */ 401 for (i = 0; i < nmx; i++) 402 { 403 for (j = i + 1; j < nmx; j++) 404 { | 266 /* sort the records */ 267 for (i = 0; i < nmx; i++) 268 { 269 for (j = i + 1; j < nmx; j++) 270 { |
405 if (prefs[i] > prefs[j] || 406 (prefs[i] == prefs[j] && weight[i] > weight[j])) | 271 if (prefer[i] > prefer[j] || 272 (prefer[i] == prefer[j] && weight[i] > weight[j])) |
407 { 408 register int temp; 409 register char *temp1; 410 | 273 { 274 register int temp; 275 register char *temp1; 276 |
411 temp = prefs[i]; 412 prefs[i] = prefs[j]; 413 prefs[j] = temp; | 277 temp = prefer[i]; 278 prefer[i] = prefer[j]; 279 prefer[j] = temp; |
414 temp1 = mxhosts[i]; 415 mxhosts[i] = mxhosts[j]; 416 mxhosts[j] = temp1; 417 temp = weight[i]; 418 weight[i] = weight[j]; 419 weight[j] = temp; 420 } 421 } | 280 temp1 = mxhosts[i]; 281 mxhosts[i] = mxhosts[j]; 282 mxhosts[j] = temp1; 283 temp = weight[i]; 284 weight[i] = weight[j]; 285 weight[j] = temp; 286 } 287 } |
422 if (seenlocal && prefs[i] >= localpref) | 288 if (seenlocal && prefer[i] >= localpref) |
423 { 424 /* truncate higher preference part of list */ 425 nmx = i; 426 } 427 } 428 429 /* delete duplicates from list (yes, some bozos have duplicates) */ 430 for (i = 0; i < nmx - 1; ) 431 { | 289 { 290 /* truncate higher preference part of list */ 291 nmx = i; 292 } 293 } 294 295 /* delete duplicates from list (yes, some bozos have duplicates) */ 296 for (i = 0; i < nmx - 1; ) 297 { |
432 if (sm_strcasecmp(mxhosts[i], mxhosts[i + 1]) != 0) | 298 if (strcasecmp(mxhosts[i], mxhosts[i + 1]) != 0) |
433 i++; 434 else 435 { 436 /* compress out duplicate */ 437 for (j = i + 1; j < nmx; j++) | 299 i++; 300 else 301 { 302 /* compress out duplicate */ 303 for (j = i + 1; j < nmx; j++) |
438 { | |
439 mxhosts[j] = mxhosts[j + 1]; | 304 mxhosts[j] = mxhosts[j + 1]; |
440 prefs[j] = prefs[j + 1]; 441 } | |
442 nmx--; 443 } 444 } 445 446 if (nmx == 0) 447 { 448punt: | 305 nmx--; 306 } 307 } 308 309 if (nmx == 0) 310 { 311punt: |
449 if (seenlocal) | 312 if (seenlocal && 313 (!TryNullMXList || sm_gethostbyname(host) == NULL)) |
450 { | 314 { |
451 struct hostent *h = NULL; 452 | |
453 /* 454 ** If we have deleted all MX entries, this is 455 ** an error -- we should NEVER send to a host that 456 ** has an MX, and this should have been caught 457 ** earlier in the config file. 458 ** 459 ** Some sites prefer to go ahead and try the 460 ** A record anyway; that case is handled by 461 ** setting TryNullMXList. I believe this is a 462 ** bad idea, but it's up to you.... 463 */ 464 | 315 /* 316 ** If we have deleted all MX entries, this is 317 ** an error -- we should NEVER send to a host that 318 ** has an MX, and this should have been caught 319 ** earlier in the config file. 320 ** 321 ** Some sites prefer to go ahead and try the 322 ** A record anyway; that case is handled by 323 ** setting TryNullMXList. I believe this is a 324 ** bad idea, but it's up to you.... 325 */ 326 |
465 if (TryNullMXList) 466 { 467 SM_SET_H_ERRNO(0); 468 errno = 0; 469 h = sm_gethostbyname(host, AF_INET); 470 if (h == NULL) 471 { 472 if (errno == ETIMEDOUT || 473 h_errno == TRY_AGAIN || 474 (errno == ECONNREFUSED && 475 UseNameServer)) 476 { 477 *rcode = EX_TEMPFAIL; 478 return -1; 479 } 480# if NETINET6 481 SM_SET_H_ERRNO(0); 482 errno = 0; 483 h = sm_gethostbyname(host, AF_INET6); 484 if (h == NULL && 485 (errno == ETIMEDOUT || 486 h_errno == TRY_AGAIN || 487 (errno == ECONNREFUSED && 488 UseNameServer))) 489 { 490 *rcode = EX_TEMPFAIL; 491 return -1; 492 } 493# endif /* NETINET6 */ 494 } 495 } 496 497 if (h == NULL) 498 { 499 *rcode = EX_CONFIG; 500 syserr("MX list for %s points back to %s", 501 host, MyHostName); 502 return -1; 503 } 504# if NETINET6 505 freehostent(h); 506 h = NULL; 507# endif /* NETINET6 */ | 327 *rcode = EX_CONFIG; 328 syserr("MX list for %s points back to %s", 329 host, MyHostName); 330 return -1; |
508 } | 331 } |
509 if (strlen(host) >= sizeof(MXHostBuf)) | 332 if (strlen(host) >= (SIZE_T) sizeof MXHostBuf) |
510 { 511 *rcode = EX_CONFIG; 512 syserr("Host name %s too long", 513 shortenstring(host, MAXSHORTSTR)); 514 return -1; 515 } | 333 { 334 *rcode = EX_CONFIG; 335 syserr("Host name %s too long", 336 shortenstring(host, MAXSHORTSTR)); 337 return -1; 338 } |
516 (void) sm_strlcpy(MXHostBuf, host, sizeof(MXHostBuf)); | 339 snprintf(MXHostBuf, sizeof MXHostBuf, "%s", host); |
517 mxhosts[0] = MXHostBuf; | 340 mxhosts[0] = MXHostBuf; |
518 prefs[0] = 0; | |
519 if (host[0] == '[') 520 { 521 register char *p; | 341 if (host[0] == '[') 342 { 343 register char *p; |
522# if NETINET6 523 struct sockaddr_in6 tmp6; 524# endif /* NETINET6 */ | |
525 526 /* this may be an MX suppression-style address */ 527 p = strchr(MXHostBuf, ']'); 528 if (p != NULL) 529 { 530 *p = '\0'; | 344 345 /* this may be an MX suppression-style address */ 346 p = strchr(MXHostBuf, ']'); 347 if (p != NULL) 348 { 349 *p = '\0'; |
531 | |
532 if (inet_addr(&MXHostBuf[1]) != INADDR_NONE) 533 { 534 nmx++; 535 *p = ']'; 536 } | 350 if (inet_addr(&MXHostBuf[1]) != INADDR_NONE) 351 { 352 nmx++; 353 *p = ']'; 354 } |
537# if NETINET6 538 else if (anynet_pton(AF_INET6, &MXHostBuf[1], 539 &tmp6.sin6_addr) == 1) 540 { 541 nmx++; 542 *p = ']'; 543 } 544# endif /* NETINET6 */ | |
545 else 546 { | 355 else 356 { |
547 trycanon = true; | 357 trycanon = TRUE; |
548 mxhosts[0]++; 549 } 550 } 551 } 552 if (trycanon && | 358 mxhosts[0]++; 359 } 360 } 361 } 362 if (trycanon && |
553 getcanonname(mxhosts[0], sizeof(MXHostBuf) - 2, false, pttl)) | 363 getcanonname(mxhosts[0], sizeof MXHostBuf - 2, FALSE)) |
554 { | 364 { |
555 /* XXX MXHostBuf == "" ? is that possible? */ | |
556 bp = &MXHostBuf[strlen(MXHostBuf)]; 557 if (bp[-1] != '.') 558 { 559 *bp++ = '.'; 560 *bp = '\0'; 561 } 562 nmx = 1; 563 } 564 } 565 566 /* if we have a default lowest preference, include that */ 567 if (fallbackMX != NULL && !seenlocal) | 365 bp = &MXHostBuf[strlen(MXHostBuf)]; 366 if (bp[-1] != '.') 367 { 368 *bp++ = '.'; 369 *bp = '\0'; 370 } 371 nmx = 1; 372 } 373 } 374 375 /* if we have a default lowest preference, include that */ 376 if (fallbackMX != NULL && !seenlocal) |
568 { 569 nmx = fallbackmxrr(nmx, prefs, mxhosts); 570 } 571 return nmx; | 377 mxhosts[nmx++] = fallbackMX; 378 379 return (nmx); |
572} | 380} |
573/* | 381/* |
574** MXRAND -- create a randomizer for equal MX preferences 575** 576** If two MX hosts have equal preferences we want to randomize 577** the selection. But in order for signatures to be the same, 578** we need to randomize the same way each time. This function 579** computes a pseudo-random hash function from the host name. 580** 581** Parameters: 582** host -- the name of the host. 583** 584** Returns: 585** A random but repeatable value based on the host name. | 382** MXRAND -- create a randomizer for equal MX preferences 383** 384** If two MX hosts have equal preferences we want to randomize 385** the selection. But in order for signatures to be the same, 386** we need to randomize the same way each time. This function 387** computes a pseudo-random hash function from the host name. 388** 389** Parameters: 390** host -- the name of the host. 391** 392** Returns: 393** A random but repeatable value based on the host name. |
394** 395** Side Effects: 396** none. |
|
586*/ 587 | 397*/ 398 |
588static int | 399int |
589mxrand(host) 590 register char *host; 591{ 592 int hfunc; 593 static unsigned int seed; 594 595 if (seed == 0) 596 { 597 seed = (int) curtime() & 0xffff; 598 if (seed == 0) 599 seed++; 600 } 601 602 if (tTd(17, 9)) | 400mxrand(host) 401 register char *host; 402{ 403 int hfunc; 404 static unsigned int seed; 405 406 if (seed == 0) 407 { 408 seed = (int) curtime() & 0xffff; 409 if (seed == 0) 410 seed++; 411 } 412 413 if (tTd(17, 9)) |
603 sm_dprintf("mxrand(%s)", host); | 414 printf("mxrand(%s)", host); |
604 605 hfunc = seed; 606 while (*host != '\0') 607 { 608 int c = *host++; 609 610 if (isascii(c) && isupper(c)) 611 c = tolower(c); 612 hfunc = ((hfunc << 1) ^ c) % 2003; 613 } 614 615 hfunc &= 0xff; 616 hfunc++; 617 618 if (tTd(17, 9)) | 415 416 hfunc = seed; 417 while (*host != '\0') 418 { 419 int c = *host++; 420 421 if (isascii(c) && isupper(c)) 422 c = tolower(c); 423 hfunc = ((hfunc << 1) ^ c) % 2003; 424 } 425 426 hfunc &= 0xff; 427 hfunc++; 428 429 if (tTd(17, 9)) |
619 sm_dprintf(" = %d\n", hfunc); | 430 printf(" = %d\n", hfunc); |
620 return hfunc; 621} | 431 return hfunc; 432} |
622/* | 433/* |
623** BESTMX -- find the best MX for a name 624** 625** This is really a hack, but I don't see any obvious way 626** to generalize it at the moment. 627*/ 628 629/* ARGSUSED3 */ 630char * 631bestmx_map_lookup(map, name, av, statp) 632 MAP *map; 633 char *name; 634 char **av; 635 int *statp; 636{ 637 int nmx; | 434** BESTMX -- find the best MX for a name 435** 436** This is really a hack, but I don't see any obvious way 437** to generalize it at the moment. 438*/ 439 440/* ARGSUSED3 */ 441char * 442bestmx_map_lookup(map, name, av, statp) 443 MAP *map; 444 char *name; 445 char **av; 446 int *statp; 447{ 448 int nmx; |
449 auto int rcode; |
|
638 int saveopts = _res.options; | 450 int saveopts = _res.options; |
639 int i; 640 ssize_t len = 0; 641 char *result; 642 char *mxhosts[MAXMXHOSTS + 1]; 643#if _FFR_BESTMX_BETTER_TRUNCATION 644 char *buf; 645#else /* _FFR_BESTMX_BETTER_TRUNCATION */ | 451 int i, len = 0; |
646 char *p; | 452 char *p; |
647 char buf[PSBUFSIZE / 2]; 648#endif /* _FFR_BESTMX_BETTER_TRUNCATION */ | 453 char *mxhosts[MAXMXHOSTS + 1]; 454 char buf[MXHOSTBUFSIZE + 1]; |
649 650 _res.options &= ~(RES_DNSRCH|RES_DEFNAMES); | 455 456 _res.options &= ~(RES_DNSRCH|RES_DEFNAMES); |
651 nmx = getmxrr(name, mxhosts, NULL, false, statp, false, NULL); | 457 nmx = getmxrr(name, mxhosts, FALSE, &rcode); |
652 _res.options = saveopts; 653 if (nmx <= 0) 654 return NULL; 655 if (bitset(MF_MATCHONLY, map->map_mflags)) 656 return map_rewrite(map, name, strlen(name), NULL); 657 if ((map->map_coldelim == '\0') || (nmx == 1)) 658 return map_rewrite(map, mxhosts[0], strlen(mxhosts[0]), av); 659 660 /* | 458 _res.options = saveopts; 459 if (nmx <= 0) 460 return NULL; 461 if (bitset(MF_MATCHONLY, map->map_mflags)) 462 return map_rewrite(map, name, strlen(name), NULL); 463 if ((map->map_coldelim == '\0') || (nmx == 1)) 464 return map_rewrite(map, mxhosts[0], strlen(mxhosts[0]), av); 465 466 /* |
661 ** We were given a -z flag (return all MXs) and there are multiple 662 ** ones. We need to build them all into a list. | 467 ** We were given a -z flag (return all MXs) and there are multiple 468 ** ones. We need to build them all into a list. |
663 */ | 469 */ |
664 665#if _FFR_BESTMX_BETTER_TRUNCATION 666 for (i = 0; i < nmx; i++) 667 { 668 if (strchr(mxhosts[i], map->map_coldelim) != NULL) 669 { 670 syserr("bestmx_map_lookup: MX host %.64s includes map delimiter character 0x%02X", 671 mxhosts[i], map->map_coldelim); 672 return NULL; 673 } 674 len += strlen(mxhosts[i]) + 1; 675 if (len < 0) 676 { 677 len -= strlen(mxhosts[i]) + 1; 678 break; 679 } 680 } 681 buf = (char *) sm_malloc(len); 682 if (buf == NULL) 683 { 684 *statp = EX_UNAVAILABLE; 685 return NULL; 686 } 687 *buf = '\0'; 688 for (i = 0; i < nmx; i++) 689 { 690 int end; 691 692 end = sm_strlcat(buf, mxhosts[i], len); 693 if (i != nmx && end + 1 < len) 694 { 695 buf[end] = map->map_coldelim; 696 buf[end + 1] = '\0'; 697 } 698 } 699 700 /* Cleanly truncate for rulesets */ 701 truncate_at_delim(buf, PSBUFSIZE / 2, map->map_coldelim); 702#else /* _FFR_BESTMX_BETTER_TRUNCATION */ | |
703 p = buf; 704 for (i = 0; i < nmx; i++) 705 { | 470 p = buf; 471 for (i = 0; i < nmx; i++) 472 { |
706 size_t slen; 707 | 473 int slen; 474 |
708 if (strchr(mxhosts[i], map->map_coldelim) != NULL) 709 { 710 syserr("bestmx_map_lookup: MX host %.64s includes map delimiter character 0x%02X", 711 mxhosts[i], map->map_coldelim); 712 return NULL; 713 } 714 slen = strlen(mxhosts[i]); | 475 if (strchr(mxhosts[i], map->map_coldelim) != NULL) 476 { 477 syserr("bestmx_map_lookup: MX host %.64s includes map delimiter character 0x%02X", 478 mxhosts[i], map->map_coldelim); 479 return NULL; 480 } 481 slen = strlen(mxhosts[i]); |
715 if (len + slen + 2 > sizeof(buf)) | 482 if (len + slen + 2 > sizeof buf) |
716 break; 717 if (i > 0) 718 { 719 *p++ = map->map_coldelim; 720 len++; 721 } | 483 break; 484 if (i > 0) 485 { 486 *p++ = map->map_coldelim; 487 len++; 488 } |
722 (void) sm_strlcpy(p, mxhosts[i], sizeof(buf) - len); | 489 strcpy(p, mxhosts[i]); |
723 p += slen; 724 len += slen; 725 } | 490 p += slen; 491 len += slen; 492 } |
726#endif /* _FFR_BESTMX_BETTER_TRUNCATION */ 727 728 result = map_rewrite(map, buf, len, av); 729#if _FFR_BESTMX_BETTER_TRUNCATION 730 sm_free(buf); 731#endif /* _FFR_BESTMX_BETTER_TRUNCATION */ 732 return result; | 493 return map_rewrite(map, buf, len, av); |
733} | 494} |
734/* | 495/* |
735** DNS_GETCANONNAME -- get the canonical name for named host using DNS 736** 737** This algorithm tries to be smart about wildcard MX records. 738** This is hard to do because DNS doesn't tell is if we matched 739** against a wildcard or a specific MX. | 496** DNS_GETCANONNAME -- get the canonical name for named host using DNS 497** 498** This algorithm tries to be smart about wildcard MX records. 499** This is hard to do because DNS doesn't tell is if we matched 500** against a wildcard or a specific MX. |
740** | 501** |
741** We always prefer A & CNAME records, since these are presumed 742** to be specific. 743** 744** If we match an MX in one pass and lose it in the next, we use 745** the old one. For example, consider an MX matching *.FOO.BAR.COM. 746** A hostname bletch.foo.bar.com will match against this MX, but 747** will stop matching when we try bletch.bar.com -- so we know 748** that bletch.foo.bar.com must have been right. This fails if 749** there was also an MX record matching *.BAR.COM, but there are 750** some things that just can't be fixed. 751** 752** Parameters: 753** host -- a buffer containing the name of the host. 754** This is a value-result parameter. 755** hbsize -- the size of the host buffer. 756** trymx -- if set, try MX records as well as A and CNAME. 757** statp -- pointer to place to store status. | 502** We always prefer A & CNAME records, since these are presumed 503** to be specific. 504** 505** If we match an MX in one pass and lose it in the next, we use 506** the old one. For example, consider an MX matching *.FOO.BAR.COM. 507** A hostname bletch.foo.bar.com will match against this MX, but 508** will stop matching when we try bletch.bar.com -- so we know 509** that bletch.foo.bar.com must have been right. This fails if 510** there was also an MX record matching *.BAR.COM, but there are 511** some things that just can't be fixed. 512** 513** Parameters: 514** host -- a buffer containing the name of the host. 515** This is a value-result parameter. 516** hbsize -- the size of the host buffer. 517** trymx -- if set, try MX records as well as A and CNAME. 518** statp -- pointer to place to store status. |
758** pttl -- pointer to return TTL (can be NULL). | |
759** 760** Returns: | 519** 520** Returns: |
761** true -- if the host matched. 762** false -- otherwise. | 521** TRUE -- if the host matched. 522** FALSE -- otherwise. |
763*/ 764 765bool | 523*/ 524 525bool |
766dns_getcanonname(host, hbsize, trymx, statp, pttl) | 526dns_getcanonname(host, hbsize, trymx, statp) |
767 char *host; 768 int hbsize; 769 bool trymx; 770 int *statp; | 527 char *host; 528 int hbsize; 529 bool trymx; 530 int *statp; |
771 int *pttl; | |
772{ | 531{ |
773 register unsigned char *eom, *ap; | 532 register u_char *eom, *ap; |
774 register char *cp; | 533 register char *cp; |
775 register int n; | 534 register int n; |
776 HEADER *hp; 777 querybuf answer; 778 int ancount, qdcount; 779 int ret; 780 char **domain; 781 int type; | 535 HEADER *hp; 536 querybuf answer; 537 int ancount, qdcount; 538 int ret; 539 char **domain; 540 int type; |
782 int ttl = 0; | |
783 char **dp; 784 char *mxmatch; 785 bool amatch; | 541 char **dp; 542 char *mxmatch; 543 bool amatch; |
786 bool gotmx = false; | 544 bool gotmx = FALSE; |
787 int qtype; | 545 int qtype; |
788 int initial; | |
789 int loopcnt; | 546 int loopcnt; |
790 char nbuf[SM_MAX(MAXPACKET, MAXDNAME*2+2)]; 791 char *searchlist[MAXDNSRCH + 2]; | 547 char *xp; 548 char nbuf[MAX(MAXPACKET, MAXDNAME*2+2)]; 549 char *searchlist[MAXDNSRCH+2]; 550 extern char *gethostalias __P((char *)); |
792 793 if (tTd(8, 2)) | 551 552 if (tTd(8, 2)) |
794 sm_dprintf("dns_getcanonname(%s, trymx=%d)\n", host, trymx); | 553 printf("dns_getcanonname(%s, trymx=%d)\n", host, trymx); |
795 796 if ((_res.options & RES_INIT) == 0 && res_init() == -1) 797 { 798 *statp = EX_UNAVAILABLE; | 554 555 if ((_res.options & RES_INIT) == 0 && res_init() == -1) 556 { 557 *statp = EX_UNAVAILABLE; |
799 return false; | 558 return FALSE; |
800 } 801 | 559 } 560 |
802 *statp = EX_OK; 803 | |
804 /* 805 ** Initialize domain search list. If there is at least one 806 ** dot in the name, search the unmodified name first so we 807 ** find "vse.CS" in Czechoslovakia instead of in the local | 561 /* 562 ** Initialize domain search list. If there is at least one 563 ** dot in the name, search the unmodified name first so we 564 ** find "vse.CS" in Czechoslovakia instead of in the local |
808 ** domain (e.g., vse.CS.Berkeley.EDU). Note that there is no 809 ** longer a country named Czechoslovakia but this type of problem 810 ** is still present. | 565 ** domain (e.g., vse.CS.Berkeley.EDU). |
811 ** 812 ** Older versions of the resolver could create this 813 ** list by tearing apart the host name. 814 */ 815 816 loopcnt = 0; 817cnameloop: 818 /* Check for dots in the name */ 819 for (cp = host, n = 0; *cp != '\0'; cp++) 820 if (*cp == '.') 821 n++; 822 823 /* | 566 ** 567 ** Older versions of the resolver could create this 568 ** list by tearing apart the host name. 569 */ 570 571 loopcnt = 0; 572cnameloop: 573 /* Check for dots in the name */ 574 for (cp = host, n = 0; *cp != '\0'; cp++) 575 if (*cp == '.') 576 n++; 577 578 /* |
824 ** Build the search list. | 579 ** If this is a simple name, determine whether it matches an 580 ** alias in the file defined by the environment variable HOSTALIASES. 581 */ 582 if (n == 0 && (xp = gethostalias(host)) != NULL) 583 { 584 if (loopcnt++ > MAXCNAMEDEPTH) 585 { 586 syserr("loop in ${HOSTALIASES} file"); 587 } 588 else 589 { 590 strncpy(host, xp, hbsize); 591 host[hbsize - 1] = '\0'; 592 goto cnameloop; 593 } 594 } 595 596 /* 597 ** Build the search list. |
825 ** If there is at least one dot in name, start with a null 826 ** domain to search the unmodified name first. 827 ** If name does not end with a dot and search up local domain 828 ** tree desired, append each local domain component to the 829 ** search list; if name contains no dots and default domain 830 ** name is desired, append default domain name to search list; 831 ** else if name ends in a dot, remove that dot. 832 */ 833 834 dp = searchlist; 835 if (n > 0) 836 *dp++ = ""; 837 if (n >= 0 && *--cp != '.' && bitset(RES_DNSRCH, _res.options)) 838 { | 598 ** If there is at least one dot in name, start with a null 599 ** domain to search the unmodified name first. 600 ** If name does not end with a dot and search up local domain 601 ** tree desired, append each local domain component to the 602 ** search list; if name contains no dots and default domain 603 ** name is desired, append default domain name to search list; 604 ** else if name ends in a dot, remove that dot. 605 */ 606 607 dp = searchlist; 608 if (n > 0) 609 *dp++ = ""; 610 if (n >= 0 && *--cp != '.' && bitset(RES_DNSRCH, _res.options)) 611 { |
839 /* make sure there are less than MAXDNSRCH domains */ 840 for (domain = RES_DNSRCH_VARIABLE, ret = 0; 841 *domain != NULL && ret < MAXDNSRCH; 842 ret++) | 612 for (domain = _res.dnsrch; *domain != NULL; ) |
843 *dp++ = *domain++; 844 } 845 else if (n == 0 && bitset(RES_DEFNAMES, _res.options)) 846 { 847 *dp++ = _res.defdname; 848 } 849 else if (*cp == '.') 850 { 851 *cp = '\0'; 852 } 853 *dp = NULL; 854 855 /* 856 ** Now loop through the search list, appending each domain in turn 857 ** name and searching for a match. 858 */ 859 860 mxmatch = NULL; | 613 *dp++ = *domain++; 614 } 615 else if (n == 0 && bitset(RES_DEFNAMES, _res.options)) 616 { 617 *dp++ = _res.defdname; 618 } 619 else if (*cp == '.') 620 { 621 *cp = '\0'; 622 } 623 *dp = NULL; 624 625 /* 626 ** Now loop through the search list, appending each domain in turn 627 ** name and searching for a match. 628 */ 629 630 mxmatch = NULL; |
861 initial = T_A; 862# if NETINET6 863 if (InetMode == AF_INET6) 864 initial = T_AAAA; 865# endif /* NETINET6 */ 866 qtype = initial; | 631 qtype = T_ANY; |
867 868 for (dp = searchlist; *dp != NULL; ) 869 { | 632 633 for (dp = searchlist; *dp != NULL; ) 634 { |
870 if (qtype == initial) 871 gotmx = false; | 635 if (qtype == T_ANY) 636 gotmx = FALSE; |
872 if (tTd(8, 5)) | 637 if (tTd(8, 5)) |
873 sm_dprintf("dns_getcanonname: trying %s.%s (%s)\n", | 638 printf("dns_getcanonname: trying %s.%s (%s)\n", |
874 host, *dp, | 639 host, *dp, |
875# if NETINET6 876 qtype == T_AAAA ? "AAAA" : 877# endif /* NETINET6 */ 878 qtype == T_A ? "A" : 879 qtype == T_MX ? "MX" : 880 "???"); 881 errno = 0; | 640 qtype == T_ANY ? "ANY" : qtype == T_A ? "A" : 641 qtype == T_MX ? "MX" : "???"); |
882 ret = res_querydomain(host, *dp, C_IN, qtype, 883 answer.qb2, sizeof(answer.qb2)); 884 if (ret <= 0) 885 { | 642 ret = res_querydomain(host, *dp, C_IN, qtype, 643 answer.qb2, sizeof(answer.qb2)); 644 if (ret <= 0) 645 { |
886 int save_errno = errno; 887 | |
888 if (tTd(8, 7)) | 646 if (tTd(8, 7)) |
889 sm_dprintf("\tNO: errno=%d, h_errno=%d\n", 890 save_errno, h_errno); | 647 printf("\tNO: errno=%d, h_errno=%d\n", 648 errno, h_errno); |
891 | 649 |
892 if (save_errno == ECONNREFUSED || h_errno == TRY_AGAIN) | 650 if (errno == ECONNREFUSED || h_errno == TRY_AGAIN) |
893 { | 651 { |
894 /* 895 ** the name server seems to be down or broken. 896 */ 897 898 SM_SET_H_ERRNO(TRY_AGAIN); 899 if (**dp == '\0') 900 { 901 if (*statp == EX_OK) 902 *statp = EX_TEMPFAIL; 903 goto nexttype; 904 } | 652 /* the name server seems to be down */ 653 h_errno = TRY_AGAIN; |
905 *statp = EX_TEMPFAIL; | 654 *statp = EX_TEMPFAIL; |
906 907 if (WorkAroundBrokenAAAA) 908 { 909 /* 910 ** Only return if not TRY_AGAIN as an 911 ** attempt with a different qtype may 912 ** succeed (res_querydomain() calls 913 ** res_query() calls res_send() which 914 ** sets errno to ETIMEDOUT if the 915 ** nameservers could be contacted but 916 ** didn't give an answer). 917 */ 918 919 if (save_errno != ETIMEDOUT) 920 return false; 921 } 922 else 923 return false; | 655 return FALSE; |
924 } 925 | 656 } 657 |
926nexttype: | |
927 if (h_errno != HOST_NOT_FOUND) 928 { 929 /* might have another type of interest */ | 658 if (h_errno != HOST_NOT_FOUND) 659 { 660 /* might have another type of interest */ |
930# if NETINET6 931 if (qtype == T_AAAA) | 661 if (qtype == T_ANY) |
932 { 933 qtype = T_A; 934 continue; 935 } | 662 { 663 qtype = T_A; 664 continue; 665 } |
936 else 937# endif /* NETINET6 */ 938 if (qtype == T_A && !gotmx && 939 (trymx || **dp == '\0')) | 666 else if (qtype == T_A && !gotmx && trymx) |
940 { 941 qtype = T_MX; 942 continue; 943 } 944 } 945 946 /* definite no -- try the next domain */ 947 dp++; | 667 { 668 qtype = T_MX; 669 continue; 670 } 671 } 672 673 /* definite no -- try the next domain */ 674 dp++; |
948 qtype = initial; | 675 qtype = T_ANY; |
949 continue; 950 } 951 else if (tTd(8, 7)) | 676 continue; 677 } 678 else if (tTd(8, 7)) |
952 sm_dprintf("\tYES\n"); | 679 printf("\tYES\n"); |
953 954 /* avoid problems after truncation in tcp packets */ 955 if (ret > sizeof(answer)) 956 ret = sizeof(answer); | 680 681 /* avoid problems after truncation in tcp packets */ 682 if (ret > sizeof(answer)) 683 ret = sizeof(answer); |
957 SM_ASSERT(ret >= 0); | |
958 959 /* 960 ** Appear to have a match. Confirm it by searching for A or 961 ** CNAME records. If we don't have a local domain 962 ** wild card MX record, we will accept MX as well. 963 */ 964 965 hp = (HEADER *) &answer; | 684 685 /* 686 ** Appear to have a match. Confirm it by searching for A or 687 ** CNAME records. If we don't have a local domain 688 ** wild card MX record, we will accept MX as well. 689 */ 690 691 hp = (HEADER *) &answer; |
966 ap = (unsigned char *) &answer + HFIXEDSZ; 967 eom = (unsigned char *) &answer + ret; | 692 ap = (u_char *) &answer + HFIXEDSZ; 693 eom = (u_char *) &answer + ret; |
968 969 /* skip question part of response -- we know what we asked */ | 694 695 /* skip question part of response -- we know what we asked */ |
970 for (qdcount = ntohs((unsigned short) hp->qdcount); 971 qdcount--; 972 ap += ret + QFIXEDSZ) | 696 for (qdcount = ntohs(hp->qdcount); qdcount--; ap += ret + QFIXEDSZ) |
973 { 974 if ((ret = dn_skipname(ap, eom)) < 0) 975 { 976 if (tTd(8, 20)) | 697 { 698 if ((ret = dn_skipname(ap, eom)) < 0) 699 { 700 if (tTd(8, 20)) |
977 sm_dprintf("qdcount failure (%d)\n", 978 ntohs((unsigned short) hp->qdcount)); | 701 printf("qdcount failure (%d)\n", 702 ntohs(hp->qdcount)); |
979 *statp = EX_SOFTWARE; | 703 *statp = EX_SOFTWARE; |
980 return false; /* ???XXX??? */ | 704 return FALSE; /* ???XXX??? */ |
981 } 982 } 983 | 705 } 706 } 707 |
984 amatch = false; 985 for (ancount = ntohs((unsigned short) hp->ancount); 986 --ancount >= 0 && ap < eom; 987 ap += n) | 708 amatch = FALSE; 709 for (ancount = ntohs(hp->ancount); --ancount >= 0 && ap < eom; 710 ap += n) |
988 { | 711 { |
989 n = dn_expand((unsigned char *) &answer, eom, ap, 990 (RES_UNC_T) nbuf, sizeof(nbuf)); | 712 n = dn_expand((u_char *) &answer, eom, ap, 713 (RES_UNC_T) nbuf, sizeof nbuf); |
991 if (n < 0) 992 break; 993 ap += n; 994 GETSHORT(type, ap); | 714 if (n < 0) 715 break; 716 ap += n; 717 GETSHORT(type, ap); |
995 ap += INT16SZ; /* skip over class */ 996 GETLONG(ttl, ap); 997 GETSHORT(n, ap); /* rdlength */ | 718 ap += INT16SZ + INT32SZ; 719 GETSHORT(n, ap); |
998 switch (type) 999 { 1000 case T_MX: | 720 switch (type) 721 { 722 case T_MX: |
1001 gotmx = true; | 723 gotmx = TRUE; |
1002 if (**dp != '\0' && HasWildcardMX) 1003 { 1004 /* 1005 ** If we are using MX matches and have 1006 ** not yet gotten one, save this one | 724 if (**dp != '\0' && HasWildcardMX) 725 { 726 /* 727 ** If we are using MX matches and have 728 ** not yet gotten one, save this one |
1007 ** but keep searching for an A or | 729 ** but keep searching for an A or |
1008 ** CNAME match. 1009 */ 1010 1011 if (trymx && mxmatch == NULL) 1012 mxmatch = *dp; 1013 continue; 1014 } 1015 1016 /* 1017 ** If we did not append a domain name, this 1018 ** must have been a canonical name to start 1019 ** with. Even if we did append a domain name, 1020 ** in the absence of a wildcard MX this must 1021 ** still be a real MX match. 1022 ** Such MX matches are as good as an A match, 1023 ** fall through. 1024 */ | 730 ** CNAME match. 731 */ 732 733 if (trymx && mxmatch == NULL) 734 mxmatch = *dp; 735 continue; 736 } 737 738 /* 739 ** If we did not append a domain name, this 740 ** must have been a canonical name to start 741 ** with. Even if we did append a domain name, 742 ** in the absence of a wildcard MX this must 743 ** still be a real MX match. 744 ** Such MX matches are as good as an A match, 745 ** fall through. 746 */ |
1025 /* FALLTHROUGH */ | |
1026 | 747 |
1027# if NETINET6 1028 case T_AAAA: 1029# endif /* NETINET6 */ | |
1030 case T_A: 1031 /* Flag that a good match was found */ | 748 case T_A: 749 /* Flag that a good match was found */ |
1032 amatch = true; | 750 amatch = TRUE; |
1033 1034 /* continue in case a CNAME also exists */ 1035 continue; 1036 1037 case T_CNAME: 1038 if (DontExpandCnames) 1039 { 1040 /* got CNAME -- guaranteed canonical */ | 751 752 /* continue in case a CNAME also exists */ 753 continue; 754 755 case T_CNAME: 756 if (DontExpandCnames) 757 { 758 /* got CNAME -- guaranteed canonical */ |
1041 amatch = true; | 759 amatch = TRUE; |
1042 break; 1043 } 1044 1045 if (loopcnt++ > MAXCNAMEDEPTH) 1046 { 1047 /*XXX should notify postmaster XXX*/ 1048 message("DNS failure: CNAME loop for %s", 1049 host); 1050 if (CurEnv->e_message == NULL) 1051 { 1052 char ebuf[MAXLINE]; 1053 | 760 break; 761 } 762 763 if (loopcnt++ > MAXCNAMEDEPTH) 764 { 765 /*XXX should notify postmaster XXX*/ 766 message("DNS failure: CNAME loop for %s", 767 host); 768 if (CurEnv->e_message == NULL) 769 { 770 char ebuf[MAXLINE]; 771 |
1054 (void) sm_snprintf(ebuf, 1055 sizeof(ebuf), | 772 snprintf(ebuf, sizeof ebuf, |
1056 "Deferred: DNS failure: CNAME loop for %.100s", 1057 host); | 773 "Deferred: DNS failure: CNAME loop for %.100s", 774 host); |
1058 CurEnv->e_message = 1059 sm_rpool_strdup_x( 1060 CurEnv->e_rpool, ebuf); | 775 CurEnv->e_message = newstr(ebuf); |
1061 } | 776 } |
1062 SM_SET_H_ERRNO(NO_RECOVERY); | 777 h_errno = NO_RECOVERY; |
1063 *statp = EX_CONFIG; | 778 *statp = EX_CONFIG; |
1064 return false; | 779 return FALSE; |
1065 } 1066 1067 /* value points at name */ | 780 } 781 782 /* value points at name */ |
1068 if ((ret = dn_expand((unsigned char *)&answer, 1069 eom, ap, (RES_UNC_T) nbuf, 1070 sizeof(nbuf))) < 0) | 783 if ((ret = dn_expand((u_char *)&answer, 784 eom, ap, (RES_UNC_T) nbuf, sizeof(nbuf))) < 0) |
1071 break; | 785 break; |
1072 (void) sm_strlcpy(host, nbuf, hbsize); | 786 (void)strncpy(host, nbuf, hbsize); /* XXX */ 787 host[hbsize - 1] = '\0'; |
1073 1074 /* 1075 ** RFC 1034 section 3.6 specifies that CNAME 1076 ** should point at the canonical name -- but 1077 ** urges software to try again anyway. 1078 */ 1079 1080 goto cnameloop; 1081 1082 default: 1083 /* not a record of interest */ 1084 continue; 1085 } 1086 } 1087 1088 if (amatch) 1089 { | 788 789 /* 790 ** RFC 1034 section 3.6 specifies that CNAME 791 ** should point at the canonical name -- but 792 ** urges software to try again anyway. 793 */ 794 795 goto cnameloop; 796 797 default: 798 /* not a record of interest */ 799 continue; 800 } 801 } 802 803 if (amatch) 804 { |
1090 /* | 805 /* |
1091 ** Got a good match -- either an A, CNAME, or an 1092 ** exact MX record. Save it and get out of here. 1093 */ 1094 1095 mxmatch = *dp; 1096 break; 1097 } 1098 1099 /* 1100 ** Nothing definitive yet. | 806 ** Got a good match -- either an A, CNAME, or an 807 ** exact MX record. Save it and get out of here. 808 */ 809 810 mxmatch = *dp; 811 break; 812 } 813 814 /* 815 ** Nothing definitive yet. |
816 ** If this was a T_ANY query, we don't really know what 817 ** was returned -- it might have been a T_NS, 818 ** for example. Try T_A to be more specific 819 ** during the next pass. |
|
1101 ** If this was a T_A query and we haven't yet found a MX 1102 ** match, try T_MX if allowed to do so. 1103 ** Otherwise, try the next domain. 1104 */ 1105 | 820 ** If this was a T_A query and we haven't yet found a MX 821 ** match, try T_MX if allowed to do so. 822 ** Otherwise, try the next domain. 823 */ 824 |
1106# if NETINET6 1107 if (qtype == T_AAAA) | 825 if (qtype == T_ANY) |
1108 qtype = T_A; | 826 qtype = T_A; |
1109 else 1110# endif /* NETINET6 */ 1111 if (qtype == T_A && !gotmx && (trymx || **dp == '\0')) | 827 else if (qtype == T_A && !gotmx && trymx) |
1112 qtype = T_MX; 1113 else 1114 { | 828 qtype = T_MX; 829 else 830 { |
1115 qtype = initial; | 831 qtype = T_ANY; |
1116 dp++; 1117 } 1118 } 1119 1120 /* if nothing was found, we are done */ 1121 if (mxmatch == NULL) 1122 { | 832 dp++; 833 } 834 } 835 836 /* if nothing was found, we are done */ 837 if (mxmatch == NULL) 838 { |
1123 if (*statp == EX_OK) 1124 *statp = EX_NOHOST; 1125 return false; | 839 *statp = EX_NOHOST; 840 return FALSE; |
1126 } 1127 1128 /* 1129 ** Create canonical name and return. 1130 ** If saved domain name is null, name was already canonical. 1131 ** Otherwise append the saved domain name. 1132 */ 1133 | 841 } 842 843 /* 844 ** Create canonical name and return. 845 ** If saved domain name is null, name was already canonical. 846 ** Otherwise append the saved domain name. 847 */ 848 |
1134 (void) sm_snprintf(nbuf, sizeof(nbuf), "%.*s%s%.*s", MAXDNAME, host, 1135 *mxmatch == '\0' ? "" : ".", 1136 MAXDNAME, mxmatch); 1137 (void) sm_strlcpy(host, nbuf, hbsize); | 849 (void) snprintf(nbuf, sizeof nbuf, "%.*s%s%.*s", MAXDNAME, host, 850 *mxmatch == '\0' ? "" : ".", 851 MAXDNAME, mxmatch); 852 strncpy(host, nbuf, hbsize); 853 host[hbsize - 1] = '\0'; |
1138 if (tTd(8, 5)) | 854 if (tTd(8, 5)) |
1139 sm_dprintf("dns_getcanonname: %s\n", host); | 855 printf("dns_getcanonname: %s\n", host); |
1140 *statp = EX_OK; | 856 *statp = EX_OK; |
857 return TRUE; 858} |
|
1141 | 859 |
1142 /* return only one TTL entry, that should be sufficient */ 1143 if (ttl > 0 && pttl != NULL) 1144 *pttl = ttl; 1145 return true; | 860 861 862char * 863gethostalias(host) 864 char *host; 865{ 866 char *fname; 867 FILE *fp; 868 register char *p = NULL; 869 int sff = SFF_REGONLY; 870 char buf[MAXLINE]; 871 static char hbuf[MAXDNAME]; 872 873 if (DontLockReadFiles) 874 sff |= SFF_NOLOCK; 875 fname = getenv("HOSTALIASES"); 876 if (fname == NULL || 877 (fp = safefopen(fname, O_RDONLY, 0, sff)) == NULL) 878 return NULL; 879 while (fgets(buf, sizeof buf, fp) != NULL) 880 { 881 for (p = buf; p != '\0' && !(isascii(*p) && isspace(*p)); p++) 882 continue; 883 if (*p == 0) 884 { 885 /* syntax error */ 886 continue; 887 } 888 *p++ = '\0'; 889 if (strcasecmp(buf, host) == 0) 890 break; 891 } 892 893 if (feof(fp)) 894 { 895 /* no match */ 896 fclose(fp); 897 return NULL; 898 } 899 fclose(fp); 900 901 /* got a match; extract the equivalent name */ 902 while (*p != '\0' && isascii(*p) && isspace(*p)) 903 p++; 904 host = p; 905 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 906 p++; 907 *p = '\0'; 908 strncpy(hbuf, host, sizeof hbuf - 1); 909 hbuf[sizeof hbuf - 1] = '\0'; 910 return hbuf; |
1146} | 911} |
912 |
|
1147#endif /* NAMED_BIND */ | 913#endif /* NAMED_BIND */ |