diff options
author | peter <peter@FreeBSD.org> | 1999-11-30 02:43:11 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 1999-11-30 02:43:11 +0000 |
commit | 4ef23ce6957fc75fc005885496d605fed48213e1 (patch) | |
tree | 7828b08c74ef918938b1b853c98f0cb41edac52c /contrib/bind/lib/resolv | |
parent | 67e0f3ce71726dc4058c2f80a813341a59244dbd (diff) | |
download | FreeBSD-src-4ef23ce6957fc75fc005885496d605fed48213e1.zip FreeBSD-src-4ef23ce6957fc75fc005885496d605fed48213e1.tar.gz |
Import bind v8.2.2.p5, minus the crypto for the time being. The bind
package does have BXA export approval, but the licensing strings on the
dnssafe code are a bit unpleasant. The crypto is easy to restore and bind
will run without it - just without full dnssec support.
Obtained from: The Internet Software Consortium (www.isc.org)
Diffstat (limited to 'contrib/bind/lib/resolv')
-rw-r--r-- | contrib/bind/lib/resolv/Makefile | 36 | ||||
-rw-r--r-- | contrib/bind/lib/resolv/herror.c | 37 | ||||
-rw-r--r-- | contrib/bind/lib/resolv/res_comp.c | 8 | ||||
-rw-r--r-- | contrib/bind/lib/resolv/res_data.c | 251 | ||||
-rw-r--r-- | contrib/bind/lib/resolv/res_debug.c | 213 | ||||
-rw-r--r-- | contrib/bind/lib/resolv/res_debug.h | 34 | ||||
-rw-r--r-- | contrib/bind/lib/resolv/res_findzonecut.c | 596 | ||||
-rw-r--r-- | contrib/bind/lib/resolv/res_init.c | 200 | ||||
-rw-r--r-- | contrib/bind/lib/resolv/res_mkquery.c | 40 | ||||
-rw-r--r-- | contrib/bind/lib/resolv/res_mkupdate.c | 721 | ||||
-rw-r--r-- | contrib/bind/lib/resolv/res_mkupdate.h | 17 | ||||
-rw-r--r-- | contrib/bind/lib/resolv/res_query.c | 180 | ||||
-rw-r--r-- | contrib/bind/lib/resolv/res_send.c | 479 | ||||
-rw-r--r-- | contrib/bind/lib/resolv/res_sendsigned.c | 130 | ||||
-rw-r--r-- | contrib/bind/lib/resolv/res_update.c | 589 |
15 files changed, 2525 insertions, 1006 deletions
diff --git a/contrib/bind/lib/resolv/Makefile b/contrib/bind/lib/resolv/Makefile index 5be600d..243e69b 100644 --- a/contrib/bind/lib/resolv/Makefile +++ b/contrib/bind/lib/resolv/Makefile @@ -1,4 +1,4 @@ -# Copyright (c) 1996 by Internet Software Consortium +# Copyright (c) 1996,1999 by Internet Software Consortium # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above @@ -13,7 +13,7 @@ # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS # SOFTWARE. -# $Id: Makefile,v 8.17 1997/05/21 19:32:09 halley Exp $ +# $Id: Makefile,v 8.30 1999/10/07 08:24:15 vixie Exp $ # these are only appropriate for BSD 4.4 or derivatives, and are used in # development. normal builds will be done in the top level directory and @@ -31,35 +31,53 @@ TOP= ../.. INCL = ${TOP}/include PORTINCL = ${TOP}/port/${SYSTYPE}/include LIBBIND = ${TOP}/lib/libbind.${A} +LIBBINDR = ../${TOP}/lib/libbind_r.${A} CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL} +# -D__BIND_NOSTATIC LD_LIBFLAGS= -x -r -AR= ar cruv +AR= ar cru RANLIB= ranlib INSTALL= install +INSTALL_EXEC= +INSTALL_LIB=-o bin -g bin +THREADED= threaded SRCS= herror.c res_debug.c res_data.c res_comp.c res_init.c \ - res_mkquery.c res_query.c res_send.c res_mkupdate.c \ - res_update.c + res_mkquery.c res_query.c res_send.c res_sendsigned.c \ + res_mkupdate.c res_update.c \ + res_findzonecut.c OBJS= herror.${O} res_debug.${O} res_data.${O} res_comp.${O} res_init.${O} \ - res_mkquery.${O} res_query.${O} res_send.${O} res_mkupdate.${O} \ - res_update.${O} + res_mkquery.${O} res_query.${O} res_send.${O} res_sendsigned.${O} \ + res_mkupdate.${O} res_update.${O} \ + res_findzonecut.${O} all: ${LIBBIND} ${LIBBIND}: ${OBJS} + ( cd ${THREADED} ; \ + ${AR} ${LIBBINDR} ${ARPREF} ${OBJS} ${ARSUFF} ; \ + ${RANLIB} ${LIBBINDR} ) ${AR} ${LIBBIND} ${ARPREF} ${OBJS} ${ARSUFF} ${RANLIB} ${LIBBIND} .c.${O}: - ${CC} ${CPPFLAGS} ${CFLAGS} -c $*.c - -${LDS} ${LD} ${LD_LIBFLAGS} $*.${O} && ${LDS} mv a.out $*.${O} + if test ! -d ${THREADED} ; then mkdir ${THREADED} ; fi + ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} ${REENTRANT} -c $*.c \ + -o ${THREADED}/$*.${O} + -${LDS} ${LD} ${LD_LIBFLAGS} ${THREADED}/$*.${O} -o a.out && \ + ${LDS} mv a.out ${THREADED}/$*.${O} + ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} -c $*.c + -${LDS} ${LD} ${LD_LIBFLAGS} $*.${O} -o a.out && \ + ${LDS} mv a.out $*.${O} distclean: clean clean: FRC rm -f .depend a.out core ${LIB} tags rm -f *.${O} *.BAK *.CKP *~ + rm -f ${THREADED}/*.${O} + -rmdir ${THREADED} depend: FRC mkdep -I${INCL} -I${PORTINCL} ${CPPFLAGS} ${SRCS} diff --git a/contrib/bind/lib/resolv/herror.c b/contrib/bind/lib/resolv/herror.c index 38217db..bf4cce6 100644 --- a/contrib/bind/lib/resolv/herror.c +++ b/contrib/bind/lib/resolv/herror.c @@ -32,7 +32,7 @@ */ /* - * Portions Copyright (c) 1996 by Internet Software Consortium. + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -49,18 +49,27 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)herror.c 8.1 (Berkeley) 6/4/93"; -static char rcsid[] = "$Id: herror.c,v 8.7 1996/11/18 09:10:00 vixie Exp $"; +static const char sccsid[] = "@(#)herror.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "$Id: herror.c,v 8.11 1999/10/13 16:39:39 vixie Exp $"; #endif /* LIBC_SCCS and not lint */ #include "port_before.h" + #include <sys/types.h> #include <sys/param.h> #include <sys/uio.h> + +#include <netinet/in.h> +#include <arpa/nameser.h> + #include <netdb.h> +#include <resolv.h> #include <string.h> #include <unistd.h> +#include <irs.h> + #include "port_after.h" +#undef h_errno const char *h_errlist[] = { "Resolver Error 0 (no error)", @@ -78,21 +87,19 @@ int h_errno; * print the error indicated by the h_errno value. */ void -herror(s) - const char *s; -{ - struct iovec iov[4]; - register struct iovec *v = iov; +herror(const char *s) { + struct iovec iov[4], *v = iov; + extern int * __h_errno(); - if (s && *s) { - v->iov_base = (char *)s; + if (s != NULL && *s != '\0') { + v->iov_base = (/*noconst*/ char *)s; v->iov_len = strlen(s); v++; v->iov_base = ": "; v->iov_len = 2; v++; } - v->iov_base = (char *)hstrerror(h_errno); + v->iov_base = (char *)hstrerror(*__h_errno()); v->iov_len = strlen(v->iov_base); v++; v->iov_base = "\n"; @@ -100,10 +107,12 @@ herror(s) writev(STDERR_FILENO, iov, (v - iov) + 1); } +/* + * hstrerror -- + * return the string associated with a given "host" errno value. + */ const char * -hstrerror(err) - int err; -{ +hstrerror(int err) { if (err < 0) return ("Resolver internal error"); else if (err < h_nerr) diff --git a/contrib/bind/lib/resolv/res_comp.c b/contrib/bind/lib/resolv/res_comp.c index c1f946e..d972848 100644 --- a/contrib/bind/lib/resolv/res_comp.c +++ b/contrib/bind/lib/resolv/res_comp.c @@ -52,7 +52,7 @@ */ /* - * Portions Copyright (c) 1996 by Internet Software Consortium. + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -69,8 +69,8 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)res_comp.c 8.1 (Berkeley) 6/4/93"; -static char rcsid[] = "$Id: res_comp.c,v 8.11 1997/05/21 19:31:04 halley Exp $"; +static const char sccsid[] = "@(#)res_comp.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "$Id: res_comp.c,v 8.15 1999/10/13 16:39:39 vixie Exp $"; #endif /* LIBC_SCCS and not lint */ #include "port_before.h" @@ -244,6 +244,8 @@ res_dnok(const char *dn) { */ void __putlong(u_int32_t src, u_char *dst) { ns_put32(src, dst); } void __putshort(u_int16_t src, u_char *dst) { ns_put16(src, dst); } +#ifndef __ultrix__ u_int32_t _getlong(const u_char *src) { return (ns_get32(src)); } u_int16_t _getshort(const u_char *src) { return (ns_get16(src)); } +#endif /*__ultrix__*/ #endif /*BIND_4_COMPAT*/ diff --git a/contrib/bind/lib/resolv/res_data.c b/contrib/bind/lib/resolv/res_data.c index ca06d64..7688637 100644 --- a/contrib/bind/lib/resolv/res_data.c +++ b/contrib/bind/lib/resolv/res_data.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995,1996 by Internet Software Consortium. + * Copyright (c) 1995-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -16,24 +16,31 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char rcsid[] = "$Id: res_data.c,v 8.5 1996/11/18 09:10:02 vixie Exp $"; +static const char rcsid[] = "$Id: res_data.c,v 8.17 1999/10/13 17:11:31 vixie Exp $"; #endif /* LIBC_SCCS and not lint */ #include "port_before.h" + #include <sys/types.h> #include <sys/param.h> #include <sys/socket.h> #include <sys/time.h> + #include <netinet/in.h> #include <arpa/inet.h> #include <arpa/nameser.h> + #include <ctype.h> +#include <netdb.h> #include <resolv.h> +#include <res_update.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> + #include "port_after.h" +#undef _res const char *_res_opcodes[] = { "QUERY", @@ -54,25 +61,6 @@ const char *_res_opcodes[] = { "ZONEREF", }; -const char *_res_resultcodes[] = { - "NOERROR", - "FORMERR", - "SERVFAIL", - "NXDOMAIN", - "NOTIMP", - "REFUSED", - "YXDOMAIN", - "YXRRSET", - "NXRRSET", - "NOTAUTH", - "ZONEERR", - "11", - "12", - "13", - "14", - "NOCHANGE", -}; - #ifdef BIND_UPDATE const char *_res_sectioncodes[] = { "ZONE", @@ -81,3 +69,224 @@ const char *_res_sectioncodes[] = { "ADDITIONAL", }; #endif + +#ifndef __BIND_NOSTATIC +struct __res_state _res +# if defined(__BIND_RES_TEXT) + = { RES_TIMEOUT, } /* Motorola, et al. */ +# endif + ; + +/* Proto. */ + +int res_ourserver_p(const res_state, const struct sockaddr_in *); +void res_pquery(const res_state, const u_char *, int, FILE *); + +int +res_init(void) { + extern int __res_vinit(res_state, int); + + /* + * These three fields used to be statically initialized. This made + * it hard to use this code in a shared library. It is necessary, + * now that we're doing dynamic initialization here, that we preserve + * the old semantics: if an application modifies one of these three + * fields of _res before res_init() is called, res_init() will not + * alter them. Of course, if an application is setting them to + * _zero_ before calling res_init(), hoping to override what used + * to be the static default, we can't detect it and unexpected results + * will follow. Zero for any of these fields would make no sense, + * so one can safely assume that the applications were already getting + * unexpected results. + * + * _res.options is tricky since some apps were known to diddle the bits + * before res_init() was first called. We can't replicate that semantic + * with dynamic initialization (they may have turned bits off that are + * set in RES_DEFAULT). Our solution is to declare such applications + * "broken". They could fool us by setting RES_INIT but none do (yet). + */ + if (!_res.retrans) + _res.retrans = RES_TIMEOUT; + if (!_res.retry) + _res.retry = 4; + if (!(_res.options & RES_INIT)) + _res.options = RES_DEFAULT; + + /* + * This one used to initialize implicitly to zero, so unless the app + * has set it to something in particular, we can randomize it now. + */ + if (!_res.id) + _res.id = res_randomid(); + + return (__res_vinit(&_res, 1)); +} + +void +p_query(const u_char *msg) { + fp_query(msg, stdout); +} + +void +fp_query(const u_char *msg, FILE *file) { + fp_nquery(msg, PACKETSZ, file); +} + +void +fp_nquery(const u_char *msg, int len, FILE *file) { + if ((_res.options & RES_INIT) == 0 && res_init() == -1) + return; + + res_pquery(&_res, msg, len, file); +} + +int +res_mkquery(int op, /* opcode of query */ + const char *dname, /* domain name */ + int class, int type, /* class and type of query */ + const u_char *data, /* resource record data */ + int datalen, /* length of data */ + const u_char *newrr_in, /* new rr for modify or append */ + u_char *buf, /* buffer to put query */ + int buflen) /* size of buffer */ +{ + if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + RES_SET_H_ERRNO(&_res, NETDB_INTERNAL); + return (-1); + } + return (res_nmkquery(&_res, op, dname, class, type, + data, datalen, + newrr_in, buf, buflen)); +} + +int +res_mkupdate(ns_updrec *rrecp_in, u_char *buf, int buflen) { + if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + RES_SET_H_ERRNO(&_res, NETDB_INTERNAL); + return (-1); + } + + return (res_nmkupdate(&_res, rrecp_in, buf, buflen)); +} + +int +res_query(const char *name, /* domain name */ + int class, int type, /* class and type of query */ + u_char *answer, /* buffer to put answer */ + int anslen) /* size of answer buffer */ +{ + if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + RES_SET_H_ERRNO(&_res, NETDB_INTERNAL); + return (-1); + } + return (res_nquery(&_res, name, class, type, answer, anslen)); +} + +void +res_send_setqhook(res_send_qhook hook) { + _res.qhook = hook; +} + +void +res_send_setrhook(res_send_rhook hook) { + _res.rhook = hook; +} + +int +res_isourserver(const struct sockaddr_in *inp) { + return (res_ourserver_p(&_res, inp)); +} + +int +res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { + if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + /* errno should have been set by res_init() in this case. */ + return (-1); + } + + return (res_nsend(&_res, buf, buflen, ans, anssiz)); +} + +int +res_sendsigned(const u_char *buf, int buflen, ns_tsig_key *key, + u_char *ans, int anssiz) +{ + if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + /* errno should have been set by res_init() in this case. */ + return (-1); + } + + return (res_nsendsigned(&_res, buf, buflen, key, ans, anssiz)); +} + +void +res_close(void) { + res_nclose(&_res); +} + +int +res_update(ns_updrec *rrecp_in) { + if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + RES_SET_H_ERRNO(&_res, NETDB_INTERNAL); + return (-1); + } + + return (res_nupdate(&_res, rrecp_in, NULL)); +} + +int +res_search(const char *name, /* domain name */ + int class, int type, /* class and type of query */ + u_char *answer, /* buffer to put answer */ + int anslen) /* size of answer */ +{ + if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + RES_SET_H_ERRNO(&_res, NETDB_INTERNAL); + return (-1); + } + + return (res_nsearch(&_res, name, class, type, answer, anslen)); +} + +int +res_querydomain(const char *name, + const char *domain, + int class, int type, /* class and type of query */ + u_char *answer, /* buffer to put answer */ + int anslen) /* size of answer */ +{ + if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + RES_SET_H_ERRNO(&_res, NETDB_INTERNAL); + return (-1); + } + + return (res_nquerydomain(&_res, name, domain, + class, type, + answer, anslen)); +} + +const char * +hostalias(const char *name) { + static char abuf[MAXDNAME]; + + return (res_hostalias(&_res, name, abuf, sizeof abuf)); +} + +#ifdef ultrix +int +local_hostname_length(const char *hostname) { + int len_host, len_domain; + + if (!*_res.defdname) + res_init(); + len_host = strlen(hostname); + len_domain = strlen(_res.defdname); + if (len_host > len_domain && + !strcasecmp(hostname + len_host - len_domain, _res.defdname) && + hostname[len_host - len_domain - 1] == '.') + return (len_host - len_domain - 1); + return (0); +} +#endif /*ultrix*/ + +#endif diff --git a/contrib/bind/lib/resolv/res_debug.c b/contrib/bind/lib/resolv/res_debug.c index 80d1477..39f5e9f 100644 --- a/contrib/bind/lib/resolv/res_debug.c +++ b/contrib/bind/lib/resolv/res_debug.c @@ -77,7 +77,7 @@ */ /* - * Portions Copyright (c) 1996 by Internet Software Consortium. + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -94,8 +94,8 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)res_debug.c 8.1 (Berkeley) 6/4/93"; -static char rcsid[] = "$Id: res_debug.c,v 8.20 1998/02/13 01:11:34 halley Exp $"; +static const char sccsid[] = "@(#)res_debug.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "$Id: res_debug.c,v 8.32 1999/10/13 16:39:39 vixie Exp $"; #endif /* LIBC_SCCS and not lint */ #include "port_before.h" @@ -127,19 +127,16 @@ static char rcsid[] = "$Id: res_debug.c,v 8.20 1998/02/13 01:11:34 halley Exp $" #endif extern const char *_res_opcodes[]; -extern const char *_res_resultcodes[]; extern const char *_res_sectioncodes[]; /* * Print the current options. */ void -fp_resstat(struct __res_state *statp, FILE *file) { +fp_resstat(const res_state statp, FILE *file) { u_long mask; fprintf(file, ";; res options:"); - if (!statp) - statp = &_res; for (mask = 1; mask != 0; mask <<= 1) if (statp->options & mask) fprintf(file, " %s", p_option(mask)); @@ -147,7 +144,10 @@ fp_resstat(struct __res_state *statp, FILE *file) { } static void -do_section(ns_msg *handle, ns_sect section, int pflag, FILE *file) { +do_section(const res_state statp, + ns_msg *handle, ns_sect section, + int pflag, FILE *file) +{ int n, sflag, rrnum; char buf[2048]; /* XXX need to malloc */ ns_opcode opcode; @@ -156,11 +156,11 @@ do_section(ns_msg *handle, ns_sect section, int pflag, FILE *file) { /* * Print answer records. */ - sflag = (_res.pfcode & pflag); - if (_res.pfcode && !sflag) + sflag = (statp->pfcode & pflag); + if (statp->pfcode && !sflag) return; - opcode = ns_msg_getflag(*handle, ns_f_opcode); + opcode = (ns_opcode) ns_msg_getflag(*handle, ns_f_opcode); rrnum = 0; for (;;) { if (ns_parserr(handle, section, rrnum, &rr)) { @@ -168,11 +168,11 @@ do_section(ns_msg *handle, ns_sect section, int pflag, FILE *file) { fprintf(file, ";; ns_parserr: %s\n", strerror(errno)); else if (rrnum > 0 && sflag != 0 && - (_res.pfcode & RES_PRF_HEAD1)) + (statp->pfcode & RES_PRF_HEAD1)) putc('\n', file); return; } - if (rrnum == 0 && sflag != 0 && (_res.pfcode & RES_PRF_HEAD1)) + if (rrnum == 0 && sflag != 0 && (statp->pfcode & RES_PRF_HEAD1)) fprintf(file, ";; %s SECTION:\n", p_section(section, opcode)); if (section == ns_s_qd) @@ -195,29 +195,16 @@ do_section(ns_msg *handle, ns_sect section, int pflag, FILE *file) { } } -void -p_query(const u_char *msg) { - fp_query(msg, stdout); -} - -void -fp_query(const u_char *msg, FILE *file) { - fp_nquery(msg, PACKETSZ, file); -} - /* * Print the contents of a query. * This is intended to be primarily a debugging routine. */ void -fp_nquery(const u_char *msg, int len, FILE *file) { +res_pquery(const res_state statp, const u_char *msg, int len, FILE *file) { ns_msg handle; - int n, qdcount, ancount, nscount, arcount; + int qdcount, ancount, nscount, arcount; u_int opcode, rcode, id; - if ((_res.options & RES_INIT) == 0 && res_init() == -1) - return; - if (ns_initparse(msg, len, &handle) < 0) { fprintf(file, ";; ns_initparse: %s\n", strerror(errno)); return; @@ -233,13 +220,13 @@ fp_nquery(const u_char *msg, int len, FILE *file) { /* * Print header fields. */ - if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEADX) || rcode) + if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEADX) || rcode) fprintf(file, ";; ->>HEADER<<- opcode: %s, status: %s, id: %d\n", - _res_opcodes[opcode], _res_resultcodes[rcode], id); - if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEADX)) + _res_opcodes[opcode], p_rcode(rcode), id); + if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEADX)) putc(';', file); - if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEAD2)) { + if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEAD2)) { fprintf(file, "; flags:"); if (ns_msg_getflag(handle, ns_f_qr)) fprintf(file, " qr"); @@ -258,7 +245,7 @@ fp_nquery(const u_char *msg, int len, FILE *file) { if (ns_msg_getflag(handle, ns_f_cd)) fprintf(file, " cd"); } - if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEAD1)) { + if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEAD1)) { fprintf(file, "; %s: %d", p_section(ns_s_qd, opcode), qdcount); fprintf(file, ", %s: %d", @@ -268,17 +255,17 @@ fp_nquery(const u_char *msg, int len, FILE *file) { fprintf(file, ", %s: %d", p_section(ns_s_ar, opcode), arcount); } - if ((!_res.pfcode) || (_res.pfcode & + if ((!statp->pfcode) || (statp->pfcode & (RES_PRF_HEADX | RES_PRF_HEAD2 | RES_PRF_HEAD1))) { putc('\n',file); } /* * Print the various sections. */ - do_section(&handle, ns_s_qd, RES_PRF_QUES, file); - do_section(&handle, ns_s_an, RES_PRF_ANS, file); - do_section(&handle, ns_s_ns, RES_PRF_AUTH, file); - do_section(&handle, ns_s_ar, RES_PRF_ADD, file); + do_section(statp, &handle, ns_s_qd, RES_PRF_QUES, file); + do_section(statp, &handle, ns_s_an, RES_PRF_ANS, file); + do_section(statp, &handle, ns_s_ns, RES_PRF_AUTH, file); + do_section(statp, &handle, ns_s_ar, RES_PRF_ADD, file); if (qdcount == 0 && ancount == 0 && nscount == 0 && arcount == 0) putc('\n', file); @@ -375,55 +362,99 @@ const struct res_sym __p_update_section_syms[] = { {0, (char *)0} }; +const struct res_sym __p_key_syms[] = { + {NS_ALG_MD5RSA, "RSA", "RSA KEY with MD5 hash"}, + {NS_ALG_DH, "DH", "Diffie Hellman"}, + {NS_ALG_DSA, "DSA", "Digital Signature Algorithm"}, + {NS_ALG_EXPIRE_ONLY, "EXPIREONLY", "No algorithm"}, + {NS_ALG_PRIVATE_OID, "PRIVATE", "Algorithm obtained from OID"}, + {0, NULL, NULL} +}; + +const struct res_sym __p_cert_syms[] = { + {cert_t_pkix, "PKIX", "PKIX (X.509v3) Certificate"}, + {cert_t_spki, "SPKI", "SPKI certificate"}, + {cert_t_pgp, "PGP", "PGP certificate"}, + {cert_t_url, "URL", "URL Private"}, + {cert_t_oid, "OID", "OID Private"}, + {0, NULL, NULL} +}; + /* * Names of RR types and qtypes. Types and qtypes are the same, except * that T_ANY is a qtype but not a type. (You can ask for records of type * T_ANY, but you can't have any records of that type in the database.) */ const struct res_sym __p_type_syms[] = { - {T_A, "A", "address"}, - {T_NS, "NS", "name server"}, - {T_MD, "MD", "mail destination (deprecated)"}, - {T_MF, "MF", "mail forwarder (deprecated)"}, - {T_CNAME, "CNAME", "canonical name"}, - {T_SOA, "SOA", "start of authority"}, - {T_MB, "MB", "mailbox"}, - {T_MG, "MG", "mail group member"}, - {T_MR, "MR", "mail rename"}, - {T_NULL, "NULL", "null"}, - {T_WKS, "WKS", "well-known service (deprecated)"}, - {T_PTR, "PTR", "domain name pointer"}, - {T_HINFO, "HINFO", "host information"}, - {T_MINFO, "MINFO", "mailbox information"}, - {T_MX, "MX", "mail exchanger"}, - {T_TXT, "TXT", "text"}, - {T_RP, "RP", "responsible person"}, - {T_AFSDB, "AFSDB", "DCE or AFS server"}, - {T_X25, "X25", "X25 address"}, - {T_ISDN, "ISDN", "ISDN address"}, - {T_RT, "RT", "router"}, - {T_NSAP, "NSAP", "nsap address"}, - {T_NSAP_PTR, "NSAP_PTR", "domain name pointer"}, - {T_SIG, "SIG", "signature"}, - {T_KEY, "KEY", "key"}, - {T_PX, "PX", "mapping information"}, - {T_GPOS, "GPOS", "geographical position (withdrawn)"}, - {T_AAAA, "AAAA", "IPv6 address"}, - {T_LOC, "LOC", "location"}, - {T_NXT, "NXT", "next valid name (unimplemented)"}, - {T_EID, "EID", "endpoint identifier (unimplemented)"}, - {T_NIMLOC, "NIMLOC", "NIMROD locator (unimplemented)"}, - {T_SRV, "SRV", "server selection"}, - {T_ATMA, "ATMA", "ATM address (unimplemented)"}, - {T_IXFR, "IXFR", "incremental zone transfer"}, - {T_AXFR, "AXFR", "zone transfer"}, - {T_MAILB, "MAILB", "mailbox-related data (deprecated)"}, - {T_MAILA, "MAILA", "mail agent (deprecated)"}, - {T_NAPTR, "NAPTR", "URN Naming Authority"}, - {T_ANY, "ANY", "\"any\""}, + {ns_t_a, "A", "address"}, + {ns_t_ns, "NS", "name server"}, + {ns_t_md, "MD", "mail destination (deprecated)"}, + {ns_t_mf, "MF", "mail forwarder (deprecated)"}, + {ns_t_cname, "CNAME", "canonical name"}, + {ns_t_soa, "SOA", "start of authority"}, + {ns_t_mb, "MB", "mailbox"}, + {ns_t_mg, "MG", "mail group member"}, + {ns_t_mr, "MR", "mail rename"}, + {ns_t_null, "NULL", "null"}, + {ns_t_wks, "WKS", "well-known service (deprecated)"}, + {ns_t_ptr, "PTR", "domain name pointer"}, + {ns_t_hinfo, "HINFO", "host information"}, + {ns_t_minfo, "MINFO", "mailbox information"}, + {ns_t_mx, "MX", "mail exchanger"}, + {ns_t_txt, "TXT", "text"}, + {ns_t_rp, "RP", "responsible person"}, + {ns_t_afsdb, "AFSDB", "DCE or AFS server"}, + {ns_t_x25, "X25", "X25 address"}, + {ns_t_isdn, "ISDN", "ISDN address"}, + {ns_t_rt, "RT", "router"}, + {ns_t_nsap, "NSAP", "nsap address"}, + {ns_t_nsap_ptr, "NSAP_PTR", "domain name pointer"}, + {ns_t_sig, "SIG", "signature"}, + {ns_t_key, "KEY", "key"}, + {ns_t_px, "PX", "mapping information"}, + {ns_t_gpos, "GPOS", "geographical position (withdrawn)"}, + {ns_t_aaaa, "AAAA", "IPv6 address"}, + {ns_t_loc, "LOC", "location"}, + {ns_t_nxt, "NXT", "next valid name (unimplemented)"}, + {ns_t_eid, "EID", "endpoint identifier (unimplemented)"}, + {ns_t_nimloc, "NIMLOC", "NIMROD locator (unimplemented)"}, + {ns_t_srv, "SRV", "server selection"}, + {ns_t_atma, "ATMA", "ATM address (unimplemented)"}, + {ns_t_tsig, "TSIG", "transaction signature"}, + {ns_t_ixfr, "IXFR", "incremental zone transfer"}, + {ns_t_axfr, "AXFR", "zone transfer"}, + {ns_t_zxfr, "ZXFR", "compressed zone transfer"}, + {ns_t_mailb, "MAILB", "mailbox-related data (deprecated)"}, + {ns_t_maila, "MAILA", "mail agent (deprecated)"}, + {ns_t_naptr, "NAPTR", "URN Naming Authority"}, + {ns_t_kx, "KX", "Key Exchange"}, + {ns_t_cert, "CERT", "Certificate"}, + {ns_t_any, "ANY", "\"any\""}, {0, NULL, NULL} }; +/* + * Names of DNS rcodes. + */ +const struct res_sym __p_rcode_syms[] = { + {ns_r_noerror, "NOERROR", "no error"}, + {ns_r_formerr, "FORMERR", "format error"}, + {ns_r_servfail, "SERVFAIL", "server failed"}, + {ns_r_nxdomain, "NXDOMAIN", "no such domain name"}, + {ns_r_notimpl, "NOTIMP", "not implemented"}, + {ns_r_refused, "REFUSED", "refused"}, + {ns_r_yxdomain, "YXDOMAIN", "domain name exists"}, + {ns_r_yxrrset, "YXRRSET", "rrset exists"}, + {ns_r_nxrrset, "NXRRSET", "rrset doesn't exist"}, + {ns_r_notauth, "NOTAUTH", "not authoritative"}, + {ns_r_notzone, "NOTZONE", "Not in zone"}, + {ns_r_max, "", ""}, + {ns_r_badsig, "BADSIG", "bad signature"}, + {ns_r_badkey, "BADKEY", "bad key"}, + {ns_r_badtime, "BADTIME", "bad time"}, + {0, NULL, NULL} +}; + int sym_ston(const struct res_sym *syms, const char *name, int *success) { for ((void)NULL; syms->name != 0; syms++) { @@ -450,7 +481,7 @@ sym_ntos(const struct res_sym *syms, int number, int *success) { } } - sprintf(unname, "%d", number); + sprintf(unname, "%d", number); /* XXX nonreentrant */ if (success) *success = 0; return (unname); @@ -467,7 +498,7 @@ sym_ntop(const struct res_sym *syms, int number, int *success) { return (syms->humanname); } } - sprintf(unname, "%d", number); + sprintf(unname, "%d", number); /* XXX nonreentrant */ if (success) *success = 0; return (unname); @@ -527,6 +558,7 @@ p_option(u_long option) { case RES_DNSRCH: return "dnsrch"; case RES_INSECURE1: return "insecure1"; case RES_INSECURE2: return "insecure2"; + /* XXX nonreentrant */ default: sprintf(nbuf, "?0x%lx?", (u_long)option); return (nbuf); } @@ -537,13 +569,20 @@ p_option(u_long option) { */ const char * p_time(u_int32_t value) { - static char nbuf[40]; + static char nbuf[40]; /* XXX nonreentrant */ if (ns_format_ttl(value, nbuf, sizeof nbuf) < 0) sprintf(nbuf, "%u", value); return (nbuf); } +/* + * Return a string for the rcode. + */ +const char * +p_rcode(int rcode) { + return (sym_ntos(__p_rcode_syms, rcode, (int *)0)); +} /* * routines to convert between on-the-wire RR format and zone file format. @@ -559,7 +598,7 @@ static const char * precsize_ntoa(prec) u_int8_t prec; { - static char retbuf[sizeof "90000000.00"]; + static char retbuf[sizeof "90000000.00"]; /* XXX nonreentrant */ unsigned long val; int mantissa, exponent; @@ -831,6 +870,8 @@ loc_ntoa(binary, ascii) char *ascii; { static char *error = "?"; + static char tmpbuf[sizeof +"1000 60 60.000 N 1000 60 60.000 W -12345678.00m 90000000.00m 90000000.00m 90000000.00m"]; const u_char *cp = binary; int latdeg, latmin, latsec, latsecfrac; @@ -848,6 +889,9 @@ loc_ntoa(binary, ascii) versionval = *cp++; + if (ascii == NULL) + ascii = tmpbuf; + if (versionval) { (void) sprintf(ascii, "; error: unknown LOC RR version"); return (ascii); @@ -960,11 +1004,16 @@ dn_count_labels(const char *name) { */ char * p_secstodate (u_long secs) { + /* XXX nonreentrant */ static char output[15]; /* YYYYMMDDHHMMSS and null */ time_t clock = secs; struct tm *time; +#ifdef HAVE_TIME_R + gmtime_r(&clock, &time); +#else time = gmtime(&clock); +#endif time->tm_year += 1900; time->tm_mon += 1; sprintf(output, "%04d%02d%02d%02d%02d%02d", diff --git a/contrib/bind/lib/resolv/res_debug.h b/contrib/bind/lib/resolv/res_debug.h new file mode 100644 index 0000000..1150551 --- /dev/null +++ b/contrib/bind/lib/resolv/res_debug.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#ifndef _RES_DEBUG_H_ +#define _RES_DEBUG_H_ + +#ifndef DEBUG +# define Dprint(cond, args) /*empty*/ +# define DprintQ(cond, args, query, size) /*empty*/ +# define Aerror(file, string, error, address) /*empty*/ +# define Perror(file, string, error) /*empty*/ +#else +# define Dprint(cond, args) if (cond) {fprintf args;} else {} +# define DprintQ(cond, args, query, size) if (cond) {\ + fprintf args;\ + res_pquery(statp, query, size, stdout);\ + } else {} +#endif + +#endif /* _RES_DEBUG_H_ */ diff --git a/contrib/bind/lib/resolv/res_findzonecut.c b/contrib/bind/lib/resolv/res_findzonecut.c new file mode 100644 index 0000000..73a42a2 --- /dev/null +++ b/contrib/bind/lib/resolv/res_findzonecut.c @@ -0,0 +1,596 @@ +#if !defined(lint) && !defined(SABER) +static const char rcsid[] = "$Id: res_findzonecut.c,v 8.8 1999/10/15 19:49:11 vixie Exp $"; +#endif /* not lint */ + +/* + * Copyright (c) 1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* Import. */ + +#include "port_before.h" + +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/time.h> + +#include <netinet/in.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> + +#include <errno.h> +#include <limits.h> +#include <netdb.h> +#include <resolv.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <isc/list.h> + +#include "port_after.h" + +/* Data structures. */ + +typedef struct rr_a { + LINK(struct rr_a) link; + struct in_addr addr; +} rr_a; +typedef LIST(rr_a) rrset_a; + +typedef struct rr_ns { + LINK(struct rr_ns) link; + const char * name; + rrset_a addrs; +} rr_ns; +typedef LIST(rr_ns) rrset_ns; + +/* Forward. */ + +static int satisfy(res_state, + const char *, rrset_ns *, struct in_addr *, int); +static int add_addrs(res_state, rr_ns *, struct in_addr *, int); +static int get_soa(res_state, const char *, ns_class, + char *, size_t, char *, size_t, + rrset_ns *); +static int get_ns(res_state, const char *, ns_class, rrset_ns *); +static int get_glue(res_state, ns_class, rrset_ns *); +static int save_ns(res_state, ns_msg *, ns_sect, + const char *, ns_class, rrset_ns *); +static int save_a(res_state, ns_msg *, ns_sect, + const char *, ns_class, rrset_a *); +static void free_nsrrset(rrset_ns *); +static void free_nsrr(rrset_ns *, rr_ns *); +static rr_ns * find_ns(rrset_ns *, const char *); +static int do_query(res_state, const char *, ns_class, ns_type, + u_char *, ns_msg *); +static void dprintf(const char *, ...); + +/* Macros. */ + +#define DPRINTF(x) do {\ + int save_errno = errno; \ + if ((statp->options & RES_DEBUG) != 0) dprintf x; \ + errno = save_errno; \ + } while (0) + +/* Public. */ + +/* + * int + * res_findzonecut(res, dname, class, zname, zsize, addrs, naddrs) + * find enclosing zone for a <dname,class>, and some server addresses + * parameters: + * res - resolver context to work within (is modified) + * dname - domain name whose enclosing zone is desired + * class - class of dname (and its enclosing zone) + * zname - found zone name + * zsize - allocated size of zname + * addrs - found server addresses + * naddrs - max number of addrs + * return values: + * < 0 - an error occurred (check errno) + * = 0 - zname is now valid, but addrs[] wasn't changed + * > 0 - zname is now valid, and return value is number of addrs[] found + * notes: + * this function calls res_nsend() which means it depends on correctly + * functioning recursive nameservers (usually defined in /etc/resolv.conf + * or its local equivilent). + * + * we start by asking for an SOA<dname,class>. if we get one as an + * answer, that just means <dname,class> is a zone top, which is fine. + * more than likely we'll be told to go pound sand, in the form of a + * negative answer. + * + * note that we are not prepared to deal with referrals since that would + * only come from authority servers and our correctly functioning local + * recursive server would have followed the referral and got us something + * more definite. + * + * if the authority section contains an SOA, this SOA should also be the + * closest enclosing zone, since any intermediary zone cuts would've been + * returned as referrals and dealt with by our correctly functioning local + * recursive name server. but an SOA in the authority section should NOT + * match our dname (since that would have been returned in the answer + * section). an authority section SOA has to be "above" our dname. + * + * we cannot fail to find an SOA in this way. ultimately we'll return + * a zname indicating the root zone if that's the closest enclosing zone. + * however, since authority section SOA's were once optional, it's + * possible that we'll have to go hunting for the enclosing SOA by + * ripping labels off the front of our dname -- this is known as "doing + * it the hard way." + * + * ultimately we want some server addresses, which are ideally the ones + * pertaining to the SOA.MNAME, but only if there is a matching NS RR. + * so the second phase (after we find an SOA) is to go looking for the + * NS RRset for that SOA's zone. + * + * no answer section processed by this code is allowed to contain CNAME + * or DNAME RR's. for the SOA query this means we strip a label and + * keep going. for the NS and A queries this means we just give up. + */ + +int +res_findzonecut(res_state statp, const char *dname, ns_class class, int opts, + char *zname, size_t zsize, struct in_addr *addrs, int naddrs) +{ + char mname[NS_MAXDNAME]; + u_long save_pfcode; + rrset_ns nsrrs; + int n; + + DPRINTF(("START dname='%s' class=%s, zsize=%ld, naddrs=%d", + dname, p_class(class), (long)zsize, naddrs)); + save_pfcode = statp->pfcode; + statp->pfcode |= RES_PRF_HEAD2 | RES_PRF_HEAD1 | RES_PRF_HEADX | + RES_PRF_QUES | RES_PRF_ANS | + RES_PRF_AUTH | RES_PRF_ADD; + INIT_LIST(nsrrs); + + DPRINTF(("get the soa, and see if it has enough glue")); + if ((n = get_soa(statp, dname, class, zname, zsize, + mname, sizeof mname, &nsrrs)) < 0 || + ((opts & RES_EXHAUSTIVE) == 0 && + (n = satisfy(statp, mname, &nsrrs, addrs, naddrs)) > 0)) + goto done; + + DPRINTF(("get the ns rrset and see if it has enough glue")); + if ((n = get_ns(statp, zname, class, &nsrrs)) < 0 || + ((opts & RES_EXHAUSTIVE) == 0 && + (n = satisfy(statp, mname, &nsrrs, addrs, naddrs)) > 0)) + goto done; + + DPRINTF(("get the missing glue and see if it's finally enough")); + if ((n = get_glue(statp, class, &nsrrs)) >= 0) + n = satisfy(statp, mname, &nsrrs, addrs, naddrs); + + done: + DPRINTF(("FINISH n=%d (%s)", n, (n < 0) ? strerror(errno) : "OK")); + free_nsrrset(&nsrrs); + statp->pfcode = save_pfcode; + return (n); +} + +/* Private. */ + +static int +satisfy(res_state statp, + const char *mname, rrset_ns *nsrrsp, struct in_addr *addrs, int naddrs) +{ + rr_ns *nsrr; + int n, x; + + n = 0; + nsrr = find_ns(nsrrsp, mname); + if (nsrr != NULL) { + x = add_addrs(statp, nsrr, addrs, naddrs); + addrs += x; + naddrs -= x; + n += x; + } + for (nsrr = HEAD(*nsrrsp); + nsrr != NULL && naddrs > 0; + nsrr = NEXT(nsrr, link)) + if (ns_samename(nsrr->name, mname) != 1) { + x = add_addrs(statp, nsrr, addrs, naddrs); + addrs += x; + naddrs -= x; + n += x; + } + DPRINTF(("satisfy(%s): %d", mname, n)); + return (n); +} + +static int +add_addrs(res_state statp, rr_ns *nsrr, struct in_addr *addrs, int naddrs) { + rr_a *arr; + int n = 0; + + for (arr = HEAD(nsrr->addrs); arr != NULL; arr = NEXT(arr, link)) { + if (naddrs <= 0) + return (0); + *addrs++ = arr->addr; + naddrs--; + n++; + } + DPRINTF(("add_addrs: %d", n)); + return (n); +} + +static int +get_soa(res_state statp, const char *dname, ns_class class, + char *zname, size_t zsize, char *mname, size_t msize, + rrset_ns *nsrrsp) +{ + char tname[NS_MAXDNAME]; + u_char resp[NS_PACKETSZ]; + int n, i, ancount, nscount; + ns_sect sect; + ns_msg msg; + u_int rcode; + + /* + * Find closest enclosing SOA, even if it's for the root zone. + */ + + /* First canonicalize dname (exactly one unescaped trailing "."). */ + if (ns_makecanon(dname, tname, sizeof tname) < 0) + return (-1); + dname = tname; + + /* Now grovel the subdomains, hunting for an SOA answer or auth. */ + for (;;) { + /* Leading or inter-label '.' are skipped here. */ + while (*dname == '.') + dname++; + + /* Is there an SOA? */ + n = do_query(statp, dname, class, ns_t_soa, resp, &msg); + if (n < 0) { + DPRINTF(("get_soa: do_query('%s', %s) failed (%d)", + dname, p_class(class), n)); + return (-1); + } + if (n > 0) { + DPRINTF(("get_soa: CNAME or DNAME found")); + sect = ns_s_max, n = 0; + } else { + rcode = ns_msg_getflag(msg, ns_f_rcode); + ancount = ns_msg_count(msg, ns_s_an); + nscount = ns_msg_count(msg, ns_s_ns); + if (ancount > 0 && rcode == ns_r_noerror) + sect = ns_s_an, n = ancount; + else if (nscount > 0) + sect = ns_s_ns, n = nscount; + else + sect = ns_s_max, n = 0; + } + for (i = 0; i < n; i++) { + const char *t; + const u_char *rdata; + int rdlen; + ns_rr rr; + + if (ns_parserr(&msg, sect, i, &rr) < 0) { + DPRINTF(("get_soa: ns_parserr(%s, %d) failed", + p_section(sect, ns_o_query), i)); + return (-1); + } + if (ns_rr_type(rr) == ns_t_cname || + ns_rr_type(rr) == ns_t_dname) + break; + if (ns_rr_type(rr) != ns_t_soa || + ns_rr_class(rr) != class) + continue; + t = ns_rr_name(rr); + switch (sect) { + case ns_s_an: + if (ns_samedomain(dname, t) == 0) { + DPRINTF(("get_soa: ns_samedomain('%s', '%s') == 0", + dname, t)); + errno = EPROTOTYPE; + return (-1); + } + break; + case ns_s_ns: + if (ns_samename(dname, t) == 1 || + ns_samedomain(dname, t) == 0) { + DPRINTF(("get_soa: ns_samename() || !ns_samedomain('%s', '%s')", + dname, t)); + errno = EPROTOTYPE; + return (-1); + } + break; + default: + abort(); + } + if (strlen(t) + 1 > zsize) { + DPRINTF(("get_soa: zname(%d) too small (%d)", + zsize, strlen(t) + 1)); + errno = EMSGSIZE; + return (-1); + } + strcpy(zname, t); + rdata = ns_rr_rdata(rr); + rdlen = ns_rr_rdlen(rr); + if (ns_name_uncompress(resp, ns_msg_end(msg), rdata, + mname, msize) < 0) { + DPRINTF(("get_soa: ns_name_uncompress failed")); + return (-1); + } + if (save_ns(statp, &msg, ns_s_ns, + zname, class, nsrrsp) < 0) { + DPRINTF(("get_soa: save_ns failed")); + return (-1); + } + return (0); + } + + /* If we're out of labels, then not even "." has an SOA! */ + if (*dname == '\0') + break; + + /* Find label-terminating "."; top of loop will skip it. */ + while (*dname != '.') { + if (*dname == '\\') + if (*++dname == '\0') { + errno = EMSGSIZE; + return (-1); + } + dname++; + } + } + DPRINTF(("get_soa: out of labels")); + errno = EDESTADDRREQ; + return (-1); +} + +static int +get_ns(res_state statp, const char *zname, ns_class class, rrset_ns *nsrrsp) { + u_char resp[NS_PACKETSZ]; + ns_msg msg; + int n; + + /* Go and get the NS RRs for this zone. */ + n = do_query(statp, zname, class, ns_t_ns, resp, &msg); + if (n != 0) { + DPRINTF(("get_ns: do_query('zname', %s) failed (%d)", + zname, p_class(class), n)); + return (-1); + } + + /* Remember the NS RRs and associated A RRs that came back. */ + if (save_ns(statp, &msg, ns_s_an, zname, class, nsrrsp) < 0) { + DPRINTF(("get_ns save_ns('%s', %s) failed", + zname, p_class(class))); + return (-1); + } + + return (0); +} + +static int +get_glue(res_state statp, ns_class class, rrset_ns *nsrrsp) { + rr_ns *nsrr, *nsrr_n; + + /* Go and get the A RRs for each empty NS RR on our list. */ + for (nsrr = HEAD(*nsrrsp); nsrr != NULL; nsrr = nsrr_n) { + u_char resp[NS_PACKETSZ]; + ns_msg msg; + int n; + + nsrr_n = NEXT(nsrr, link); + + if (EMPTY(nsrr->addrs)) { + n = do_query(statp, nsrr->name, class, ns_t_a, + resp, &msg); + if (n != 0) { + DPRINTF(("get_glue: do_query('%s', %s') failed", + nsrr->name, p_class(class), n)); + return (-1); + } + if (save_a(statp, &msg, ns_s_an, nsrr->name, class, + &nsrr->addrs) < 0) { + DPRINTF(("get_glue: save_r('%s', %s) failed", + nsrr->name, p_class(class))); + return (-1); + } + /* If it's still empty, it's just chaff. */ + if (EMPTY(nsrr->addrs)) { + DPRINTF(("get_glue: removing empty '%s' NS", + nsrr->name)); + free_nsrr(nsrrsp, nsrr); + } + } + } + return (0); +} + +static int +save_ns(res_state statp, ns_msg *msg, ns_sect sect, + const char *owner, ns_class class, + rrset_ns *nsrrsp) +{ + int i; + + for (i = 0; i < ns_msg_count(*msg, sect); i++) { + char tname[MAXDNAME]; + const u_char *rdata; + rr_ns *nsrr; + ns_rr rr; + int rdlen; + + if (ns_parserr(msg, sect, i, &rr) < 0) { + DPRINTF(("save_ns: ns_parserr(%s, %d) failed", + p_section(sect, ns_o_query), i)); + return (-1); + } + if (ns_rr_type(rr) != ns_t_ns || + ns_rr_class(rr) != class || + ns_samename(ns_rr_name(rr), owner) != 1) + continue; + nsrr = find_ns(nsrrsp, ns_rr_name(rr)); + if (nsrr == NULL) { + nsrr = malloc(sizeof *nsrr); + if (nsrr == NULL) { + DPRINTF(("save_ns: malloc failed")); + return (-1); + } + rdata = ns_rr_rdata(rr); + rdlen = ns_rr_rdlen(rr); + if (ns_name_uncompress(ns_msg_base(*msg), + ns_msg_end(*msg), rdata, + tname, sizeof tname) < 0) { + DPRINTF(("save_ns: ns_name_uncompress failed")); + free(nsrr); + return (-1); + } + nsrr->name = strdup(tname); + if (nsrr->name == NULL) { + DPRINTF(("save_ns: strdup failed")); + free(nsrr); + return (-1); + } + INIT_LIST(nsrr->addrs); + APPEND(*nsrrsp, nsrr, link); + } + if (save_a(statp, msg, ns_s_ar, + nsrr->name, class, &nsrr->addrs) < 0) { + DPRINTF(("save_ns: save_r('%s', %s) failed", + nsrr->name, p_class(class))); + return (-1); + } + } + return (0); +} + +static int +save_a(res_state statp, ns_msg *msg, ns_sect sect, + const char *owner, ns_class class, + rrset_a *arrsp) +{ + int i; + + for (i = 0; i < ns_msg_count(*msg, sect); i++) { + ns_rr rr; + rr_a *arr; + + if (ns_parserr(msg, sect, i, &rr) < 0) { + DPRINTF(("save_a: ns_parserr(%s, %d) failed", + p_section(sect, ns_o_query), i)); + return (-1); + } + if (ns_rr_type(rr) != ns_t_a || + ns_rr_class(rr) != class || + ns_samename(ns_rr_name(rr), owner) != 1 || + ns_rr_rdlen(rr) != NS_INADDRSZ) + continue; + arr = malloc(sizeof *arr); + if (arr == NULL) { + DPRINTF(("save_a: malloc failed")); + return (-1); + } + memcpy(&arr->addr, ns_rr_rdata(rr), NS_INADDRSZ); + APPEND(*arrsp, arr, link); + } + return (0); +} + +static void +free_nsrrset(rrset_ns *nsrrsp) { + rr_ns *nsrr; + + while ((nsrr = HEAD(*nsrrsp)) != NULL) + free_nsrr(nsrrsp, nsrr); +} + +static void +free_nsrr(rrset_ns *nsrrsp, rr_ns *nsrr) { + rr_a *arr; + + while ((arr = HEAD(nsrr->addrs)) != NULL) { + UNLINK(nsrr->addrs, arr, link); + free(arr); + } + free((char *)nsrr->name); + UNLINK(*nsrrsp, nsrr, link); + free(nsrr); +} + +static rr_ns * +find_ns(rrset_ns *nsrrsp, const char *dname) { + rr_ns *nsrr; + + for (nsrr = HEAD(*nsrrsp); nsrr != NULL; nsrr = NEXT(nsrr, link)) + if (ns_samename(nsrr->name, dname) == 1) + return (nsrr); + return (NULL); +} + +static int +do_query(res_state statp, const char *dname, ns_class class, ns_type qtype, + u_char *resp, ns_msg *msg) +{ + u_char req[NS_PACKETSZ]; + int i, n; + + n = res_nmkquery(statp, ns_o_query, dname, class, qtype, + NULL, 0, NULL, req, NS_PACKETSZ); + if (n < 0) { + DPRINTF(("do_query: res_nmkquery failed")); + return (-1); + } + n = res_nsend(statp, req, n, resp, NS_PACKETSZ); + if (n < 0) { + DPRINTF(("do_query: res_nsend failed")); + return (-1); + } + if (n == 0) { + DPRINTF(("do_query: res_nsend returned 0")); + errno = EMSGSIZE; + return (-1); + } + if (ns_initparse(resp, n, msg) < 0) { + DPRINTF(("do_query: ns_initparse failed")); + return (-1); + } + n = 0; + for (i = 0; i < ns_msg_count(*msg, ns_s_an); i++) { + ns_rr rr; + + if (ns_parserr(msg, ns_s_an, i, &rr) < 0) { + DPRINTF(("do_query: ns_parserr failed")); + return (-1); + } + n += (ns_rr_class(rr) == class && + (ns_rr_type(rr) == ns_t_cname || + ns_rr_type(rr) == ns_t_dname)); + } + return (n); +} + +static void +dprintf(const char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + fputs(";; res_findzonecut: ", stderr); + vfprintf(stderr, fmt, ap); + fputc('\n', stderr); + va_end(ap); +} diff --git a/contrib/bind/lib/resolv/res_init.c b/contrib/bind/lib/resolv/res_init.c index f374d51..85dc7e3 100644 --- a/contrib/bind/lib/resolv/res_init.c +++ b/contrib/bind/lib/resolv/res_init.c @@ -52,7 +52,7 @@ */ /* - * Portions Copyright (c) 1996 by Internet Software Consortium. + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -69,24 +69,28 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)res_init.c 8.1 (Berkeley) 6/7/93"; -static char rcsid[] = "$Id: res_init.c,v 8.7 1996/11/18 09:10:04 vixie Exp $"; +static const char sccsid[] = "@(#)res_init.c 8.1 (Berkeley) 6/7/93"; +static const char rcsid[] = "$Id: res_init.c,v 8.13 1999/10/13 16:39:40 vixie Exp $"; #endif /* LIBC_SCCS and not lint */ #include "port_before.h" + #include <sys/types.h> #include <sys/param.h> #include <sys/socket.h> #include <sys/time.h> + #include <netinet/in.h> #include <arpa/inet.h> #include <arpa/nameser.h> + #include <ctype.h> #include <resolv.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> + #include "port_after.h" /* Options. Should all be left alone. */ @@ -94,7 +98,7 @@ static char rcsid[] = "$Id: res_init.c,v 8.7 1996/11/18 09:10:04 vixie Exp $"; #define RFC1535 #define DEBUG -static void res_setoptions __P((char *, char *)); +static void res_setoptions __P((res_state, const char *, const char *)); #ifdef RESOLVSORT static const char sort_mask[] = "/&"; @@ -110,13 +114,6 @@ static u_int32_t net_mask __P((struct in_addr)); * Resolver state default settings. */ -struct __res_state _res -# if defined(__BIND_RES_TEXT) - = { RES_TIMEOUT, } /* Motorola, et al. */ -# endif - ; - - /* * Set up default settings. If the configuration file exist, the values * there will have precedence. Otherwise, the server address is set to @@ -139,7 +136,15 @@ struct __res_state _res * Return 0 if completes successfully, -1 on error */ int -res_init() { +res_ninit(res_state statp) { + extern int __res_vinit(res_state, int); + + return (__res_vinit(statp, 0)); +} + +/* This function has to be reachable by res_data.c but not publically. */ +int +__res_vinit(res_state statp, int preinit) { register FILE *fp; register char *cp, **pp; register int n; @@ -155,53 +160,32 @@ res_init() { int dots; #endif - /* - * These three fields used to be statically initialized. This made - * it hard to use this code in a shared library. It is necessary, - * now that we're doing dynamic initialization here, that we preserve - * the old semantics: if an application modifies one of these three - * fields of _res before res_init() is called, res_init() will not - * alter them. Of course, if an application is setting them to - * _zero_ before calling res_init(), hoping to override what used - * to be the static default, we can't detect it and unexpected results - * will follow. Zero for any of these fields would make no sense, - * so one can safely assume that the applications were already getting - * unexpected results. - * - * _res.options is tricky since some apps were known to diddle the bits - * before res_init() was first called. We can't replicate that semantic - * with dynamic initialization (they may have turned bits off that are - * set in RES_DEFAULT). Our solution is to declare such applications - * "broken". They could fool us by setting RES_INIT but none do (yet). - */ - if (!_res.retrans) - _res.retrans = RES_TIMEOUT; - if (!_res.retry) - _res.retry = 4; - if (!(_res.options & RES_INIT)) - _res.options = RES_DEFAULT; - - /* - * This one used to initialize implicitly to zero, so unless the app - * has set it to something in particular, we can randomize it now. - */ - if (!_res.id) - _res.id = res_randomid(); + if (!preinit) { + statp->retrans = RES_TIMEOUT; + statp->retry = RES_DFLRETRY; + statp->options = RES_DEFAULT; + statp->id = res_randomid(); + } #ifdef USELOOPBACK - _res.nsaddr.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1); + statp->nsaddr.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1); #else - _res.nsaddr.sin_addr.s_addr = INADDR_ANY; + statp->nsaddr.sin_addr.s_addr = INADDR_ANY; #endif - _res.nsaddr.sin_family = AF_INET; - _res.nsaddr.sin_port = htons(NAMESERVER_PORT); - _res.nscount = 1; - _res.ndots = 1; - _res.pfcode = 0; + statp->nsaddr.sin_family = AF_INET; + statp->nsaddr.sin_port = htons(NAMESERVER_PORT); + statp->nscount = 1; + statp->ndots = 1; + statp->pfcode = 0; + statp->_sock = -1; + statp->_flags = 0; + statp->qhook = NULL; + statp->rhook = NULL; /* Allow user to override the local domain definition */ if ((cp = getenv("LOCALDOMAIN")) != NULL) { - (void)strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1); + (void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); + statp->defdname[sizeof(statp->defdname) - 1] = '\0'; haveenv++; /* @@ -211,10 +195,10 @@ res_init() { * one that they want to use as an individual (even more * important now that the rfc1535 stuff restricts searches) */ - cp = _res.defdname; - pp = _res.dnsrch; + cp = statp->defdname; + pp = statp->dnsrch; *pp++ = cp; - for (n = 0; *cp && pp < _res.dnsrch + MAXDNSRCH; cp++) { + for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) { if (*cp == '\n') /* silly backwards compat */ break; else if (*cp == ' ' || *cp == '\t') { @@ -253,8 +237,9 @@ res_init() { cp++; if ((*cp == '\0') || (*cp == '\n')) continue; - strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1); - if ((cp = strpbrk(_res.defdname, " \t\n")) != NULL) + strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); + statp->defdname[sizeof(statp->defdname) - 1] = '\0'; + if ((cp = strpbrk(statp->defdname, " \t\n")) != NULL) *cp = '\0'; havesearch = 0; continue; @@ -268,17 +253,18 @@ res_init() { cp++; if ((*cp == '\0') || (*cp == '\n')) continue; - strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1); - if ((cp = strchr(_res.defdname, '\n')) != NULL) + strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); + statp->defdname[sizeof(statp->defdname) - 1] = '\0'; + if ((cp = strchr(statp->defdname, '\n')) != NULL) *cp = '\0'; /* * Set search list to be blank-separated strings * on rest of line. */ - cp = _res.defdname; - pp = _res.dnsrch; + cp = statp->defdname; + pp = statp->dnsrch; *pp++ = cp; - for (n = 0; *cp && pp < _res.dnsrch + MAXDNSRCH; cp++) { + for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) { if (*cp == ' ' || *cp == '\t') { *cp = 0; n = 1; @@ -303,9 +289,9 @@ res_init() { while (*cp == ' ' || *cp == '\t') cp++; if ((*cp != '\0') && (*cp != '\n') && inet_aton(cp, &a)) { - _res.nsaddr_list[nserv].sin_addr = a; - _res.nsaddr_list[nserv].sin_family = AF_INET; - _res.nsaddr_list[nserv].sin_port = + statp->nsaddr_list[nserv].sin_addr = a; + statp->nsaddr_list[nserv].sin_family = AF_INET; + statp->nsaddr_list[nserv].sin_port = htons(NAMESERVER_PORT); nserv++; } @@ -328,7 +314,7 @@ res_init() { n = *cp; *cp = 0; if (inet_aton(net, &a)) { - _res.sort_list[nsort].addr = a; + statp->sort_list[nsort].addr = a; if (ISSORTMASK(n)) { *cp++ = n; net = cp; @@ -338,14 +324,14 @@ res_init() { n = *cp; *cp = 0; if (inet_aton(net, &a)) { - _res.sort_list[nsort].mask = a.s_addr; + statp->sort_list[nsort].mask = a.s_addr; } else { - _res.sort_list[nsort].mask = - net_mask(_res.sort_list[nsort].addr); + statp->sort_list[nsort].mask = + net_mask(statp->sort_list[nsort].addr); } } else { - _res.sort_list[nsort].mask = - net_mask(_res.sort_list[nsort].addr); + statp->sort_list[nsort].mask = + net_mask(statp->sort_list[nsort].addr); } nsort++; } @@ -355,35 +341,35 @@ res_init() { } #endif if (MATCH(buf, "options")) { - res_setoptions(buf + sizeof("options") - 1, "conf"); + res_setoptions(statp, buf + sizeof("options") - 1, "conf"); continue; } } if (nserv > 1) - _res.nscount = nserv; + statp->nscount = nserv; #ifdef RESOLVSORT - _res.nsort = nsort; + statp->nsort = nsort; #endif (void) fclose(fp); } - if (_res.defdname[0] == 0 && - gethostname(buf, sizeof(_res.defdname) - 1) == 0 && + if (statp->defdname[0] == 0 && + gethostname(buf, sizeof(statp->defdname) - 1) == 0 && (cp = strchr(buf, '.')) != NULL) - strcpy(_res.defdname, cp + 1); + strcpy(statp->defdname, cp + 1); /* find components of local domain that might be searched */ if (havesearch == 0) { - pp = _res.dnsrch; - *pp++ = _res.defdname; + pp = statp->dnsrch; + *pp++ = statp->defdname; *pp = NULL; #ifndef RFC1535 dots = 0; - for (cp = _res.defdname; *cp; cp++) + for (cp = statp->defdname; *cp; cp++) dots += (*cp == '.'); - cp = _res.defdname; - while (pp < _res.dnsrch + MAXDFLSRCH) { + cp = statp->defdname; + while (pp < statp->dnsrch + MAXDFLSRCH) { if (dots < LOCALDOMAINPARTS) break; cp = strchr(cp, '.') + 1; /* we know there is one */ @@ -392,9 +378,9 @@ res_init() { } *pp = NULL; #ifdef DEBUG - if (_res.options & RES_DEBUG) { + if (statp->options & RES_DEBUG) { printf(";; res_init()... default dnsrch list:\n"); - for (pp = _res.dnsrch; *pp; pp++) + for (pp = statp->dnsrch; *pp; pp++) printf(";;\t%s\n", *pp); printf(";;\t..END..\n"); } @@ -403,20 +389,18 @@ res_init() { } if ((cp = getenv("RES_OPTIONS")) != NULL) - res_setoptions(cp, "env"); - _res.options |= RES_INIT; + res_setoptions(statp, cp, "env"); + statp->options |= RES_INIT; return (0); } static void -res_setoptions(options, source) - char *options, *source; -{ - char *cp = options; +res_setoptions(res_state statp, const char *options, const char *source) { + const char *cp = options; int i; #ifdef DEBUG - if (_res.options & RES_DEBUG) + if (statp->options & RES_DEBUG) printf(";; res_setoptions(\"%s\", \"%s\")...\n", options, source); #endif @@ -428,24 +412,41 @@ res_setoptions(options, source) if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) { i = atoi(cp + sizeof("ndots:") - 1); if (i <= RES_MAXNDOTS) - _res.ndots = i; + statp->ndots = i; else - _res.ndots = RES_MAXNDOTS; + statp->ndots = RES_MAXNDOTS; #ifdef DEBUG - if (_res.options & RES_DEBUG) - printf(";;\tndots=%d\n", _res.ndots); + if (statp->options & RES_DEBUG) + printf(";;\tndots=%d\n", statp->ndots); #endif + } else if (!strncmp(cp, "timeout:", sizeof("timeout:") - 1)) { + i = atoi(cp + sizeof("timeout:") - 1); + if (i <= RES_MAXRETRANS) + statp->retrans = i; + else + statp->retrans = RES_MAXRETRANS; + } else if (!strncmp(cp, "attempts:", sizeof("attempts:") - 1)){ + i = atoi(cp + sizeof("attempts:") - 1); + if (i <= RES_MAXRETRY) + statp->retry = i; + else + statp->retry = RES_MAXRETRY; } else if (!strncmp(cp, "debug", sizeof("debug") - 1)) { #ifdef DEBUG - if (!(_res.options & RES_DEBUG)) { + if (!(statp->options & RES_DEBUG)) { printf(";; res_setoptions(\"%s\", \"%s\")..\n", options, source); - _res.options |= RES_DEBUG; + statp->options |= RES_DEBUG; } printf(";;\tdebug\n"); #endif } else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) { - _res.options |= RES_USE_INET6; + statp->options |= RES_USE_INET6; + } else if (!strncmp(cp, "rotate", sizeof("rotate") - 1)) { + statp->options |= RES_ROTATE; + } else if (!strncmp(cp, "no-check-names", + sizeof("no-check-names") - 1)) { + statp->options |= RES_NOCHECKNAME; } else { /* XXX - print a warning here? */ } @@ -472,8 +473,7 @@ net_mask(in) /* XXX - should really use system's version of this */ #endif u_int -res_randomid() -{ +res_randomid(void) { struct timeval now; gettimeofday(&now, NULL); diff --git a/contrib/bind/lib/resolv/res_mkquery.c b/contrib/bind/lib/resolv/res_mkquery.c index 74be28b..17b1ccf 100644 --- a/contrib/bind/lib/resolv/res_mkquery.c +++ b/contrib/bind/lib/resolv/res_mkquery.c @@ -52,7 +52,7 @@ */ /* - * Portions Copyright (c) 1996 by Internet Software Consortium. + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -69,8 +69,8 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)res_mkquery.c 8.1 (Berkeley) 6/4/93"; -static char rcsid[] = "$Id: res_mkquery.c,v 8.9 1997/04/24 22:22:36 vixie Exp $"; +static const char sccsid[] = "@(#)res_mkquery.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "$Id: res_mkquery.c,v 8.12 1999/10/13 16:39:40 vixie Exp $"; #endif /* LIBC_SCCS and not lint */ #include "port_before.h" @@ -87,34 +87,32 @@ static char rcsid[] = "$Id: res_mkquery.c,v 8.9 1997/04/24 22:22:36 vixie Exp $" /* Options. Leave them on. */ #define DEBUG +extern const char *_res_opcodes[]; + /* * Form all types of queries. * Returns the size of the result or -1. */ int -res_mkquery(op, dname, class, type, data, datalen, newrr_in, buf, buflen) - int op; /* opcode of query */ - const char *dname; /* domain name */ - int class, type; /* class and type of query */ - const u_char *data; /* resource record data */ - int datalen; /* length of data */ - const u_char *newrr_in; /* new rr for modify or append */ - u_char *buf; /* buffer to put query */ - int buflen; /* size of buffer */ +res_nmkquery(res_state statp, + int op, /* opcode of query */ + const char *dname, /* domain name */ + int class, int type, /* class and type of query */ + const u_char *data, /* resource record data */ + int datalen, /* length of data */ + const u_char *newrr_in, /* new rr for modify or append */ + u_char *buf, /* buffer to put query */ + int buflen) /* size of buffer */ { register HEADER *hp; register u_char *cp; register int n; u_char *dnptrs[20], **dpp, **lastdnptr; - if ((_res.options & RES_INIT) == 0 && res_init() == -1) { - h_errno = NETDB_INTERNAL; - return (-1); - } #ifdef DEBUG - if (_res.options & RES_DEBUG) - printf(";; res_mkquery(%d, %s, %d, %d)\n", - op, dname, class, type); + if (statp->options & RES_DEBUG) + printf(";; res_nmkquery(%s, %s, %s, %s)\n", + _res_opcodes[op], dname, p_class(class), p_type(type)); #endif /* * Initialize header fields. @@ -123,9 +121,9 @@ res_mkquery(op, dname, class, type, data, datalen, newrr_in, buf, buflen) return (-1); memset(buf, 0, HFIXEDSZ); hp = (HEADER *) buf; - hp->id = htons(++_res.id); + hp->id = htons(++statp->id); hp->opcode = op; - hp->rd = (_res.options & RES_RECURSE) != 0; + hp->rd = (statp->options & RES_RECURSE) != 0; hp->rcode = NOERROR; cp = buf + HFIXEDSZ; buflen -= HFIXEDSZ; diff --git a/contrib/bind/lib/resolv/res_mkupdate.c b/contrib/bind/lib/resolv/res_mkupdate.c index c6e7f4a1..14e1a60 100644 --- a/contrib/bind/lib/resolv/res_mkupdate.c +++ b/contrib/bind/lib/resolv/res_mkupdate.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -21,7 +21,7 @@ */ #if !defined(lint) && !defined(SABER) -static char rcsid[] = "$Id: res_mkupdate.c,v 1.11 1998/01/26 23:08:45 halley Exp $"; +static const char rcsid[] = "$Id: res_mkupdate.c,v 1.24 1999/10/13 17:11:32 vixie Exp $"; #endif /* not lint */ #include "port_before.h" @@ -37,6 +37,7 @@ static char rcsid[] = "$Id: res_mkupdate.c,v 1.11 1998/01/26 23:08:45 halley Exp #include <limits.h> #include <netdb.h> #include <resolv.h> +#include <res_update.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -47,12 +48,20 @@ static char rcsid[] = "$Id: res_mkupdate.c,v 1.11 1998/01/26 23:08:45 halley Exp /* Options. Leave them on. */ #define DEBUG +#define MAXPORT 1024 static int getnum_str(u_char **, u_char *); +static int gethexnum_str(u_char **, u_char *); static int getword_str(char *, int, u_char **, u_char *); +static int getstr_str(char *, int, u_char **, u_char *); #define ShrinkBuffer(x) if ((buflen -= x) < 0) return (-2); +/* Forward. */ + +int res_protocolnumber(const char *); +int res_servicenumber(const char *); + /* * Form update packets. * Returns the size of the resulting packet if no error @@ -66,23 +75,21 @@ static int getword_str(char *, int, u_char **, u_char *); * -5 unknown operation or no records */ int -res_mkupdate(ns_updrec *rrecp_in, u_char *buf, int buflen) { +res_nmkupdate(res_state statp, ns_updrec *rrecp_in, u_char *buf, int buflen) { ns_updrec *rrecp_start = rrecp_in; HEADER *hp; - u_char c, *cp, *cp1, *sp1, *sp2, *startp, *endp; - int n, i, j, found, soanum, multiline; - ns_updrec *rrecp, *tmprrecp, *recptr = NULL; + u_char *cp, *sp1, *sp2, *startp, *endp; + int n, i, soanum, multiline; + ns_updrec *rrecp; struct in_addr ina; + struct in6_addr in6a; char buf2[MAXDNAME]; + u_char buf3[MAXDNAME]; int section, numrrs = 0, counts[ns_s_max]; u_int16_t rtype, rclass; u_int32_t n1, rttl; u_char *dnptrs[20], **dpp, **lastdnptr; - - if ((_res.options & RES_INIT) == 0 && res_init() == -1) { - h_errno = NETDB_INTERNAL; - return (-1); - } + int siglen, keylen, certlen; /* * Initialize header fields. @@ -91,7 +98,7 @@ res_mkupdate(ns_updrec *rrecp_in, u_char *buf, int buflen) { return (-1); memset(buf, 0, HFIXEDSZ); hp = (HEADER *) buf; - hp->id = htons(++_res.id); + hp->id = htons(++statp->id); hp->opcode = ns_o_update; hp->rcode = NOERROR; sp1 = buf + 2*INT16SZ; /* save pointer to zocount */ @@ -108,7 +115,7 @@ res_mkupdate(ns_updrec *rrecp_in, u_char *buf, int buflen) { return (-3); memset(counts, 0, sizeof counts); - for (rrecp = rrecp_start; rrecp; rrecp = rrecp->r_grpnext) { + for (rrecp = rrecp_start; rrecp; rrecp = NEXT(rrecp, r_glink)) { numrrs++; section = rrecp->r_section; if (section < 0 || section >= ns_s_max) @@ -264,8 +271,35 @@ res_mkupdate(ns_updrec *rrecp_in, u_char *buf, int buflen) { n = getnum_str(&startp, endp); if (n < 0) return (-1); + ShrinkBuffer(INT16SZ); PUTSHORT(n, cp); + if (!getword_str(buf2, sizeof buf2, &startp, endp)) + return (-1); + n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); + if (n < 0) + return (-1); + cp += n; + ShrinkBuffer(n); + break; + case T_SRV: + n = getnum_str(&startp, endp); + if (n < 0) + return (-1); ShrinkBuffer(INT16SZ); + PUTSHORT(n, cp); + + n = getnum_str(&startp, endp); + if (n < 0) + return (-1); + ShrinkBuffer(INT16SZ); + PUTSHORT(n, cp); + + n = getnum_str(&startp, endp); + if (n < 0) + return (-1); + ShrinkBuffer(INT16SZ); + PUTSHORT(n, cp); + if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); @@ -292,17 +326,315 @@ res_mkupdate(ns_updrec *rrecp_in, u_char *buf, int buflen) { ShrinkBuffer(n); } break; - case T_WKS: + case T_WKS: { + char bm[MAXPORT/8]; + int maxbm = 0; + + if (!getword_str(buf2, sizeof buf2, &startp, endp)) + return (-1); + if (!inet_aton(buf2, &ina)) + return (-1); + n1 = ntohl(ina.s_addr); + ShrinkBuffer(INT32SZ); + PUTLONG(n1, cp); + + if (!getword_str(buf2, sizeof buf2, &startp, endp)) + return (-1); + if ((i = res_protocolnumber(buf2)) < 0) + return (-1); + ShrinkBuffer(1); + *cp++ = i & 0xff; + + for (i = 0; i < MAXPORT/8 ; i++) + bm[i] = 0; + + while (getword_str(buf2, sizeof buf2, &startp, endp)) { + if ((n1 = res_servicenumber(buf2)) <= 0) + return (-1); + + if (n1 < MAXPORT) { + bm[n1/8] |= (0x80>>(n1%8)); + if (n1 > maxbm) + maxbm = n1; + } else + return (-1); + } + maxbm = maxbm/8 + 1; + ShrinkBuffer(maxbm); + memcpy(cp, bm, maxbm); + cp += maxbm; + break; + } case T_HINFO: + for (i = 0; i < 2; i++) { + if ((n = getstr_str(buf2, sizeof buf2, + &startp, endp)) < 0) + return (-1); + if (n > 255) + return (-1); + ShrinkBuffer(n+1); + *cp++ = n; + memcpy(cp, buf2, n); + cp += n; + } + break; case T_TXT: + while (1) { + if ((n = getstr_str(buf2, sizeof buf2, + &startp, endp)) < 0) { + if (cp != (sp2 + INT16SZ)) + break; + return (-1); + } + if (n > 255) + return (-1); + ShrinkBuffer(n+1); + *cp++ = n; + memcpy(cp, buf2, n); + cp += n; + } + break; case T_X25: + /* RFC 1183 */ + if ((n = getstr_str(buf2, sizeof buf2, &startp, + endp)) < 0) + return (-1); + if (n > 255) + return (-1); + ShrinkBuffer(n+1); + *cp++ = n; + memcpy(cp, buf2, n); + cp += n; + break; case T_ISDN: + /* RFC 1183 */ + if ((n = getstr_str(buf2, sizeof buf2, &startp, + endp)) < 0) + return (-1); + if ((n > 255) || (n == 0)) + return (-1); + ShrinkBuffer(n+1); + *cp++ = n; + memcpy(cp, buf2, n); + cp += n; + if ((n = getstr_str(buf2, sizeof buf2, &startp, + endp)) < 0) + n = 0; + if (n > 255) + return (-1); + ShrinkBuffer(n+1); + *cp++ = n; + memcpy(cp, buf2, n); + cp += n; + break; case T_NSAP: + if ((n = inet_nsap_addr((char *)startp, (u_char *)buf2, sizeof(buf2))) != 0) { + ShrinkBuffer(n); + memcpy(cp, buf2, n); + cp += n; + } else { + return (-1); + } + break; case T_LOC: - /* XXX - more fine tuning needed here */ - ShrinkBuffer(rrecp->r_size); - memcpy(cp, rrecp->r_data, rrecp->r_size); - cp += rrecp->r_size; + if ((n = loc_aton((char *)startp, (u_char *)buf2)) != 0) { + ShrinkBuffer(n); + memcpy(cp, buf2, n); + cp += n; + } else + return (-1); + break; + case ns_t_sig: + { + int sig_type, success, dateerror; + u_int32_t exptime, timesigned; + + /* type */ + if ((n = getword_str(buf2, sizeof buf2, + &startp, endp)) < 0) + return (-1); + sig_type = sym_ston(__p_type_syms, buf2, &success); + if (!success || sig_type == ns_t_any) + return (-1); + ShrinkBuffer(INT16SZ); + PUTSHORT(sig_type, cp); + /* alg */ + n = getnum_str(&startp, endp); + if (n < 0) + return (-1); + ShrinkBuffer(1); + *cp++ = n; + /* labels */ + n = getnum_str(&startp, endp); + if (n <= 0 || n > 255) + return (-1); + ShrinkBuffer(1); + *cp++ = n; + /* ottl & expire */ + if (!getword_str(buf2, sizeof buf2, &startp, endp)) + return (-1); + exptime = ns_datetosecs(buf2, &dateerror); + if (!dateerror) { + ShrinkBuffer(INT32SZ); + PUTLONG(rttl, cp); + } + else { + char *ulendp; + u_int32_t ottl; + + ottl = strtoul(buf2, &ulendp, 10); + if (ulendp != NULL && *ulendp != '\0') + return (-1); + ShrinkBuffer(INT32SZ); + PUTLONG(ottl, cp); + if (!getword_str(buf2, sizeof buf2, &startp, + endp)) + return (-1); + exptime = ns_datetosecs(buf2, &dateerror); + if (dateerror) + return (-1); + } + /* expire */ + ShrinkBuffer(INT32SZ); + PUTLONG(exptime, cp); + /* timesigned */ + if (!getword_str(buf2, sizeof buf2, &startp, endp)) + return (-1); + timesigned = ns_datetosecs(buf2, &dateerror); + if (!dateerror) { + ShrinkBuffer(INT32SZ); + PUTLONG(timesigned, cp); + } + else + return (-1); + /* footprint */ + n = getnum_str(&startp, endp); + if (n < 0) + return (-1); + ShrinkBuffer(INT16SZ); + PUTSHORT(n, cp); + /* signer name */ + if (!getword_str(buf2, sizeof buf2, &startp, endp)) + return (-1); + n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); + if (n < 0) + return (-1); + cp += n; + ShrinkBuffer(n); + /* sig */ + if ((n = getword_str(buf2, sizeof buf2, + &startp, endp)) < 0) + return (-1); + siglen = b64_pton(buf2, buf3, sizeof(buf3)); + if (siglen < 0) + return (-1); + ShrinkBuffer(siglen); + memcpy(cp, buf3, siglen); + cp += siglen; + break; + } + case ns_t_key: + /* flags */ + n = gethexnum_str(&startp, endp); + if (n < 0) + return (-1); + ShrinkBuffer(INT16SZ); + PUTSHORT(n, cp); + /* proto */ + n = getnum_str(&startp, endp); + if (n < 0) + return (-1); + ShrinkBuffer(1); + *cp++ = n; + /* alg */ + n = getnum_str(&startp, endp); + if (n < 0) + return (-1); + ShrinkBuffer(1); + *cp++ = n; + /* key */ + if ((n = getword_str(buf2, sizeof buf2, + &startp, endp)) < 0) + return (-1); + keylen = b64_pton(buf2, buf3, sizeof(buf3)); + if (keylen < 0) + return (-1); + ShrinkBuffer(keylen); + memcpy(cp, buf3, keylen); + cp += keylen; + break; + case ns_t_nxt: + { + int success, nxt_type; + u_char data[32]; + int maxtype; + + /* next name */ + if (!getword_str(buf2, sizeof buf2, &startp, endp)) + return (-1); + n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); + if (n < 0) + return (-1); + cp += n; + ShrinkBuffer(n); + maxtype = 0; + memset(data, 0, sizeof data); + while (1) { + if (!getword_str(buf2, sizeof buf2, &startp, + endp)) + break; + nxt_type = sym_ston(__p_type_syms, buf2, + &success); + if (!success || !ns_t_rr_p(nxt_type)) + return (-1); + NS_NXT_BIT_SET(nxt_type, data); + if (nxt_type > maxtype) + maxtype = nxt_type; + } + n = maxtype/NS_NXT_BITS+1; + ShrinkBuffer(n); + memcpy(cp, data, n); + cp += n; + break; + } + case ns_t_cert: + /* type */ + n = getnum_str(&startp, endp); + if (n < 0) + return (-1); + ShrinkBuffer(INT16SZ); + PUTSHORT(n, cp); + /* key tag */ + n = getnum_str(&startp, endp); + if (n < 0) + return (-1); + ShrinkBuffer(INT16SZ); + PUTSHORT(n, cp); + /* alg */ + n = getnum_str(&startp, endp); + if (n < 0) + return (-1); + ShrinkBuffer(1); + *cp++ = n; + /* cert */ + if ((n = getword_str(buf2, sizeof buf2, + &startp, endp)) < 0) + return (-1); + certlen = b64_pton(buf2, buf3, sizeof(buf3)); + if (certlen < 0) + return (-1); + ShrinkBuffer(certlen); + memcpy(cp, buf3, certlen); + cp += certlen; + break; + case ns_t_aaaa: + if (!getword_str(buf2, sizeof buf2, &startp, endp)) + return (-1); + if (inet_pton(AF_INET6, buf2, &in6a) <= 0) + return (-1); + ShrinkBuffer(NS_IN6ADDRSZ); + memcpy(cp, &in6a, NS_IN6ADDRSZ); + cp += NS_IN6ADDRSZ; break; default: return (-1); @@ -348,14 +680,140 @@ getword_str(char *buf, int size, u_char **startpp, u_char *endp) { } /* - * Get a whitespace delimited number from a string (not file) into buf + * get a white spae delimited string from memory. Process quoted strings + * and \DDD escapes. Return length or -1 on error. Returned string may + * contain nulls. + */ +static char digits[] = "0123456789"; +static int +getstr_str(char *buf, int size, u_char **startpp, u_char *endp) { + char *cp; + int c, c1 = 0; + int inquote = 0; + int seen_quote = 0; + int escape = 0; + int dig = 0; + + for (cp = buf; *startpp <= endp; ) { + if ((c = **startpp) == '\0') + break; + /* leading white space */ + if ((cp == buf) && !seen_quote && isspace(c)) { + (*startpp)++; + continue; + } + + switch (c) { + case '\\': + if (!escape) { + escape = 1; + dig = 0; + c1 = 0; + (*startpp)++; + continue; + } + goto do_escape; + case '"': + if (!escape) { + inquote = !inquote; + seen_quote = 1; + (*startpp)++; + continue; + } + /* fall through */ + default: + do_escape: + if (escape) { + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + c1 = c1 * 10 + + (strchr(digits, c) - digits); + + if (++dig == 3) { + c = c1 &0xff; + break; + } + (*startpp)++; + continue; + } + escape = 0; + } else if (!inquote && isspace(c)) + goto done; + if (cp >= buf+size-1) + goto done; + *cp++ = (u_char)c; + (*startpp)++; + } + } + done: + *cp = '\0'; + return ((cp == buf)? (seen_quote? 0: -1): (cp - buf)); +} +/* + * Get a whitespace delimited base 16 number from a string (not file) into buf + * update the start pointer to point after the number in the string. + */ +static int +gethexnum_str(u_char **startpp, u_char *endp) { + int c, n; + int seendigit = 0; + int m = 0; + + if (*startpp + 2 >= endp || strncasecmp((char *)*startpp, "0x", 2) != 0) + return getnum_str(startpp, endp); + (*startpp)+=2; + for (n = 0; *startpp <= endp; ) { + c = **startpp; + if (isspace(c) || c == '\0') { + if (seendigit) /* trailing whitespace */ + break; + else { /* leading whitespace */ + (*startpp)++; + continue; + } + } + if (c == ';') { + while ((*startpp <= endp) && + ((c = **startpp) != '\n')) + (*startpp)++; + if (seendigit) + break; + continue; + } + if (!isxdigit(c)) { + if (c == ')' && seendigit) { + (*startpp)--; + break; + } + return (-1); + } + (*startpp)++; + if (isdigit(c)) + n = n * 16 + (c - '0'); + else + n = n * 16 + (tolower(c) - 'a' + 10); + seendigit = 1; + } + return (n + m); +} + +/* + * Get a whitespace delimited base 16 number from a string (not file) into buf * update the start pointer to point after the number in the string. */ static int getnum_str(u_char **startpp, u_char *endp) { int c, n; int seendigit = 0; - int seendecimal = 0; int m = 0; for (n = 0; *startpp <= endp; ) { @@ -398,8 +856,11 @@ res_mkupdrec(int section, const char *dname, u_int class, u_int type, u_long ttl) { ns_updrec *rrecp = (ns_updrec *)calloc(1, sizeof(ns_updrec)); - if (!rrecp || !(rrecp->r_dname = strdup(dname))) + if (!rrecp || !(rrecp->r_dname = strdup(dname))) { + if (rrecp) + free((char *)rrecp); return (NULL); + } rrecp->r_class = class; rrecp->r_type = type; rrecp->r_ttl = ttl; @@ -417,3 +878,221 @@ res_freeupdrec(ns_updrec *rrecp) { free(rrecp->r_dname); free(rrecp); } + +struct valuelist { + struct valuelist * next; + struct valuelist * prev; + char * name; + char * proto; + int port; +}; +static struct valuelist *servicelist, *protolist; + +void +res_buildservicelist() { + struct servent *sp; + struct valuelist *slp; + +#ifdef MAYBE_HESIOD + setservent(0); +#else + setservent(1); +#endif + while ((sp = getservent()) != NULL) { + slp = (struct valuelist *)malloc(sizeof(struct valuelist)); + if (!slp) + break; + slp->name = strdup(sp->s_name); + slp->proto = strdup(sp->s_proto); + if ((slp->name == NULL) || (slp->proto == NULL)) { + if (slp->name) free(slp->name); + if (slp->proto) free(slp->proto); + free(slp); + break; + } + slp->port = ntohs((u_int16_t)sp->s_port); /* host byt order */ + slp->next = servicelist; + slp->prev = NULL; + if (servicelist) + servicelist->prev = slp; + servicelist = slp; + } + endservent(); +} + +void +res_destroyservicelist() { + struct valuelist *slp, *slp_next; + + for (slp = servicelist; slp != NULL; slp = slp_next) { + slp_next = slp->next; + free(slp->name); + free(slp->proto); + free(slp); + } + servicelist = (struct valuelist *)0; +} + +void +res_buildprotolist() { + struct protoent *pp; + struct valuelist *slp; + +#ifdef MAYBE_HESIOD + setprotoent(0); +#else + setprotoent(1); +#endif + while ((pp = getprotoent()) != NULL) { + slp = (struct valuelist *)malloc(sizeof(struct valuelist)); + if (!slp) + break; + slp->name = strdup(pp->p_name); + if (slp->name == NULL) { + free(slp); + break; + } + slp->port = pp->p_proto; /* host byte order */ + slp->next = protolist; + slp->prev = NULL; + if (protolist) + protolist->prev = slp; + protolist = slp; + } + endprotoent(); +} + +void +res_destroyprotolist() { + struct valuelist *plp, *plp_next; + + for (plp = protolist; plp != NULL; plp = plp_next) { + plp_next = plp->next; + free(plp->name); + free(plp); + } + protolist = (struct valuelist *)0; +} + +static int +findservice(const char *s, struct valuelist **list) { + struct valuelist *lp = *list; + int n; + + for (; lp != NULL; lp = lp->next) + if (strcasecmp(lp->name, s) == 0) { + if (lp != *list) { + lp->prev->next = lp->next; + if (lp->next) + lp->next->prev = lp->prev; + (*list)->prev = lp; + lp->next = *list; + *list = lp; + } + return (lp->port); /* host byte order */ + } + if (sscanf(s, "%d", &n) != 1 || n <= 0) + n = -1; + return (n); +} + +/* + * Convert service name or (ascii) number to int. + */ +int +res_servicenumber(const char *p) { + if (servicelist == (struct valuelist *)0) + res_buildservicelist(); + return (findservice(p, &servicelist)); +} + +/* + * Convert protocol name or (ascii) number to int. + */ +int +res_protocolnumber(const char *p) { + if (protolist == (struct valuelist *)0) + res_buildprotolist(); + return (findservice(p, &protolist)); +} + +static struct servent * +cgetservbyport(u_int16_t port, const char *proto) { /* Host byte order. */ + struct valuelist **list = &servicelist; + struct valuelist *lp = *list; + static struct servent serv; + + port = ntohs(port); + for (; lp != NULL; lp = lp->next) { + if (port != (u_int16_t)lp->port) /* Host byte order. */ + continue; + if (strcasecmp(lp->proto, proto) == 0) { + if (lp != *list) { + lp->prev->next = lp->next; + if (lp->next) + lp->next->prev = lp->prev; + (*list)->prev = lp; + lp->next = *list; + *list = lp; + } + serv.s_name = lp->name; + serv.s_port = htons((u_int16_t)lp->port); + serv.s_proto = lp->proto; + return (&serv); + } + } + return (0); +} + +static struct protoent * +cgetprotobynumber(int proto) { /* Host byte order. */ + struct valuelist **list = &protolist; + struct valuelist *lp = *list; + static struct protoent prot; + + for (; lp != NULL; lp = lp->next) + if (lp->port == proto) { /* Host byte order. */ + if (lp != *list) { + lp->prev->next = lp->next; + if (lp->next) + lp->next->prev = lp->prev; + (*list)->prev = lp; + lp->next = *list; + *list = lp; + } + prot.p_name = lp->name; + prot.p_proto = lp->port; /* Host byte order. */ + return (&prot); + } + return (0); +} + +const char * +res_protocolname(int num) { + static char number[8]; + struct protoent *pp; + + if (protolist == (struct valuelist *)0) + res_buildprotolist(); + pp = cgetprotobynumber(num); + if (pp == 0) { + (void) sprintf(number, "%d", num); + return (number); + } + return (pp->p_name); +} + +const char * +res_servicename(u_int16_t port, const char *proto) { /* Host byte order. */ + static char number[8]; + struct servent *ss; + + if (servicelist == (struct valuelist *)0) + res_buildservicelist(); + ss = cgetservbyport(htons(port), proto); + if (ss == 0) { + (void) sprintf(number, "%d", port); + return (number); + } + return (ss->s_name); +} diff --git a/contrib/bind/lib/resolv/res_mkupdate.h b/contrib/bind/lib/resolv/res_mkupdate.h index eb2be3f..48edf63 100644 --- a/contrib/bind/lib/resolv/res_mkupdate.h +++ b/contrib/bind/lib/resolv/res_mkupdate.h @@ -1,3 +1,20 @@ +/* + * Copyright (c) 1998,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + #ifndef _RES_MKUPDATE_H_ #define _RES_MKUPDATE_H_ diff --git a/contrib/bind/lib/resolv/res_query.c b/contrib/bind/lib/resolv/res_query.c index aeef49d..26c1a60 100644 --- a/contrib/bind/lib/resolv/res_query.c +++ b/contrib/bind/lib/resolv/res_query.c @@ -52,7 +52,7 @@ */ /* - * Portions Copyright (c) 1996 by Internet Software Consortium. + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -69,8 +69,8 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)res_query.c 8.1 (Berkeley) 6/4/93"; -static char rcsid[] = "$Id: res_query.c,v 8.14 1997/06/09 17:47:05 halley Exp $"; +static const char sccsid[] = "@(#)res_query.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "$Id: res_query.c,v 8.19 1999/10/15 19:49:11 vixie Exp $"; #endif /* LIBC_SCCS and not lint */ #include "port_before.h" @@ -103,16 +103,16 @@ static char rcsid[] = "$Id: res_query.c,v 8.14 1997/06/09 17:47:05 halley Exp $" * Perform preliminary check of answer, returning success only * if no error is indicated and the answer count is nonzero. * Return the size of the response on success, -1 on error. - * Error number is left in h_errno. + * Error number is left in H_ERRNO. * * Caller must parse answer and determine whether it answers the question. */ int -res_query(name, class, type, answer, anslen) - const char *name; /* domain name */ - int class, type; /* class and type of query */ - u_char *answer; /* buffer to put answer */ - int anslen; /* size of answer buffer */ +res_nquery(res_state statp, + const char *name, /* domain name */ + int class, int type, /* class and type of query */ + u_char *answer, /* buffer to put answer */ + int anslen) /* size of answer buffer */ { u_char buf[MAXPACKET]; HEADER *hp = (HEADER *) answer; @@ -120,56 +120,52 @@ res_query(name, class, type, answer, anslen) hp->rcode = NOERROR; /* default */ - if ((_res.options & RES_INIT) == 0 && res_init() == -1) { - h_errno = NETDB_INTERNAL; - return (-1); - } #ifdef DEBUG - if (_res.options & RES_DEBUG) + if (statp->options & RES_DEBUG) printf(";; res_query(%s, %d, %d)\n", name, class, type); #endif - n = res_mkquery(QUERY, name, class, type, NULL, 0, NULL, - buf, sizeof(buf)); + n = res_nmkquery(statp, QUERY, name, class, type, NULL, 0, NULL, + buf, sizeof(buf)); if (n <= 0) { #ifdef DEBUG - if (_res.options & RES_DEBUG) + if (statp->options & RES_DEBUG) printf(";; res_query: mkquery failed\n"); #endif - h_errno = NO_RECOVERY; + RES_SET_H_ERRNO(statp, NO_RECOVERY); return (n); } - n = res_send(buf, n, answer, anslen); + n = res_nsend(statp, buf, n, answer, anslen); if (n < 0) { #ifdef DEBUG - if (_res.options & RES_DEBUG) + if (statp->options & RES_DEBUG) printf(";; res_query: send error\n"); #endif - h_errno = TRY_AGAIN; + RES_SET_H_ERRNO(statp, TRY_AGAIN); return (n); } if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { #ifdef DEBUG - if (_res.options & RES_DEBUG) + if (statp->options & RES_DEBUG) printf(";; rcode = %d, ancount=%d\n", hp->rcode, ntohs(hp->ancount)); #endif switch (hp->rcode) { case NXDOMAIN: - h_errno = HOST_NOT_FOUND; + RES_SET_H_ERRNO(statp, HOST_NOT_FOUND); break; case SERVFAIL: - h_errno = TRY_AGAIN; + RES_SET_H_ERRNO(statp, TRY_AGAIN); break; case NOERROR: - h_errno = NO_DATA; + RES_SET_H_ERRNO(statp, NO_DATA); break; case FORMERR: case NOTIMP: case REFUSED: default: - h_errno = NO_RECOVERY; + RES_SET_H_ERRNO(statp, NO_RECOVERY); break; } return (-1); @@ -181,50 +177,43 @@ res_query(name, class, type, answer, anslen) * Formulate a normal query, send, and retrieve answer in supplied buffer. * Return the size of the response on success, -1 on error. * If enabled, implement search rules until answer or unrecoverable failure - * is detected. Error code, if any, is left in h_errno. + * is detected. Error code, if any, is left in H_ERRNO. */ int -res_search(name, class, type, answer, anslen) - const char *name; /* domain name */ - int class, type; /* class and type of query */ - u_char *answer; /* buffer to put answer */ - int anslen; /* size of answer */ +res_nsearch(res_state statp, + const char *name, /* domain name */ + int class, int type, /* class and type of query */ + u_char *answer, /* buffer to put answer */ + int anslen) /* size of answer */ { const char *cp, * const *domain; HEADER *hp = (HEADER *) answer; + char tmp[NS_MAXDNAME]; u_int dots; - int trailing_dot, ret, saved_herrno; - int got_nodata = 0, got_servfail = 0, tried_as_is = 0; + int trailing_dot, ret; + int got_nodata = 0, got_servfail = 0, root_on_list = 0; - if ((_res.options & RES_INIT) == 0 && res_init() == -1) { - h_errno = NETDB_INTERNAL; - return (-1); - } errno = 0; - h_errno = HOST_NOT_FOUND; /* default, if we never query */ + RES_SET_H_ERRNO(statp, HOST_NOT_FOUND); /* True if we never query. */ + dots = 0; - for (cp = name; *cp; cp++) + for (cp = name; *cp != '\0'; cp++) dots += (*cp == '.'); trailing_dot = 0; if (cp > name && *--cp == '.') trailing_dot++; /* If there aren't any dots, it could be a user-level alias. */ - if (!dots && (cp = hostalias(name)) != NULL) - return (res_query(cp, class, type, answer, anslen)); + if (!dots && (cp = res_hostalias(statp, name, tmp, sizeof tmp))!= NULL) + return (res_nquery(statp, cp, class, type, answer, anslen)); /* - * If there are dots in the name already, let's just give it a try - * 'as is'. The threshold can be set with the "ndots" option. + * If there are enough dots in the name, do no searching. + * (The threshold can be set with the "ndots" option.) */ - saved_herrno = -1; - if (dots >= _res.ndots) { - ret = res_querydomain(name, NULL, class, type, answer, anslen); - if (ret > 0) - return (ret); - saved_herrno = h_errno; - tried_as_is++; - } + if (dots >= statp->ndots || trailing_dot) + return (res_nquerydomain(statp, name, NULL, class, type, + answer, anslen)); /* * We do at least one level of search if @@ -232,16 +221,21 @@ res_search(name, class, type, answer, anslen) * - there is at least one dot, there is no trailing dot, * and RES_DNSRCH is set. */ - if ((!dots && (_res.options & RES_DEFNAMES)) || - (dots && !trailing_dot && (_res.options & RES_DNSRCH))) { + if ((!dots && (statp->options & RES_DEFNAMES) != 0) || + (dots && !trailing_dot && (statp->options & RES_DNSRCH) != 0)) { int done = 0; - for (domain = (const char * const *)_res.dnsrch; + for (domain = (const char * const *)statp->dnsrch; *domain && !done; domain++) { - ret = res_querydomain(name, *domain, class, type, - answer, anslen); + if (domain[0][0] == '\0' || + (domain[0][0] == '.' && domain[0][1] == '\0')) + root_on_list++; + + ret = res_nquerydomain(statp, name, *domain, + class, type, + answer, anslen); if (ret > 0) return (ret); @@ -259,11 +253,11 @@ res_search(name, class, type, answer, anslen) * fully-qualified. */ if (errno == ECONNREFUSED) { - h_errno = TRY_AGAIN; + RES_SET_H_ERRNO(statp, TRY_AGAIN); return (-1); } - switch (h_errno) { + switch (statp->res_h_errno) { case NO_DATA: got_nodata++; /* FALLTHROUGH */ @@ -285,35 +279,33 @@ res_search(name, class, type, answer, anslen) /* if we got here for some reason other than DNSRCH, * we only wanted one iteration of the loop, so stop. */ - if (!(_res.options & RES_DNSRCH)) + if ((statp->options & RES_DNSRCH) == 0) done++; } } /* - * If we have not already tried the name "as is", do that now. - * note that we do this regardless of how many dots were in the - * name or whether it ends with a dot. + * If the name has any dots at all, and "." is not on the search + * list, then try an as-is query now. */ - if (!tried_as_is) { - ret = res_querydomain(name, NULL, class, type, answer, anslen); + if (statp->ndots) { + ret = res_nquerydomain(statp, name, NULL, class, type, + answer, anslen); if (ret > 0) return (ret); } /* if we got here, we didn't satisfy the search. - * if we did an initial full query, return that query's h_errno + * if we did an initial full query, return that query's H_ERRNO * (note that we wouldn't be here if that query had succeeded). * else if we ever got a nodata, send that back as the reason. - * else send back meaningless h_errno, that being the one from + * else send back meaningless H_ERRNO, that being the one from * the last DNSRCH we did. */ - if (saved_herrno != -1) - h_errno = saved_herrno; - else if (got_nodata) - h_errno = NO_DATA; + if (got_nodata) + RES_SET_H_ERRNO(statp, NO_DATA); else if (got_servfail) - h_errno = TRY_AGAIN; + RES_SET_H_ERRNO(statp, TRY_AGAIN); return (-1); } @@ -322,23 +314,20 @@ res_search(name, class, type, answer, anslen) * removing a trailing dot from name if domain is NULL. */ int -res_querydomain(name, domain, class, type, answer, anslen) - const char *name, *domain; - int class, type; /* class and type of query */ - u_char *answer; /* buffer to put answer */ - int anslen; /* size of answer */ +res_nquerydomain(res_state statp, + const char *name, + const char *domain, + int class, int type, /* class and type of query */ + u_char *answer, /* buffer to put answer */ + int anslen) /* size of answer */ { char nbuf[MAXDNAME]; const char *longname = nbuf; int n, d; - if ((_res.options & RES_INIT) == 0 && res_init() == -1) { - h_errno = NETDB_INTERNAL; - return (-1); - } #ifdef DEBUG - if (_res.options & RES_DEBUG) - printf(";; res_querydomain(%s, %s, %d, %d)\n", + if (statp->options & RES_DEBUG) + printf(";; res_nquerydomain(%s, %s, %d, %d)\n", name, domain?domain:"<Nil>", class, type); #endif if (domain == NULL) { @@ -348,7 +337,7 @@ res_querydomain(name, domain, class, type, answer, anslen) */ n = strlen(name); if (n >= MAXDNAME) { - h_errno = NO_RECOVERY; + RES_SET_H_ERRNO(statp, NO_RECOVERY); return (-1); } n--; @@ -361,23 +350,21 @@ res_querydomain(name, domain, class, type, answer, anslen) n = strlen(name); d = strlen(domain); if (n + d + 1 >= MAXDNAME) { - h_errno = NO_RECOVERY; + RES_SET_H_ERRNO(statp, NO_RECOVERY); return (-1); } sprintf(nbuf, "%s.%s", name, domain); } - return (res_query(longname, class, type, answer, anslen)); + return (res_nquery(statp, longname, class, type, answer, anslen)); } const char * -hostalias(const char *name) { - char *cp1, *cp2; - FILE *fp; - char *file; +res_hostalias(const res_state statp, const char *name, char *dst, size_t siz) { + char *file, *cp1, *cp2; char buf[BUFSIZ]; - static char abuf[MAXDNAME]; + FILE *fp; - if (_res.options & RES_NOALIASES) + if (statp->options & RES_NOALIASES) return (NULL); file = getenv("HOSTALIASES"); if (file == NULL || (fp = fopen(file, "r")) == NULL) @@ -390,17 +377,18 @@ hostalias(const char *name) { if (!*cp1) break; *cp1 = '\0'; - if (!strcasecmp(buf, name)) { + if (ns_samename(buf, name) == 1) { while (isspace(*++cp1)) ; if (!*cp1) break; for (cp2 = cp1 + 1; *cp2 && !isspace(*cp2); ++cp2) ; - abuf[sizeof(abuf) - 1] = *cp2 = '\0'; - strncpy(abuf, cp1, sizeof(abuf) - 1); + *cp2 = '\0'; + strncpy(dst, cp1, siz - 1); + dst[siz - 1] = '\0'; fclose(fp); - return (abuf); + return (dst); } } fclose(fp); diff --git a/contrib/bind/lib/resolv/res_send.c b/contrib/bind/lib/resolv/res_send.c index f8ac77b..80c9e44 100644 --- a/contrib/bind/lib/resolv/res_send.c +++ b/contrib/bind/lib/resolv/res_send.c @@ -52,7 +52,7 @@ */ /* - * Portions Copyright (c) 1996 by Internet Software Consortium. + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -69,8 +69,8 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93"; -static char rcsid[] = "$Id: res_send.c,v 8.20 1998/04/06 23:27:51 halley Exp $"; +static const char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "$Id: res_send.c,v 8.36 1999/10/15 19:49:11 vixie Exp $"; #endif /* LIBC_SCCS and not lint */ /* @@ -93,78 +93,60 @@ static char rcsid[] = "$Id: res_send.c,v 8.20 1998/04/06 23:27:51 halley Exp $"; #include <errno.h> #include <netdb.h> #include <resolv.h> +#include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> +#include <isc/eventlib.h> + #include "port_after.h" /* Options. Leave them on. */ #define DEBUG -#define CHECK_SRVR_ADDR - -static int s = -1; /* socket used for communications */ -static int connected = 0; /* is the socket connected */ -static int vc = 0; /* is the socket a virtual circuit? */ -static res_send_qhook Qhook = NULL; -static res_send_rhook Rhook = NULL; +#include "res_debug.h" +#ifdef NEED_PSELECT +static int pselect(int, void *, void *, void *, + struct timespec *, + const sigset_t *); +#endif -#ifndef DEBUG -# define Dprint(cond, args) /*empty*/ -# define DprintQ(cond, args, query, size) /*empty*/ -# define Aerror(file, string, error, address) /*empty*/ -# define Perror(file, string, error) /*empty*/ -#else -# define Dprint(cond, args) if (cond) {fprintf args;} else {} -# define DprintQ(cond, args, query, size) if (cond) {\ - fprintf args;\ - __fp_nquery(query, size, stdout);\ - } else {} +#define CHECK_SRVR_ADDR + +#ifdef DEBUG static void - Aerror(file, string, error, address) - FILE *file; - char *string; - int error; - struct sockaddr_in address; + Aerror(const res_state statp, FILE *file, const char *string, int error, + struct sockaddr_in address) { int save = errno; - if (_res.options & RES_DEBUG) { + if ((statp->options & RES_DEBUG) != 0) { + char tmp[sizeof "255.255.255.255"]; + fprintf(file, "res_send: %s ([%s].%u): %s\n", string, - inet_ntoa(address.sin_addr), + inet_ntop(address.sin_family, &address.sin_addr, + tmp, sizeof tmp), ntohs(address.sin_port), strerror(error)); } errno = save; } static void - Perror(file, string, error) - FILE *file; - char *string; - int error; - { + Perror(const res_state statp, FILE *file, const char *string, int error) { int save = errno; - if (_res.options & RES_DEBUG) { + if ((statp->options & RES_DEBUG) != 0) fprintf(file, "res_send: %s: %s\n", string, strerror(error)); - } errno = save; } #endif -void -res_send_setqhook(res_send_qhook hook) { - Qhook = hook; -} - -void -res_send_setrhook(res_send_rhook hook) { - Rhook = hook; -} +static int cmpsock(struct sockaddr_in *a1, struct sockaddr_in *a2); +void res_pquery(const res_state, const u_char *, int, FILE *); /* int * res_isourserver(ina) @@ -176,24 +158,21 @@ res_send_setrhook(res_send_rhook hook) { * paul vixie, 29may94 */ int -res_isourserver(const struct sockaddr_in *inp) { +res_ourserver_p(const res_state statp, const struct sockaddr_in *inp) { struct sockaddr_in ina; - int ns, ret; + int ns; ina = *inp; - ret = 0; - for (ns = 0; ns < _res.nscount; ns++) { - const struct sockaddr_in *srv = &_res.nsaddr_list[ns]; + for (ns = 0; ns < statp->nscount; ns++) { + const struct sockaddr_in *srv = &statp->nsaddr_list[ns]; if (srv->sin_family == ina.sin_family && srv->sin_port == ina.sin_port && (srv->sin_addr.s_addr == INADDR_ANY || - srv->sin_addr.s_addr == ina.sin_addr.s_addr)) { - ret++; - break; - } + srv->sin_addr.s_addr == ina.sin_addr.s_addr)) + return (1); } - return (ret); + return (0); } /* int @@ -227,9 +206,8 @@ res_nameinquery(const char *name, int type, int class, return (-1); ttype = ns_get16(cp); cp += INT16SZ; tclass = ns_get16(cp); cp += INT16SZ; - if (ttype == type && - tclass == class && - strcasecmp(tname, name) == 0) + if (ttype == type && tclass == class && + ns_samename(tname, name) == 1) return (1); } return (0); @@ -285,54 +263,66 @@ res_queriesmatch(const u_char *buf1, const u_char *eom1, } int -res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { +res_nsend(res_state statp, + const u_char *buf, int buflen, u_char *ans, int anssiz) +{ HEADER *hp = (HEADER *) buf; HEADER *anhp = (HEADER *) ans; int gotsomewhere, connreset, terrno, try, v_circuit, resplen, ns, n; u_int badns; /* XXX NSMAX can't exceed #/bits in this variable */ + static int highestFD = FD_SETSIZE - 1; - if ((_res.options & RES_INIT) == 0 && res_init() == -1) { - /* errno should have been set by res_init() in this case. */ - return (-1); - } if (anssiz < HFIXEDSZ) { errno = EINVAL; return (-1); } - DprintQ((_res.options & RES_DEBUG) || (_res.pfcode & RES_PRF_QUERY), + DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY), (stdout, ";; res_send()\n"), buf, buflen); - v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ; + v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ; gotsomewhere = 0; connreset = 0; terrno = ETIMEDOUT; badns = 0; /* + * Some callers want to even out the load on their resolver list. + */ + if (statp->nscount > 0 && (statp->options & RES_ROTATE) != 0) { + struct sockaddr_in ina; + int lastns = statp->nscount - 1; + + ina = statp->nsaddr_list[0]; + for (ns = 0; ns < lastns; ns++) + statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1]; + statp->nsaddr_list[lastns] = ina; + } + + /* * Send request, RETRY times, or until successful */ - for (try = 0; try < _res.retry; try++) { - for (ns = 0; ns < _res.nscount; ns++) { - struct sockaddr_in *nsap = &_res.nsaddr_list[ns]; + for (try = 0; try < statp->retry; try++) { + for (ns = 0; ns < statp->nscount; ns++) { + struct sockaddr_in *nsap = &statp->nsaddr_list[ns]; same_ns: if (badns & (1 << ns)) { - res_close(); + res_nclose(statp); goto next_ns; } - if (Qhook) { + if (statp->qhook) { int done = 0, loops = 0; do { res_sendhookact act; - act = (*Qhook)(&nsap, &buf, &buflen, - ans, anssiz, &resplen); + act = (*statp->qhook)(&nsap, &buf, &buflen, + ans, anssiz, &resplen); switch (act) { case res_goahead: done = 1; break; case res_nextns: - res_close(); + res_nclose(statp); goto next_ns; case res_done: return (resplen); @@ -349,7 +339,7 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { } while (!done); } - Dprint(_res.options & RES_DEBUG, + Dprint(statp->options & RES_DEBUG, (stdout, ";; Querying server (# %d) address = %s\n", ns + 1, inet_ntoa(nsap->sin_addr))); @@ -359,33 +349,53 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { u_short len; u_char *cp; - /* - * Use virtual circuit; - * at most one attempt per server. - */ - try = _res.retry; + /* Use VC; at most one attempt per server. */ + try = statp->retry; truncated = 0; - if (s < 0 || !vc || hp->opcode == ns_o_update) { - if (s >= 0) - res_close(); - s = socket(PF_INET, SOCK_STREAM, 0); - if (s < 0) { + /* Are we still talking to whom we want to talk to? */ + if (statp->_sock >= 0 && + (statp->_flags & RES_F_VC) != 0) { + struct sockaddr_in peer; + int size = sizeof(peer); + + if (getpeername(statp->_sock, + (struct sockaddr *)&peer, + &size) < 0) { + res_nclose(statp); + statp->_flags &= ~RES_F_VC; + } else if (!cmpsock(&peer, nsap)) { + res_nclose(statp); + statp->_flags &= ~RES_F_VC; + } + } + + if (statp->_sock < 0 || + (statp->_flags & RES_F_VC) == 0) { + if (statp->_sock >= 0) + res_nclose(statp); + + statp->_sock = socket(PF_INET, + SOCK_STREAM, 0); + if (statp->_sock < 0 || + statp->_sock > highestFD) { terrno = errno; - Perror(stderr, "socket(vc)", errno); + Perror(statp, stderr, + "socket(vc)", errno); return (-1); } errno = 0; - if (connect(s, (struct sockaddr *)nsap, + if (connect(statp->_sock, + (struct sockaddr *)nsap, sizeof *nsap) < 0) { terrno = errno; - Aerror(stderr, "connect/vc", + Aerror(statp, stderr, "connect/vc", errno, *nsap); badns |= (1 << ns); - res_close(); + res_nclose(statp); goto next_ns; } - vc = 1; + statp->_flags |= RES_F_VC; } /* * Send length & message @@ -395,11 +405,12 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { iov[0].iov_len = INT16SZ; iov[1].iov_base = (caddr_t)buf; iov[1].iov_len = buflen; - if (writev(s, iov, 2) != (INT16SZ + buflen)) { + if (writev(statp->_sock, iov, 2) != + (INT16SZ + buflen)) { terrno = errno; - Perror(stderr, "write failed", errno); + Perror(statp, stderr, "write failed", errno); badns |= (1 << ns); - res_close(); + res_nclose(statp); goto next_ns; } /* @@ -408,15 +419,16 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { read_len: cp = ans; len = INT16SZ; - while ((n = read(s, (char *)cp, (int)len)) > 0) { + while ((n = read(statp->_sock, + (char *)cp, (int)len)) > 0) { cp += n; if ((len -= n) <= 0) break; } if (n <= 0) { terrno = errno; - Perror(stderr, "read failed", errno); - res_close(); + Perror(statp, stderr, "read failed", errno); + res_nclose(statp); /* * A long running process might get its TCP * connection reset if the remote server was @@ -428,15 +440,15 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { */ if (terrno == ECONNRESET && !connreset) { connreset = 1; - res_close(); + res_nclose(statp); goto same_ns; } - res_close(); + res_nclose(statp); goto next_ns; } resplen = ns_get16(ans); if (resplen > anssiz) { - Dprint(_res.options & RES_DEBUG, + Dprint(statp->options & RES_DEBUG, (stdout, ";; response truncated\n") ); truncated = 1; @@ -447,23 +459,24 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { /* * Undersized message. */ - Dprint(_res.options & RES_DEBUG, + Dprint(statp->options & RES_DEBUG, (stdout, ";; undersized: %d\n", len)); terrno = EMSGSIZE; badns |= (1 << ns); - res_close(); + res_nclose(statp); goto next_ns; } cp = ans; while (len != 0 && - (n = read(s, (char *)cp, (int)len)) > 0) { + (n = read(statp->_sock, (char *)cp, (int)len)) + > 0) { cp += n; len -= n; } if (n <= 0) { terrno = errno; - Perror(stderr, "read(vc)", errno); - res_close(); + Perror(statp, stderr, "read(vc)", errno); + res_nclose(statp); goto next_ns; } if (truncated) { @@ -479,7 +492,8 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { n = (len > sizeof(junk) ? sizeof(junk) : len); - if ((n = read(s, junk, n)) > 0) + n = read(statp->_sock, junk, n); + if (n > 0) len -= n; else break; @@ -493,8 +507,8 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { * wait for the correct one. */ if (hp->id != anhp->id) { - DprintQ((_res.options & RES_DEBUG) || - (_res.pfcode & RES_PRF_REPLY), + DprintQ((statp->options & RES_DEBUG) || + (statp->pfcode & RES_PRF_REPLY), (stdout, ";; old answer (unexpected):\n"), ans, (resplen>anssiz)?anssiz:resplen); goto read_len; @@ -503,24 +517,27 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { /* * Use datagrams. */ - struct timeval timeout; + struct timespec start, timeout, finish; fd_set dsmask; struct sockaddr_in from; - int fromlen; - - if ((s < 0) || vc) { - if (vc) - res_close(); - s = socket(PF_INET, SOCK_DGRAM, 0); - if (s < 0) { + int fromlen, seconds; + + if (statp->_sock < 0 || + (statp->_flags & RES_F_VC) != 0) { + if ((statp->_flags & RES_F_VC) != 0) + res_nclose(statp); + statp->_sock = socket(PF_INET, SOCK_DGRAM, 0); + if (statp->_sock < 0 || + statp->_sock > highestFD) { #ifndef CAN_RECONNECT bad_dg_sock: #endif terrno = errno; - Perror(stderr, "socket(dg)", errno); + Perror(statp, stderr, + "socket(dg)", errno); return (-1); } - connected = 0; + statp->_flags &= ~RES_F_CONN; } #ifndef CANNOT_CONNECT_DGRAM /* @@ -538,28 +555,29 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { * as we wish to receive answers from the first * server to respond. */ - if (_res.nscount == 1 || (try == 0 && ns == 0)) { + if (statp->nscount == 1 || (try == 0 && ns == 0)) { /* * Connect only if we are sure we won't * receive a response from another server. */ - if (!connected) { - if (connect(s, (struct sockaddr *)nsap, - sizeof *nsap - ) < 0) { - Aerror(stderr, + if ((statp->_flags & RES_F_CONN) == 0) { + if (connect(statp->_sock, + (struct sockaddr *)nsap, + sizeof *nsap) < 0) { + Aerror(statp, stderr, "connect(dg)", errno, *nsap); badns |= (1 << ns); - res_close(); + res_nclose(statp); goto next_ns; } - connected = 1; + statp->_flags |= RES_F_CONN; } - if (send(s, (char*)buf, buflen, 0) != buflen) { - Perror(stderr, "send", errno); + if (send(statp->_sock, (char*)buf, buflen, 0) + != buflen) { + Perror(statp, stderr, "send", errno); badns |= (1 << ns); - res_close(); + res_nclose(statp); goto next_ns; } } else { @@ -567,86 +585,115 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { * Disconnect if we want to listen * for responses from more than one server. */ - if (connected) { + if ((statp->_flags & RES_F_CONN) != 0) { #ifdef CAN_RECONNECT struct sockaddr_in no_addr; no_addr.sin_family = AF_INET; no_addr.sin_addr.s_addr = INADDR_ANY; no_addr.sin_port = 0; - (void) connect(s, + (void) connect(statp->_sock, (struct sockaddr *) &no_addr, sizeof no_addr); #else - int s1 = socket(PF_INET, SOCK_DGRAM,0); + struct sockaddr_in local_addr; + int len, result, s1; + + len = sizeof(local_addr); + s1 = socket(PF_INET, SOCK_DGRAM, 0); + result = getsockname(statp->_sock, + (struct sockaddr *)&local_addr, + &len); if (s1 < 0) goto bad_dg_sock; - (void) dup2(s1, s); + (void) dup2(s1, statp->_sock); (void) close(s1); - Dprint(_res.options & RES_DEBUG, + if (result == 0) { + /* + * Attempt to rebind to old + * port. Note connected socket + * has an sin_addr set. + */ + local_addr.sin_addr.s_addr = + htonl(0); + (void)bind(statp->_sock, + (struct sockaddr *) + &local_addr, len); + } + Dprint(statp->options & RES_DEBUG, (stdout, ";; new DG socket\n")) #endif /* CAN_RECONNECT */ - connected = 0; + statp->_flags &= ~RES_F_CONN; errno = 0; } #endif /* !CANNOT_CONNECT_DGRAM */ - if (sendto(s, (char*)buf, buflen, 0, + if (sendto(statp->_sock, + (char*)buf, buflen, 0, (struct sockaddr *)nsap, sizeof *nsap) != buflen) { - Aerror(stderr, "sendto", errno, *nsap); + Aerror(statp, stderr, "sendto", errno, *nsap); badns |= (1 << ns); - res_close(); + res_nclose(statp); goto next_ns; } #ifndef CANNOT_CONNECT_DGRAM } #endif /* !CANNOT_CONNECT_DGRAM */ + if (statp->_sock < 0 || statp->_sock > highestFD) { + Perror(statp, stderr, + "fd out-of-bounds", EMFILE); + res_nclose(statp); + goto next_ns; + } + /* * Wait for reply */ - timeout.tv_sec = (_res.retrans << try); + seconds = (statp->retrans << try); if (try > 0) - timeout.tv_sec /= _res.nscount; - if ((long) timeout.tv_sec <= 0) - timeout.tv_sec = 1; - timeout.tv_usec = 0; + seconds /= statp->nscount; + if (seconds <= 0) + seconds = 1; + start = evNowTime(); + timeout = evConsTime(seconds, 0); + finish = evAddTime(start, timeout); wait: - if (s < 0 || s >= FD_SETSIZE) { - Perror(stderr, "s out-of-bounds", EMFILE); - res_close(); - goto next_ns; - } FD_ZERO(&dsmask); - FD_SET(s, &dsmask); - n = select(s+1, &dsmask, (fd_set *)NULL, - (fd_set *)NULL, &timeout); - if (n < 0) { - if (errno == EINTR) - goto wait; - Perror(stderr, "select", errno); - res_close(); - goto next_ns; - } + FD_SET(statp->_sock, &dsmask); + n = pselect(statp->_sock + 1, + &dsmask, NULL, NULL, + &timeout, NULL); if (n == 0) { - /* - * timeout - */ - Dprint(_res.options & RES_DEBUG, + Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n")); gotsomewhere = 1; - res_close(); + goto next_ns; + } + if (n < 0) { + if (errno == EINTR) { + struct timespec now; + + now = evNowTime(); + if (evCmpTime(finish, now) >= 0) { + timeout = evSubTime(finish, + now); + goto wait; + } + } + Perror(statp, stderr, "select", errno); + res_nclose(statp); goto next_ns; } errno = 0; fromlen = sizeof(struct sockaddr_in); - resplen = recvfrom(s, (char*)ans, anssiz, 0, + resplen = recvfrom(statp->_sock, (char*)ans, anssiz,0, (struct sockaddr *)&from, &fromlen); if (resplen <= 0) { - Perror(stderr, "recvfrom", errno); - res_close(); + Perror(statp, stderr, "recvfrom", errno); + res_nclose(statp); goto next_ns; } gotsomewhere = 1; @@ -654,12 +701,12 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { /* * Undersized message. */ - Dprint(_res.options & RES_DEBUG, + Dprint(statp->options & RES_DEBUG, (stdout, ";; undersized: %d\n", resplen)); terrno = EMSGSIZE; badns |= (1 << ns); - res_close(); + res_nclose(statp); goto next_ns; } if (hp->id != anhp->id) { @@ -668,28 +715,28 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { * XXX - potential security hazard could * be detected here. */ - DprintQ((_res.options & RES_DEBUG) || - (_res.pfcode & RES_PRF_REPLY), + DprintQ((statp->options & RES_DEBUG) || + (statp->pfcode & RES_PRF_REPLY), (stdout, ";; old answer:\n"), ans, (resplen>anssiz)?anssiz:resplen); goto wait; } #ifdef CHECK_SRVR_ADDR - if (!(_res.options & RES_INSECURE1) && - !res_isourserver(&from)) { + if (!(statp->options & RES_INSECURE1) && + !res_ourserver_p(statp, &from)) { /* * response from wrong server? ignore it. * XXX - potential security hazard could * be detected here. */ - DprintQ((_res.options & RES_DEBUG) || - (_res.pfcode & RES_PRF_REPLY), + DprintQ((statp->options & RES_DEBUG) || + (statp->pfcode & RES_PRF_REPLY), (stdout, ";; not our server:\n"), ans, (resplen>anssiz)?anssiz:resplen); goto wait; } #endif - if (!(_res.options & RES_INSECURE2) && + if (!(statp->options & RES_INSECURE2) && !res_queriesmatch(buf, buf + buflen, ans, ans + anssiz)) { /* @@ -697,8 +744,8 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { * XXX - potential security hazard could * be detected here. */ - DprintQ((_res.options & RES_DEBUG) || - (_res.pfcode & RES_PRF_REPLY), + DprintQ((statp->options & RES_DEBUG) || + (statp->pfcode & RES_PRF_REPLY), (stdout, ";; wrong query name:\n"), ans, (resplen>anssiz)?anssiz:resplen); goto wait; @@ -706,33 +753,33 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { if (anhp->rcode == SERVFAIL || anhp->rcode == NOTIMP || anhp->rcode == REFUSED) { - DprintQ(_res.options & RES_DEBUG, + DprintQ(statp->options & RES_DEBUG, (stdout, "server rejected query:\n"), ans, (resplen>anssiz)?anssiz:resplen); badns |= (1 << ns); - res_close(); + res_nclose(statp); /* don't retry if called from dig */ - if (!_res.pfcode) + if (!statp->pfcode) goto next_ns; } - if (!(_res.options & RES_IGNTC) && anhp->tc) { + if (!(statp->options & RES_IGNTC) && anhp->tc) { /* * get rest of answer; * use TCP with same server. */ - Dprint(_res.options & RES_DEBUG, + Dprint(statp->options & RES_DEBUG, (stdout, ";; truncated answer\n")); v_circuit = 1; - res_close(); + res_nclose(statp); goto same_ns; } } /*if vc/dg*/ - Dprint((_res.options & RES_DEBUG) || - ((_res.pfcode & RES_PRF_REPLY) && - (_res.pfcode & RES_PRF_HEAD1)), + Dprint((statp->options & RES_DEBUG) || + ((statp->pfcode & RES_PRF_REPLY) && + (statp->pfcode & RES_PRF_HEAD1)), (stdout, ";; got answer:\n")); - DprintQ((_res.options & RES_DEBUG) || - (_res.pfcode & RES_PRF_REPLY), + DprintQ((statp->options & RES_DEBUG) || + (statp->pfcode & RES_PRF_REPLY), (stdout, ""), ans, (resplen>anssiz)?anssiz:resplen); /* @@ -743,25 +790,25 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { * or if we haven't been asked to keep a socket open, * close the socket. */ - if ((v_circuit && (!(_res.options & RES_USEVC) || ns != 0)) || - !(_res.options & RES_STAYOPEN)) { - res_close(); + if ((v_circuit && (!(statp->options & RES_USEVC) || ns != 0)) || + !(statp->options & RES_STAYOPEN)) { + res_nclose(statp); } - if (Rhook) { + if (statp->rhook) { int done = 0, loops = 0; do { res_sendhookact act; - act = (*Rhook)(nsap, buf, buflen, - ans, anssiz, &resplen); + act = (*statp->rhook)(nsap, buf, buflen, + ans, anssiz, &resplen); switch (act) { case res_goahead: case res_done: done = 1; break; case res_nextns: - res_close(); + res_nclose(statp); goto next_ns; case res_modified: /* give the hook another try */ @@ -780,7 +827,7 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { next_ns: ; } /*foreach ns*/ } /*foreach retry*/ - res_close(); + res_nclose(statp); if (!v_circuit) { if (!gotsomewhere) errno = ECONNREFUSED; /* no nameservers found */ @@ -799,11 +846,45 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { * This routine is not expected to be user visible. */ void -res_close() { - if (s >= 0) { - (void) close(s); - s = -1; - connected = 0; - vc = 0; +res_nclose(res_state statp) { + if (statp->_sock >= 0) { + (void) close(statp->_sock); + statp->_sock = -1; + statp->_flags &= ~(RES_F_VC | RES_F_CONN); } } + +/* Private */ +static int +cmpsock(struct sockaddr_in *a1, struct sockaddr_in *a2) { + return ((a1->sin_family == a2->sin_family) && + (a1->sin_port == a2->sin_port) && + (a1->sin_addr.s_addr == a2->sin_addr.s_addr)); +} + +#ifdef NEED_PSELECT +/* XXX needs to move to the porting library. */ +static int +pselect(int nfds, void *rfds, void *wfds, void *efds, + struct timespec *tsp, + const sigset_t *sigmask) +{ + struct timeval tv, *tvp; + sigset_t sigs; + int n; + + if (tsp) { + tvp = &tv; + tv = evTimeVal(*tsp); + } else + tvp = NULL; + if (sigmask) + sigprocmask(SIG_SETMASK, sigmask, &sigs); + n = select(nfds, rfds, wfds, efds, tvp); + if (sigmask) + sigprocmask(SIG_SETMASK, &sigs, NULL); + if (tsp) + *tsp = evTimeSpec(tv); + return (n); +} +#endif diff --git a/contrib/bind/lib/resolv/res_sendsigned.c b/contrib/bind/lib/resolv/res_sendsigned.c new file mode 100644 index 0000000..efa463c --- /dev/null +++ b/contrib/bind/lib/resolv/res_sendsigned.c @@ -0,0 +1,130 @@ +#include "port_before.h" +#include "fd_setsize.h" + +#include <sys/types.h> +#include <sys/param.h> + +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <arpa/inet.h> + +#include <isc/dst.h> + +#include <errno.h> +#include <netdb.h> +#include <resolv.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "port_after.h" + +#define DEBUG +#include "res_debug.h" + + +/* res_nsendsigned */ +int +res_nsendsigned(res_state statp, const u_char *msg, int msglen, + ns_tsig_key *key, u_char *answer, int anslen) +{ + res_state nstatp; + DST_KEY *dstkey; + int usingTCP = 0; + u_char *newmsg; + int newmsglen, bufsize, siglen; + u_char sig[64]; + HEADER *hp; + time_t tsig_time; + int ret; + + dst_init(); + + nstatp = (res_state) malloc(sizeof(*statp)); + if (nstatp == NULL) { + errno = ENOMEM; + return (-1); + } + memcpy(nstatp, statp, sizeof(*statp)); + + bufsize = msglen + 1024; + newmsg = (u_char *) malloc(bufsize); + if (newmsg == NULL) { + errno = ENOMEM; + return (-1); + } + memcpy(newmsg, msg, msglen); + newmsglen = msglen; + + if (ns_samename(key->alg, NS_TSIG_ALG_HMAC_MD5) != 1) + dstkey = NULL; + else + dstkey = dst_buffer_to_key(key->name, KEY_HMAC_MD5, + NS_KEY_TYPE_AUTH_ONLY, + NS_KEY_PROT_ANY, + key->data, key->len); + if (dstkey == NULL) { + errno = EINVAL; + free(nstatp); + free(newmsg); + return (-1); + } + + nstatp->nscount = 1; + siglen = sizeof(sig); + ret = ns_sign(newmsg, &newmsglen, bufsize, NOERROR, dstkey, NULL, 0, + sig, &siglen, 0); + if (ret < 0) { + free (nstatp); + free (newmsg); + if (ret == NS_TSIG_ERROR_NO_SPACE) + errno = EMSGSIZE; + else if (ret == -1) + errno = EINVAL; + return (ret); + } + + if (newmsglen > PACKETSZ || (nstatp->options & RES_IGNTC)) + usingTCP = 1; + if (usingTCP == 0) + nstatp->options |= RES_IGNTC; + else + nstatp->options |= RES_USEVC; + +retry: + + ret = res_nsend(nstatp, newmsg, newmsglen, answer, anslen); + if (ret < 0) { + free (nstatp); + free (newmsg); + return (ret); + } + + anslen = ret; + ret = ns_verify(answer, &anslen, dstkey, sig, siglen, + NULL, NULL, &tsig_time, nstatp->options & RES_KEEPTSIG); + if (ret != 0) { + Dprint(nstatp->pfcode & RES_PRF_REPLY, + (stdout, ";; TSIG invalid (%s)\n", p_rcode(ret))); + free (nstatp); + free (newmsg); + if (ret == -1) + errno = EINVAL; + else + errno = ENOTTY; + return (-1); + } + Dprint(nstatp->pfcode & RES_PRF_REPLY, (stdout, ";; TSIG ok\n")); + + hp = (HEADER *) answer; + if (hp->tc && usingTCP == 0) { + nstatp->options &= ~RES_IGNTC; + usingTCP = 1; + goto retry; + } + + free (nstatp); + free (newmsg); + return (anslen); +} diff --git a/contrib/bind/lib/resolv/res_update.c b/contrib/bind/lib/resolv/res_update.c index 8e6c448..bb2456e 100644 --- a/contrib/bind/lib/resolv/res_update.c +++ b/contrib/bind/lib/resolv/res_update.c @@ -1,9 +1,9 @@ #if !defined(lint) && !defined(SABER) -static char rcsid[] = "$Id: res_update.c,v 1.14 1998/03/10 22:04:48 halley Exp $"; +static const char rcsid[] = "$Id: res_update.c,v 1.24 1999/10/15 19:49:12 vixie Exp $"; #endif /* not lint */ /* - * Copyright (c) 1996 by Internet Software Consortium. + * Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -25,19 +25,27 @@ static char rcsid[] = "$Id: res_update.c,v 1.14 1998/03/10 22:04:48 halley Exp $ */ #include "port_before.h" + #include <sys/param.h> #include <sys/socket.h> #include <sys/time.h> + #include <netinet/in.h> #include <arpa/inet.h> #include <arpa/nameser.h> + #include <errno.h> #include <limits.h> #include <netdb.h> #include <resolv.h> +#include <res_update.h> +#include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> + +#include <isc/list.h> + #include "port_after.h" /* @@ -54,465 +62,166 @@ static char rcsid[] = "$Id: res_update.c,v 1.14 1998/03/10 22:04:48 halley Exp $ * was encountered while updating the reverse zone. */ -#define NSMAX 16 - -struct ns1 { - char nsname[MAXDNAME]; - struct in_addr nsaddr1; -}; - struct zonegrp { - char z_origin[MAXDNAME]; - int16_t z_class; - char z_soardata[MAXDNAME + 5 * INT32SZ]; - struct ns1 z_ns[NSMAX]; - int z_nscount; - ns_updrec * z_rr; - struct zonegrp *z_next; + char z_origin[MAXDNAME]; + ns_class z_class; + struct in_addr z_nsaddrs[MAXNS]; + int z_nscount; + int z_flags; + LIST(ns_updrec) z_rrlist; + LINK(struct zonegrp) z_link; }; +#define ZG_F_ZONESECTADDED 0x0001 -int -res_update(ns_updrec *rrecp_in) { - ns_updrec *rrecp, *tmprrecp; - u_char buf[PACKETSZ], answer[PACKETSZ], packet[2*PACKETSZ]; - char name[MAXDNAME], zname[MAXDNAME], primary[MAXDNAME], - mailaddr[MAXDNAME]; - u_char soardata[2*MAXCDNAME+5*INT32SZ]; - char *dname, *svdname, *cp1, *target; - u_char *cp, *eom; - HEADER *hp = (HEADER *) answer; - struct zonegrp *zptr = NULL, *tmpzptr, *prevzptr, *zgrp_start = NULL; - int i, j, k = 0, n, ancount, nscount, arcount, rcode, rdatasize, - newgroup, done, myzone, seen_before, numzones = 0; - u_int16_t dlen, class, qclass, type, qtype; - u_int32_t ttl; +/* Forward. */ - if ((_res.options & RES_INIT) == 0 && res_init() == -1) { - h_errno = NETDB_INTERNAL; - return (-1); - } +static int nscopy(struct sockaddr_in *, const struct sockaddr_in *, int); +static int nsprom(struct sockaddr_in *, const struct in_addr *, int); +static void dprintf(const char *, ...); - for (rrecp = rrecp_in; rrecp; rrecp = rrecp->r_next) { - dname = rrecp->r_dname; - n = strlen(dname); - if (dname[n-1] == '.') - dname[n-1] = '\0'; - qtype = T_SOA; - qclass = rrecp->r_class; - done = 0; - seen_before = 0; +/* Macros. */ - while (!done && dname) { - if (qtype == T_SOA) { - for (tmpzptr = zgrp_start; - tmpzptr && !seen_before; - tmpzptr = tmpzptr->z_next) { - if (strcasecmp(dname, - tmpzptr->z_origin) == 0 && - tmpzptr->z_class == qclass) - seen_before++; - for (tmprrecp = tmpzptr->z_rr; - tmprrecp && !seen_before; - tmprrecp = tmprrecp->r_grpnext) - if (strcasecmp(dname, tmprrecp->r_dname) == 0 - && tmprrecp->r_class == qclass) { - seen_before++; - break; - } - if (seen_before) { - /* - * Append to the end of - * current group. - */ - for (tmprrecp = tmpzptr->z_rr; - tmprrecp->r_grpnext; - tmprrecp = tmprrecp->r_grpnext) - (void)NULL; - tmprrecp->r_grpnext = rrecp; - rrecp->r_grpnext = NULL; - done = 1; - break; - } - } - } else if (qtype == T_A) { - for (tmpzptr = zgrp_start; - tmpzptr && !done; - tmpzptr = tmpzptr->z_next) - for (i = 0; i < tmpzptr->z_nscount; i++) - if (tmpzptr->z_class == qclass && - strcasecmp(tmpzptr->z_ns[i].nsname, - dname) == 0 && - tmpzptr->z_ns[i].nsaddr1.s_addr != 0) { - zptr->z_ns[k].nsaddr1.s_addr = - tmpzptr->z_ns[i].nsaddr1.s_addr; - done = 1; - break; - } - } - if (done) - break; - n = res_mkquery(QUERY, dname, qclass, qtype, NULL, - 0, NULL, buf, sizeof buf); - if (n <= 0) { - fprintf(stderr, "res_update: mkquery failed\n"); - return (n); - } - n = res_send(buf, n, answer, sizeof answer); - if (n < 0) { - fprintf(stderr, "res_update: send error for %s\n", - rrecp->r_dname); - return (n); - } - if (n < HFIXEDSZ) - return (-1); - ancount = ntohs(hp->ancount); - nscount = ntohs(hp->nscount); - arcount = ntohs(hp->arcount); - rcode = hp->rcode; - cp = answer + HFIXEDSZ; - eom = answer + n; - /* skip the question section */ - n = dn_skipname(cp, eom); - if (n < 0 || cp + n + 2 * INT16SZ > eom) - return (-1); - cp += n + 2 * INT16SZ; +#define DPRINTF(x) do {\ + int save_errno = errno; \ + if ((statp->options & RES_DEBUG) != 0) dprintf x; \ + errno = save_errno; \ + } while (0) - if (qtype == T_SOA) { - if (ancount == 0 && nscount == 0 && arcount == 0) { - /* - * if (rcode == NOERROR) then the dname exists but - * has no soa record associated with it. - * if (rcode == NXDOMAIN) then the dname does not - * exist and the server is replying out of NCACHE. - * in either case, proceed with the next try - */ - dname = strchr(dname, '.'); - if (dname != NULL) - dname++; - continue; - } else if ((rcode == NOERROR || rcode == NXDOMAIN) && - ancount == 0 && - nscount == 1 && arcount == 0) { - /* - * name/data does not exist, soa record supplied in the - * authority section - */ - /* authority section must contain the soa record */ - if ((n = dn_expand(answer, eom, cp, zname, - sizeof zname)) < 0) - return (n); - cp += n; - if (cp + 2 * INT16SZ > eom) - return (-1); - GETSHORT(type, cp); - GETSHORT(class, cp); - if (type != T_SOA || class != qclass) { - fprintf(stderr, "unknown answer\n"); - return (-1); - } - myzone = 0; - svdname = dname; - while (dname) - if (strcasecmp(dname, zname) == 0) { - myzone = 1; - break; - } else if ((dname = strchr(dname, '.')) != NULL) - dname++; - if (!myzone) { - dname = strchr(svdname, '.'); - if (dname != NULL) - dname++; - continue; - } - nscount = 0; - /* fallthrough */ - } else if (rcode == NOERROR && ancount == 1) { - /* - * found the zone name - * new servers will supply NS records for the zone - * in authority section and A records for those - * nameservers in the additional section - * older servers have to be explicitly queried for - * NS records for the zone - */ - /* answer section must contain the soa record */ - if ((n = dn_expand(answer, eom, cp, zname, - sizeof zname)) < 0) - return (n); - else - cp += n; - if (cp + 2 * INT16SZ > eom) - return (-1); - GETSHORT(type, cp); - GETSHORT(class, cp); - if (type == T_CNAME) { - dname = strchr(dname, '.'); - if (dname != NULL) - dname++; - continue; - } - if (strcasecmp(dname, zname) != 0 || - type != T_SOA || - class != rrecp->r_class) { - fprintf(stderr, "unknown answer\n"); - return (-1); - } - /* FALLTHROUGH */ - } else { - fprintf(stderr, - "unknown response: ans=%d, auth=%d, add=%d, rcode=%d\n", - ancount, nscount, arcount, hp->rcode); - return (-1); - } - if (cp + INT32SZ + INT16SZ > eom) - return (-1); - /* continue processing the soa record */ - GETLONG(ttl, cp); - GETSHORT(dlen, cp); - if (cp + dlen > eom) - return (-1); - newgroup = 1; - zptr = zgrp_start; - prevzptr = NULL; - while (zptr) { - if (strcasecmp(zname, zptr->z_origin) == 0 && - type == T_SOA && class == qclass) { - newgroup = 0; - break; - } - prevzptr = zptr; - zptr = zptr->z_next; - } - if (!newgroup) { - for (tmprrecp = zptr->z_rr; - tmprrecp->r_grpnext; - tmprrecp = tmprrecp->r_grpnext) - ; - tmprrecp->r_grpnext = rrecp; - rrecp->r_grpnext = NULL; - done = 1; - cp += dlen; - break; - } else { - if ((n = dn_expand(answer, eom, cp, primary, - sizeof primary)) < 0) - return (n); - cp += n; - /* - * We don't have to bounds check here because the - * next use of 'cp' is in dn_expand(). - */ - cp1 = (char *)soardata; - strcpy(cp1, primary); - cp1 += strlen(cp1) + 1; - if ((n = dn_expand(answer, eom, cp, mailaddr, - sizeof mailaddr)) < 0) - return (n); - cp += n; - strcpy(cp1, mailaddr); - cp1 += strlen(cp1) + 1; - if (cp + 5*INT32SZ > eom) - return (-1); - memcpy(cp1, cp, 5*INT32SZ); - cp += 5*INT32SZ; - cp1 += 5*INT32SZ; - rdatasize = (u_char *)cp1 - soardata; - zptr = calloc(1, sizeof(struct zonegrp)); - if (zptr == NULL) - return (-1); - if (zgrp_start == NULL) - zgrp_start = zptr; - else - prevzptr->z_next = zptr; - zptr->z_rr = rrecp; - rrecp->r_grpnext = NULL; - strcpy(zptr->z_origin, zname); - zptr->z_class = class; - memcpy(zptr->z_soardata, soardata, rdatasize); - /* fallthrough to process NS and A records */ - } - } else if (qtype == T_NS) { - if (rcode == NOERROR && ancount > 0) { - strcpy(zname, dname); - for (zptr = zgrp_start; zptr; zptr = zptr->z_next) { - if (strcasecmp(zname, zptr->z_origin) == 0) - break; - } - if (zptr == NULL) - /* should not happen */ - return (-1); - if (nscount > 0) { - /* - * answer and authority sections contain - * the same information, skip answer section - */ - for (j = 0; j < ancount; j++) { - n = dn_skipname(cp, eom); - if (n < 0) - return (-1); - n += 2*INT16SZ + INT32SZ; - if (cp + n + INT16SZ > eom) - return (-1); - cp += n; - GETSHORT(dlen, cp); - cp += dlen; - } - } else - nscount = ancount; - /* fallthrough to process NS and A records */ - } else { - fprintf(stderr, "cannot determine nameservers for %s:\ -ans=%d, auth=%d, add=%d, rcode=%d\n", - dname, ancount, nscount, arcount, hp->rcode); - return (-1); - } - } else if (qtype == T_A) { - if (rcode == NOERROR && ancount > 0) { - arcount = ancount; - ancount = nscount = 0; - /* fallthrough to process A records */ - } else { - fprintf(stderr, "cannot determine address for %s:\ -ans=%d, auth=%d, add=%d, rcode=%d\n", - dname, ancount, nscount, arcount, hp->rcode); - return (-1); - } - } - /* process NS records for the zone */ - j = 0; - for (i = 0; i < nscount; i++) { - if ((n = dn_expand(answer, eom, cp, name, - sizeof name)) < 0) - return (n); - cp += n; - if (cp + 3 * INT16SZ + INT32SZ > eom) - return (-1); - GETSHORT(type, cp); - GETSHORT(class, cp); - GETLONG(ttl, cp); - GETSHORT(dlen, cp); - if (cp + dlen > eom) - return (-1); - if (strcasecmp(name, zname) == 0 && - type == T_NS && class == qclass) { - if ((n = dn_expand(answer, eom, cp, - name, sizeof name)) < 0) - return (n); - target = zptr->z_ns[j++].nsname; - strcpy(target, name); - } - cp += dlen; +/* Public. */ + +int +res_nupdate(res_state statp, ns_updrec *rrecp_in, ns_tsig_key *key) { + ns_updrec *rrecp; + u_char answer[PACKETSZ], packet[2*PACKETSZ]; + struct zonegrp *zptr, tgrp; + LIST(struct zonegrp) zgrps; + int nzones = 0, nscount = 0, n; + struct sockaddr_in nsaddrs[MAXNS]; + + /* Thread all of the updates onto a list of groups. */ + INIT_LIST(zgrps); + for (rrecp = rrecp_in; rrecp; rrecp = NEXT(rrecp, r_link)) { + /* Find the origin for it if there is one. */ + tgrp.z_class = rrecp->r_class; + tgrp.z_nscount = + res_findzonecut(statp, rrecp->r_dname, tgrp.z_class, + RES_EXHAUSTIVE, + tgrp.z_origin, + sizeof tgrp.z_origin, + tgrp.z_nsaddrs, MAXNS); + if (tgrp.z_nscount <= 0) { + DPRINTF(("res_findzonecut failed (%d)", + tgrp.z_nscount)); + goto done; } - if (zptr->z_nscount == 0) - zptr->z_nscount = j; - /* get addresses for the nameservers */ - for (i = 0; i < arcount; i++) { - if ((n = dn_expand(answer, eom, cp, name, - sizeof name)) < 0) - return (n); - cp += n; - if (cp + 3 * INT16SZ + INT32SZ > eom) - return (-1); - GETSHORT(type, cp); - GETSHORT(class, cp); - GETLONG(ttl, cp); - GETSHORT(dlen, cp); - if (cp + dlen > eom) - return (-1); - if (type == T_A && dlen == INT32SZ && class == qclass) { - for (j = 0; j < zptr->z_nscount; j++) - if (strcasecmp(name, zptr->z_ns[j].nsname) == 0) { - memcpy(&zptr->z_ns[j].nsaddr1.s_addr, cp, - INT32SZ); + /* Find the group for it if there is one. */ + for (zptr = HEAD(zgrps); zptr != NULL; zptr = NEXT(zptr, z_link)) + if (ns_samename(tgrp.z_origin, zptr->z_origin) == 1 && + tgrp.z_class == zptr->z_class) break; - } - } - cp += dlen; - } - if (zptr->z_nscount == 0) { - dname = zname; - qtype = T_NS; - continue; + /* Make a group for it if there isn't one. */ + if (zptr == NULL) { + zptr = malloc(sizeof *zptr); + if (zptr == NULL) { + DPRINTF(("malloc failed")); + goto done; + } + *zptr = tgrp; + zptr->z_flags = 0; + INIT_LIST(zptr->z_rrlist); + APPEND(zgrps, zptr, z_link); } - done = 1; - for (k = 0; k < zptr->z_nscount; k++) - if (zptr->z_ns[k].nsaddr1.s_addr == 0) { - done = 0; - dname = zptr->z_ns[k].nsname; - qtype = T_A; - } - - } /* while */ + /* Thread this rrecp onto the right group. */ + APPEND(zptr->z_rrlist, rrecp, r_glink); } - _res.options |= RES_DEBUG; - for (zptr = zgrp_start; zptr; zptr = zptr->z_next) { - - /* append zone section */ + for (zptr = HEAD(zgrps); zptr != NULL; zptr = NEXT(zptr, z_link)) { + /* Construct zone section and prepend it. */ rrecp = res_mkupdrec(ns_s_zn, zptr->z_origin, zptr->z_class, ns_t_soa, 0); if (rrecp == NULL) { - fprintf(stderr, "saverrec error\n"); - fflush(stderr); - return (-1); + DPRINTF(("res_mkupdrec failed")); + goto done; } - rrecp->r_grpnext = zptr->z_rr; - zptr->z_rr = rrecp; - - n = res_mkupdate(zptr->z_rr, packet, sizeof packet); + PREPEND(zptr->z_rrlist, rrecp, r_glink); + zptr->z_flags |= ZG_F_ZONESECTADDED; + + /* Marshall the update message. */ + n = res_nmkupdate(statp, HEAD(zptr->z_rrlist), + packet, sizeof packet); + DPRINTF(("res_mkupdate -> %d", n)); + if (n < 0) + goto done; + + /* Temporarily replace the resolver's nameserver set. */ + nscount = nscopy(nsaddrs, statp->nsaddr_list, statp->nscount); + statp->nscount = nsprom(statp->nsaddr_list, + zptr->z_nsaddrs, zptr->z_nscount); + + /* Send the update and remember the result. */ + if (key != NULL) + n = res_nsendsigned(statp, packet, n, key, + answer, sizeof answer); + else + n = res_nsend(statp, packet, n, answer, sizeof answer); if (n < 0) { - fprintf(stderr, "res_mkupdate error\n"); - fflush(stderr); - return (-1); - } else - fprintf(stdout, "res_mkupdate: packet size = %d\n", n); - - /* - * Override the list of NS records from res_init() with - * the authoritative nameservers for the zone being updated. - * Sort primary to be the first in the list of nameservers. - */ - for (i = 0; i < zptr->z_nscount; i++) { - if (strcasecmp(zptr->z_ns[i].nsname, - zptr->z_soardata) == 0) { - struct in_addr tmpaddr; - - if (i != 0) { - strcpy(zptr->z_ns[i].nsname, - zptr->z_ns[0].nsname); - strcpy(zptr->z_ns[0].nsname, - zptr->z_soardata); - tmpaddr = zptr->z_ns[i].nsaddr1; - zptr->z_ns[i].nsaddr1 = - zptr->z_ns[0].nsaddr1; - zptr->z_ns[0].nsaddr1 = tmpaddr; - } - break; - } - } - for (i = 0; i < MAXNS; i++) { - _res.nsaddr_list[i].sin_addr = zptr->z_ns[i].nsaddr1; - _res.nsaddr_list[i].sin_family = AF_INET; - _res.nsaddr_list[i].sin_port = htons(NAMESERVER_PORT); + DPRINTF(("res_nsend: send error, n=%d (%s)\n", + n, strerror(errno))); + goto done; } - _res.nscount = (zptr->z_nscount < MAXNS) ? - zptr->z_nscount : MAXNS; - n = res_send(packet, n, answer, sizeof(answer)); - if (n < 0) { - fprintf(stderr, "res_send: send error, n=%d\n", n); - break; - } else - numzones++; + if (((HEADER *)answer)->rcode == NOERROR) + nzones++; + + /* Restore resolver's nameserver set. */ + statp->nscount = nscopy(statp->nsaddr_list, nsaddrs, nscount); + nscount = 0; + } + done: + while (!EMPTY(zgrps)) { + zptr = HEAD(zgrps); + if ((zptr->z_flags & ZG_F_ZONESECTADDED) != 0) + res_freeupdrec(HEAD(zptr->z_rrlist)); + UNLINK(zgrps, zptr, z_link); + free(zptr); } + if (nscount != 0) + statp->nscount = nscopy(statp->nsaddr_list, nsaddrs, nscount); + + return (nzones); +} + +/* Private. */ - /* free malloc'ed memory */ - while(zgrp_start) { - zptr = zgrp_start; - zgrp_start = zgrp_start->z_next; - res_freeupdrec(zptr->z_rr); /* Zone section we allocated. */ - free((char *)zptr); +static int +nscopy(struct sockaddr_in *dst, const struct sockaddr_in *src, int n) { + int i; + + for (i = 0; i < n; i++) + dst[i] = src[i]; + return (n); +} + +static int +nsprom(struct sockaddr_in *dst, const struct in_addr *src, int n) { + int i; + + for (i = 0; i < n; i++) { + memset(&dst[i], 0, sizeof dst[i]); + dst[i].sin_family = AF_INET; + dst[i].sin_port = htons(NS_DEFAULTPORT); + dst[i].sin_addr = src[i]; } + return (n); +} + +static void +dprintf(const char *fmt, ...) { + va_list ap; - return (numzones); + va_start(ap, fmt); + fputs(";; res_nupdate: ", stderr); + vfprintf(stderr, fmt, ap); + fputc('\n', stderr); + va_end(ap); } |