diff options
-rw-r--r-- | include/resolv.h | 52 | ||||
-rw-r--r-- | lib/libc/net/res_init.c | 115 | ||||
-rw-r--r-- | lib/libc/net/res_send.c | 202 |
3 files changed, 321 insertions, 48 deletions
diff --git a/include/resolv.h b/include/resolv.h index 1f9cf6a89d4..a4d3b108508 100644 --- a/include/resolv.h +++ b/include/resolv.h @@ -1,4 +1,33 @@ -/* $OpenBSD: resolv.h,v 1.3 1997/03/13 19:11:51 downsj Exp $ */ +/* $OpenBSD: resolv.h,v 1.4 2000/06/22 07:31:18 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ /* * ++Copyright++ 1983, 1987, 1989, 1993 @@ -70,6 +99,7 @@ # include <sys/types.h> #endif #include <sys/cdefs.h> +#include <sys/socket.h> #include <stdio.h> /* @@ -128,6 +158,23 @@ struct __res_state { char pad[68]; /* on an i386 this means 512b total */ }; +#if 1 /* INET6 */ +/* + * replacement of __res_state, separated to keep binary compatibility. + */ +struct __res_state_ext { + struct sockaddr_storage nsaddr_list[MAXNS]; + struct { + int af; /* address family for addr, mask */ + union { + struct in_addr ina; + struct in6_addr in6a; + } addr, mask; + } sort_list[MAXRESOLVSORT]; +}; +#endif + + /* * Resolver options (keep these in synch with res_debug.c, please) */ @@ -193,6 +240,9 @@ struct res_sym { }; extern struct __res_state _res; +#if 1 /* INET6 */ +extern struct __res_state_ext _res_ext; +#endif extern const struct res_sym __p_class_syms[]; extern const struct res_sym __p_type_syms[]; diff --git a/lib/libc/net/res_init.c b/lib/libc/net/res_init.c index fd8d279cf08..ac75a4babb9 100644 --- a/lib/libc/net/res_init.c +++ b/lib/libc/net/res_init.c @@ -1,4 +1,4 @@ -/* $OpenBSD: res_init.c,v 1.18 1999/09/03 21:14:51 deraadt Exp $ */ +/* $OpenBSD: res_init.c,v 1.19 2000/06/22 07:31:18 itojun Exp $ */ /* * ++Copyright++ 1985, 1989, 1993 @@ -55,12 +55,16 @@ * --Copyright-- */ +#ifndef INET6 +#define INET6 +#endif + #if defined(LIBC_SCCS) && !defined(lint) #if 0 static char sccsid[] = "@(#)res_init.c 8.1 (Berkeley) 6/7/93"; static char rcsid[] = "$From: res_init.c,v 8.7 1996/09/28 06:51:07 vixie Exp $"; #else -static char rcsid[] = "$OpenBSD: res_init.c,v 1.18 1999/09/03 21:14:51 deraadt Exp $"; +static char rcsid[] = "$OpenBSD: res_init.c,v 1.19 2000/06/22 07:31:18 itojun Exp $"; #endif #endif /* LIBC_SCCS and not lint */ @@ -78,6 +82,9 @@ static char rcsid[] = "$OpenBSD: res_init.c,v 1.18 1999/09/03 21:14:51 deraadt E #include <unistd.h> #include <stdlib.h> #include <string.h> +#ifdef INET6 +#include <netdb.h> +#endif /* INET6 */ /*-------------------------------------- info about "sortlist" -------------- * Marc Majka 1994/04/16 @@ -119,6 +126,9 @@ struct __res_state _res = { RES_TIMEOUT, } /* Motorola, et al. */ # endif ; +#ifdef INET6 +struct __res_state_ext _res_ext; +#endif /* INET6 */ /* * Set up default settings. If the configuration file exist, the values @@ -193,6 +203,11 @@ res_init() #endif _res.nsaddr.sin_family = AF_INET; _res.nsaddr.sin_port = htons(NAMESERVER_PORT); + _res.nsaddr.sin_len = sizeof(struct sockaddr_in); +#ifdef INET6 + if (sizeof(_res_ext.nsaddr) >= _res.nsaddr.sin_len) + memcpy(&_res_ext.nsaddr, &_res.nsaddr, _res.nsaddr.sin_len); +#endif _res.nscount = 1; _res.ndots = 1; _res.pfcode = 0; @@ -336,23 +351,69 @@ res_init() } /* read nameservers to query */ if (MATCH(buf, "nameserver") && nserv < MAXNS) { +#ifdef INET6 + char *q; + struct addrinfo hints, *res; + char pbuf[NI_MAXSERV]; +#else struct in_addr a; +#endif /* INET6 */ cp = buf + sizeof("nameserver") - 1; while (*cp == ' ' || *cp == '\t') cp++; +#ifdef INET6 + if ((*cp == '\0') || (*cp == '\n')) + continue; + for (q = cp; *q; q++) { + if (isspace(*q)) { + *q = '\0'; + break; + } + } + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_NUMERICHOST; + hints.ai_socktype = SOCK_DGRAM; + snprintf(pbuf, sizeof(pbuf), "%d", NAMESERVER_PORT); + if (getaddrinfo(cp, pbuf, &hints, &res) == 0 && + res->ai_next == NULL) { + if (res->ai_addrlen <= sizeof(_res_ext.nsaddr_list[nserv])) { + memcpy(&_res_ext.nsaddr_list[nserv], res->ai_addr, + res->ai_addrlen); + } else { + memset(&_res_ext.nsaddr_list[nserv], 0, + sizeof(_res_ext.nsaddr_list[nserv])); + } + if (res->ai_addrlen <= sizeof(_res.nsaddr_list[nserv])) { + memcpy(&_res.nsaddr_list[nserv], res->ai_addr, + res->ai_addrlen); + } else { + memset(&_res.nsaddr_list[nserv], 0, + sizeof(_res.nsaddr_list[nserv])); + } + nserv++; + } +#else /* INET6 */ 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 = htons(NAMESERVER_PORT); + _res.nsaddr_list[nserv].sin_len = + sizeof(struct sockaddr_in); nserv++; } +#endif /* INET6 */ continue; } #ifdef RESOLVSORT if (MATCH(buf, "sortlist")) { struct in_addr a; +#ifdef INET6 + struct in6_addr a6; + int m, i; + u_char *u; +#endif /* INET6 */ cp = buf + sizeof("sortlist") - 1; while (nsort < MAXRESOLVSORT) { @@ -386,8 +447,58 @@ res_init() _res.sort_list[nsort].mask = net_mask(_res.sort_list[nsort].addr); } +#ifdef INET6 + _res_ext.sort_list[nsort].af = AF_INET; + _res_ext.sort_list[nsort].addr.ina = + _res.sort_list[nsort].addr; + _res_ext.sort_list[nsort].mask.ina.s_addr = + _res.sort_list[nsort].mask; +#endif /* INET6 */ + nsort++; + } +#ifdef INET6 + else if (inet_pton(AF_INET6, net, &a6) == 1) { + _res_ext.sort_list[nsort].af = AF_INET6; + _res_ext.sort_list[nsort].addr.in6a = a6; + u = (u_char *)&_res_ext.sort_list[nsort].mask.in6a; + *cp++ = n; + net = cp; + while (*cp && *cp != ';' && + isascii(*cp) && !isspace(*cp)) + cp++; + m = n; + n = *cp; + *cp = 0; + switch (m) { + case '/': + m = atoi(net); + break; + case '&': + if (inet_pton(AF_INET6, net, u) == 1) { + m = -1; + break; + } + /*FALLTHRU*/ + default: + m = sizeof(struct in6_addr) * NBBY; + break; + } + if (m >= 0) { + for (i = 0; i < sizeof(struct in6_addr); i++) { + if (m <= 0) { + *u = 0; + } else { + m -= NBBY; + *u = (u_char)~0; + if (m < 0) + *u <<= -m; + } + u++; + } + } nsort++; } +#endif /* INET6 */ *cp = n; } continue; diff --git a/lib/libc/net/res_send.c b/lib/libc/net/res_send.c index 0cda3510ebe..d0f17af8ed9 100644 --- a/lib/libc/net/res_send.c +++ b/lib/libc/net/res_send.c @@ -1,4 +1,4 @@ -/* $OpenBSD: res_send.c,v 1.8 1998/03/19 00:30:08 millert Exp $ */ +/* $OpenBSD: res_send.c,v 1.9 2000/06/22 07:31:18 itojun Exp $ */ /* * ++Copyright++ 1985, 1989, 1993 @@ -55,12 +55,16 @@ * --Copyright-- */ +#ifndef INET6 +#define INET6 +#endif + #if defined(LIBC_SCCS) && !defined(lint) #if 0 static char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93"; static char rcsid[] = "$From: res_send.c,v 8.12 1996/10/08 04:51:06 vixie Exp $"; #else -static char rcsid[] = "$OpenBSD: res_send.c,v 1.8 1998/03/19 00:30:08 millert Exp $"; +static char rcsid[] = "$OpenBSD: res_send.c,v 1.9 2000/06/22 07:31:18 itojun Exp $"; #endif #endif /* LIBC_SCCS and not lint */ @@ -95,6 +99,7 @@ static char rcsid[] = "$OpenBSD: res_send.c,v 1.8 1998/03/19 00:30:08 millert Ex 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 ciruit? */ +static int af = 0; /* address family of socket */ #ifndef FD_SET /* XXX - should be in portability.h */ @@ -119,21 +124,29 @@ static int vc = 0; /* is the socket a virtual ciruit? */ fprintf args;\ __fp_nquery(query, size, stdout);\ } else {} +static char abuf[NI_MAXHOST]; +static char pbuf[NI_MAXSERV]; +static void Aerror __P((FILE *, char *, int, struct sockaddr *)); +static void Perror __P((FILE *, char *, int)); + static void Aerror(file, string, error, address) FILE *file; char *string; int error; - struct sockaddr_in address; + struct sockaddr *address; { int save = errno; if (_res.options & RES_DEBUG) { - fprintf(file, "res_send: %s ([%s].%u): %s\n", - string, - inet_ntoa(address.sin_addr), - ntohs(address.sin_port), - strerror(error)); + if (getnameinfo(address, address->sa_len, abuf, sizeof(abuf), + pbuf, sizeof(pbuf), + NI_NUMERICHOST|NI_NUMERICSERV|NI_WITHSCOPEID) != 0) { + strncpy(abuf, "?", sizeof(abuf)); + strncpy(pbuf, "?", sizeof(pbuf)); + } + fprintf(file, "res_send: %s ([%s].%s): %s\n", + string, abuf, pbuf, strerror(error)); } errno = save; } @@ -172,6 +185,37 @@ res_send_setrhook(hook) Rhook = hook; } +#ifdef INET6 +static struct sockaddr * get_nsaddr __P((size_t)); + +/* + * pick appropriate nsaddr_list for use. see res_init() for initialization. + */ +static struct sockaddr * +get_nsaddr(n) + size_t n; +{ + + if (!_res.nsaddr_list[n].sin_family) { + /* + * - _res_ext.nsaddr_list[n] holds an address that is larger + * than struct sockaddr, and + * - user code did not update _res.nsaddr_list[n]. + */ + return (struct sockaddr *)&_res_ext.nsaddr_list[n]; + } else { + /* + * - user code updated _res.nsaddr_list[n], or + * - _res.nsaddr_list[n] has the same content as + * _res_ext.nsaddr_list[n]. + */ + return (struct sockaddr *)&_res.nsaddr_list[n]; + } +} +#else +#define get_nsaddr(n) ((struct sockaddr *)&_res.nsaddr_list[(n)]) +#endif + /* int * res_isourserver(ina) * looks up "ina" in _res.ns_addr_list[] @@ -185,21 +229,43 @@ int res_isourserver(inp) const struct sockaddr_in *inp; { - struct sockaddr_in ina; - register int ns, ret; +#ifdef INET6 + const struct sockaddr_in6 *in6p = (const struct sockaddr_in6 *)inp; + const struct sockaddr_in6 *srv6; +#endif + const struct sockaddr_in *srv; + int ns, ret; - ina = *inp; ret = 0; - for (ns = 0; ns < _res.nscount; ns++) { - register const struct sockaddr_in *srv = &_res.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; + switch (inp->sin_family) { +#ifdef INET6 + case AF_INET6: + for (ns = 0; ns < _res.nscount; ns++) { + srv6 = (struct sockaddr_in6 *)get_nsaddr(ns); + if (srv6->sin6_family == in6p->sin6_family && + srv6->sin6_port == in6p->sin6_port && + srv6->sin6_scope_id == in6p->sin6_scope_id && + (IN6_IS_ADDR_UNSPECIFIED(&srv6->sin6_addr) || + IN6_ARE_ADDR_EQUAL(&srv6->sin6_addr, + &in6p->sin6_addr))) { + ret++; + break; + } + } + break; +#endif + case AF_INET: + for (ns = 0; ns < _res.nscount; ns++) { + srv = (struct sockaddr_in *)get_nsaddr(ns); + if (srv->sin_family == inp->sin_family && + srv->sin_port == inp->sin_port && + (srv->sin_addr.s_addr == INADDR_ANY || + srv->sin_addr.s_addr == inp->sin_addr.s_addr)) { + ret++; + break; + } } + break; } return (ret); } @@ -308,7 +374,20 @@ res_send(buf, buflen, ans, anssiz) */ for (try = 0; try < _res.retry; try++) { for (ns = 0; ns < _res.nscount; ns++) { - struct sockaddr_in *nsap = &_res.nsaddr_list[ns]; + struct sockaddr *nsap = get_nsaddr(ns); + socklen_t salen; + + if (nsap->sa_len) + salen = nsap->sa_len; +#ifdef INET6 + else if (nsap->sa_family == AF_INET6) + salen = sizeof(struct sockaddr_in6); +#endif + else if (nsap->sa_family == AF_INET) + salen = sizeof(struct sockaddr_in); + else + salen = 0; /*unknown, die on connect*/ + same_ns: if (badns & (1 << ns)) { res_close(); @@ -321,7 +400,8 @@ res_send(buf, buflen, ans, anssiz) do { res_sendhookact act; - act = (*Qhook)(&nsap, &buf, &buflen, + act = (*Qhook)((struct sockaddr_in **)&nsap, + &buf, &buflen, ans, anssiz, &resplen); switch (act) { case res_goahead: @@ -345,9 +425,11 @@ res_send(buf, buflen, ans, anssiz) } while (!done); } - Dprint(_res.options & RES_DEBUG, + Dprint((_res.options & RES_DEBUG) && + getnameinfo(nsap, salen, abuf, sizeof(abuf), + NULL, 0, NI_NUMERICHOST | NI_WITHSCOPEID) == 0, (stdout, ";; Querying server (# %d) address = %s\n", - ns + 1, inet_ntoa(nsap->sin_addr))); + ns + 1, abuf)); if (v_circuit) { int truncated; @@ -361,22 +443,28 @@ res_send(buf, buflen, ans, anssiz) */ try = _res.retry; truncated = 0; - if ((s < 0) || (!vc)) { + if ((s < 0) || (!vc) || (af != nsap->sa_family)) { if (s >= 0) res_close(); - s = socket(PF_INET, SOCK_STREAM, 0); + af = nsap->sa_family; + s = socket(af, SOCK_STREAM, 0); if (s < 0) { terrno = errno; Perror(stderr, "socket(vc)", errno); +#if 0 return (-1); +#else + badns |= (1 << ns); + res_close(); + goto next_ns; +#endif } errno = 0; - if (connect(s, (struct sockaddr *)nsap, - sizeof(struct sockaddr)) < 0) { + if (connect(s, nsap, salen) < 0) { terrno = errno; Aerror(stderr, "connect/vc", - errno, *nsap); + errno, nsap); badns |= (1 << ns); res_close(); goto next_ns; @@ -490,21 +578,36 @@ read_len: */ struct timeval timeout; fd_set *dsmaskp; - struct sockaddr_in from; + struct sockaddr_storage from; int fromlen; - if ((s < 0) || vc) { + if ((s < 0) || vc || (af != nsap->sa_family)) { if (vc) res_close(); - s = socket(PF_INET, SOCK_DGRAM, 0); + af = nsap->sa_family; + s = socket(af, SOCK_DGRAM, 0); if (s < 0) { #if !CAN_RECONNECT bad_dg_sock: #endif terrno = errno; Perror(stderr, "socket(dg)", errno); +#if 0 return (-1); +#else + badns |= (1 << ns); + res_close(); + goto next_ns; +#endif + } +#ifdef IPV6_MINMTU + if (af == AF_INET6) { + const int yes = 1; + (void)setsockopt(s, IPPROTO_IPV6, + IPV6_USE_MIN_MTU, &yes, + sizeof(yes)); } +#endif connected = 0; } /* @@ -528,12 +631,10 @@ read_len: * receive a response from another server. */ if (!connected) { - if (connect(s, (struct sockaddr *)nsap, - sizeof(struct sockaddr) - ) < 0) { + if (connect(s, nsap, salen) < 0) { Aerror(stderr, "connect(dg)", - errno, *nsap); + errno, nsap); badns |= (1 << ns); res_close(); goto next_ns; @@ -553,6 +654,9 @@ read_len: */ if (connected) { #if CAN_RECONNECT +#ifdef INET6 + /* XXX: any errornous address */ +#endif /* INET6 */ struct sockaddr_in no_addr; no_addr.sin_family = AF_INET; @@ -563,7 +667,7 @@ read_len: &no_addr, sizeof(no_addr)); #else - int s1 = socket(PF_INET, SOCK_DGRAM,0); + int s1 = socket(af, SOCK_DGRAM,0); if (s1 < 0) goto bad_dg_sock; (void) dup2(s1, s); @@ -571,14 +675,20 @@ read_len: Dprint(_res.options & RES_DEBUG, (stdout, ";; new DG socket\n")) #endif +#ifdef IPV6_MINMTU + if (af == AF_INET6) { + const int yes = 1; + (void)setsockopt(s, IPPROTO_IPV6, + IPV6_USE_MIN_MTU, &yes, + sizeof(yes)); + } +#endif connected = 0; errno = 0; } if (sendto(s, (char*)buf, buflen, 0, - (struct sockaddr *)nsap, - sizeof(struct sockaddr)) - != buflen) { - Aerror(stderr, "sendto", errno, *nsap); + nsap, salen) != buflen) { + Aerror(stderr, "sendto", errno, nsap); badns |= (1 << ns); res_close(); goto next_ns; @@ -623,7 +733,7 @@ read_len: goto next_ns; } errno = 0; - fromlen = sizeof(struct sockaddr_in); + fromlen = sizeof(from); resplen = recvfrom(s, (char*)ans, anssiz, 0, (struct sockaddr *)&from, &fromlen); if (resplen <= 0) { @@ -646,7 +756,7 @@ read_len: } #if CHECK_SRVR_ADDR if (!(_res.options & RES_INSECURE1) && - !res_isourserver(&from)) { + !res_isourserver((struct sockaddr_in *)&from)) { /* * response from wrong server? ignore it. * XXX - potential security hazard could @@ -703,7 +813,7 @@ read_len: (stdout, ";; got answer:\n")); DprintQ((_res.options & RES_DEBUG) || (_res.pfcode & RES_PRF_REPLY), - (stdout, ""), + (stdout, "%s", ""), ans, (resplen>anssiz)?anssiz:resplen); /* * If using virtual circuits, we assume that the first server @@ -723,7 +833,8 @@ read_len: do { res_sendhookact act; - act = (*Rhook)(nsap, buf, buflen, + act = (*Rhook)((struct sockaddr_in *)nsap, + buf, buflen, ans, anssiz, &resplen); switch (act) { case res_goahead: @@ -776,5 +887,6 @@ res_close() s = -1; connected = 0; vc = 0; + af = 0; } } |