* Copyright (c) 1986 Eric P. Allman
* Copyright (c) 1988 Regents of the University of California.
* %sccs.include.redist.c%
static char sccsid
[] = "@(#)domain.c 6.3 (Berkeley) %G% (with name server)";
static char sccsid
[] = "@(#)domain.c 6.3 (Berkeley) %G% (without name server)";
#include <arpa/nameser.h>
static char hostbuf
[MAXMXHOSTS
*PACKETSZ
];
#define MAXDNSRCH 6 /* number of possible domains to search */
getmxrr(host
, mxhosts
, localhost
, rcode
)
char *host
, **mxhosts
, *localhost
;
register u_char
*eom
, *cp
;
register int i
, j
, n
, nmx
;
int ancount
, qdcount
, buflen
, seenlocal
;
u_short pref
, localpref
, type
, prefer
[MAXMXHOSTS
];
n
= res_search(host
, C_IN
, T_MX
, (char *)&answer
, sizeof(answer
));
printf("getmxrr: res_search(%s) failed (errno=%d, h_errno=%d)\n",
(host
== NULL
) ? "<NULL>" : host
, errno
, h_errno
);
/* no MX data on this host */
/* the host just doesn't exist */
/* couldn't connect to the name server */
if (!UseNameServer
&& errno
== ECONNREFUSED
)
/* it might come up later; better queue it up */
/* irreconcilable differences */
/* find first satisfactory answer */
cp
= (u_char
*)&answer
+ sizeof(HEADER
);
eom
= (u_char
*)&answer
+ n
;
for (qdcount
= ntohs(hp
->qdcount
); qdcount
--; cp
+= n
+ QFIXEDSZ
)
if ((n
= dn_skipname(cp
, eom
)) < 0)
buflen
= sizeof(hostbuf
) - 1;
ancount
= ntohs(hp
->ancount
);
while (--ancount
>= 0 && cp
< eom
&& nmx
< MAXMXHOSTS
)
if ((n
= dn_expand((u_char
*)&answer
,
eom
, cp
, (u_char
*)bp
, buflen
)) < 0)
cp
+= sizeof(u_short
) + sizeof(u_long
);
if (tTd(8, 8) || _res
.options
& RES_DEBUG
)
printf("unexpected answer type %d, size %d\n",
if ((n
= dn_expand((u_char
*)&answer
, eom
, cp
,
(u_char
*)bp
, buflen
)) < 0)
if (!strcasecmp(bp
, localhost
))
if (seenlocal
== 0 || pref
< localpref
)
weight
[nmx
] = mxrand(bp
);
punt
: mxhosts
[0] = strcpy(hostbuf
, host
);
for (i
= 0; i
< nmx
; i
++)
for (j
= i
+ 1; j
< nmx
; j
++)
if (prefer
[i
] > prefer
[j
] ||
(prefer
[i
] == prefer
[j
] && weight
[i
] > weight
[j
]))
if (seenlocal
&& prefer
[i
] >= localpref
)
* truncate higher pref part of list; if we're
* the best choice left, we should have realized
* awhile ago that this was a local delivery.
** MXRAND -- create a randomizer for equal MX preferences
** If two MX hosts have equal preferences we want to randomize
** the selection. But in order for signatures to be the same,
** we need to randomize the same way each time. This function
** computes a pseudo-random hash function from the host name.
** host -- the name of the host.
** A random but repeatable value based on the host name.
static unsigned int seed
;
seed
= (int) curtime() & 0xffff;
printf("mxrand(%s)", host
);
if (isascii(c
) && isupper(c
))
hfunc
= ((hfunc
<< 1) + c
) % 2003;
printf(" = %d\n", hfunc
);
** GETCANONNAME -- get the canonical name for named host
** This algorithm tries to be smart about wildcard MX records.
** This is hard to do because DNS doesn't tell is if we matched
** against a wildcard or a specific MX.
** We always prefer A & CNAME records, since these are presumed
** If we match an MX in one pass and lose it in the next, we use
** the old one. For example, consider an MX matching *.FOO.BAR.COM.
** A hostname bletch.foo.bar.com will match against this MX, but
** will stop matching when we try bletch.bar.com -- so we know
** that bletch.foo.bar.com must have been right. This fails if
** there was also an MX record matching *.BAR.COM, but there are
** some things that just can't be fixed.
** host -- a buffer containing the name of the host.
** This is a value-result parameter.
** hbsize -- the size of the host buffer.
** TRUE -- if the host matched.
getcanonname(host
, hbsize
)
register u_char
*eom
, *ap
;
int first
, ancount
, qdcount
;
char *searchlist
[MAXDNSRCH
+1];
printf("getcanonname(%s)\n", host
);
if ((_res
.options
& RES_INIT
) == 0 && res_init() == -1)
for (cp
= host
, n
= 0; *cp
; cp
++)
** Initialize domain search list. If there is at least one
** dot in the name, search the unmodified name first so we
** find "vse.CS" in Czechoslovakia instead of in the local
** domain (e.g., vse.CS.Berkeley.EDU).
** Older versions of the resolver could create this
** list by tearing apart the host name.
if (n
== 0 || n
> 0 && *--cp
!= '.')
for (domain
= _res
.dnsrch
; *domain
!= NULL
; )
** Now run through the search list for the name in question.
for (dp
= searchlist
; *dp
!= NULL
; dp
++)
(void) sprintf(nbuf
, "%.*s%s%.*s", MAXDNAME
, host
,
printf("getcanonname: trying %s\n", nbuf
);
ret
= res_query(nbuf
, C_IN
, T_ANY
, &answer
, sizeof(answer
));
printf("\tNO: h_errno=%d\n", h_errno
);
if (errno
== ECONNREFUSED
)
/* the name server seems to be down */
/* we matched before -- use that one */
** This might be a bogus match. Search for A or
** CNAME records. If we don't have a matching
** wild card MX record, we will accept MX as well.
ap
= (u_char
*) &answer
+ sizeof(HEADER
);
eom
= (u_char
*) &answer
+ ret
;
/* skip question part of response -- we know what we asked */
for (qdcount
= ntohs(hp
->qdcount
); qdcount
--; ap
+= ret
+ QFIXEDSZ
)
if ((ret
= dn_skipname(ap
, eom
)) < 0)
printf("qdcount failure (%d)\n",
return FALSE
; /* ???XXX??? */
for (ancount
= ntohs(hp
->ancount
); --ancount
>= 0 && ap
< eom
; ap
+= n
)
n
= dn_expand((u_char
*) &answer
, eom
, ap
,
(u_char
*) nbuf
, sizeof nbuf
);
ap
+= sizeof(u_short
) + sizeof(u_long
);
/* got a match -- save that info */
/* exact MX matches are as good as an A match */
/* continue in case a CNAME also exists */
/* value points at name */
if ((ret
= dn_expand((u_char
*)&answer
,
eom
, ap
, (u_char
*)nbuf
, sizeof(nbuf
))) < 0)
(void)strncpy(host
, nbuf
, hbsize
); /* XXX */
/* not a record of interest */
/* got an A record and no CNAME */
/* create matching name and return */
(void) sprintf(nbuf
, "%.*s%s%.*s", MAXDNAME
, host
,
*mxmatch
== '\0' ? "" : ".",
strncpy(host
, nbuf
, hbsize
);
#else /* not NAMED_BIND */
getcanonname(host
, hbsize
)
hp
= gethostbyname(host
);
if (strlen(hp
->h_name
) >= hbsize
)
(void) strcpy(host
, hp
->h_name
);
#endif /* not NAMED_BIND */