mirror of
https://github.com/0intro/conterm
synced 2024-11-25 07:09:34 +03:00
23a48c7cfe
Addresses are now stored as uchar[16] instead of ulong, with enough room for IPv6. Generic IP functions have been removed from devip.c and replaced by libip, imported from Plan 9. Names and addresses are resolved using either gethostbyname() or getaddrinfo() functions. On Windows, IPv6 name resolution is not enabled, because mingw32 doesn't provide inet_ntop(). R=rsc http://codereview.appspot.com/6408044
185 lines
3.4 KiB
C
185 lines
3.4 KiB
C
#include <u.h>
|
|
#include <libc.h>
|
|
#include <ctype.h>
|
|
#include <ip.h>
|
|
|
|
char*
|
|
v4parseip(uchar *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;
|
|
}
|
|
|
|
/*
|
|
* `from' may contain an address followed by other characters,
|
|
* at least in /boot, so we permit whitespace (and more) after the address.
|
|
* we do ensure that "delete" cannot be parsed as "de::".
|
|
*
|
|
* some callers don't check the return value for errors, so
|
|
* set `to' to something distinctive in the case of a parse error.
|
|
*/
|
|
vlong
|
|
parseip(uchar *to, char *from)
|
|
{
|
|
int i, elipsis = 0, v4 = 1;
|
|
ulong 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;
|
|
}
|
|
|
|
/*
|
|
* hack to allow ip v4 masks to be entered in the old
|
|
* style
|
|
*/
|
|
vlong
|
|
parseipmask(uchar *to, char *from)
|
|
{
|
|
int i, w;
|
|
vlong x;
|
|
uchar *p;
|
|
|
|
if(*from == '/'){
|
|
/* as a number of prefix bits */
|
|
i = atoi(from+1);
|
|
if(i < 0)
|
|
i = 0;
|
|
if(i > 128)
|
|
i = 128;
|
|
w = i;
|
|
memset(to, 0, IPaddrlen);
|
|
for(p = to; i >= 8; i -= 8)
|
|
*p++ = 0xff;
|
|
if(i > 0)
|
|
*p = ~((1<<(8-i))-1);
|
|
x = nhgetl(to+IPv4off);
|
|
/*
|
|
* identify as ipv6 if the mask is inexpressible as a v4 mask
|
|
* (because it has too few mask bits). Arguably, we could
|
|
* always return 6 here.
|
|
*/
|
|
if (w < 8*(IPaddrlen-IPv4addrlen))
|
|
return 6;
|
|
} else {
|
|
/* as a straight v4 bit mask */
|
|
x = parseip(to, from);
|
|
if (x != -1)
|
|
x = (ulong)nhgetl(to + IPv4off);
|
|
if(memcmp(to, v4prefix, IPv4off) == 0)
|
|
memset(to, 0xff, IPv4off);
|
|
}
|
|
return x;
|
|
}
|
|
|
|
/*
|
|
* parse a v4 ip address/mask in cidr format
|
|
*/
|
|
char*
|
|
v4parsecidr(uchar *addr, uchar *mask, char *from)
|
|
{
|
|
int i;
|
|
char *p;
|
|
uchar *a;
|
|
|
|
p = v4parseip(addr, from);
|
|
|
|
if(*p == '/'){
|
|
/* as a number of prefix bits */
|
|
i = strtoul(p+1, &p, 0);
|
|
if(i > 32)
|
|
i = 32;
|
|
memset(mask, 0, IPv4addrlen);
|
|
for(a = mask; i >= 8; i -= 8)
|
|
*a++ = 0xff;
|
|
if(i > 0)
|
|
*a = ~((1<<(8-i))-1);
|
|
} else
|
|
memcpy(mask, defmask(addr), IPv4addrlen);
|
|
return p;
|
|
}
|