diff options
Diffstat (limited to 'resolv')
-rw-r--r-- | resolv/Depend | 1 | ||||
-rw-r--r-- | resolv/Makefile | 4 | ||||
-rw-r--r-- | resolv/Versions | 2 | ||||
-rw-r--r-- | resolv/gai_cancel.c | 4 | ||||
-rw-r--r-- | resolv/gai_error.c | 4 | ||||
-rw-r--r-- | resolv/gai_misc.c | 32 | ||||
-rw-r--r-- | resolv/gai_misc.h | 4 | ||||
-rw-r--r-- | resolv/gai_notify.c | 53 | ||||
-rw-r--r-- | resolv/gai_sigqueue.c | 36 | ||||
-rw-r--r-- | resolv/gai_suspend.c | 19 | ||||
-rw-r--r-- | resolv/getaddrinfo_a.c | 21 | ||||
-rw-r--r-- | resolv/gethnamaddr.c | 10 | ||||
-rw-r--r-- | resolv/herror.c | 5 | ||||
-rw-r--r-- | resolv/inet_ntop.c | 2 | ||||
-rw-r--r-- | resolv/nss_dns/dns-canon.c | 16 | ||||
-rw-r--r-- | resolv/nss_dns/dns-host.c | 15 | ||||
-rw-r--r-- | resolv/nss_dns/dns-network.c | 47 | ||||
-rw-r--r-- | resolv/res-state.c | 45 | ||||
-rw-r--r-- | resolv/res_data.c | 4 | ||||
-rw-r--r-- | resolv/res_debug.c | 24 | ||||
-rw-r--r-- | resolv/res_hconf.c | 221 | ||||
-rw-r--r-- | resolv/res_hconf.h | 13 | ||||
-rw-r--r-- | resolv/res_init.c | 36 | ||||
-rw-r--r-- | resolv/res_libc.c | 16 | ||||
-rw-r--r-- | resolv/res_mkquery.c | 48 | ||||
-rw-r--r-- | resolv/res_query.c | 6 | ||||
-rw-r--r-- | resolv/res_send.c | 123 | ||||
-rw-r--r-- | resolv/tst-inet_ntop.c | 111 |
28 files changed, 531 insertions, 391 deletions
diff --git a/resolv/Depend b/resolv/Depend index fe673ba..8d2587b 100644 --- a/resolv/Depend +++ b/resolv/Depend @@ -1 +1,2 @@ linuxthreads +nptl diff --git a/resolv/Makefile b/resolv/Makefile index f6230da..6ac2267 100644 --- a/resolv/Makefile +++ b/resolv/Makefile @@ -1,4 +1,4 @@ -# Copyright (C) 1994,1995,1996,1997,1998,1999,2000,2001,2003,2004 +# Copyright (C) 1994,1995,1996,1997,1998,1999,2000,2001,2003,2004,2007 # Free Software Foundation, Inc. # This file is part of the GNU C Library. @@ -32,7 +32,7 @@ distribute := ../conf/portability.h mapv4v6addr.h mapv4v6hostent.h \ routines := herror inet_addr inet_ntop inet_pton nsap_addr res_init \ res_hconf res_libc res-state -tests = tst-aton tst-leaks +tests = tst-aton tst-leaks tst-inet_ntop xtests = tst-leaks2 generate := mtrace-tst-leaks tst-leaks.mtrace tst-leaks2.mtrace diff --git a/resolv/Versions b/resolv/Versions index 2a67677..7016365 100644 --- a/resolv/Versions +++ b/resolv/Versions @@ -39,7 +39,7 @@ libc { h_errno; __resp; %endif - __res_maybe_init; + __res_maybe_init; __res_iclose; } } diff --git a/resolv/gai_cancel.c b/resolv/gai_cancel.c index 4543206..19a0a9b 100644 --- a/resolv/gai_cancel.c +++ b/resolv/gai_cancel.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2001 Free Software Foundation, Inc. +/* Copyright (C) 2001, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2001. @@ -20,7 +20,7 @@ #include <netdb.h> #include <pthread.h> -#include "gai_misc.h" +#include <gai_misc.h> int diff --git a/resolv/gai_error.c b/resolv/gai_error.c index 0620b04..4c91628 100644 --- a/resolv/gai_error.c +++ b/resolv/gai_error.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2001 Free Software Foundation, Inc. +/* Copyright (C) 2001, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2001. @@ -19,7 +19,7 @@ #include <netdb.h> -#include "gai_misc.h" +#include <gai_misc.h> int gai_error (struct gaicb *req) diff --git a/resolv/gai_misc.c b/resolv/gai_misc.c index b3334f3..2eec0f5 100644 --- a/resolv/gai_misc.c +++ b/resolv/gai_misc.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2001 Free Software Foundation, Inc. +/* Copyright (C) 2001, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2001. @@ -23,10 +23,31 @@ #include <stdlib.h> #include <sys/time.h> -#include "gai_misc.h" +#include <gai_misc.h> +#ifndef gai_create_helper_thread +# define gai_create_helper_thread __gai_create_helper_thread + +extern inline int +__gai_create_helper_thread (pthread_t *threadp, void *(*tf) (void *), + void *arg) +{ + pthread_attr_t attr; + + /* Make sure the thread is created detached. */ + pthread_attr_init (&attr); + pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); + + int ret = pthread_create (threadp, &attr, tf, arg); + + (void) pthread_attr_destroy (&attr); + return ret; +} +#endif + + /* Pool of request list entries. */ static struct requestlist **pool; @@ -229,16 +250,11 @@ __gai_enqueue_request (struct gaicb *gaicbp) if (nthreads < optim.gai_threads && idle_thread_count == 0) { pthread_t thid; - pthread_attr_t attr; newp->running = 1; - /* Make sure the thread is created detached. */ - pthread_attr_init (&attr); - pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); - /* Now try to start a thread. */ - if (pthread_create (&thid, &attr, handle_requests, newp) == 0) + if (gai_create_helper_thread (&thid, handle_requests, newp) == 0) /* We managed to enqueue the request. All errors which can happen now can be recognized by calls to `gai_error'. */ ++nthreads; diff --git a/resolv/gai_misc.h b/resolv/gai_misc.h index 48a9397..94005de 100644 --- a/resolv/gai_misc.h +++ b/resolv/gai_misc.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2001 Free Software Foundation, Inc. +/* Copyright (C) 2001, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2001. @@ -29,7 +29,9 @@ struct waitlist { struct waitlist *next; +#ifndef DONT_NEED_GAI_MISC_COND pthread_cond_t *cond; +#endif volatile int *counterp; /* The next field is used in asynchronous `lio_listio' operations. */ struct sigevent *sigevp; diff --git a/resolv/gai_notify.c b/resolv/gai_notify.c index 987a64c..c3ce0af 100644 --- a/resolv/gai_notify.c +++ b/resolv/gai_notify.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2001 Free Software Foundation, Inc. +/* Copyright (C) 2001, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2001. @@ -20,15 +20,24 @@ #include <netdb.h> #include <pthread.h> #include <stdlib.h> +#include <gai_misc.h> -#include "gai_misc.h" +struct notify_func + { + void (*func) (sigval_t); + sigval_t value; + }; static void * notify_func_wrapper (void *arg) { - struct sigevent *sigev = arg; - sigev->sigev_notify_function (sigev->sigev_value); + gai_start_notify_thread (); + struct notify_func *const n = arg; + void (*func) (sigval_t) = n->func; + sigval_t value = n->value; + free (n); + (*func) (value); return NULL; } @@ -54,8 +63,26 @@ __gai_notify_only (struct sigevent *sigev, pid_t caller_pid) pattr = &attr; } - if (pthread_create (&tid, pattr, notify_func_wrapper, sigev) < 0) + /* SIGEV may be freed as soon as we return, so we cannot let the + notification thread use that pointer. Even though a sigval_t is + only one word and the same size as a void *, we cannot just pass + the value through pthread_create as the argument and have the new + thread run the user's function directly, because on some machines + the calling convention for a union like sigval_t is different from + that for a pointer type like void *. */ + struct notify_func *nf = malloc (sizeof *nf); + if (nf == NULL) result = -1; + else + { + nf->func = sigev->sigev_notify_function; + nf->value = sigev->sigev_value; + if (pthread_create (&tid, pattr, notify_func_wrapper, nf) < 0) + { + free (nf); + result = -1; + } + } } else if (sigev->sigev_notify == SIGEV_SIGNAL) /* We have to send a signal. */ @@ -79,15 +106,21 @@ __gai_notify (struct requestlist *req) { struct waitlist *next = waitlist->next; - /* Decrement the counter. This is used in both cases. */ - --*waitlist->counterp; - if (waitlist->sigevp == NULL) - pthread_cond_signal (waitlist->cond); + { +#ifdef DONT_NEED_GAI_MISC_COND + GAI_MISC_NOTIFY (waitlist); +#else + /* Decrement the counter. */ + --*waitlist->counterp; + + pthread_cond_signal (waitlist->cond); +#endif + } else /* This is part of a asynchronous `getaddrinfo_a' operation. If this request is the last one, send the signal. */ - if (*waitlist->counterp == 0) + if (--*waitlist->counterp == 0) { __gai_notify_only (waitlist->sigevp, waitlist->caller_pid); /* This is tricky. See getaddrinfo_a.c for the reason why diff --git a/resolv/gai_sigqueue.c b/resolv/gai_sigqueue.c new file mode 100644 index 0000000..278a1d8 --- /dev/null +++ b/resolv/gai_sigqueue.c @@ -0,0 +1,36 @@ +/* Copyright (C) 2001, 2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <aio.h> +#include <errno.h> +#include <signal.h> + +#include <gai_misc.h> + +int +__gai_sigqueue (sig, val, caller_pid) + int sig; + const union sigval val; + pid_t caller_pid; +{ + __set_errno (ENOSYS); + return -1; +} + +stub_warning (__gai_sigqueue) +#include <stub-tag.h> diff --git a/resolv/gai_suspend.c b/resolv/gai_suspend.c index bb3c9c3..4d85ac2 100644 --- a/resolv/gai_suspend.c +++ b/resolv/gai_suspend.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2001 Free Software Foundation, Inc. +/* Copyright (C) 2001, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2001. @@ -23,7 +23,7 @@ #include <stdlib.h> #include <sys/time.h> -#include "gai_misc.h" +#include <gai_misc.h> int @@ -32,9 +32,11 @@ gai_suspend (const struct gaicb *const list[], int ent, { struct waitlist waitlist[ent]; struct requestlist *requestlist[ent]; +#ifndef DONT_NEED_GAI_MISC_COND pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +#endif int cnt; - int dummy; + int cntr = 1; int none = 1; int result; @@ -50,9 +52,11 @@ gai_suspend (const struct gaicb *const list[], int ent, if (requestlist[cnt] != NULL) { +#ifndef DONT_NEED_GAI_MISC_COND waitlist[cnt].cond = &cond; +#endif waitlist[cnt].next = requestlist[cnt]->waiting; - waitlist[cnt].counterp = &dummy; + waitlist[cnt].counterp = &cntr; waitlist[cnt].sigevp = NULL; waitlist[cnt].caller_pid = 0; /* Not needed. */ requestlist[cnt]->waiting = &waitlist[cnt]; @@ -78,6 +82,10 @@ gai_suspend (const struct gaicb *const list[], int ent, which we must remove. So defer cancelation for now. */ pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &oldstate); +#ifdef DONT_NEED_GAI_MISC_COND + result = 0; + GAI_MISC_WAIT (result, cntr, timeout, 1); +#else if (timeout == NULL) result = pthread_cond_wait (&cond, &__gai_requests_mutex); else @@ -99,6 +107,7 @@ gai_suspend (const struct gaicb *const list[], int ent, result = pthread_cond_timedwait (&cond, &__gai_requests_mutex, &abstime); } +#endif /* Now remove the entry in the waiting list for all requests which didn't terminate. */ @@ -121,10 +130,12 @@ gai_suspend (const struct gaicb *const list[], int ent, /* Now it's time to restore the cancelation state. */ pthread_setcancelstate (oldstate, NULL); +#ifndef DONT_NEED_GAI_MISC_COND /* Release the conditional variable. */ if (pthread_cond_destroy (&cond) != 0) /* This must never happen. */ abort (); +#endif if (result != 0) { diff --git a/resolv/getaddrinfo_a.c b/resolv/getaddrinfo_a.c index abac27d..f6af3aa 100644 --- a/resolv/getaddrinfo_a.c +++ b/resolv/getaddrinfo_a.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2001 Free Software Foundation, Inc. +/* Copyright (C) 2001, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2001. @@ -23,7 +23,7 @@ #include <stdlib.h> #include <unistd.h> -#include "gai_misc.h" +#include <gai_misc.h> /* We need this special structure to handle asynchronous I/O. */ @@ -96,7 +96,9 @@ getaddrinfo_a (int mode, struct gaicb *list[], int ent, struct sigevent *sig) } else if (mode == GAI_WAIT) { +#ifndef DONT_NEED_GAI_MISC_COND pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +#endif struct waitlist waitlist[ent]; int oldstate; @@ -104,7 +106,9 @@ getaddrinfo_a (int mode, struct gaicb *list[], int ent, struct sigevent *sig) for (cnt = 0; cnt < ent; ++cnt) if (requests[cnt] != NULL) { +#ifndef DONT_NEED_GAI_MISC_COND waitlist[cnt].cond = &cond; +#endif waitlist[cnt].next = requests[cnt]->waiting; waitlist[cnt].counterp = &total; waitlist[cnt].sigevp = NULL; @@ -119,15 +123,24 @@ getaddrinfo_a (int mode, struct gaicb *list[], int ent, struct sigevent *sig) pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &oldstate); while (total > 0) - pthread_cond_wait (&cond, &__gai_requests_mutex); + { +#ifdef DONT_NEED_GAI_MISC_COND + int result; + GAI_MISC_WAIT (result, total, NULL, 1); +#else + pthread_cond_wait (&cond, &__gai_requests_mutex); +#endif + } /* Now it's time to restore the cancelation state. */ pthread_setcancelstate (oldstate, NULL); +#ifndef DONT_NEED_GAI_MISC_COND /* Release the conditional variable. */ if (pthread_cond_destroy (&cond) != 0) /* This must never happen. */ abort (); +#endif } else { @@ -147,7 +160,9 @@ getaddrinfo_a (int mode, struct gaicb *list[], int ent, struct sigevent *sig) for (cnt = 0; cnt < ent; ++cnt) if (requests[cnt] != NULL) { +#ifndef DONT_NEED_GAI_MISC_COND waitlist->list[cnt].cond = NULL; +#endif waitlist->list[cnt].next = requests[cnt]->waiting; waitlist->list[cnt].counterp = &waitlist->counter; waitlist->list[cnt].sigevp = &waitlist->sigev; diff --git a/resolv/gethnamaddr.c b/resolv/gethnamaddr.c index 3698e4b..7be2315 100644 --- a/resolv/gethnamaddr.c +++ b/resolv/gethnamaddr.c @@ -51,7 +51,6 @@ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)gethostnamadr.c 8.1 (Berkeley) 6/4/93"; -static char rcsid[] = "$Id$"; #endif /* LIBC_SCCS and not lint */ #include <sys/types.h> @@ -177,11 +176,7 @@ Dprintf(msg, num) static struct hostent * -getanswer(answer, anslen, qname, qtype) - const querybuf *answer; - int anslen; - const char *qname; - int qtype; +getanswer (const querybuf *answer, int anslen, const char *qname, int qtype) { register const HEADER *hp; register const u_char *cp; @@ -523,7 +518,6 @@ gethostbyname2(name, af) char *bp; int n, size, type, len; struct hostent *ret; - extern struct hostent *_gethtbyname2(); if (__res_maybe_init (&_res, 0) == -1) { __set_h_errno (NETDB_INTERNAL); @@ -667,7 +661,6 @@ gethostbyaddr(addr, len, af) u_long old_options; char hname2[MAXDNAME+1]; #endif /*SUNSECURITY*/ - extern struct hostent *_gethtbyaddr(); if (__res_maybe_init (&_res, 0) == -1) { __set_h_errno (NETDB_INTERNAL); @@ -880,7 +873,6 @@ struct hostent * _gethtbyname(name) const char *name; { - extern struct hostent *_gethtbyname2(); struct hostent *hp; if (_res.options & RES_USE_INET6) { diff --git a/resolv/herror.c b/resolv/herror.c index a61a3a9..0aaf29f 100644 --- a/resolv/herror.c +++ b/resolv/herror.c @@ -64,14 +64,14 @@ static const char rcsid[] = "$BINDId: herror.c,v 8.11 1999/10/13 16:39:39 vixie #include <libintl.h> #include <not-cancel.h> -const char *h_errlist[] = { +const char *const h_errlist[] = { N_("Resolver Error 0 (no error)"), N_("Unknown host"), /* 1 HOST_NOT_FOUND */ N_("Host name lookup failure"), /* 2 TRY_AGAIN */ N_("Unknown server error"), /* 3 NO_RECOVERY */ N_("No address associated with name"), /* 4 NO_ADDRESS */ }; -int h_nerr = { sizeof h_errlist / sizeof h_errlist[0] }; +const int h_nerr = { sizeof h_errlist / sizeof h_errlist[0] }; /* * herror -- @@ -80,7 +80,6 @@ int h_nerr = { sizeof h_errlist / sizeof h_errlist[0] }; void herror(const char *s) { struct iovec iov[4], *v = iov; - extern int * __h_errno(); if (s != NULL && *s != '\0') { v->iov_base = (/*noconst*/ char *)s; diff --git a/resolv/inet_ntop.c b/resolv/inet_ntop.c index e5553a1..1222d08 100644 --- a/resolv/inet_ntop.c +++ b/resolv/inet_ntop.c @@ -96,7 +96,7 @@ inet_ntop4(src, dst, size) static const char fmt[] = "%u.%u.%u.%u"; char tmp[sizeof "255.255.255.255"]; - if (SPRINTF((tmp, fmt, src[0], src[1], src[2], src[3])) > size) { + if (SPRINTF((tmp, fmt, src[0], src[1], src[2], src[3])) >= size) { __set_errno (ENOSPC); return (NULL); } diff --git a/resolv/nss_dns/dns-canon.c b/resolv/nss_dns/dns-canon.c index 91708df..fca6cd8 100644 --- a/resolv/nss_dns/dns-canon.c +++ b/resolv/nss_dns/dns-canon.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2004 Free Software Foundation, Inc. +/* Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2004. @@ -40,6 +40,10 @@ typedef union querybuf } querybuf; +static const short int qtypes[] = { ns_t_a, ns_t_aaaa }; +#define nqtypes (sizeof (qtypes) / sizeof (qtypes[0])) + + enum nss_status _nss_dns_getcanonname_r (const char *name, char *buffer, size_t buflen, char **result,int *errnop, int *h_errnop) @@ -53,8 +57,6 @@ _nss_dns_getcanonname_r (const char *name, char *buffer, size_t buflen, unsigned char *ptr; } ansp = { .ptr = buf }; enum nss_status status = NSS_STATUS_UNAVAIL; - int qtypes[] = { ns_t_a, ns_t_aaaa }; -#define nqtypes (sizeof (qtypes) / sizeof (qtypes[0])) for (int i = 0; i < nqtypes; ++i) { @@ -101,7 +103,8 @@ _nss_dns_getcanonname_r (const char *name, char *buffer, size_t buflen, ptr += s; /* Check whether type and class match. */ - unsigned int type = ntohs (*(uint16_t *) ptr); + uint_fast16_t type; + NS_GET16 (type, ptr); if (type == qtypes[i]) { /* We found the record. */ @@ -130,15 +133,14 @@ _nss_dns_getcanonname_r (const char *name, char *buffer, size_t buflen, if (type != ns_t_cname) goto unavail; - ptr += sizeof (uint16_t); - if (*(uint16_t *) ptr != htons (ns_c_in)) + if (ns_get16 (ptr) != ns_c_in) goto unavail; /* Also skip over the TTL. */ ptr += sizeof (uint16_t) + sizeof (uint32_t); /* Skip over the data length and data. */ - ptr += sizeof (uint16_t) + ntohs (*(uint16_t *) ptr); + ptr += sizeof (uint16_t) + ns_get16 (ptr); } } } diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c index 7045c59..cf060be 100644 --- a/resolv/nss_dns/dns-host.c +++ b/resolv/nss_dns/dns-host.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1996-2003, 2004 Free Software Foundation, Inc. +/* Copyright (C) 1996-2003, 2004, 2007 Free Software Foundation, Inc. This file is part of the GNU C Library. Extended from original form by Ulrich Drepper <drepper@cygnus.com>, 1996. @@ -465,8 +465,8 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype, char *aliases[MAX_NR_ALIASES]; unsigned char host_addr[16]; /* IPv4 or IPv6 */ char *h_addr_ptrs[0]; - } *host_data = (struct host_data *) buffer; - int linebuflen = buflen - sizeof (struct host_data); + } *host_data; + int linebuflen; register const HEADER *hp; const u_char *end_of_message, *cp; int n, ancount, qdcount; @@ -478,8 +478,9 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype, u_char packtmp[NS_MAXCDNAME]; int have_to_map = 0; int32_t ttl = 0; - - if (__builtin_expect (linebuflen, 0) < 0) + uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data); + buffer += pad; + if (__builtin_expect (buflen < sizeof (struct host_data) + pad, 0)) { /* The buffer is too small. */ too_small: @@ -487,6 +488,10 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype, *h_errnop = NETDB_INTERNAL; return NSS_STATUS_TRYAGAIN; } + host_data = (struct host_data *) buffer; + linebuflen = buflen - sizeof (struct host_data); + if (buflen - sizeof (struct host_data) != linebuflen) + linebuflen = INT_MAX; tname = qname; result->h_name = NULL; diff --git a/resolv/nss_dns/dns-network.c b/resolv/nss_dns/dns-network.c index 6ff60f3..4552b5b 100644 --- a/resolv/nss_dns/dns-network.c +++ b/resolv/nss_dns/dns-network.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1996, 1997, 1998, 1999, 2002, 2004 +/* Copyright (C) 1996, 1997, 1998, 1999, 2002, 2004, 2007 Free Software Foundation, Inc. This file is part of the GNU C Library. Extended from original form by Ulrich Drepper <drepper@cygnus.com>, 1996. @@ -102,7 +102,8 @@ extern int __ns_name_unpack (const u_char *, const u_char *, /* Prototypes for local functions. */ static enum nss_status getanswer_r (const querybuf *answer, int anslen, struct netent *result, char *buffer, - size_t buflen, lookup_method net_i); + size_t buflen, int *errnop, int *h_errnop, + lookup_method net_i); enum nss_status @@ -142,7 +143,8 @@ _nss_dns_getnetbyname_r (const char *name, struct netent *result, ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND; } - status = getanswer_r (net_buffer.buf, anslen, result, buffer, buflen, BYNAME); + status = getanswer_r (net_buffer.buf, anslen, result, buffer, buflen, + errnop, herrnop, BYNAME); if (net_buffer.buf != orig_net_buffer) free (net_buffer.buf); return status; @@ -218,7 +220,8 @@ _nss_dns_getnetbyaddr_r (uint32_t net, int type, struct netent *result, ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND; } - status = getanswer_r (net_buffer.buf, anslen, result, buffer, buflen, BYADDR); + status = getanswer_r (net_buffer.buf, anslen, result, buffer, buflen, + errnop, herrnop, BYADDR); if (net_buffer.buf != orig_net_buffer) free (net_buffer.buf); if (status == NSS_STATUS_SUCCESS) @@ -240,7 +243,8 @@ _nss_dns_getnetbyaddr_r (uint32_t net, int type, struct netent *result, static enum nss_status getanswer_r (const querybuf *answer, int anslen, struct netent *result, - char *buffer, size_t buflen, lookup_method net_i) + char *buffer, size_t buflen, int *errnop, int *h_errnop, + lookup_method net_i) { /* * Find first satisfactory answer @@ -260,16 +264,33 @@ getanswer_r (const querybuf *answer, int anslen, struct netent *result, { char *aliases[MAX_NR_ALIASES]; char linebuffer[0]; - } *net_data = (struct net_data *) buffer; + } *net_data; + + uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct net_data); + buffer += pad; + + if (__builtin_expect (buflen < sizeof (*net_data) + pad, 0)) + { + /* The buffer is too small. */ + too_small: + *errnop = ERANGE; + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + buflen -= pad; + + net_data = (struct net_data *) buffer; int linebuflen = buflen - offsetof (struct net_data, linebuffer); - const char *end_of_message = &answer->buf[anslen]; + if (buflen - offsetof (struct net_data, linebuffer) != linebuflen) + linebuflen = INT_MAX; + const unsigned char *end_of_message = &answer->buf[anslen]; const HEADER *header_pointer = &answer->hdr; /* #/records in the answer section. */ int answer_count = ntohs (header_pointer->ancount); /* #/entries in the question section. */ int question_count = ntohs (header_pointer->qdcount); char *bp = net_data->linebuffer; - const char *cp = &answer->buf[HFIXEDSZ]; + const unsigned char *cp = &answer->buf[HFIXEDSZ]; char **alias_pointer; int have_answer; char *ans; @@ -319,10 +340,7 @@ getanswer_r (const querybuf *answer, int anslen, struct netent *result, if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1) { if (errno == EMSGSIZE) - { - errno = ERANGE; - return NSS_STATUS_TRYAGAIN; - } + goto too_small; n = -1; } @@ -346,10 +364,7 @@ getanswer_r (const querybuf *answer, int anslen, struct netent *result, if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1) { if (errno == EMSGSIZE) - { - errno = ERANGE; - return NSS_STATUS_TRYAGAIN; - } + goto too_small; n = -1; } diff --git a/resolv/res-state.c b/resolv/res-state.c new file mode 100644 index 0000000..e327e34 --- /dev/null +++ b/resolv/res-state.c @@ -0,0 +1,45 @@ +/* Copyright (C) 1996, 97, 98, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <resolv.h> +#include <tls.h> + +#if ! USE___THREAD + +# undef _res +extern struct __res_state _res; + +/* When threaded, _res may be a per-thread variable. */ +struct __res_state * +weak_const_function +__res_state (void) +{ + return &_res; +} + +#else + +struct __res_state * +__res_state (void) +{ + return __resp; +} + +#endif + +libc_hidden_def (__res_state) diff --git a/resolv/res_data.c b/resolv/res_data.c index adadcdc..1beea1d 100644 --- a/resolv/res_data.c +++ b/resolv/res_data.c @@ -246,7 +246,9 @@ res_close(void) { if ((_res.options & RES_INIT) == 0) return; #endif - res_nclose(&_res); + /* We don't free the name server addresses because we never + did it and it would be done implicitly on shutdown. */ + __res_iclose(&_res, false); } #ifdef BIND_UPDATE diff --git a/resolv/res_debug.c b/resolv/res_debug.c index 839069d..d9f1607 100644 --- a/resolv/res_debug.c +++ b/resolv/res_debug.c @@ -626,8 +626,7 @@ static const unsigned int poweroften[10]= /* takes an XeY precision/size value, returns a string representation. */ static const char * -precsize_ntoa(prec) - u_int8_t prec; +precsize_ntoa (u_int8_t prec) { static char retbuf[sizeof "90000000.00"]; /* XXX nonreentrant */ unsigned long val; @@ -644,8 +643,7 @@ precsize_ntoa(prec) /* converts ascii size/precision X * 10**Y(cm) to 0xXY. moves pointer. */ static u_int8_t -precsize_aton(strptr) - const char **strptr; +precsize_aton (const char **strptr) { unsigned int mval = 0, cmval = 0; u_int8_t retval = 0; @@ -686,9 +684,7 @@ precsize_aton(strptr) /* converts ascii lat/lon to unsigned encoded 32-bit number. moves pointer. */ static u_int32_t -latlon2ul(latlonstrptr,which) - const char **latlonstrptr; - int *which; +latlon2ul (const char **latlonstrptr, int *which) { const char *cp; u_int32_t retval; @@ -900,7 +896,7 @@ loc_ntoa(binary, ascii) const u_char *binary; char *ascii; { - static char *error = "?"; + static const 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; @@ -980,11 +976,11 @@ loc_ntoa(binary, ascii) altmeters = (altval / 100) * altsign; if ((sizestr = strdup(precsize_ntoa(sizeval))) == NULL) - sizestr = error; + sizestr = (char *) error; if ((hpstr = strdup(precsize_ntoa(hpval))) == NULL) - hpstr = error; + hpstr = (char *) error; if ((vpstr = strdup(precsize_ntoa(vpval))) == NULL) - vpstr = error; + vpstr = (char *) error; sprintf(ascii, "%d %.2d %.2d.%.3d %c %d %.2d %.2d.%.3d %c %d.%.2dm %sm %sm %sm", @@ -992,11 +988,11 @@ loc_ntoa(binary, ascii) longdeg, longmin, longsec, longsecfrac, eastwest, altmeters, altfrac, sizestr, hpstr, vpstr); - if (sizestr != error) + if (sizestr != (char *) error) free(sizestr); - if (hpstr != error) + if (hpstr != (char *) error) free(hpstr); - if (vpstr != error) + if (vpstr != (char *) error) free(vpstr); return (ascii); diff --git a/resolv/res_hconf.c b/resolv/res_hconf.c index 91cd300..f458889 100644 --- a/resolv/res_hconf.c +++ b/resolv/res_hconf.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1993, 1995-2003, 2004 Free Software Foundation, Inc. +/* Copyright (C) 1993, 1995-2005, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by David Mosberger (davidm@azstarnet.com). @@ -53,35 +53,34 @@ /* Environment vars that all user to override default behavior: */ #define ENV_HOSTCONF "RESOLV_HOST_CONF" -#define ENV_SERVORDER "RESOLV_SERV_ORDER" #define ENV_SPOOF "RESOLV_SPOOF_CHECK" #define ENV_TRIM_OVERR "RESOLV_OVERRIDE_TRIM_DOMAINS" #define ENV_TRIM_ADD "RESOLV_ADD_TRIM_DOMAINS" #define ENV_MULTI "RESOLV_MULTI" #define ENV_REORDER "RESOLV_REORDER" -static const char *arg_service_list (const char *, int, const char *, - unsigned int); -static const char *arg_trimdomain_list (const char *, int, const char *, - unsigned int); -static const char *arg_spoof (const char *, int, const char *, unsigned int); -static const char *arg_bool (const char *, int, const char *, unsigned int); +enum parse_cbs + { + CB_none, + CB_arg_trimdomain_list, + CB_arg_spoof, + CB_arg_bool + }; -static struct cmd +static const struct cmd { - const char *name; - const char *(*parse_args) (const char * filename, int line_num, - const char * args, unsigned int arg); + const char name[11]; + uint8_t cb; unsigned int arg; } cmd[] = { - {"order", arg_service_list, 0}, - {"trim", arg_trimdomain_list, 0}, - {"spoof", arg_spoof, 0}, - {"multi", arg_bool, HCONF_FLAG_MULTI}, - {"nospoof", arg_bool, HCONF_FLAG_SPOOF}, - {"spoofalert", arg_bool, HCONF_FLAG_SPOOFALERT}, - {"reorder", arg_bool, HCONF_FLAG_REORDER} + {"order", CB_none, 0}, + {"trim", CB_arg_trimdomain_list, 0}, + {"spoof", CB_arg_spoof, 0}, + {"multi", CB_arg_bool, HCONF_FLAG_MULTI}, + {"nospoof", CB_arg_bool, HCONF_FLAG_SPOOF}, + {"spoofalert", CB_arg_bool, HCONF_FLAG_SPOOFALERT}, + {"reorder", CB_arg_bool, HCONF_FLAG_REORDER} }; /* Structure containing the state. */ @@ -107,118 +106,7 @@ skip_string (const char *str) static const char * -arg_service_list (const char *fname, int line_num, const char *args, - unsigned int arg) -{ - enum Name_Service service; - const char *start; - size_t len; - size_t i; - static struct - { - const char * name; - enum Name_Service service; - } svcs[] = - { - {"bind", SERVICE_BIND}, - {"hosts", SERVICE_HOSTS}, - {"nis", SERVICE_NIS}, - }; - - do - { - start = args; - args = skip_string (args); - len = args - start; - - service = SERVICE_NONE; - for (i = 0; i < sizeof (svcs) / sizeof (svcs[0]); ++i) - { - if (__strncasecmp (start, svcs[i].name, len) == 0 - && len == strlen (svcs[i].name)) - { - service = svcs[i].service; - break; - } - } - if (service == SERVICE_NONE) - { - char *buf; - - if (__asprintf (&buf, - _("%s: line %d: expected service, found `%s'\n"), - fname, line_num, start) < 0) - return 0; - -#ifdef USE_IN_LIBIO - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else -#endif - fputs (buf, stderr); - - free (buf); - return 0; - } - if (_res_hconf.num_services >= SERVICE_MAX) - { - char *buf; - - if (__asprintf (&buf, _("\ -%s: line %d: cannot specify more than %d services"), - fname, line_num, SERVICE_MAX) < 0) - return 0; - -#ifdef USE_IN_LIBIO - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else -#endif - fputs (buf, stderr); - - free (buf); - return 0; - } - _res_hconf.service[_res_hconf.num_services++] = service; - - args = skip_ws (args); - switch (*args) - { - case ',': - case ';': - case ':': - args = skip_ws (++args); - if (!*args || *args == '#') - { - char *buf; - - if (__asprintf (&buf, _("\ -%s: line %d: list delimiter not followed by keyword"), - fname, line_num) < 0) - return 0; - -#ifdef USE_IN_LIBIO - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else -#endif - fputs (buf, stderr); - - free (buf); - return 0; - } - default: - break; - } - } - while (*args && *args != '#'); - return args; -} - - -static const char * -arg_trimdomain_list (const char *fname, int line_num, const char *args, - unsigned int flag) +arg_trimdomain_list (const char *fname, int line_num, const char *args) { const char * start; size_t len; @@ -238,14 +126,9 @@ arg_trimdomain_list (const char *fname, int line_num, const char *args, fname, line_num, TRIMDOMAINS_MAX) < 0) return 0; -#ifdef USE_IN_LIBIO - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else -#endif - fputs (buf, stderr); + __fxprintf (NULL, "%s", buf); - free (buf); + free (buf); return 0; } _res_hconf.trimdomain[_res_hconf.num_trimdomains++] = @@ -264,12 +147,7 @@ arg_trimdomain_list (const char *fname, int line_num, const char *args, fname, line_num) < 0) return 0; -#ifdef USE_IN_LIBIO - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else -#endif - fputs (buf, stderr); + __fxprintf (NULL, "%s", buf); free (buf); return 0; @@ -284,7 +162,7 @@ arg_trimdomain_list (const char *fname, int line_num, const char *args, static const char * -arg_spoof (const char *fname, int line_num, const char *args, unsigned flag) +arg_spoof (const char *fname, int line_num, const char *args) { const char *start = args; size_t len; @@ -327,12 +205,7 @@ arg_bool (const char *fname, int line_num, const char *args, unsigned flag) fname, line_num, args) < 0) return 0; -#ifdef USE_IN_LIBIO - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else -#endif - fputs (buf, stderr); + __fxprintf (NULL, "%s", buf); free (buf); return 0; @@ -345,7 +218,7 @@ static void parse_line (const char *fname, int line_num, const char *str) { const char *start; - struct cmd *c = 0; + const struct cmd *c = 0; size_t len; size_t i; @@ -375,12 +248,7 @@ parse_line (const char *fname, int line_num, const char *str) fname, line_num, start) < 0) return; -#ifdef USE_IN_LIBIO - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else -#endif - fputs (buf, stderr); + __fxprintf (NULL, "%s", buf); free (buf); return; @@ -388,7 +256,17 @@ parse_line (const char *fname, int line_num, const char *str) /* process args: */ str = skip_ws (str); - str = (*c->parse_args) (fname, line_num, str, c->arg); + + if (c->cb == CB_arg_trimdomain_list) + str = arg_trimdomain_list (fname, line_num, str); + else if (c->cb == CB_arg_spoof) + str = arg_spoof (fname, line_num, str); + else if (c->cb == CB_arg_bool) + str = arg_bool (fname, line_num, str, c->arg); + else + /* Ignore the line. */ + return; + if (!str) return; @@ -405,12 +283,7 @@ parse_line (const char *fname, int line_num, const char *str) fname, line_num, str) < 0) break; -#ifdef USE_IN_LIBIO - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s", buf); - else -#endif - fputs (buf, stderr); + __fxprintf (NULL, "%s", buf); free (buf); } @@ -436,10 +309,7 @@ do_init (void) hconf_name = _PATH_HOSTCONF; fp = fopen (hconf_name, "rc"); - if (!fp) - /* make up something reasonable: */ - _res_hconf.service[_res_hconf.num_services++] = SERVICE_BIND; - else + if (fp) { /* No threads using this stream. */ __fsetlocking (fp, FSETLOCKING_BYCALLER); @@ -453,16 +323,9 @@ do_init (void) fclose (fp); } - envval = getenv (ENV_SERVORDER); - if (envval) - { - _res_hconf.num_services = 0; - arg_service_list (ENV_SERVORDER, 1, envval, 0); - } - envval = getenv (ENV_SPOOF); if (envval) - arg_spoof (ENV_SPOOF, 1, envval, 0); + arg_spoof (ENV_SPOOF, 1, envval); envval = getenv (ENV_MULTI); if (envval) @@ -474,13 +337,13 @@ do_init (void) envval = getenv (ENV_TRIM_ADD); if (envval) - arg_trimdomain_list (ENV_TRIM_ADD, 1, envval, 0); + arg_trimdomain_list (ENV_TRIM_ADD, 1, envval); envval = getenv (ENV_TRIM_OVERR); if (envval) { _res_hconf.num_trimdomains = 0; - arg_trimdomain_list (ENV_TRIM_OVERR, 1, envval, 0); + arg_trimdomain_list (ENV_TRIM_OVERR, 1, envval); } _res_hconf.initialized = 1; diff --git a/resolv/res_hconf.h b/resolv/res_hconf.h index 77eeca4..b40da0d 100644 --- a/resolv/res_hconf.h +++ b/resolv/res_hconf.h @@ -1,4 +1,4 @@ -/* Copyright (C) 1993, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. +/* Copyright (C) 1993, 1995-1998, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by David Mosberger (davidm@azstarnet.com). @@ -24,18 +24,11 @@ #define TRIMDOMAINS_MAX 4 -enum Name_Service -{ - SERVICE_NONE = 0, - SERVICE_BIND, SERVICE_HOSTS, SERVICE_NIS, - SERVICE_MAX -}; - struct hconf { int initialized; - int num_services; - enum Name_Service service[SERVICE_MAX]; + int unused1; + int unused2[4]; int num_trimdomains; const char *trimdomain[TRIMDOMAINS_MAX]; unsigned int flags; diff --git a/resolv/res_init.c b/resolv/res_init.c index 731c784..b5a03d1 100644 --- a/resolv/res_init.c +++ b/resolv/res_init.c @@ -537,10 +537,7 @@ net_mask(in) /* XXX - should really use system's version of this */ u_int res_randomid(void) { - struct timeval now; - - __gettimeofday(&now, NULL); - return (0xffff & (now.tv_sec ^ now.tv_usec ^ __getpid())); + return 0xffff & __getpid(); } #ifdef _LIBC libc_hidden_def (__res_randomid) @@ -555,7 +552,7 @@ libc_hidden_def (__res_randomid) * This routine is not expected to be user visible. */ void -res_nclose(res_state statp) { +__res_iclose(res_state statp, bool free_addr) { int ns; if (statp->_vcsock >= 0) { @@ -568,13 +565,25 @@ res_nclose(res_state statp) { #else for (ns = 0; ns < statp->_u._ext.nscount; ns++) #endif - if (statp->_u._ext.nsaddrs[ns] - && statp->_u._ext.nssocks[ns] != -1) { - close_not_cancel_no_status(statp->_u._ext.nssocks[ns]); - statp->_u._ext.nssocks[ns] = -1; + if (statp->_u._ext.nsaddrs[ns]) { + if (statp->_u._ext.nssocks[ns] != -1) { + close_not_cancel_no_status(statp->_u._ext.nssocks[ns]); + statp->_u._ext.nssocks[ns] = -1; + } + if (free_addr) { + free (statp->_u._ext.nsaddrs[ns]); + statp->_u._ext.nsaddrs[ns] = NULL; + } } statp->_u._ext.nsinit = 0; } +libc_hidden_def (__res_iclose) + +void +res_nclose(res_state statp) +{ + __res_iclose (statp, true); +} #ifdef _LIBC libc_hidden_def (__res_nclose) #endif @@ -589,14 +598,7 @@ res_thread_freeres (void) /* Never called res_ninit. */ return; - __res_nclose (&_res); /* Close any VC sockets. */ - - for (int ns = 0; ns < MAXNS; ns++) - if (_res._u._ext.nsaddrs[ns] != NULL) - { - free (_res._u._ext.nsaddrs[ns]); - _res._u._ext.nsaddrs[ns] = NULL; - } + __res_iclose (&_res, true); /* Close any VC sockets. */ /* Make sure we do a full re-initialization the next time. */ _res.options = 0; diff --git a/resolv/res_libc.c b/resolv/res_libc.c index 76abca8..834773c 100644 --- a/resolv/res_libc.c +++ b/resolv/res_libc.c @@ -70,14 +70,8 @@ res_init(void) { _res.retry = 4; if (!(_res.options & RES_INIT)) _res.options = RES_DEFAULT; - else if (_res.nscount > 0) { - __res_nclose (&_res); /* Close any VC sockets. */ - - for (int ns = 0; ns < MAXNS; ns++) { - free (_res._u._ext.nsaddrs[ns]); - _res._u._ext.nsaddrs[ns] = NULL; - } - } + else if (_res.nscount > 0) + __res_iclose (&_res, true); /* Close any VC sockets. */ /* * This one used to initialize implicitly to zero, so unless the app @@ -103,11 +97,7 @@ __res_maybe_init (res_state resp, int preinit) if (resp->options & RES_INIT) { if (__res_initstamp != resp->_u._ext.initstamp) { if (resp->nscount > 0) { - __res_nclose (resp); - for (int ns = 0; ns < MAXNS; ns++) { - free (resp->_u._ext.nsaddrs[ns]); - resp->_u._ext.nsaddrs[ns] = NULL; - } + __res_iclose (resp, true); return __res_vinit (resp, 1); } } diff --git a/resolv/res_mkquery.c b/resolv/res_mkquery.c index 815fcf8..fd80569 100644 --- a/resolv/res_mkquery.c +++ b/resolv/res_mkquery.c @@ -124,10 +124,6 @@ res_nmkquery(res_state statp, incremented by one after the initial randomization which still predictable if the application does multiple requests. */ -#if 0 - hp->id = htons(++statp->id); -#else - hp->id = htons(statp->id); int randombits; do { @@ -141,7 +137,7 @@ res_nmkquery(res_state statp, } while ((randombits & 0xffff) == 0); statp->id = (statp->id + randombits) & 0xffff; -#endif + hp->id = statp->id; hp->opcode = op; hp->rd = (statp->options & RES_RECURSE) != 0; hp->rcode = NOERROR; @@ -155,38 +151,36 @@ res_nmkquery(res_state statp, * perform opcode specific processing */ switch (op) { - case QUERY: /*FALLTHROUGH*/ case NS_NOTIFY_OP: + if ((buflen -= QFIXEDSZ + (data == NULL ? 0 : RRFIXEDSZ)) < 0) + return (-1); + goto compose; + + case QUERY: if ((buflen -= QFIXEDSZ) < 0) return (-1); + compose: if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0) return (-1); cp += n; buflen -= n; - __putshort(type, cp); - cp += INT16SZ; - __putshort(class, cp); - cp += INT16SZ; + NS_PUT16 (type, cp); + NS_PUT16 (class, cp); hp->qdcount = htons(1); if (op == QUERY || data == NULL) break; /* * Make an additional record for completion domain. */ - buflen -= RRFIXEDSZ; n = dn_comp((char *)data, cp, buflen, dnptrs, lastdnptr); - if (n < 0) + if (__builtin_expect (n < 0, 0)) return (-1); cp += n; buflen -= n; - __putshort(T_NULL, cp); - cp += INT16SZ; - __putshort(class, cp); - cp += INT16SZ; - __putlong(0, cp); - cp += INT32SZ; - __putshort(0, cp); - cp += INT16SZ; + NS_PUT16 (T_NULL, cp); + NS_PUT16 (class, cp); + NS_PUT32 (0, cp); + NS_PUT16 (0, cp); hp->arcount = htons(1); break; @@ -194,17 +188,13 @@ res_nmkquery(res_state statp, /* * Initialize answer section */ - if (buflen < 1 + RRFIXEDSZ + datalen) + if (__builtin_expect (buflen < 1 + RRFIXEDSZ + datalen, 0)) return (-1); *cp++ = '\0'; /* no domain name */ - __putshort(type, cp); - cp += INT16SZ; - __putshort(class, cp); - cp += INT16SZ; - __putlong(0, cp); - cp += INT32SZ; - __putshort(datalen, cp); - cp += INT16SZ; + NS_PUT16 (type, cp); + NS_PUT16 (class, cp); + NS_PUT32 (0, cp); + NS_PUT16 (datalen, cp); if (datalen) { memcpy(cp, data, datalen); cp += datalen; diff --git a/resolv/res_query.c b/resolv/res_query.c index 0feba66..85bad97 100644 --- a/resolv/res_query.c +++ b/resolv/res_query.c @@ -69,6 +69,7 @@ static const char sccsid[] = "@(#)res_query.c 8.1 (Berkeley) 6/4/93"; static const char rcsid[] = "$BINDId: res_query.c,v 8.20 2000/02/29 05:39:12 vixie Exp $"; #endif /* LIBC_SCCS and not lint */ +#include <assert.h> #include <sys/types.h> #include <sys/param.h> #include <netinet/in.h> @@ -151,6 +152,7 @@ __libc_res_nquery(res_state statp, free (buf); return (n); } + assert (answerp == NULL || (void *) *answerp == (void *) answer); n = __libc_res_nsend(statp, buf, n, answer, anslen, answerp); if (use_malloc) free (buf); @@ -163,6 +165,10 @@ __libc_res_nquery(res_state statp, return (n); } + if (answerp != NULL) + /* __libc_res_nsend might have reallocated the buffer. */ + hp = (HEADER *) *answerp; + if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { #ifdef DEBUG if (statp->options & RES_DEBUG) diff --git a/resolv/res_send.c b/resolv/res_send.c index 8fb21a9..887d048 100644 --- a/resolv/res_send.c +++ b/resolv/res_send.c @@ -267,8 +267,8 @@ res_nameinquery(const char *name, int type, int class, cp += n; if (cp + 2 * INT16SZ > eom) return (-1); - ttype = ns_get16(cp); cp += INT16SZ; - tclass = ns_get16(cp); cp += INT16SZ; + NS_GET16(ttype, cp); + NS_GET16(tclass, cp); if (ttype == type && tclass == class && ns_samename(tname, name) == 1) return (1); @@ -292,9 +292,6 @@ int res_queriesmatch(const u_char *buf1, const u_char *eom1, const u_char *buf2, const u_char *eom2) { - const u_char *cp = buf1 + HFIXEDSZ; - int qdcount = ntohs(((HEADER*)buf1)->qdcount); - if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2) return (-1); @@ -306,8 +303,16 @@ res_queriesmatch(const u_char *buf1, const u_char *eom1, (((HEADER *)buf2)->opcode == ns_o_update)) return (1); - if (qdcount != ntohs(((HEADER*)buf2)->qdcount)) + /* Note that we initially do not convert QDCOUNT to the host byte + order. We can compare it with the second buffer's QDCOUNT + value without doing this. */ + int qdcount = ((HEADER*)buf1)->qdcount; + if (qdcount != ((HEADER*)buf2)->qdcount) return (0); + + qdcount = htons (qdcount); + const u_char *cp = buf1 + HFIXEDSZ; + while (qdcount-- > 0) { char tname[MAXDNAME+1]; int n, ttype, tclass; @@ -318,8 +323,8 @@ res_queriesmatch(const u_char *buf1, const u_char *eom1, cp += n; if (cp + 2 * INT16SZ > eom1) return (-1); - ttype = ns_get16(cp); cp += INT16SZ; - tclass = ns_get16(cp); cp += INT16SZ; + NS_GET16(ttype, cp); + NS_GET16(tclass, cp); if (!res_nameinquery(tname, ttype, tclass, buf2, eom2)) return (0); } @@ -381,7 +386,7 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen, } } if (needclose) - res_nclose(statp); + __res_iclose(statp, false); } /* @@ -488,7 +493,7 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen, done = 1; break; case res_nextns: - res_nclose(statp); + __res_iclose(statp, false); goto next_ns; case res_done: return (resplen); @@ -553,7 +558,7 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen, */ if ((v_circuit && (statp->options & RES_USEVC) == 0) || (statp->options & RES_STAYOPEN) == 0) { - res_nclose(statp); + __res_iclose(statp, false); } if (statp->rhook) { int done = 0, loops = 0; @@ -570,7 +575,7 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen, done = 1; break; case res_nextns: - res_nclose(statp); + __res_iclose(statp, false); goto next_ns; case res_modified: /* give the hook another try */ @@ -589,7 +594,7 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen, next_ns: ; } /*foreach ns*/ } /*foreach retry*/ - res_nclose(statp); + __res_iclose(statp, false); if (!v_circuit) { if (!gotsomewhere) __set_errno (ECONNREFUSED); /* no nameservers found */ @@ -632,19 +637,19 @@ send_vc(res_state statp, /* Are we still talking to whom we want to talk to? */ if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) { struct sockaddr_in6 peer; - int size = sizeof peer; + socklen_t size = sizeof peer; if (getpeername(statp->_vcsock, (struct sockaddr *)&peer, &size) < 0 || !sock_eq(&peer, nsap)) { - res_nclose(statp); + __res_iclose(statp, false); statp->_flags &= ~RES_F_VC; } } if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) { if (statp->_vcsock >= 0) - res_nclose(statp); + __res_iclose(statp, false); statp->_vcsock = socket(nsap->sin6_family, SOCK_STREAM, 0); if (statp->_vcsock < 0) { @@ -654,11 +659,13 @@ send_vc(res_state statp, } __set_errno (0); if (connect(statp->_vcsock, (struct sockaddr *)nsap, - sizeof *nsap) < 0) { + nsap->sin6_family == AF_INET + ? sizeof (struct sockaddr_in) + : sizeof (struct sockaddr_in6)) < 0) { *terrno = errno; Aerror(statp, stderr, "connect/vc", errno, (struct sockaddr *) nsap); - res_nclose(statp); + __res_iclose(statp, false); return (0); } statp->_flags |= RES_F_VC; @@ -667,14 +674,14 @@ send_vc(res_state statp, /* * Send length & message */ - putshort((u_short)buflen, (u_char*)&len); + ns_put16((u_short)buflen, (u_char*)&len); evConsIovec(&len, INT16SZ, &iov[0]); evConsIovec((void*)buf, buflen, &iov[1]); if (TEMP_FAILURE_RETRY (writev(statp->_vcsock, iov, 2)) != (INT16SZ + buflen)) { *terrno = errno; Perror(statp, stderr, "write failed", errno); - res_nclose(statp); + __res_iclose(statp, false); return (0); } /* @@ -692,7 +699,7 @@ send_vc(res_state statp, if (n <= 0) { *terrno = errno; Perror(statp, stderr, "read failed", errno); - res_nclose(statp); + __res_iclose(statp, false); /* * A long running process might get its TCP * connection reset if the remote server was @@ -704,10 +711,8 @@ send_vc(res_state statp, */ if (*terrno == ECONNRESET && !connreset) { connreset = 1; - res_nclose(statp); goto same_ns; } - res_nclose(statp); return (0); } resplen = ns_get16(ans); @@ -716,7 +721,7 @@ send_vc(res_state statp, ans = malloc (MAXPACKET); if (ans == NULL) { *terrno = ENOMEM; - res_nclose(statp); + __res_iclose(statp, false); return (0); } anssiz = MAXPACKET; @@ -741,7 +746,7 @@ send_vc(res_state statp, Dprint(statp->options & RES_DEBUG, (stdout, ";; undersized: %d\n", len)); *terrno = EMSGSIZE; - res_nclose(statp); + __res_iclose(statp, false); return (0); } cp = ans; @@ -752,7 +757,7 @@ send_vc(res_state statp, if (n <= 0) { *terrno = errno; Perror(statp, stderr, "read(vc)", errno); - res_nclose(statp); + __res_iclose(statp, false); return (0); } if (truncating) { @@ -809,7 +814,8 @@ send_dg(res_state statp, int ptimeout; struct sockaddr_in6 from; static int socket_pf = 0; - int fromlen, resplen, seconds, n; + socklen_t fromlen; + int resplen, seconds, n; if (EXT(statp).nssocks[ns] == -1) { /* only try IPv6 if IPv6 NS and if not failed before */ @@ -844,7 +850,7 @@ send_dg(res_state statp, sizeof *nsap) < 0) { Aerror(statp, stderr, "connect(dg)", errno, (struct sockaddr *) nsap); - res_nclose(statp); + __res_iclose(statp, false); return (0); } /* Make socket non-blocking. */ @@ -873,10 +879,13 @@ send_dg(res_state statp, pfd[0].events = POLLOUT; wait: if (need_recompute) { + recompute_resend: evNowTime(&now); if (evCmpTime(finish, now) <= 0) { - Perror(statp, stderr, "select", errno); - res_nclose(statp); + poll_err_out: + Perror(statp, stderr, "poll", errno); + err_out: + __res_iclose(statp, false); return (0); } evSubTime(&timeout, &finish, &now); @@ -898,26 +907,18 @@ send_dg(res_state statp, return (0); } if (n < 0) { - if (errno == EINTR) { - recompute_resend: - evNowTime(&now); - if (evCmpTime(finish, now) > 0) { - evSubTime(&timeout, &finish, &now); - goto wait; - } - } - Perror(statp, stderr, "poll", errno); - res_nclose(statp); - return (0); + if (errno == EINTR) + goto recompute_resend; + + goto poll_err_out; } __set_errno (0); if (pfd[0].revents & POLLOUT) { - if (send(pfd[0].fd, (char*)buf, buflen, 0) != buflen) { + if (send (pfd[0].fd, buf, buflen, MSG_NOSIGNAL) != buflen) { if (errno == EINTR || errno == EAGAIN) goto recompute_resend; Perror(statp, stderr, "send", errno); - res_nclose(statp); - return (0); + goto err_out; } pfd[0].events = POLLIN; ++nwritten; @@ -947,8 +948,7 @@ send_dg(res_state statp, goto wait; } Perror(statp, stderr, "recvfrom", errno); - res_nclose(statp); - return (0); + goto err_out; } *gotsomewhere = 1; if (resplen < HFIXEDSZ) { @@ -959,8 +959,7 @@ send_dg(res_state statp, (stdout, ";; undersized: %d\n", resplen)); *terrno = EMSGSIZE; - res_nclose(statp); - return (0); + goto err_out; } if (hp->id != anhp->id) { /* @@ -1007,11 +1006,19 @@ send_dg(res_state statp, DprintQ(statp->options & RES_DEBUG, (stdout, "server rejected query:\n"), ans, (resplen > anssiz) ? anssiz : resplen); - res_nclose(statp); + next_ns: + __res_iclose(statp, false); /* don't retry if called from dig */ if (!statp->pfcode) return (0); } + if (anhp->rcode == NOERROR && anhp->ancount == 0 + && anhp->aa == 0 && anhp->ra == 0 && anhp->arcount == 0) { + DprintQ(statp->options & RES_DEBUG, + (stdout, "referred query:\n"), + ans, (resplen > anssiz) ? anssiz : resplen); + goto next_ns; + } if (!(statp->options & RES_IGNTC) && anhp->tc) { /* * To get the rest of answer, @@ -1020,7 +1027,7 @@ send_dg(res_state statp, Dprint(statp->options & RES_DEBUG, (stdout, ";; truncated answer\n")); *v_circuit = 1; - res_nclose(statp); + __res_iclose(statp, false); return (1); } /* @@ -1030,8 +1037,11 @@ send_dg(res_state statp, return (resplen); } else if (pfd[0].revents & (POLLERR | POLLHUP | POLLNVAL)) { /* Something went wrong. We can stop trying. */ - res_nclose(statp); - return (0); + goto err_out; + } + else { + /* poll should not have returned > 0 in this case. */ + abort (); } } @@ -1047,8 +1057,13 @@ Aerror(const res_state statp, FILE *file, const char *string, int error, fprintf(file, "res_send: %s ([%s].%u): %s\n", string, - inet_ntop(address->sa_family, address->sa_data, - tmp, sizeof tmp), + (address->sa_family == AF_INET + ? inet_ntop(address->sa_family, + &((const struct sockaddr_in *) address)->sin_addr, + tmp, sizeof tmp) + : inet_ntop(address->sa_family, + &((const struct sockaddr_in6 *) address)->sin6_addr, + tmp, sizeof tmp)), (address->sa_family == AF_INET ? ntohs(((struct sockaddr_in *) address)->sin_port) : address->sa_family == AF_INET6 diff --git a/resolv/tst-inet_ntop.c b/resolv/tst-inet_ntop.c new file mode 100644 index 0000000..a042c74 --- /dev/null +++ b/resolv/tst-inet_ntop.c @@ -0,0 +1,111 @@ +#include <arpa/inet.h> +#include <errno.h> +#include <netinet/in.h> +#include <stdio.h> +#include <string.h> + +int +main (void) +{ + struct in_addr addr4; + struct in6_addr addr6; + char buf[64]; + int result = 0; + + addr4.s_addr = 0xe0e0e0e0; + addr6.s6_addr16[0] = 0; + addr6.s6_addr16[1] = 0; + addr6.s6_addr16[2] = 0; + addr6.s6_addr16[3] = 0; + addr6.s6_addr16[4] = 0; + addr6.s6_addr16[5] = 0xffff; + addr6.s6_addr32[3] = 0xe0e0e0e0; + memset (buf, 'x', sizeof buf); + + if (inet_ntop (AF_INET, &addr4, buf, 15) != NULL) + { + puts ("1st inet_ntop returned non-NULL"); + result++; + } + else if (errno != ENOSPC) + { + puts ("1st inet_ntop didn't fail with ENOSPC"); + result++; + } + if (buf[15] != 'x') + { + puts ("1st inet_ntop wrote past the end of buffer"); + result++; + } + + if (inet_ntop (AF_INET, &addr4, buf, 16) != buf) + { + puts ("2nd inet_ntop did not return buf"); + result++; + } + if (memcmp (buf, "224.224.224.224\0" "xxxxxxxx", 24) != 0) + { + puts ("2nd inet_ntop wrote past the end of buffer"); + result++; + } + + if (inet_ntop (AF_INET6, &addr6, buf, 22) != NULL) + { + puts ("3rd inet_ntop returned non-NULL"); + result++; + } + else if (errno != ENOSPC) + { + puts ("3rd inet_ntop didn't fail with ENOSPC"); + result++; + } + if (buf[22] != 'x') + { + puts ("3rd inet_ntop wrote past the end of buffer"); + result++; + } + + if (inet_ntop (AF_INET6, &addr6, buf, 23) != buf) + { + puts ("4th inet_ntop did not return buf"); + result++; + } + if (memcmp (buf, "::ffff:224.224.224.224\0" "xxxxxxxx", 31) != 0) + { + puts ("4th inet_ntop wrote past the end of buffer"); + result++; + } + + memset (&addr6.s6_addr, 0xe0, sizeof (addr6.s6_addr)); + + if (inet_ntop (AF_INET6, &addr6, buf, 39) != NULL) + { + puts ("5th inet_ntop returned non-NULL"); + result++; + } + else if (errno != ENOSPC) + { + puts ("5th inet_ntop didn't fail with ENOSPC"); + result++; + } + if (buf[39] != 'x') + { + puts ("5th inet_ntop wrote past the end of buffer"); + result++; + } + + if (inet_ntop (AF_INET6, &addr6, buf, 40) != buf) + { + puts ("6th inet_ntop did not return buf"); + result++; + } + if (memcmp (buf, "e0e0:e0e0:e0e0:e0e0:e0e0:e0e0:e0e0:e0e0\0" + "xxxxxxxx", 48) != 0) + { + puts ("6th inet_ntop wrote past the end of buffer"); + result++; + } + + + return result; +} |