1 #include <u.h> 2 #include <libc.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 == '.' && i <= IPaddrlen-4) || (*p == 0 && i == 0)){ 77 /* ends with v4 */ 78 p = v4parseip(to+i, op); 79 i += 4; 80 break; 81 } 82 /* v6: at most 4 hex digits, followed by colon or delim */ 83 if(x != (ushort)x || *p != ':' && !delimchar(*p)) { 84 memset(to, 0, IPaddrlen); 85 return -1; /* parse error */ 86 } 87 to[i] = x>>8; 88 to[i+1] = x; 89 if(*p == ':'){ 90 v4 = 0; 91 if(*++p == ':'){ /* :: is elided zero short(s) */ 92 if (elipsis) { 93 memset(to, 0, IPaddrlen); 94 return -1; /* second :: */ 95 } 96 elipsis = i+2; 97 p++; 98 } 99 } else if (p == op) /* strtoul made no progress? */ 100 break; 101 } 102 if (p == from || !delimchar(*p)) { 103 memset(to, 0, IPaddrlen); 104 return -1; /* parse error */ 105 } 106 if(i < IPaddrlen){ 107 memmove(&to[elipsis+IPaddrlen-i], &to[elipsis], i-elipsis); 108 memset(&to[elipsis], 0, IPaddrlen-i); 109 } 110 if(v4){ 111 to[10] = to[11] = 0xff; 112 return nhgetl(to + IPv4off); 113 } else 114 return 6; 115 } 116 117 /* 118 * hack to allow ip v4 masks to be entered in the old 119 * style 120 */ 121 vlong 122 parseipmask(uchar *to, char *from) 123 { 124 int i, w; 125 vlong x; 126 uchar *p; 127 128 if(*from == '/'){ 129 /* as a number of prefix bits */ 130 i = atoi(from+1); 131 if(i < 0) 132 i = 0; 133 if(i > 128) 134 i = 128; 135 w = i; 136 memset(to, 0, IPaddrlen); 137 for(p = to; i >= 8; i -= 8) 138 *p++ = 0xff; 139 if(i > 0) 140 *p = ~((1<<(8-i))-1); 141 x = nhgetl(to+IPv4off); 142 /* 143 * identify as ipv6 if the mask is inexpressible as a v4 mask 144 * (because it has too few mask bits). Arguably, we could 145 * always return 6 here. 146 */ 147 if (w < 8*(IPaddrlen-IPv4addrlen)) 148 return 6; 149 } else { 150 /* as a straight v4 bit mask */ 151 x = parseip(to, from); 152 if (x != -1) 153 x = (ulong)nhgetl(to + IPv4off); 154 if(memcmp(to, v4prefix, IPv4off) == 0) 155 memset(to, 0xff, IPv4off); 156 } 157 return x; 158 } 159 160 /* 161 * parse a v4 ip address/mask in cidr format 162 */ 163 char* 164 v4parsecidr(uchar *addr, uchar *mask, char *from) 165 { 166 int i; 167 char *p; 168 uchar *a; 169 170 p = v4parseip(addr, from); 171 172 if(*p == '/'){ 173 /* as a number of prefix bits */ 174 i = strtoul(p+1, &p, 0); 175 if(i > 32) 176 i = 32; 177 memset(mask, 0, IPv4addrlen); 178 for(a = mask; i >= 8; i -= 8) 179 *a++ = 0xff; 180 if(i > 0) 181 *a = ~((1<<(8-i))-1); 182 } else 183 memcpy(mask, defmask(addr), IPv4addrlen); 184 return p; 185 } 186