diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/network/getaddrinfo.c | 1 | ||||
| -rw-r--r-- | src/network/getnameinfo.c | 32 | ||||
| -rw-r--r-- | src/network/lookup_name.c | 31 | 
3 files changed, 56 insertions, 8 deletions
| diff --git a/src/network/getaddrinfo.c b/src/network/getaddrinfo.c index 70b6cfda..d9913445 100644 --- a/src/network/getaddrinfo.c +++ b/src/network/getaddrinfo.c @@ -105,6 +105,7 @@ int getaddrinfo(const char *restrict host, const char *restrict serv, const stru  		case AF_INET6:  			out[k].sa.sin6.sin6_family = AF_INET6;  			out[k].sa.sin6.sin6_port = htons(ports[j].port); +			out[k].sa.sin6.sin6_scope_id = addrs[i].scopeid;  			memcpy(&out[k].sa.sin6.sin6_addr, &addrs[i].addr, 16);  			break;			  		} diff --git a/src/network/getnameinfo.c b/src/network/getnameinfo.c index dfcf6eda..6962ed1a 100644 --- a/src/network/getnameinfo.c +++ b/src/network/getnameinfo.c @@ -5,6 +5,7 @@  #include <sys/socket.h>  #include <netinet/in.h>  #include <arpa/inet.h> +#include <net/if.h>  int __dns_parse(const unsigned char *, int, int (*)(void *, int, const void *, int, const void *), void *);  int __dn_expand(const unsigned char *, const unsigned char *, const unsigned char *, char *, int); @@ -14,6 +15,16 @@ int __res_send(const unsigned char *, int, unsigned char *, int);  #define PTR_MAX (64 + sizeof ".in-addr.arpa")  #define RR_PTR 12 +static char *itoa(char *p, unsigned x) { +	p += 3*sizeof(int); +	*--p = 0; +	do { +		*--p = '0' + x % 10; +		x /= 10; +	} while (x); +	return p; +} +  static void mkptr4(char *s, const unsigned char *ip)  {  	sprintf(s, "%d.%d.%d.%d.in-addr.arpa", @@ -48,9 +59,10 @@ int getnameinfo(const struct sockaddr *restrict sa, socklen_t sl,  	int flags)  {  	char ptr[PTR_MAX]; -	char buf[256]; +	char buf[256], num[3*sizeof(int)+1];  	int af = sa->sa_family;  	unsigned char *a; +	unsigned x;  	switch (af) {  	case AF_INET: @@ -84,16 +96,28 @@ int getnameinfo(const struct sockaddr *restrict sa, socklen_t sl,  		if (!*buf) {  			if (flags & NI_NAMEREQD) return EAI_NONAME;  			inet_ntop(af, a, buf, sizeof buf); +			if (af == AF_INET6 && +			    (x = ((struct sockaddr_in6 *)sa)->sin6_scope_id)) { +				char *p = 0, tmp[IF_NAMESIZE+1]; +				if (!(flags & NI_NUMERICSCOPE) && +				    (IN6_IS_ADDR_LINKLOCAL(a) || +				     IN6_IS_ADDR_MC_LINKLOCAL(a))) +					p = if_indextoname(x, tmp+1); +				if (!p) +					p = itoa(num, x); +				*--p = '%'; +				strcat(buf, p); +			}  		}  		if (strlen(buf) >= nodelen) return EAI_OVERFLOW;  		strcpy(node, buf);  	}  	if (serv && servlen) { -		if (snprintf(buf, sizeof buf, "%d", -			ntohs(((struct sockaddr_in *)sa)->sin_port))>=servlen) +		char *p = itoa(num, ntohs(((struct sockaddr_in *)sa)->sin_port)); +		if (strlen(p) >= servlen)  			return EAI_OVERFLOW; -		strcpy(serv, buf); +		strcpy(serv, p);  	}  	return 0; diff --git a/src/network/lookup_name.c b/src/network/lookup_name.c index 02920930..492e932c 100644 --- a/src/network/lookup_name.c +++ b/src/network/lookup_name.c @@ -1,6 +1,7 @@  #include <sys/socket.h>  #include <netinet/in.h>  #include <netdb.h> +#include <net/if.h>  #include <arpa/inet.h>  #include <ctype.h>  #include <stdlib.h> @@ -47,9 +48,31 @@ static int name_from_numeric(struct address buf[static 1], const char *name, int  		buf[0].family = AF_INET;  		return 1;  	} -	if (family != AF_INET && inet_pton(AF_INET6, name, &a6)>0) { +	if (family != AF_INET) { +		char tmp[64]; +		char *p = strchr(name, '%'), *z; +		unsigned long long scopeid; +		if (p && p-name < 64) { +			memcpy(tmp, name, p-name); +			tmp[p-name] = 0; +			name = tmp; +		} +		if (inet_pton(AF_INET6, name, &a6)<=0) return 0;  		memcpy(&buf[0].addr, &a6, sizeof a6);  		buf[0].family = AF_INET6; +		if (p) { +			if (isdigit(*++p)) scopeid = strtoull(p, &z, 10); +			else z = p-1; +			if (*z) { +				if (!IN6_IS_ADDR_LINKLOCAL(&a6) && +				    !IN6_IS_ADDR_MC_LINKLOCAL(&a6)) +					return EAI_NONAME; +				scopeid = if_nametoindex(p); +				if (!scopeid) return EAI_NONAME; +			} +			if (scopeid > UINT_MAX) return EAI_NONAME; +			buf[0].scopeid = scopeid; +		}  		return 1;  	}  	return 0; @@ -179,10 +202,10 @@ int __lookup_name(struct address buf[static MAXADDRS], char canon[static 256], c  	/* Try each backend until there's at least one result. */  	cnt = name_from_null(buf, name, family, flags); -	if (cnt<=0) cnt = name_from_numeric(buf, name, family); -	if (cnt<=0 && !(flags & AI_NUMERICHOST)) { +	if (!cnt) cnt = name_from_numeric(buf, name, family); +	if (!cnt && !(flags & AI_NUMERICHOST)) {  		cnt = name_from_hosts(buf, canon, name, family); -		if (cnt<=0) cnt = name_from_dns(buf, canon, name, family); +		if (!cnt) cnt = name_from_dns(buf, canon, name, family);  	}  	if (cnt<=0) return cnt ? cnt : EAI_NONAME; | 
