diff -r 64a4df2c106f Makefile --- a/Makefile Mon Jan 03 15:08:59 2011 -0500 +++ b/Makefile Fri Aug 03 00:00:00 2012 +0200 @@ -12,10 +12,11 @@ qlock.o\ rendez.o\ task.o\ + ip.o\ all: $(LIB) primes tcpproxy testdelay -$(OFILES): taskimpl.h task.h 386-ucontext.h power-ucontext.h +$(OFILES): taskimpl.h task.h 386-ucontext.h power-ucontext.h ip.h AS=gcc -c CC=gcc diff -r 64a4df2c106f Makefile.sun --- a/Makefile.sun Mon Jan 03 15:08:59 2011 -0500 +++ b/Makefile.sun Fri Aug 03 00:00:00 2012 +0200 @@ -9,10 +9,11 @@ qlock.o\ rendez.o\ task.o\ + ip.o\ all: $(LIB) primes tcpproxy testdelay -$(OFILES): taskimpl.h task.h 386-ucontext.h power-ucontext.h +$(OFILES): taskimpl.h task.h 386-ucontext.h power-ucontext.h ip.h AS=as CC=cc diff -r 64a4df2c106f README --- a/README Mon Jan 03 15:08:59 2011 -0500 +++ b/README Fri Aug 03 00:00:00 2012 +0200 @@ -131,10 +131,10 @@ Get the next connection that comes in to the listener fd. Returns a fd to use to talk to the guy who just connected. If server is not null, it must point at a buffer of at least - 16 bytes that is filled in with the remote IP address. + 46 bytes that is filled in with the remote IP address. If port is not null, it is filled in with the report port. Example: - char server[16]; + char server[46]; int port; if(netaccept(fd, server, &port) >= 0) diff -r 64a4df2c106f ip.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ip.c Fri Aug 03 00:00:00 2012 +0200 @@ -0,0 +1,211 @@ +#include "taskimpl.h" +#include +#include +#include "ip.h" + +void +hnputl(void *p, uint v) +{ + uchar *a; + + a = p; + a[0] = v>>24; + a[1] = v>>16; + a[2] = v>>8; + a[3] = v; +} + +void +hnputs(void *p, ushort v) +{ + uchar *a; + + a = p; + a[0] = v>>8; + a[1] = v; +} + +uint32_t +nhgetl(void *p) +{ + unsigned char *a; + + a = p; + return (a[0]<<24)|(a[1]<<16)|(a[2]<<8)|(a[3]<<0); +} + +uint16_t +nhgets(void *p) +{ + unsigned char *a; + + a = p; + return (a[0]<<8)|(a[1]<<0); +} + +char* +v4parseip(unsigned char *to, char *from) +{ + int i; + char *p; + + p = from; + for(i = 0; i < 4 && *p; i++){ + to[i] = strtoul(p, &p, 0); + if(*p == '.') + p++; + } + switch(CLASS(to)){ + case 0: /* class A - 1 uchar net */ + case 1: + if(i == 3){ + to[3] = to[2]; + to[2] = to[1]; + to[1] = 0; + } else if (i == 2){ + to[3] = to[1]; + to[1] = 0; + } + break; + case 2: /* class B - 2 uchar net */ + if(i == 3){ + to[3] = to[2]; + to[2] = 0; + } + break; + } + return p; +} + +static int +ipcharok(int c) +{ + return c == '.' || c == ':' || (isascii(c) && isxdigit(c)); +} + +static int +delimchar(int c) +{ + if(c == '\0') + return 1; + if(c == '.' || c == ':' || (isascii(c) && isalnum(c))) + return 0; + return 1; +} + +uint32_t +parseip(uchar *to, char *from) +{ + int i, elipsis = 0, v4 = 1; + uint32_t x; + char *p, *op; + + memset(to, 0, IPaddrlen); + p = from; + for(i = 0; i < IPaddrlen && ipcharok(*p); i+=2){ + op = p; + x = strtoul(p, &p, 16); + if(*p == '.' || (*p == 0 && i == 0)){ /* ends with v4? */ + p = v4parseip(to+i, op); + i += 4; + break; + } + /* v6: at most 4 hex digits, followed by colon or delim */ + if(x != (ushort)x || (*p != ':' && !delimchar(*p))) { + memset(to, 0, IPaddrlen); + return -1; /* parse error */ + } + to[i] = x>>8; + to[i+1] = x; + if(*p == ':'){ + v4 = 0; + if(*++p == ':'){ /* :: is elided zero short(s) */ + if (elipsis) { + memset(to, 0, IPaddrlen); + return -1; /* second :: */ + } + elipsis = i+2; + p++; + } + } else if (p == op) /* strtoul made no progress? */ + break; + } + if (p == from || !delimchar(*p)) { + memset(to, 0, IPaddrlen); + return -1; /* parse error */ + } + if(i < IPaddrlen){ + memmove(&to[elipsis+IPaddrlen-i], &to[elipsis], i-elipsis); + memset(&to[elipsis], 0, IPaddrlen-i); + } + if(v4){ + to[10] = to[11] = 0xff; + return nhgetl(to + IPv4off); + } else + return 6; +} + +uchar IPnoaddr[IPaddrlen]; + +uchar v4prefix[IPaddrlen] = { + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0xff, 0xff, + 0, 0, 0, 0 +}; + +int +isv4(uchar *ip) +{ + return memcmp(ip, v4prefix, IPv4off) == 0; +} + +void +v4tov6(unsigned char *v6, unsigned char *v4) +{ + v6[0] = 0; + v6[1] = 0; + v6[2] = 0; + v6[3] = 0; + v6[4] = 0; + v6[5] = 0; + v6[6] = 0; + v6[7] = 0; + v6[8] = 0; + v6[9] = 0; + v6[10] = 0xff; + v6[11] = 0xff; + v6[12] = v4[0]; + v6[13] = v4[1]; + v6[14] = v4[2]; + v6[15] = v4[3]; +} + +int +v6tov4(unsigned char *v4, unsigned char *v6) +{ + if(v6[0] == 0 + && v6[1] == 0 + && v6[2] == 0 + && v6[3] == 0 + && v6[4] == 0 + && v6[5] == 0 + && v6[6] == 0 + && v6[7] == 0 + && v6[8] == 0 + && v6[9] == 0 + && v6[10] == 0xff + && v6[11] == 0xff) + { + v4[0] = v6[12]; + v4[1] = v6[13]; + v4[2] = v6[14]; + v4[3] = v6[15]; + return 0; + } else { + memset(v4, 0, 4); + if(memcmp(v6, IPnoaddr, IPaddrlen) == 0) + return 0; + return -1; + } +} diff -r 64a4df2c106f ip.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ip.h Fri Aug 03 00:00:00 2012 +0200 @@ -0,0 +1,32 @@ +#ifndef _IP_H_ +#define _IP_H_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +enum +{ + IPaddrlen = 16, + IPv4addrlen = 4, + IPv4off = 12 +}; + +int isv4(unsigned char*); +uint32_t parseip(unsigned char*, char*); +char* v4parseip(unsigned char*, char*); + +void hnputl(void*, uint32_t); +void hnputs(void*, uint16_t); +uint32_t nhgetl(void*); +uint16_t nhgets(void*); + +int v6tov4(unsigned char*, unsigned char*); +void v4tov6(unsigned char*, unsigned char*); + +#define CLASS(p) ((*(uchar*)(p))>>6) + +#ifdef __cplusplus +} +#endif +#endif diff -r 64a4df2c106f net.c --- a/net.c Mon Jan 03 15:08:59 2011 -0500 +++ b/net.c Fri Aug 03 00:00:00 2012 +0200 @@ -4,29 +4,56 @@ #include #include #include +#include #include +#include "ip.h" + +static int +family(unsigned char *addr) +{ + if(isv4(addr)) + return AF_INET; + return AF_INET6; +} int netannounce(int istcp, char *server, int port) { int fd, n, proto; - struct sockaddr_in sa; + struct sockaddr_storage ss; socklen_t sn; - uint32_t ip; + unsigned char ip[IPaddrlen]; taskstate("netannounce"); proto = istcp ? SOCK_STREAM : SOCK_DGRAM; - memset(&sa, 0, sizeof sa); - sa.sin_family = AF_INET; + memset(&ss, 0, sizeof ss); if(server != nil && strcmp(server, "*") != 0){ - if(netlookup(server, &ip) < 0){ + if(netlookup(server, ip) < 0){ taskstate("netlookup failed"); return -1; } - memmove(&sa.sin_addr, &ip, 4); + ss.ss_family = family(ip); + switch(ss.ss_family){ + case AF_INET: + v6tov4((unsigned char*)&((struct sockaddr_in*)&ss)->sin_addr.s_addr, ip); + break; + case AF_INET6: + memcpy(&((struct sockaddr_in6*)&ss)->sin6_addr.s6_addr, ip, sizeof(struct in6_addr)); + break; + } + }else{ + ss.ss_family = AF_INET6; + ((struct sockaddr_in6*)&ss)->sin6_addr = in6addr_any; } - sa.sin_port = htons(port); - if((fd = socket(AF_INET, proto, 0)) < 0){ + switch(ss.ss_family){ + case AF_INET: + hnputs(&((struct sockaddr_in*)&ss)->sin_port, port); + break; + case AF_INET6: + hnputs(&((struct sockaddr_in6*)&ss)->sin6_port, port); + break; + } + if((fd = socket(ss.ss_family, proto, 0)) < 0){ taskstate("socket failed"); return -1; } @@ -37,7 +64,7 @@ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&n, sizeof n); } - if(bind(fd, (struct sockaddr*)&sa, sizeof sa) < 0){ + if(bind(fd, (struct sockaddr*)&ss, sizeof ss) < 0){ taskstate("bind failed"); close(fd); return -1; @@ -55,24 +82,32 @@ netaccept(int fd, char *server, int *port) { int cfd, one; - struct sockaddr_in sa; - uchar *ip; + struct sockaddr_storage ss; socklen_t len; fdwait(fd, 'r'); taskstate("netaccept"); - len = sizeof sa; - if((cfd = accept(fd, (void*)&sa, &len)) < 0){ + len = sizeof ss; + if((cfd = accept(fd, (void*)&ss, &len)) < 0){ taskstate("accept failed"); return -1; } - if(server){ - ip = (uchar*)&sa.sin_addr; - snprint(server, 16, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); + + switch(ss.ss_family){ + case AF_INET: + if(server) + inet_ntop(AF_INET, &((struct sockaddr_in*)&ss)->sin_addr.s_addr, server, INET_ADDRSTRLEN); + if(port) + *port = nhgets(&((struct sockaddr_in*)&ss)->sin_port); + break; + case AF_INET6: + if(server) + inet_ntop(AF_INET6, &((struct sockaddr_in6*)&ss)->sin6_addr.s6_addr, server, INET6_ADDRSTRLEN); + if(port) + *port = nhgets(&((struct sockaddr_in6*)&ss)->sin6_port); + break; } - if(port) - *port = ntohs(sa.sin_port); fdnoblock(cfd); one = 1; setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof one); @@ -80,64 +115,30 @@ return cfd; } -#define CLASS(p) ((*(unsigned char*)(p))>>6) -static int -parseip(char *name, uint32_t *ip) -{ - unsigned char addr[4]; - char *p; - int i, x; - - p = name; - for(i=0; i<4 && *p; i++){ - x = strtoul(p, &p, 0); - if(x < 0 || x >= 256) - return -1; - if(*p != '.' && *p != 0) - return -1; - if(*p == '.') - p++; - addr[i] = x; - } - - switch(CLASS(addr)){ - case 0: - case 1: - if(i == 3){ - addr[3] = addr[2]; - addr[2] = addr[1]; - addr[1] = 0; - }else if(i == 2){ - addr[3] = addr[1]; - addr[2] = 0; - addr[1] = 0; - }else if(i != 4) - return -1; - break; - case 2: - if(i == 3){ - addr[3] = addr[2]; - addr[2] = 0; - }else if(i != 4) - return -1; - break; - } - *ip = *(uint32_t*)addr; - return 0; -} - int -netlookup(char *name, uint32_t *ip) +netlookup(char *name, unsigned char *ip) { struct hostent *he; + struct addrinfo *result; - if(parseip(name, ip) >= 0) + if(parseip(ip, name) >= 0) return 0; /* BUG - Name resolution blocks. Need a non-blocking DNS. */ taskstate("netlookup"); if((he = gethostbyname(name)) != 0){ - *ip = *(uint32_t*)he->h_addr; + ip = (unsigned char*)he->h_addr; + taskstate("netlookup succeeded"); + return 0; + }else if(getaddrinfo(name, NULL, NULL, &result) == 0) { + switch (result->ai_family) { + case AF_INET: + v4tov6(ip, (unsigned char*)&((struct sockaddr_in*)result->ai_addr)->sin_addr.s_addr); + break; + case AF_INET6: + memcpy(ip, (unsigned char*)&((struct sockaddr_in6*)result->ai_addr)->sin6_addr.s6_addr, sizeof(struct in6_addr)); + break; + } taskstate("netlookup succeeded"); return 0; } @@ -150,16 +151,16 @@ netdial(int istcp, char *server, int port) { int proto, fd, n; - uint32_t ip; - struct sockaddr_in sa; + unsigned char ip[IPaddrlen]; + struct sockaddr_storage ss; socklen_t sn; - if(netlookup(server, &ip) < 0) + if(netlookup(server, ip) < 0) return -1; taskstate("netdial"); proto = istcp ? SOCK_STREAM : SOCK_DGRAM; - if((fd = socket(AF_INET, proto, 0)) < 0){ + if((fd = socket(family(ip), proto, 0)) < 0){ taskstate("socket failed"); return -1; } @@ -172,11 +173,20 @@ } /* start connecting */ - memset(&sa, 0, sizeof sa); - memmove(&sa.sin_addr, &ip, 4); - sa.sin_family = AF_INET; - sa.sin_port = htons(port); - if(connect(fd, (struct sockaddr*)&sa, sizeof sa) < 0 && errno != EINPROGRESS){ + memset(&ss, 0, sizeof ss); + ss.ss_family = family(ip); + switch(ss.ss_family){ + case AF_INET: + v6tov4((unsigned char*)&((struct sockaddr_in*)&ss)->sin_addr.s_addr, ip); + hnputs(&((struct sockaddr_in*)&ss)->sin_port, port); + break; + case AF_INET6: + memcpy(&((struct sockaddr_in6*)&ss)->sin6_addr.s6_addr, ip, sizeof(struct in6_addr)); + hnputs(&((struct sockaddr_in6*)&ss)->sin6_port, port); + break; + } + + if(connect(fd, (struct sockaddr*)&ss, sizeof ss) < 0 && errno != EINPROGRESS){ taskstate("connect failed"); close(fd); return -1; @@ -184,8 +194,8 @@ /* wait for finish */ fdwait(fd, 'w'); - sn = sizeof sa; - if(getpeername(fd, (struct sockaddr*)&sa, &sn) >= 0){ + sn = sizeof ss; + if(getpeername(fd, (struct sockaddr*)&ss, &sn) >= 0){ taskstate("connect succeeded"); return fd; } diff -r 64a4df2c106f task.h --- a/task.h Mon Jan 03 15:08:59 2011 -0500 +++ b/task.h Fri Aug 03 00:00:00 2012 +0200 @@ -172,7 +172,7 @@ int netannounce(int, char*, int); int netaccept(int, char*, int*); int netdial(int, char*, int); -int netlookup(char*, uint32_t*); /* blocks entire program! */ +int netlookup(char*, unsigned char*); /* blocks entire program! */ int netdial(int, char*, int); #ifdef __cplusplus diff -r 64a4df2c106f tcpproxy.c --- a/tcpproxy.c Mon Jan 03 15:08:59 2011 -0500 +++ b/tcpproxy.c Fri Aug 03 00:00:00 2012 +0200 @@ -36,7 +36,7 @@ { int cfd, fd; int rport; - char remote[16]; + char remote[46]; if(argc != 4){ fprintf(stderr, "usage: tcpproxy localport server remoteport\n"); @@ -52,7 +52,7 @@ fdnoblock(fd); while((cfd = netaccept(fd, remote, &rport)) >= 0){ fprintf(stderr, "connection from %s:%d\n", remote, rport); - taskcreate(proxytask, (void*)cfd, STACK); + taskcreate(proxytask, (void*)(uintptr_t)cfd, STACK); } } @@ -61,7 +61,7 @@ { int fd, remotefd; - fd = (int)v; + fd = (int)(uintptr_t)v; if((remotefd = netdial(TCP, server, port)) < 0){ close(fd); return; diff -r 64a4df2c106f testdelay.c --- a/testdelay.c Mon Jan 03 15:08:59 2011 -0500 +++ b/testdelay.c Fri Aug 03 00:00:00 2012 +0200 @@ -12,8 +12,8 @@ void delaytask(void *v) { - taskdelay((int)v); - printf("awake after %d ms\n", (int)v); + taskdelay((int)(uintptr_t)v); + printf("awake after %d ms\n", (int)(uintptr_t)v); chansendul(c, 0); } @@ -28,7 +28,7 @@ for(i=1; i