vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | Refs

parseip.c (3525B)


      1 #include "u.h"
      2 #include "lib.h"
      3 #include "ctype.h"
      4 #include "ip.h"
      5 
      6 char*
      7 v4parseip(uchar *to, char *from)
      8 {
      9 	int i;
     10 	char *p;
     11 
     12 	p = from;
     13 	for(i = 0; i < 4 && *p; i++){
     14 		to[i] = strtoul(p, &p, 0);
     15 		if(*p == '.')
     16 			p++;
     17 	}
     18 	switch(CLASS(to)){
     19 	case 0:	/* class A - 1 uchar net */
     20 	case 1:
     21 		if(i == 3){
     22 			to[3] = to[2];
     23 			to[2] = to[1];
     24 			to[1] = 0;
     25 		} else if (i == 2){
     26 			to[3] = to[1];
     27 			to[1] = 0;
     28 		}
     29 		break;
     30 	case 2:	/* class B - 2 uchar net */
     31 		if(i == 3){
     32 			to[3] = to[2];
     33 			to[2] = 0;
     34 		}
     35 		break;
     36 	}
     37 	return p;
     38 }
     39 
     40 static int
     41 ipcharok(int c)
     42 {
     43 	return c == '.' || c == ':' || (isascii(c) && isxdigit(c));
     44 }
     45 
     46 static int
     47 delimchar(int c)
     48 {
     49 	if(c == '\0')
     50 		return 1;
     51 	if(c == '.' || c == ':' || (isascii(c) && isalnum(c)))
     52 		return 0;
     53 	return 1;
     54 }
     55 
     56 /*
     57  * `from' may contain an address followed by other characters,
     58  * at least in /boot, so we permit whitespace (and more) after the address.
     59  * we do ensure that "delete" cannot be parsed as "de::".
     60  *
     61  * some callers don't check the return value for errors, so
     62  * set `to' to something distinctive in the case of a parse error.
     63  */
     64 vlong
     65 parseip(uchar *to, char *from)
     66 {
     67 	int i, elipsis = 0, v4 = 1;
     68 	ulong x;
     69 	char *p, *op;
     70 
     71 	memset(to, 0, IPaddrlen);
     72 	p = from;
     73 	for(i = 0; i < IPaddrlen && ipcharok(*p); i+=2){
     74 		op = p;
     75 		x = strtoul(p, &p, 16);
     76 		if(*p == '.' || (*p == 0 && i == 0)){	/* ends with v4? */
     77 			p = v4parseip(to+i, op);
     78 			i += 4;
     79 			break;
     80 		}
     81 		/* v6: at most 4 hex digits, followed by colon or delim */
     82 		if(x != (ushort)x || (*p != ':' && !delimchar(*p))) {
     83 			memset(to, 0, IPaddrlen);
     84 			return -1;			/* parse error */
     85 		}
     86 		to[i] = x>>8;
     87 		to[i+1] = x;
     88 		if(*p == ':'){
     89 			v4 = 0;
     90 			if(*++p == ':'){	/* :: is elided zero short(s) */
     91 				if (elipsis) {
     92 					memset(to, 0, IPaddrlen);
     93 					return -1;	/* second :: */
     94 				}
     95 				elipsis = i+2;
     96 				p++;
     97 			}
     98 		} else if (p == op)		/* strtoul made no progress? */
     99 			break;
    100 	}
    101 	if (p == from || !delimchar(*p)) {
    102 		memset(to, 0, IPaddrlen);
    103 		return -1;				/* parse error */
    104 	}
    105 	if(i < IPaddrlen){
    106 		memmove(&to[elipsis+IPaddrlen-i], &to[elipsis], i-elipsis);
    107 		memset(&to[elipsis], 0, IPaddrlen-i);
    108 	}
    109 	if(v4){
    110 		to[10] = to[11] = 0xff;
    111 		return nhgetl(to + IPv4off);
    112 	} else
    113 		return 6;
    114 }
    115 
    116 /*
    117  *  hack to allow ip v4 masks to be entered in the old
    118  *  style
    119  */
    120 vlong
    121 parseipmask(uchar *to, char *from)
    122 {
    123 	int i, w;
    124 	vlong x;
    125 	uchar *p;
    126 
    127 	if(*from == '/'){
    128 		/* as a number of prefix bits */
    129 		i = atoi(from+1);
    130 		if(i < 0)
    131 			i = 0;
    132 		if(i > 128)
    133 			i = 128;
    134 		w = i;
    135 		memset(to, 0, IPaddrlen);
    136 		for(p = to; i >= 8; i -= 8)
    137 			*p++ = 0xff;
    138 		if(i > 0)
    139 			*p = ~((1<<(8-i))-1);
    140 		x = nhgetl(to+IPv4off);
    141 		/*
    142 		 * identify as ipv6 if the mask is inexpressible as a v4 mask
    143 		 * (because it has too few mask bits).  Arguably, we could
    144 		 * always return 6 here.
    145 		 */
    146 		if (w < 8*(IPaddrlen-IPv4addrlen))
    147 			return 6;
    148 	} else {
    149 		/* as a straight v4 bit mask */
    150 		x = parseip(to, from);
    151 		if (x != -1)
    152 			x = (ulong)nhgetl(to + IPv4off);
    153 		if(memcmp(to, v4prefix, IPv4off) == 0)
    154 			memset(to, 0xff, IPv4off);
    155 	}
    156 	return x;
    157 }
    158 
    159 /*
    160  *  parse a v4 ip address/mask in cidr format
    161  */
    162 char*
    163 v4parsecidr(uchar *addr, uchar *mask, char *from)
    164 {
    165 	int i;
    166 	char *p;
    167 	uchar *a;
    168 
    169 	p = v4parseip(addr, from);
    170 
    171 	if(*p == '/'){
    172 		/* as a number of prefix bits */
    173 		i = strtoul(p+1, &p, 0);
    174 		if(i > 32)
    175 			i = 32;
    176 		memset(mask, 0, IPv4addrlen);
    177 		for(a = mask; i >= 8; i -= 8)
    178 			*a++ = 0xff;
    179 		if(i > 0)
    180 			*a = ~((1<<(8-i))-1);
    181 	} else 
    182 		memcpy(mask, defmask(addr), IPv4addrlen);
    183 	return p;
    184 }