diff options
-rw-r--r-- | winsup/cygwin/ChangeLog | 17 | ||||
-rw-r--r-- | winsup/cygwin/cygwin.din | 1 | ||||
-rw-r--r-- | winsup/cygwin/include/cygwin/version.h | 3 | ||||
-rw-r--r-- | winsup/cygwin/libc/minires.c | 64 | ||||
-rw-r--r-- | winsup/cygwin/net.cc | 322 | ||||
-rw-r--r-- | winsup/cygwin/posix.sgml | 1 |
6 files changed, 384 insertions, 24 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index c8250556f..c1adc0715 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,20 @@ +2009-03-06 Pierre A. Humblet <pierre@phumblet.no-ip.org> + + * cygwin.din: Export gethostbyname2. + * net.cc: define _CYGWIN_IN_H and include resolv.h. + (realloc_ent): New function. + (dup_ent): Call realloc_ent. + (memcpy4to6): New function. + (dn_length1): New function. + (gethostby_helper): New function. + (gethostbyname2): New function. + * posix.sgml: Add gethostbyname2. + * include/cygwin/version.h: Bump API minor number. + * libc/minires.c (get_options): Look for "inet6" and apply bounds + to "retry" and "retrans". + (res_ninit): Set the default options at the beginning. + (dn_expand): Fix "off by one". + 2009-03-06 Corinna Vinschen <corinna@vinschen.de> * cygwin.din: Export wprintf, fwprintf, swprintf, vwprintf, vfwprintf, diff --git a/winsup/cygwin/cygwin.din b/winsup/cygwin/cygwin.din index b55c9ce56..6977b5999 100644 --- a/winsup/cygwin/cygwin.din +++ b/winsup/cygwin/cygwin.din @@ -636,6 +636,7 @@ _getgroups = getgroups SIGFE _getgroups32 = getgroups32 SIGFE gethostbyaddr = cygwin_gethostbyaddr SIGFE gethostbyname = cygwin_gethostbyname SIGFE +gethostbyname2 SIGFE gethostid SIGFE gethostname = cygwin_gethostname SIGFE _gethostname = cygwin_gethostname SIGFE diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h index bbf98784f..b51ddb665 100644 --- a/winsup/cygwin/include/cygwin/version.h +++ b/winsup/cygwin/include/cygwin/version.h @@ -350,12 +350,13 @@ details. */ 199: Export open_wmemstream. 200: Export mbsnrtowcs, wcsnrtombs. 201: Export wprintf, fwprintf, swprintf, vwprintf, vfwprintf, vswprintf. + 202: Export gethostbyname2. */ /* Note that we forgot to bump the api for ualarm, strtoll, strtoull */ #define CYGWIN_VERSION_API_MAJOR 0 -#define CYGWIN_VERSION_API_MINOR 201 +#define CYGWIN_VERSION_API_MINOR 202 /* There is also a compatibity version number associated with the shared memory regions. It is incremented when incompatible diff --git a/winsup/cygwin/libc/minires.c b/winsup/cygwin/libc/minires.c index 8af24ac8a..606c05dee 100644 --- a/winsup/cygwin/libc/minires.c +++ b/winsup/cygwin/libc/minires.c @@ -1,6 +1,6 @@ /* minires.c. Stub synchronous resolver for Cygwin. - Copyright 2006, 2008 Red Hat, Inc. + Copyright 2006, 2008, 2009 Red Hat, Inc. Written by Pierre A. Humblet <Pierre.Humblet@ieee.org> @@ -99,6 +99,11 @@ static void get_options(res_state statp, int i, char **words) DPRINTF(statp->options & RES_DEBUG, "%s: 1\n", words[i]); continue; } + if (!strcasecmp("inet6", words[i])) { + statp->options |= RES_USE_INET6; + DPRINTF(statp->options & RES_DEBUG, "%s: 1\n", words[i]); + continue; + } if (!strcasecmp("osquery", words[i])) { statp->use_os = 1; DPRINTF(statp->options & RES_DEBUG, "%s: 1\n", words[i]); @@ -114,16 +119,22 @@ static void get_options(res_state statp, int i, char **words) continue; } */ - if (!strcasecmp("retry", words[i])) { + if (!strcasecmp("retry", words[i]) + || !strcasecmp("attempts", words[i])) { if (value < 1) value = 1; + else if (value > RES_MAXRETRY) + value = RES_MAXRETRY; statp->retry = value; DPRINTF(statp->options & RES_DEBUG, "%s: %d\n", words[i], value); continue; } - if (!strcasecmp("retrans", words[i])) { + if (!strcasecmp("retrans", words[i]) + || !strcasecmp("timeout", words[i])) { if (value < 1) value = 1; + else if (value > RES_MAXRETRANS) + value = RES_MAXRETRANS; statp->retrans = value; DPRINTF(statp->options & RES_DEBUG, "%s: %d\n", words[i], value); continue; @@ -270,6 +281,9 @@ int res_ninit(res_state statp) int i; statp->res_h_errno = NETDB_SUCCESS; + /* Only debug may be set before calling init */ + statp->options &= RES_DEBUG; + statp->options |= RES_INIT | RES_DEFAULT; statp->nscount = 0; statp->os_query = NULL; statp->retrans = RES_TIMEOUT; /* timeout in seconds */ @@ -299,9 +313,6 @@ int res_ninit(res_state statp) statp->nsaddr_list[i].sin_port = htons(NAMESERVER_PORT); bzero(statp->nsaddr_list[i].sin_zero, sizeof(statp->nsaddr_list[i].sin_zero)); } - /* Only debug may be set before calling init */ - statp->options &= RES_DEBUG; - statp->options |= RES_INIT | RES_DEFAULT; return 0; } @@ -806,7 +817,7 @@ int dn_expand(const unsigned char *msg, const unsigned char *eomorig, exp_dn++; else do { if (len <= MAXLABEL) { - if ((length -= (len + 1)) > 0 /* Need space for final . */ + if ((length -= (len + 1)) >= 0 /* Need space for final . */ && comp_dn + len <= eomorig) { do { *exp_dn++ = *comp_dn++; } while (--len != 0); *exp_dn++ = '.'; @@ -836,7 +847,6 @@ expand_fail: return -1; } - /***************************************************************** * dn_comp @@ -926,8 +936,7 @@ int dn_comp(const char * exp_dn, u_char * comp_dn, int length, } /***************************************************************** - * - dn_skipname + * dn_skipname Measures the compressed domain name length and returns it. *****************************************************************/ @@ -949,3 +958,38 @@ int dn_skipname(const unsigned char *comp_dn, const unsigned char *eom) return comp_dn - comp_dn_orig; } + +/***************************************************************** + * dn_length1 For internal use + + Return length of uncompressesed name incl final 0. + *****************************************************************/ + +int dn_length1(const unsigned char *msg, const unsigned char *eomorig, + const unsigned char *comp_dn) +{ + unsigned int len, length = 0; + + errno = EINVAL; + if (comp_dn >= eomorig) + goto expand_fail; + else while ((len = *comp_dn++) != 0) { + if (len <= MAXLABEL) { + if ((comp_dn += len) <= eomorig) + length += len + 1; + else + goto expand_fail; + } + else if (len >= (128+64)) { + comp_dn = msg + (((len & ~(128+64)) << 8) + *comp_dn); + if (comp_dn >= eomorig) + goto expand_fail; + } + else + goto expand_fail; + } + return length; + +expand_fail: + return -1; +} diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc index 8ffc041b3..132d639bc 100644 --- a/winsup/cygwin/net.cc +++ b/winsup/cygwin/net.cc @@ -1,7 +1,7 @@ /* net.cc: network-related routines. Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, - 2005, 2006, 2007 Red Hat, Inc. + 2005, 2006, 2007, 2008, 2009 Red Hat, Inc. This file is part of Cygwin. @@ -43,6 +43,8 @@ details. */ #include "cygwin/in6.h" #include "ifaddrs.h" #include "tls_pbuf.h" +#define _CYGWIN_IN_H +#include <resolv.h> extern "C" { @@ -53,6 +55,9 @@ extern "C" int sscanf (const char *, const char *, ...); int cygwin_inet_aton(const char *, struct in_addr *); const char *cygwin_inet_ntop (int, const void *, char *, socklen_t); + int dn_length1(const unsigned char *, const unsigned char *, + const unsigned char *); + } /* End of "C" section */ const struct in6_addr in6addr_any = {{IN6ADDR_ANY_INIT}}; @@ -264,6 +269,25 @@ struct pservent static const char *entnames[] = {"host", "proto", "serv"}; +static unionent * +realloc_ent (unionent *&dst, int sz) +{ + /* Allocate the storage needed. Allocate a rounded size to attempt to force + reuse of this buffer so that a poorly-written caller will not be using + a freed buffer. */ + unsigned rsz = 256 * ((sz + 255) / 256); + unionent * ptr; + if ((ptr = (unionent *) realloc (dst, rsz))) + dst = ptr; + return ptr; +} + +static inline hostent * +realloc_ent (int sz, hostent *) +{ + return (hostent *) realloc_ent (_my_tls.locals.hostent_buf, sz); +} + /* Generic "dup a {host,proto,serv}ent structure" function. This is complicated because we need to be able to free the structure at any point and we can't rely on the pointer contents @@ -310,7 +334,7 @@ dup_ent (unionent *&dst, unionent *src, unionent::struct_type type) break; } - /* Every *ent begins with a name. Calculate it's length. */ + /* Every *ent begins with a name. Calculate its length. */ int namelen = strlen_round (src->name); sz = struct_sz + namelen; @@ -355,13 +379,8 @@ dup_ent (unionent *&dst, unionent *src, unionent::struct_type type) } } - /* Allocate the storage needed. Allocate a rounded size to attempt to force - reuse of this buffer so that a poorly-written caller will not be using - a freed buffer. */ - unsigned rsz = 256 * ((sz + 255) / 256); - dst = (unionent *) realloc (dst, rsz); - - if (dst) + /* Allocate the storage needed. */ + if (realloc_ent (dst, sz)) { memset (dst, 0, sz); /* This field is common to all *ent structures but named differently @@ -857,6 +876,287 @@ cygwin_gethostbyaddr (const char *addr, int len, int type) return res; } +static void +memcpy4to6 (char *dst, const u_char *src) +{ + const unsigned int h[] = {0, 0, htonl (0xFFFF)}; + memcpy (dst, h, 12); + memcpy (dst + 12, src, NS_INADDRSZ); +} + +static hostent * +gethostby_helper (const char *name, const int af, const int type, + const int addrsize_in, const int addrsize_out) +{ + /* Get the data from the name server */ + const int maxcount = 3; + int old_errno, ancount = 0, anlen = 1024, msgsize = 0; + u_char *ptr, *msg = NULL; + int sz; + hostent *ret; + char *string_ptr; + + while ((anlen > msgsize) && (ancount++ < maxcount)) + { + msgsize = anlen; + ptr = (u_char *) realloc (msg, msgsize); + if (ptr == NULL ) + { + old_errno = errno; + free (msg); + set_errno (old_errno); + h_errno = NETDB_INTERNAL; + return NULL; + } + msg = ptr; + anlen = res_search (name, ns_c_in, type, msg, msgsize); + } + + if (ancount >= maxcount) + { + free (msg); + h_errno = NO_RECOVERY; + return NULL; + } + if (anlen < 0) /* errno and h_errno are set */ + { + old_errno = errno; + free (msg); + set_errno (old_errno); + return NULL; + } + u_char *eomsg = msg + anlen - 1; + + + /* We scan the answer records to determine the required memory size. + They can be corrupted and we don't fully trust that the message + follows the standard exactly. glibc applies some checks that + we emulate. + The answers are copied in the hostent structure in a second scan. + To simplify the second scan we store information as follows: + - "class" is replaced by the compressed name size + - the first 16 bits of the "ttl" store the expanded name size + 1 + - the last 16 bits of the "ttl" store the offset to the next valid record. + Note that "type" is rewritten in host byte order. */ + + class record { + public: + unsigned type: 16; // type + unsigned complen: 16; // class or compressed length + unsigned namelen1: 16; // expanded length (with final 0) + unsigned next_o: 16; // offset to next valid + unsigned size: 16; // data size + u_char data[]; // data + record * next () { return (record *) (((char *) this) + next_o); } + void set_next ( record * nxt) { next_o = ((char *) nxt) - ((char *) this); } + u_char * name () { return (u_char *) (((char *) this) - complen); } + }; + + record * anptr = NULL, * prevptr = NULL, * curptr; + int i, alias_count = 0, string_size = 0, address_count = 0; + int complen, namelen1 = 0, address_len = 0, antype, anclass, ansize; + + /* Get the count of answers */ + ancount = ntohs (((HEADER *) msg)->ancount); + + /* Skip the question, it was verified by res_send */ + ptr = msg + sizeof (HEADER); + if ((complen = dn_skipname (ptr, eomsg)) < 0) + goto corrupted; + /* Point to the beginning of the answer section */ + ptr += complen + NS_QFIXEDSZ; + + /* Scan the answer records to determine the sizes */ + for (i = 0; i < ancount; i++, ptr = curptr->data + ansize) + { + if ((complen = dn_skipname (ptr, eomsg)) < 0) + goto corrupted; + + curptr = (record *) (ptr + complen); + antype = ntohs (curptr->type); + anclass = ntohs (curptr->complen); + ansize = ntohs (curptr->size); + /* Class must be internet */ + if (anclass != ns_c_in) + continue; + + curptr->complen = complen; + if ((namelen1 = dn_length1 (msg, eomsg, curptr-> name())) <= 0) + goto corrupted; + + if (antype == ns_t_cname) + { + alias_count++; + string_size += namelen1; + } + else if (antype == type) + { + ansize = ntohs (curptr->size); + if (ansize != addrsize_in) + continue; + if (address_count == 0) + { + address_len = namelen1; + string_size += namelen1; + } + else if (address_len != namelen1) + continue; + address_count++; + } + /* Update the records */ + curptr->type = antype; /* Host byte order */ + curptr->namelen1 = namelen1; + if (! anptr) + anptr = prevptr = curptr; + else + { + prevptr->set_next (curptr); + prevptr = curptr; + } + } + + /* If there is no address, quit */ + if (address_count == 0) + { + free (msg); + h_errno = NO_DATA; + return NULL; + } + + /* Determine the total size */ + sz = DWORD_round (sizeof(hostent)) + + sizeof (char *) * (alias_count + address_count + 2) + + string_size + + address_count * addrsize_out; + + ret = realloc_ent (sz, (hostent *) NULL); + if (! ret) + { + old_errno = errno; + free (msg); + set_errno (old_errno); + h_errno = NETDB_INTERNAL; + return NULL; + } + + ret->h_addrtype = af; + ret->h_length = addrsize_out; + ret->h_aliases = (char **) (((char *) ret) + DWORD_round (sizeof(hostent))); + ret->h_addr_list = ret->h_aliases + alias_count + 1; + string_ptr = (char *) (ret->h_addr_list + address_count + 1); + + /* Rescan the answers */ + ancount = alias_count + address_count; /* Valid records */ + alias_count = address_count = 0; + + for (i = 0, curptr = anptr; i < ancount; i++, curptr = curptr->next ()) + { + antype = curptr->type; + if (antype == ns_t_cname) + { + complen = dn_expand (msg, eomsg, curptr->name (), string_ptr, string_size); +#ifdef DEBUGGING + if (complen != curptr->complen) + go to debugging; +#endif + ret->h_aliases[alias_count++] = string_ptr; + namelen1 = curptr->namelen1; + string_ptr += namelen1; + string_size -= namelen1; + continue; + } + if (antype == type) + { + if (address_count == 0) + { + complen = dn_expand (msg, eomsg, curptr->name(), string_ptr, string_size); +#ifdef DEBUGGING + if (complen != curptr->complen) + go to debugging; +#endif + ret->h_name = string_ptr; + namelen1 = curptr->namelen1; + string_ptr += namelen1; + string_size -= namelen1; + } + ret->h_addr_list[address_count++] = string_ptr; + if (addrsize_in != addrsize_out) + memcpy4to6 (string_ptr, curptr->data); + else + memcpy (string_ptr, curptr->data, addrsize_in); + string_ptr += addrsize_out; + string_size -= addrsize_out; + continue; + } +#ifdef DEBUGGING + /* Should not get here */ + go to debugging; +#endif + } +#ifdef DEBUGGING + if (string_size < 0) + go to debugging; +#endif + + free (msg); + + ret->h_aliases[alias_count] = NULL; + ret->h_addr_list[address_count] = NULL; + + return ret; + + corrupted: + free (msg); + /* Hopefully message corruption errors are temporary. + Should it be NO_RECOVERY ? */ + h_errno = TRY_AGAIN; + return NULL; + + +#ifdef DEBUGGING + debugging: + system_printf ("Please debug."); + free (msg); + free (ret); + h_errno = NO_RECOVERY; + return NULL; +#endif +} + +/* gethostbyname2: standards? */ +extern "C" struct hostent * +gethostbyname2 (const char *name, int af) +{ + sig_dispatch_pending (); + myfault efault; + if (efault.faulted (EFAULT)) + return NULL; + + if (!(_res.options & RES_INIT)) + res_init(); + bool v4to6 = _res.options & RES_USE_INET6; + + int type, addrsize_in, addrsize_out; + switch (af) + { + case AF_INET: + addrsize_in = NS_INADDRSZ; + addrsize_out = (v4to6) ? NS_IN6ADDRSZ : NS_INADDRSZ; + type = ns_t_a; + break; + case AF_INET6: + addrsize_in = addrsize_out = NS_IN6ADDRSZ; + type = ns_t_aaaa; + break; + default: + set_errno (EAFNOSUPPORT); + h_errno = NETDB_INTERNAL; + return NULL; + } + + return gethostby_helper (name, af, type, addrsize_in, addrsize_out); +} + /* exported as accept: standards? */ extern "C" int cygwin_accept (int fd, struct sockaddr *peer, socklen_t *len) @@ -2486,10 +2786,6 @@ cygwin_sendmsg (int fd, const struct msghdr *msg, int flags) * SOFTWARE. */ -#define IN6ADDRSZ 16 -#define INADDRSZ 4 -#define INT16SZ 2 - /* int * inet_pton4(src, dst) * like inet_aton() but without all the hexadecimal and shorthand. diff --git a/winsup/cygwin/posix.sgml b/winsup/cygwin/posix.sgml index c97d09d5b..ab3351551 100644 --- a/winsup/cygwin/posix.sgml +++ b/winsup/cygwin/posix.sgml @@ -1067,6 +1067,7 @@ also IEEE Std 1003.1-2008 (POSIX.1-2008).</para> gcvt (SUSv3) gethostbyaddr (SUSv3) gethostbyname (SUSv3) + gethostbyname2 (first defined in BIND 4.9.4) getpass (SUSv2) getutent (XPG2) getutid (XPG2) |