|  | /* | 
|  | * This file is part of the UCB release of Plan 9. It is subject to the license | 
|  | * terms in the LICENSE file found in the top-level directory of this | 
|  | * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No | 
|  | * part of the UCB release of Plan 9, including this file, may be copied, | 
|  | * modified, propagated, or distributed except according to the terms contained | 
|  | * in the LICENSE file. | 
|  | */ | 
|  | #include <stdlib.h> | 
|  |  | 
|  | #include <stdio.h> | 
|  | #include <parlib.h> | 
|  | #include <unistd.h> | 
|  | #include <signal.h> | 
|  | #include <iplib.h> | 
|  |  | 
|  | static int isascii(int c) {return ((c >=0) && (c <= 128));} | 
|  | static int isalnum(int c) {return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||(c >= '0' && c <= '9'));} | 
|  | static int isdigit(int c) {return ((c >= '0' && c <= '9'));} | 
|  | static int isxdigit(int c) {return ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') ||(c >= '0' && c <= '9'));} | 
|  |  | 
|  | char* | 
|  | v4parseip(uint8_t *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. | 
|  | */ | 
|  | int64_t | 
|  | parseip(uint8_t *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 != (uint16_t)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 | 
|  | */ | 
|  | int64_t | 
|  | parseipmask(uint8_t *to, char *from) | 
|  | { | 
|  | int i, w; | 
|  | int64_t x; | 
|  | uint8_t *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 = (uint32_t)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(uint8_t *addr, uint8_t *mask, char *from) | 
|  | { | 
|  | int i; | 
|  | char *p; | 
|  | uint8_t *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; | 
|  | } |