1 /*- 2 * BSD LICENSE 3 * 4 * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * Copyright (c) 2009, Olivier MATZ <[email protected]> 36 * All rights reserved. 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions are met: 39 * 40 * * Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * * Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * * Neither the name of the University of California, Berkeley nor the 46 * names of its contributors may be used to endorse or promote products 47 * derived from this software without specific prior written permission. 48 * 49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 50 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 51 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 52 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 53 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 54 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 55 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 56 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 57 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 58 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 59 */ 60 61 /* 62 * For inet_ntop() functions: 63 * 64 * Copyright (c) 1996 by Internet Software Consortium. 65 * 66 * Permission to use, copy, modify, and distribute this software for any 67 * purpose with or without fee is hereby granted, provided that the above 68 * copyright notice and this permission notice appear in all copies. 69 * 70 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS 71 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 72 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE 73 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 74 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 75 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 76 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 77 * SOFTWARE. 78 */ 79 80 81 #include <stdio.h> 82 #include <stdlib.h> 83 #include <stdarg.h> 84 #include <inttypes.h> 85 #include <ctype.h> 86 #include <string.h> 87 #include <errno.h> 88 #include <netinet/in.h> 89 #ifndef __linux__ 90 #ifndef __FreeBSD__ 91 #include <net/socket.h> 92 #else 93 #include <sys/socket.h> 94 #endif 95 #endif 96 97 #include <rte_string_fns.h> 98 99 #include "cmdline_parse.h" 100 #include "cmdline_parse_ipaddr.h" 101 102 struct cmdline_token_ops cmdline_token_ipaddr_ops = { 103 .parse = cmdline_parse_ipaddr, 104 .complete_get_nb = NULL, 105 .complete_get_elt = NULL, 106 .get_help = cmdline_get_help_ipaddr, 107 }; 108 109 #define INADDRSZ 4 110 #define IN6ADDRSZ 16 111 #define PREFIXMAX 128 112 #define V4PREFIXMAX 32 113 114 /* 115 * WARNING: Don't even consider trying to compile this on a system where 116 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. 117 */ 118 119 static int inet_pton4(const char *src, unsigned char *dst); 120 static int inet_pton6(const char *src, unsigned char *dst); 121 122 /* int 123 * inet_pton(af, src, dst) 124 * convert from presentation format (which usually means ASCII printable) 125 * to network format (which is usually some kind of binary format). 126 * return: 127 * 1 if the address was valid for the specified address family 128 * 0 if the address wasn't valid (`dst' is untouched in this case) 129 * -1 if some other error occurred (`dst' is untouched in this case, too) 130 * author: 131 * Paul Vixie, 1996. 132 */ 133 static int 134 my_inet_pton(int af, const char *src, void *dst) 135 { 136 switch (af) { 137 case AF_INET: 138 return inet_pton4(src, dst); 139 case AF_INET6: 140 return inet_pton6(src, dst); 141 default: 142 errno = EAFNOSUPPORT; 143 return -1; 144 } 145 /* NOTREACHED */ 146 } 147 148 /* int 149 * inet_pton4(src, dst) 150 * like inet_aton() but without all the hexadecimal and shorthand. 151 * return: 152 * 1 if `src' is a valid dotted quad, else 0. 153 * notice: 154 * does not touch `dst' unless it's returning 1. 155 * author: 156 * Paul Vixie, 1996. 157 */ 158 static int 159 inet_pton4(const char *src, unsigned char *dst) 160 { 161 static const char digits[] = "0123456789"; 162 int saw_digit, octets, ch; 163 unsigned char tmp[INADDRSZ], *tp; 164 165 saw_digit = 0; 166 octets = 0; 167 *(tp = tmp) = 0; 168 while ((ch = *src++) != '\0') { 169 const char *pch; 170 171 if ((pch = strchr(digits, ch)) != NULL) { 172 unsigned int new = *tp * 10 + (pch - digits); 173 174 if (new > 255) 175 return 0; 176 if (! saw_digit) { 177 if (++octets > 4) 178 return 0; 179 saw_digit = 1; 180 } 181 *tp = (unsigned char)new; 182 } else if (ch == '.' && saw_digit) { 183 if (octets == 4) 184 return 0; 185 *++tp = 0; 186 saw_digit = 0; 187 } else 188 return 0; 189 } 190 if (octets < 4) 191 return 0; 192 193 memcpy(dst, tmp, INADDRSZ); 194 return 1; 195 } 196 197 /* int 198 * inet_pton6(src, dst) 199 * convert presentation level address to network order binary form. 200 * return: 201 * 1 if `src' is a valid [RFC1884 2.2] address, else 0. 202 * notice: 203 * (1) does not touch `dst' unless it's returning 1. 204 * (2) :: in a full address is silently ignored. 205 * credit: 206 * inspired by Mark Andrews. 207 * author: 208 * Paul Vixie, 1996. 209 */ 210 static int 211 inet_pton6(const char *src, unsigned char *dst) 212 { 213 static const char xdigits_l[] = "0123456789abcdef", 214 xdigits_u[] = "0123456789ABCDEF"; 215 unsigned char tmp[IN6ADDRSZ], *tp = 0, *endp = 0, *colonp = 0; 216 const char *xdigits = 0, *curtok = 0; 217 int ch = 0, saw_xdigit = 0, count_xdigit = 0; 218 unsigned int val = 0; 219 unsigned dbloct_count = 0; 220 221 memset((tp = tmp), '\0', IN6ADDRSZ); 222 endp = tp + IN6ADDRSZ; 223 colonp = NULL; 224 /* Leading :: requires some special handling. */ 225 if (*src == ':') 226 if (*++src != ':') 227 return 0; 228 curtok = src; 229 saw_xdigit = count_xdigit = 0; 230 val = 0; 231 232 while ((ch = *src++) != '\0') { 233 const char *pch; 234 235 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) 236 pch = strchr((xdigits = xdigits_u), ch); 237 if (pch != NULL) { 238 if (count_xdigit >= 4) 239 return 0; 240 val <<= 4; 241 val |= (pch - xdigits); 242 if (val > 0xffff) 243 return 0; 244 saw_xdigit = 1; 245 count_xdigit++; 246 continue; 247 } 248 if (ch == ':') { 249 curtok = src; 250 if (!saw_xdigit) { 251 if (colonp) 252 return 0; 253 colonp = tp; 254 continue; 255 } else if (*src == '\0') { 256 return 0; 257 } 258 if (tp + sizeof(int16_t) > endp) 259 return 0; 260 *tp++ = (unsigned char) ((val >> 8) & 0xff); 261 *tp++ = (unsigned char) (val & 0xff); 262 saw_xdigit = 0; 263 count_xdigit = 0; 264 val = 0; 265 dbloct_count++; 266 continue; 267 } 268 if (ch == '.' && ((tp + INADDRSZ) <= endp) && 269 inet_pton4(curtok, tp) > 0) { 270 tp += INADDRSZ; 271 saw_xdigit = 0; 272 dbloct_count += 2; 273 break; /* '\0' was seen by inet_pton4(). */ 274 } 275 return 0; 276 } 277 if (saw_xdigit) { 278 if (tp + sizeof(int16_t) > endp) 279 return 0; 280 *tp++ = (unsigned char) ((val >> 8) & 0xff); 281 *tp++ = (unsigned char) (val & 0xff); 282 dbloct_count++; 283 } 284 if (colonp != NULL) { 285 /* if we already have 8 double octets, having a colon means error */ 286 if (dbloct_count == 8) 287 return 0; 288 289 /* 290 * Since some memmove()'s erroneously fail to handle 291 * overlapping regions, we'll do the shift by hand. 292 */ 293 const int n = tp - colonp; 294 int i; 295 296 for (i = 1; i <= n; i++) { 297 endp[- i] = colonp[n - i]; 298 colonp[n - i] = 0; 299 } 300 tp = endp; 301 } 302 if (tp != endp) 303 return 0; 304 memcpy(dst, tmp, IN6ADDRSZ); 305 return 1; 306 } 307 308 int 309 cmdline_parse_ipaddr(cmdline_parse_token_hdr_t *tk, const char *buf, void *res, 310 unsigned ressize) 311 { 312 struct cmdline_token_ipaddr *tk2; 313 unsigned int token_len = 0; 314 char ip_str[INET6_ADDRSTRLEN+4+1]; /* '+4' is for prefixlen (if any) */ 315 cmdline_ipaddr_t ipaddr; 316 char *prefix, *prefix_end; 317 long prefixlen = 0; 318 319 if (res && ressize < sizeof(cmdline_ipaddr_t)) 320 return -1; 321 322 if (!buf || !tk || ! *buf) 323 return -1; 324 325 tk2 = (struct cmdline_token_ipaddr *)tk; 326 327 while (!cmdline_isendoftoken(buf[token_len])) 328 token_len++; 329 330 /* if token is too big... */ 331 if (token_len >= INET6_ADDRSTRLEN+4) 332 return -1; 333 334 snprintf(ip_str, token_len+1, "%s", buf); 335 336 /* convert the network prefix */ 337 if (tk2->ipaddr_data.flags & CMDLINE_IPADDR_NETWORK) { 338 prefix = strrchr(ip_str, '/'); 339 if (prefix == NULL) 340 return -1; 341 *prefix = '\0'; 342 prefix ++; 343 errno = 0; 344 prefixlen = strtol(prefix, &prefix_end, 10); 345 if (errno || (*prefix_end != '\0') 346 || prefixlen < 0 || prefixlen > PREFIXMAX) 347 return -1; 348 ipaddr.prefixlen = prefixlen; 349 } 350 else { 351 ipaddr.prefixlen = 0; 352 } 353 354 /* convert the IP addr */ 355 if ((tk2->ipaddr_data.flags & CMDLINE_IPADDR_V4) && 356 my_inet_pton(AF_INET, ip_str, &ipaddr.addr.ipv4) == 1 && 357 prefixlen <= V4PREFIXMAX) { 358 ipaddr.family = AF_INET; 359 if (res) 360 memcpy(res, &ipaddr, sizeof(ipaddr)); 361 return token_len; 362 } 363 if ((tk2->ipaddr_data.flags & CMDLINE_IPADDR_V6) && 364 my_inet_pton(AF_INET6, ip_str, &ipaddr.addr.ipv6) == 1) { 365 ipaddr.family = AF_INET6; 366 if (res) 367 memcpy(res, &ipaddr, sizeof(ipaddr)); 368 return token_len; 369 } 370 return -1; 371 372 } 373 374 int cmdline_get_help_ipaddr(cmdline_parse_token_hdr_t *tk, char *dstbuf, 375 unsigned int size) 376 { 377 struct cmdline_token_ipaddr *tk2; 378 379 if (!tk || !dstbuf) 380 return -1; 381 382 tk2 = (struct cmdline_token_ipaddr *)tk; 383 384 switch (tk2->ipaddr_data.flags) { 385 case CMDLINE_IPADDR_V4: 386 snprintf(dstbuf, size, "IPv4"); 387 break; 388 case CMDLINE_IPADDR_V6: 389 snprintf(dstbuf, size, "IPv6"); 390 break; 391 case CMDLINE_IPADDR_V4|CMDLINE_IPADDR_V6: 392 snprintf(dstbuf, size, "IPv4/IPv6"); 393 break; 394 case CMDLINE_IPADDR_NETWORK|CMDLINE_IPADDR_V4: 395 snprintf(dstbuf, size, "IPv4 network"); 396 break; 397 case CMDLINE_IPADDR_NETWORK|CMDLINE_IPADDR_V6: 398 snprintf(dstbuf, size, "IPv6 network"); 399 break; 400 case CMDLINE_IPADDR_NETWORK|CMDLINE_IPADDR_V4|CMDLINE_IPADDR_V6: 401 snprintf(dstbuf, size, "IPv4/IPv6 network"); 402 break; 403 default: 404 snprintf(dstbuf, size, "IPaddr (bad flags)"); 405 break; 406 } 407 return 0; 408 } 409