* Copyright (c) 1989 Jan-Simon Pendry
* Copyright (c) 1989 Imperial College of Science, Technology & Medicine
* Copyright (c) 1989 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Jan-Simon Pendry at Imperial College, London.
* %sccs.include.redist.c%
* @(#)info_hes.c 5.4 (Berkeley) %G%
* $Id: info_hes.c,v 5.2.2.1 1992/02/09 15:08:29 jsp beta $
* Zone transfer code from Bruce Cole <cole@cs.wisc.edu>
#define HES_PREFIX "hesiod."
#include <arpa/nameser.h>
* Patch up broken system include files
static struct timeval hs_timeout
;
#endif /* HAS_HESIOD_RELOAD */
* No easy way to probe the server - check the map name begins with "hesiod."
int hesiod_init
P((char *map
, time_t *tp
));
dlog("hesiod_init(%s)", map
);
return strncmp(map
, HES_PREFIX
, HES_PREFLEN
) == 0 ? 0 : ENOENT
;
* Make Hesiod name. Skip past the "hesiod."
* at the start of the map name and append
* ".automount". The net effect is that a lookup
* of /defaults in hesiod.home will result in a
* call to hes_resolve("/defaults", "home.automount");
#define MAKE_HES_NAME(dest, src) sprintf(dest, "%s%s", src + HES_PREFLEN, ".automount")
* Do a Hesiod nameserver call.
* Modify time is ignored by Hesiod - XXX
int hesiod_search
P((mnt_map
*m
, char *map
, char **pval
, time_t *tp
));
int hesiod_search(m
, map
, key
, pval
, tp
)
char hes_key
[MAXPATHLEN
];
dlog("hesiod_search(m=%x, map=%s, key=%s, pval=%x tp=%x)", m
, map
, key
, pval
, tp
);
/*MAKE_HES_NAME(hes_map, map);*/
sprintf(hes_key
, "%s.%s", key
, map
+HES_PREFLEN
);
dlog("hesiod_search: hes_resolve(%s, %s)", hes_key
, "automount");
if (debug_flags
& D_FULL
)
_res
.options
|= RES_DEBUG
;
rvec
= hes_resolve(hes_key
, "automount");
* If a reply was forthcoming then return
* it (and free subsequent replies)
* Otherwise reflect the hesiod error into a Un*x error
dlog("hesiod_search: Error: %d", hes_error());
case HES_ER_NOTFOUND
: error
= ENOENT
; break;
case HES_ER_CONFIG
: error
= EIO
; break;
case HES_ER_NET
: error
= ETIMEDOUT
; break;
default: error
= EINVAL
; break;
dlog("hesiod_search: Returning: %d", error
);
static char nsaddr_list
[MAX_NSADDR
][sizeof(struct in_addr
)];
int hesiod_reload
P((mnt_map
*m
, char *map
, void (*fn
)()));
int hesiod_reload(m
, map
, fn
)
dlog("hesiod_reload (%x %s %x)", m
, map
, fn
);
if (status
= res_init()) {
dlog("hesiod_reload: res_init failed with %d", status
);
domainlen
= strlen(hostdomain
);
zone_name
= hes_to_bind(map
+HES_PREFLEN
, "automount");
/* Traverse the DNS tree until we find an SOA we can transfer from.
(Our initial zone_name is likely to just be a subtree of a
/* If we can't find any NS records, go up a level in the
if (hs_get_ns_list(zone_name
) == 0 &&
hs_zone_transfer(zone_name
) == 0)
/* Move up DNS tree by one component */
if (cp
= strchr(zone_name
, '.'))
} while (strlen(zone_name
) >= domainlen
);
dlog("hesiod_reload: Giving up on %s", hs_domain
);
/* Want to make sure ansbuf is well alligned */
long ansbuf
[PACKETSZ
/sizeof(long)];
dlog("hs_zone_transfer (%s)", domain
);
if ((len
= res_mkquery(QUERY
, domain
, C_HS
, T_AXFR
,
(char *)NULL
, 0, NULL
, buf
, PACKETSZ
)) == -1) {
dlog("hs_zone_transfer: res_mkquery failed");
if ((status
= hs_res_send(buf
, len
, (char *)ansbuf
, PACKETSZ
)) == -1) {
dlog("hs_zone_transfer: hs_res_send failed. status %d errno %d",
#define hs_server_addr(ns) ((struct in_addr *) nsaddr_list[ns])
hs_res_send(buf
, buflen
, answer
, anslen
)
HEADER
*hp
= (HEADER
*) buf
;
struct sockaddr_in server
;
* Send request, RETRY times, or until successful
for (retry
= _res
.retry
; retry
> 0; retry
--) {
for (ns
= 0; ns
< hs_nscount
; ns
++) {
(_res
.retrans
<< (_res
.retry
- retry
))
if (hs_timeout
.tv_sec
<= 0)
s
= socket(AF_INET
, SOCK_STREAM
, 0);
bcopy(hs_server_addr(ns
), &server
.sin_addr
,
server
.sin_family
= AF_INET
;
server
.sin_port
= htons(NAMESERVER_PORT
);
sizeof(struct sockaddr
)) < 0) {
len
= htons((u_short
)buflen
);
iov
[0].iov_base
= (caddr_t
)&len
;
iov
[0].iov_len
= sizeof(len
);
if (writev(s
, iov
, 2) != sizeof(len
) + buflen
) {
while (s
!= -1 && soacnt
< 2 && status
!= -2) {
hs_readresp(s
, answer
, anslen
)) == -1) {
/* There was a permanent error transfering this
hs_readresp(s
, answer
, anslen
)
(n
= hs_res_vcread(s
, (char *)cp
, (int)len
, &hs_timeout
)) > 0) {
if ((len
= _getshort(cp
)) > anslen
) {
dlog("hs_readresp: response too long: %d", len
);
(n
= hs_res_vcread(s
, (char *)cp
, (int)len
, &hs_timeout
)) > 0) {
return(hs_parse(answer
, answer
+PACKETSZ
));
hs_res_vcread(sock
, buf
, buflen
, timeout
)
if ((n
= hs_res_selwait(sock
, timeout
)) > 0)
return(read(sock
, buf
, buflen
));
hs_res_selwait(sock
, timeout
)
n
= select(sock
+1, &dsmask
, (fd_set
*)NULL
,
(fd_set
*)NULL
, timeout
);
char *key_cpy
, *value
, *hs_make_value();
if (hp
->rcode
!= NOERROR
|| hp
->opcode
!= QUERY
) {
dlog("Bad response (%d) from nameserver %s", hp
->rcode
, inet_dquad(dq
, hs_server_addr(servernum
)->s_addr
));
cp
= msg
+ sizeof(HEADER
);
ancount
= ntohs(hp
->ancount
);
qdcount
= ntohs(hp
->qdcount
);
cp
+= dn_skipname(cp
, eom
) + QFIXEDSZ
;
if (soacnt
== 0 && ancount
== 0) {
/* XXX We should look for NS records to find SOA */
while (ancount
-- > 0 && cp
< eom
) {
if ((n
= dn_expand(msg
, eom
, cp
, key
, PACKETSZ
)) < 0)
if ((type
= _getshort(cp
)) == T_SOA
) {
cp
+= 2*sizeof(u_short
) + sizeof(u_long
);
/* Check to see if key is in our domain */
if (type
== T_TXT
&& hs_strip_our_domain(key
)) {
value
= hs_make_value(cp
, len
);
dlog("hs_parse: Parsed key: %s, value: %s", key
,
mapc_add_kv(hs_map
, key_cpy
, value
);
/* Check to see if the domain name in the supplied argument matches
hs_domain. Strip hs_domain from supplied argument if so. */
hs_strip_our_domain(name
)
targ_len
= strlen(hs_domain
);
end_pos
= &name
[cur_len
- targ_len
];
if (strcmp(end_pos
, hs_domain
) != 0)
char *value
, *cpcpy
, *valuep
;
int cnt
, nextcnt
, totalcnt
, lencpy
;
if (totalcnt
< 1 || totalcnt
> MAXDATA
|| totalcnt
> len
) {
dlog("TXT RR not of expected length (%d %d): %s", totalcnt
,
/* Allocate null terminated string */
value
= (char *) xmalloc(totalcnt
+1);
hs_make_ns_query(domain
, ansbuf
)
if ((len
= res_mkquery(QUERY
, domain
, C_HS
, T_NS
,
(char *)NULL
, 0, NULL
, buf
, PACKETSZ
)) == -1) {
dlog("hs_get_ns_list: res_mkquery failed");
if ((status
= res_send(buf
, len
, (char *)ansbuf
, PACKETSZ
)) == -1) {
dlog("hs_get_ns_list: res_send failed. status %d errno %d",
bcopy((char *)addr
, nsaddr_list
[hs_nscount
++], sizeof(struct in_addr
));
dlog("Adding NS address %s", inet_dquad(dq
, addr
->s_addr
));
char key
[PACKETSZ
], name
[PACKETSZ
], msg
[PACKETSZ
], *eom
;
char nsname
[MAXHSNS
][MAXDATA
];
int nshaveaddr
[MAXHSNS
], i
;
if (hs_make_ns_query(domain
, msg
) == -1)
bzero(nsname
, sizeof(nsname
));
if (hp
->rcode
!= NOERROR
|| hp
->opcode
!= QUERY
) {
dlog("Bad response (%d) from nameserver %#x", hp
->rcode
,
hs_server_addr(servernum
)->s_addr
);
cp
= msg
+ sizeof(HEADER
);
qdcount
= ntohs(hp
->qdcount
);
cp
+= dn_skipname(cp
, eom
) + QFIXEDSZ
;
nscount
= ntohs(hp
->ancount
) + ntohs(hp
->nscount
) + ntohs(hp
->arcount
);
dlog("hs_get_ns_list: Processing %d response records", nscount
);
for (;nscount
; nscount
--) {
if ((n
= dn_expand(msg
, eom
, cp
, key
, PACKETSZ
)) < 0)
cp
+= 2*sizeof(u_short
) + sizeof(u_long
);
dlog("hs_get_ns_list: Record type: %d", type
);
if (numns
>= MAXHSNS
|| strcasecmp(domain
, key
) != 0)
if ((n
= dn_expand(msg
, eom
, cp
, name
, PACKETSZ
)) < 0)
dlog("hs_get_ns_list: NS name: %s", name
);
for (i
= 0; i
< numns
; i
++)
if (strcasecmp(nsname
[i
], name
) == 0)
dlog("hs_get_ns_list: Saving name %s", name
);
strncpy(nsname
[numns
], name
, MAXDATA
);
if (hs_nscount
== MAX_NSADDR
)
for (i
= 0; i
< numns
; i
++) {
if (strcasecmp(nsname
[i
], domain
) == 0) {
add_address((struct in_addr
*) cp
);
if (hs_nscount
== MAX_NSADDR
)
dlog("hs_get_ns_list: Found %d NS records", numns
);
for (i
= 0; i
< numns
; i
++) {
if ((ghp
= gethostbyname(nsname
[i
])) == 0)
for (hptr
= (long **)ghp
->h_addr_list
;
*hptr
&& hs_nscount
< MAX_NSADDR
; hptr
++) {
add_address((struct in_addr
*) *hptr
);
dlog("No NS records found for %s", domain
);
#endif /* HAS_HESIOD_RELOAD */
#endif /* HAS_HESIOD_MAPS */