* Copyright (c) 1986 Eric P. Allman
* Copyright (c) 1988 Regents of the University of California.
* %sccs.include.redist.c%
static char sccsid
[] = "@(#)domain.c 5.37 (Berkeley) %G% (with name server)";
static char sccsid
[] = "@(#)domain.c 5.37 (Berkeley) %G% (without name server)";
#include <arpa/nameser.h>
static char hostbuf
[MAXMXHOSTS
*PACKETSZ
];
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, 1) || _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
)
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
] && (rand() & 0100) == 0)) {
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.
** GETCANONNAME -- get the canonical name for named host
** 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.
** Use query type of ANY if possible (NoWildcardMX), which
** will find types CNAME, A, and MX, and will cause all
** existing records to be cached by our local server. If
** there is (might be) a wildcard MX record in the local
** domain or its parents that are searched, we can't use
** ANY; it would cause fully-qualified names to match as
** names in a local domain.
getcanonname(host
, hbsize
)
register u_char
*eom
, *ap
;
int first
, ancount
, qdcount
, loopcnt
;
int qtype
= NoWildcardMX
? T_ANY
: T_CNAME
;
printf("getcanonname(%s)\n", host
);
if ((_res
.options
& RES_INIT
) == 0 && res_init() == -1)
for (cp
= host
, n
= 0; *cp
; cp
++)
if (n
> 0 && *--cp
== '.')
** If there is at least one dot, start by searching the
** unmodified name. This lets us get "vse.CS" in Czechoslovakia
** instead of CS.Berkeley.EDU.
** Try the unmodified name.
printf("getcanonname: trying %s\n", host
);
ret
= res_query(host
, C_IN
, qtype
, &answer
, sizeof(answer
));
printf("\tNO: h_errno=%d\n", h_errno
);
if (errno
== ECONNREFUSED
)
/* no server -- try again later */
** We do at least one level of search if
** - there is no dot and RES_DEFNAME is set, or
** - there is at least one dot, there is no trailing dot,
** and RES_DNSRCH is set.
((n
== 0 && _res
.options
& RES_DEFNAMES
) ||
(n
> 0 && *--cp
!= '.' && _res
.options
& RES_DNSRCH
)))
for (domain
= _res
.dnsrch
; *domain
; domain
++)
(void) sprintf(nbuf
, "%.*s.%.*s",
MAXDNAME
, host
, MAXDNAME
, *domain
);
printf("getcanonname: trying %s\n", nbuf
);
ret
= res_query(nbuf
, C_IN
, qtype
, &answer
, sizeof(answer
));
printf("\tNO: h_errno=%d\n", h_errno
);
* If no server present, give up.
* If name isn't found in this domain,
* keep trying higher domains in the search list
* On a NO_DATA error, keep trying, otherwise
* a wildcard entry of another type could keep us
* from finding this entry higher in the domain.
* If we get some other error (negative answer or
* server failure), then stop searching up,
* but try the input name below in case it's
if (errno
== ECONNREFUSED
)
if ((h_errno
!= HOST_NOT_FOUND
) ||
(_res
.options
& RES_DNSRCH
) == 0)
** Try the unmodified name.
printf("getcanonname: trying %s\n", cp
);
ret
= res_query(cp
, C_IN
, qtype
, &answer
, sizeof(answer
));
printf("\tNO: h_errno=%d\n", h_errno
);
if (ret
<= 0 && h_errno
!= NO_DATA
)
/* find first satisfactory answer */
ancount
= ntohs(hp
->ancount
);
printf("rcode = %d, ancount=%d, qdcount=%d\n",
hp
->rcode
, ancount
, ntohs(hp
->qdcount
));
/* we don't care about errors here, only if we got an answer */
strncpy(host
, cp
, hbsize
);
ap
= (u_char
*)&answer
+ sizeof(HEADER
);
eom
= (u_char
*)&answer
+ ret
;
for (qdcount
= ntohs(hp
->qdcount
); qdcount
--; ap
+= ret
+ QFIXEDSZ
)
if ((ret
= dn_skipname(ap
, eom
)) < 0)
printf("qdcount failure (%d)\n",
return FALSE
; /* ???XXX??? */
* just in case someone puts a CNAME record after another record,
* check all records for CNAME; otherwise, just take the first
for (first
= 1; --ancount
>= 0 && ap
< eom
; ap
+= ret
)
if ((ret
= dn_expand((u_char
*)&answer
,
eom
, ap
, (u_char
*)nbuf
, sizeof(nbuf
))) < 0)
(void)strncpy(host
, nbuf
, hbsize
);
ap
+= sizeof(u_short
) + sizeof(u_long
);
* assume that only one cname will be found. More
* than one is undefined. Copy so that if dn_expand
* fails, `host' is still okay.
if ((ret
= dn_expand((u_char
*)&answer
,
eom
, ap
, (u_char
*)nbuf
, sizeof(nbuf
))) < 0)
(void)strncpy(host
, nbuf
, hbsize
); /* XXX */
if (++loopcnt
> 8) /* never be more than 1 */
return rval
; /* ???XXX??? */
#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 */