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 }