diff options
| author | Rich Felker <dalias@aerifal.cx> | 2011-04-25 17:04:40 -0400 | 
|---|---|---|
| committer | Rich Felker <dalias@aerifal.cx> | 2011-04-25 17:04:40 -0400 | 
| commit | 34d81974d341e0174d1fc690b4d3e3b9b1767586 (patch) | |
| tree | d1590bf1043fd2a29462f16dad9133f86fbf2baa | |
| parent | 5efc6af4ebb9d50eb978d0338835544fdfea0396 (diff) | |
| download | musl-34d81974d341e0174d1fc690b4d3e3b9b1767586.tar.gz | |
ipv6 parsing code (formerly dummied-out)
| -rw-r--r-- | src/network/__ipparse.c | 8 | ||||
| -rw-r--r-- | src/network/inet_pton.c | 62 | 
2 files changed, 62 insertions, 8 deletions
diff --git a/src/network/__ipparse.c b/src/network/__ipparse.c index 604bdc2f..b0647aac 100644 --- a/src/network/__ipparse.c +++ b/src/network/__ipparse.c @@ -2,11 +2,13 @@  #include <stdlib.h>  #include <sys/socket.h>  #include <netinet/in.h> +#include <arpa/inet.h>  #include "__dns.h"  #include <stdio.h> -int __ipparse(void *dest, int family, const char *s) +int __ipparse(void *dest, int family, const char *s0)  { +	const char *s = s0;  	unsigned char *d = dest;  	unsigned long a[16] = { 0 };  	const char *z; @@ -37,5 +39,7 @@ int __ipparse(void *dest, int family, const char *s)  	return 0;  not_v4: -	return -1; +	s = s0; +	((struct sockaddr_in6 *)d)->sin6_family = AF_INET6; +	return inet_pton(AF_INET6, s, (void *)&((struct sockaddr_in6 *)d)->sin6_addr) <= 0 ? -1 : 0;  } diff --git a/src/network/inet_pton.c b/src/network/inet_pton.c index b7f4834f..5affb08d 100644 --- a/src/network/inet_pton.c +++ b/src/network/inet_pton.c @@ -4,14 +4,23 @@  #include <stdlib.h>  #include <ctype.h>  #include <errno.h> -#include "__dns.h" +#include <string.h> + +static int hexval(unsigned c) +{ +	if (c-'0'<10) return c-'0'; +	c |= 32; +	if (c-'a'<6) return c-'a'+10; +	return -1; +}  int inet_pton(int af, const char *s, void *a0)  { +	uint16_t ip[8];  	unsigned char *a = a0;  	const char *z;  	unsigned long x; -	int i; +	int i, j, v, d, brk=-1, need_v4=0;  	/* Reimplement this because inet_pton cannot accept special v4 forms */  	if (af==AF_INET) { @@ -22,10 +31,51 @@ int inet_pton(int af, const char *s, void *a0)  			s=z+1;  		}  		return 1; -	} else if (af==AF_INET6) { -		return !__ipparse(a, AF_INET6, s); +	} else if (af!=AF_INET6) { +		errno = EAFNOSUPPORT; +		return -1;  	} -	errno = EAFNOSUPPORT; -	return -1; +	if (s[0]==':' && s[1]==':') { +		s+=2; +		brk=0; +	} + +	for (i=0; ; i++, s+=j+1) { +		if (s[0]==':' && brk<0) { +			brk=i; +			j=0; +			ip[i]=0; +			if (!s[1]) break; +			continue; +		} +		if (hexval(s[0])<0) return -1; +		while (s[0]=='0' && s[1]=='0') s++; +		for (v=j=0; j<5 && (d=hexval(s[j]))>=0; j++) +			v=16*v+d; +		if (v > 65535) return -1; +		ip[i] = v; +		if (!s[j]) { +			if (brk<0 && i!=7) return -1; +			break; +		} +		if (i<7) { +			if (s[j]==':') continue; +			if (s[j]!='.') return -1; +			need_v4=1; +			i++; +			break; +		} +		return -1; +	} +	if (brk>=0) { +		memmove(ip+brk+7-i, ip+brk, 2*(i+1-brk)); +		for (j=0; j<7-i; j++) ip[brk+j] = 0; +	} +	for (j=0; j<8; j++) { +		*a++ = ip[j]>>8; +		*a++ = ip[j]; +	} +	if (need_v4 &&inet_pton(AF_INET, (void *)s, a-4) <= 0) return -1; +	return 1;  }  | 
