summaryrefslogtreecommitdiffstats
path: root/winsup/cygwin/net.cc
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2015-01-23 10:46:22 +0000
committerCorinna Vinschen <corinna@vinschen.de>2015-01-23 10:46:22 +0000
commit64f8b4caa3c4b52cb06ed1b1fef3ea373054677f (patch)
tree4f837260a5a7258192e52f182a1c4a61897f2688 /winsup/cygwin/net.cc
parent2ee3908b45157408ed14eceb8f7501a0d5d8f6bb (diff)
downloadcygnal-64f8b4caa3c4b52cb06ed1b1fef3ea373054677f.tar.gz
cygnal-64f8b4caa3c4b52cb06ed1b1fef3ea373054677f.tar.bz2
cygnal-64f8b4caa3c4b52cb06ed1b1fef3ea373054677f.zip
* net.cc (cygwin_inet_pton): Declare.
(gethostby_specials): New function. (gethostby_helper): Change returned addrtype in 4-to-6 case. (gethostbyname2): Call gethostby_specials.
Diffstat (limited to 'winsup/cygwin/net.cc')
-rw-r--r--winsup/cygwin/net.cc120
1 files changed, 113 insertions, 7 deletions
diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc
index 3c485c148..e06fd52b8 100644
--- a/winsup/cygwin/net.cc
+++ b/winsup/cygwin/net.cc
@@ -72,6 +72,7 @@ extern "C"
int __stdcall rcmd (char **ahost, unsigned short inport, char *locuser,
char *remuser, char *cmd, SOCKET * fd2p);
int sscanf (const char *, const char *, ...);
+ int cygwin_inet_pton(int, const char *, void *);
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 *,
@@ -1168,6 +1169,104 @@ memcpy4to6 (char *dst, const u_char *src)
memcpy (dst + 12, src, NS_INADDRSZ);
}
+/* gethostby_specials: RFC 6761
+ Handles numerical addresses and special names for gethostbyname2 */
+static hostent *
+gethostby_specials (const char *name, const int af,
+ const int addrsize_in, const int addrsize_out)
+{
+ int namelen = strlen (name);
+ /* Ignore a final '.' */
+ if ((namelen == 0) || ((namelen -= (name[namelen - 1] == '.')) == 0))
+ {
+ set_errno (EINVAL);
+ h_errno = NETDB_INTERNAL;
+ return NULL;
+ }
+
+ int res;
+ u_char address[NS_IN6ADDRSZ];
+ /* Test for numerical addresses */
+ res = cygwin_inet_pton(af, name, address);
+ /* Test for special domain names */
+ if (res != 1)
+ {
+ {
+ char const match[] = "invalid";
+ int const matchlen = sizeof(match) - 1;
+ int start = namelen - matchlen;
+ if ((start >= 0) && ((start == 0) || (name[start-1] == '.'))
+ && (strncasecmp (&name[start], match , matchlen) == 0))
+ {
+ h_errno = HOST_NOT_FOUND;
+ return NULL;
+ }
+ }
+ {
+ char const match[] = "localhost";
+ int const matchlen = sizeof(match) - 1;
+ int start = namelen - matchlen;
+ if ((start >= 0) && ((start == 0) || (name[start-1] == '.'))
+ && (strncasecmp (&name[start], match , matchlen) == 0))
+ {
+ res = 1;
+ if (af == AF_INET)
+ {
+ address[0] = 127;
+ address[1] = address[2] = 0;
+ address[3] = 1;
+ }
+ else
+ {
+ memset (address, 0, NS_IN6ADDRSZ);
+ address[NS_IN6ADDRSZ-1] = 1;
+ }
+ }
+ }
+ }
+ if (res != 1)
+ return NULL;
+
+ int const alias_count = 0, address_count = 1;
+ char * string_ptr;
+ int sz = DWORD_round (sizeof(hostent))
+ + sizeof (char *) * (alias_count + address_count + 2)
+ + namelen + 1
+ + address_count * addrsize_out;
+ hostent *ret = realloc_ent (sz, (hostent *) NULL);
+ if (!ret)
+ {
+ /* errno is already set */
+ 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);
+ ret->h_name = string_ptr;
+
+ memcpy (string_ptr, name, namelen);
+ string_ptr[namelen] = 0;
+ string_ptr += namelen + 1;
+
+ ret->h_addr_list[0] = string_ptr;
+ if (addrsize_in != addrsize_out)
+ {
+ memcpy4to6 (string_ptr, address);
+ ret->h_addrtype = AF_INET6;
+ }
+ else
+ memcpy (string_ptr, address, addrsize_out);
+
+ ret->h_aliases[alias_count] = NULL;
+ ret->h_addr_list[address_count] = NULL;
+
+ return ret;
+}
+
static hostent *
gethostby_helper (const char *name, const int af, const int type,
const int addrsize_in, const int addrsize_out)
@@ -1211,7 +1310,6 @@ gethostby_helper (const char *name, const int af, const int type,
}
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
@@ -1347,13 +1445,17 @@ gethostby_helper (const char *name, const int af, const int type,
{
if (address_count == 0)
{
- dn_expand (msg, eomsg, curptr->name (), string_ptr, curptr->namelen1);
+ dn_expand (msg, eomsg, curptr->name (), string_ptr,
+ curptr->namelen1);
ret->h_name = string_ptr;
string_ptr += curptr->namelen1;
}
ret->h_addr_list[address_count++] = string_ptr;
if (addrsize_in != addrsize_out)
- memcpy4to6 (string_ptr, curptr->data);
+ {
+ memcpy4to6 (string_ptr, curptr->data);
+ ret->h_addrtype = AF_INET6;
+ }
else
memcpy (string_ptr, curptr->data, addrsize_in);
string_ptr += addrsize_out;
@@ -1367,7 +1469,7 @@ gethostby_helper (const char *name, const int af, const int type,
return ret;
- corrupted:
+corrupted:
free (msg);
/* Hopefully message corruption errors are temporary.
Should it be NO_RECOVERY ? */
@@ -1384,10 +1486,11 @@ gethostbyname2 (const char *name, int af)
__try
{
if (!(_res.options & RES_INIT))
- res_init();
- bool v4to6 = _res.options & RES_USE_INET6;
+ res_init();
+ bool v4to6 = _res.options & RES_USE_INET6;
int type, addrsize_in, addrsize_out;
+
switch (af)
{
case AF_INET:
@@ -1405,7 +1508,10 @@ gethostbyname2 (const char *name, int af)
__leave;
}
- res = gethostby_helper (name, af, type, addrsize_in, addrsize_out);
+ h_errno = NETDB_SUCCESS;
+ res = gethostby_specials (name, af, addrsize_in, addrsize_out);
+ if ((res == NULL) && (h_errno == NETDB_SUCCESS))
+ res = gethostby_helper (name, af, type, addrsize_in, addrsize_out);
}
__except (EFAULT) {}
__endtry