From 5ad7c2a1839b960ec96cb19a4923ae289315dc72 Mon Sep 17 00:00:00 2001 From: rofl0r Date: Thu, 25 Apr 2019 14:36:03 +0100 Subject: [PATCH] proxy_getaddrinfo: implement support for numeric ipv6 closes #282 --- src/core.c | 44 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/src/core.c b/src/core.c index 0c4de57..ef8794f 100644 --- a/src/core.c +++ b/src/core.c @@ -789,7 +789,7 @@ struct hostent *proxy_gethostbyname(const char *name, struct gethostbyname_data* struct addrinfo_data { struct addrinfo addrinfo_space; - struct sockaddr sockaddr_space; + struct sockaddr_storage sockaddr_space; char addr_name[256]; }; @@ -822,6 +822,33 @@ static int mygetservbyname_r(const char* name, const char* proto, struct servent return ret; } +static int looks_like_numeric_ipv6(const char *node) +{ + if(!strchr(node, ':')) return 0; + const char* p= node; + while(1) switch(*(p++)) { + case 0: return 1; + case ':': case '.': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + break; + default: return 0; + } +} + +static int my_inet_aton(const char *node, struct addrinfo_data* space) +{ + int ret; + ((struct sockaddr_in *) &space->sockaddr_space)->sin_family = AF_INET; + ret = inet_aton(node, &((struct sockaddr_in *) &space->sockaddr_space)->sin_addr); + if(ret || !looks_like_numeric_ipv6(node)) return ret; + ret = inet_pton(AF_INET6, node, &((struct sockaddr_in6 *) &space->sockaddr_space)->sin6_addr); + if(ret) ((struct sockaddr_in6 *) &space->sockaddr_space)->sin6_family = AF_INET6; + return ret; +} + int proxy_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) { struct gethostbyname_data ghdata; struct addrinfo_data *space; @@ -830,14 +857,14 @@ int proxy_getaddrinfo(const char *node, const char *service, const struct addrin struct servent se_buf; struct addrinfo *p; char buf[1024]; - int port; + int port, af = AF_INET; PFUNC(); // printf("proxy_getaddrinfo node %s service %s\n",node,service); space = calloc(1, sizeof(struct addrinfo_data)); if(!space) goto err1; - if(node && !inet_aton(node, &((struct sockaddr_in *) &space->sockaddr_space)->sin_addr)) { + if(node && !my_inet_aton(node, space)) { /* some folks (nmap) use getaddrinfo() with AI_NUMERICHOST to check whether a string containing a numeric ip was passed. we must return failure in that case. */ if(hints && (hints->ai_flags & AI_NUMERICHOST)) { @@ -850,21 +877,26 @@ int proxy_getaddrinfo(const char *node, const char *service, const struct addrin *(hp->h_addr_list), sizeof(in_addr_t)); else goto err2; + } else if(node) { + af = ((struct sockaddr_in *) &space->sockaddr_space)->sin_family; } if(service) mygetservbyname_r(service, NULL, &se_buf, buf, sizeof(buf), &se); port = se ? se->s_port : htons(atoi(service ? service : "0")); - ((struct sockaddr_in *) &space->sockaddr_space)->sin_port = port; + if(af == AF_INET) + ((struct sockaddr_in *) &space->sockaddr_space)->sin_port = port; + else + ((struct sockaddr_in6 *) &space->sockaddr_space)->sin6_port = port; *res = p = &space->addrinfo_space; assert((size_t)p == (size_t) space); - p->ai_addr = &space->sockaddr_space; + p->ai_addr = (void*) &space->sockaddr_space; if(node) snprintf(space->addr_name, sizeof(space->addr_name), "%s", node); p->ai_canonname = space->addr_name; p->ai_next = NULL; - p->ai_family = space->sockaddr_space.sa_family = AF_INET; + p->ai_family = space->sockaddr_space.ss_family = af; p->ai_addrlen = sizeof(space->sockaddr_space); if(hints) {