diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/libip/parseip.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/libip/parseip.c')
-rwxr-xr-x | sys/src/libip/parseip.c | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/sys/src/libip/parseip.c b/sys/src/libip/parseip.c new file mode 100755 index 000000000..7856b4a6c --- /dev/null +++ b/sys/src/libip/parseip.c @@ -0,0 +1,184 @@ +#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; +} |