1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2014 Intel Corporation
8 #include <netinet/in.h>
12 #include <net/socket.h>
14 #include <sys/socket.h>
18 #include <rte_string_fns.h>
20 #include <cmdline_parse.h>
21 #include <cmdline_parse_ipaddr.h>
23 #include "test_cmdline.h"
25 #define IP4(a,b,c,d) {((uint32_t)(((a) & 0xff)) | \
26 (((b) & 0xff) << 8) | \
27 (((c) & 0xff) << 16) | \
31 (((x & 0xFF) << 8) | ((x & 0xFF00) >> 8))
33 /* create IPv6 address, swapping bytes where needed */
35 # define s6_addr16 __u6_addr.__u6_addr16
37 #define IP6(a,b,c,d,e,f,g,h) .ipv6 = \
39 {U16_SWAP(a),U16_SWAP(b),U16_SWAP(c),U16_SWAP(d),\
40 U16_SWAP(e),U16_SWAP(f),U16_SWAP(g),U16_SWAP(h)}}
42 /** these are defined in netinet/in.h but not present in linux headers */
45 #define NIPQUAD_FMT "%u.%u.%u.%u"
46 #define NIPQUAD(addr) \
47 (unsigned)((unsigned char *)&addr)[0], \
48 (unsigned)((unsigned char *)&addr)[1], \
49 (unsigned)((unsigned char *)&addr)[2], \
50 (unsigned)((unsigned char *)&addr)[3]
52 #define NIP6_FMT "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x"
54 (unsigned)((addr).s6_addr[0]), \
55 (unsigned)((addr).s6_addr[1]), \
56 (unsigned)((addr).s6_addr[2]), \
57 (unsigned)((addr).s6_addr[3]), \
58 (unsigned)((addr).s6_addr[4]), \
59 (unsigned)((addr).s6_addr[5]), \
60 (unsigned)((addr).s6_addr[6]), \
61 (unsigned)((addr).s6_addr[7]), \
62 (unsigned)((addr).s6_addr[8]), \
63 (unsigned)((addr).s6_addr[9]), \
64 (unsigned)((addr).s6_addr[10]), \
65 (unsigned)((addr).s6_addr[11]), \
66 (unsigned)((addr).s6_addr[12]), \
67 (unsigned)((addr).s6_addr[13]), \
68 (unsigned)((addr).s6_addr[14]), \
69 (unsigned)((addr).s6_addr[15])
77 cmdline_ipaddr_t addr;
81 const struct ipaddr_str ipaddr_valid_strs[] = {
82 {"0.0.0.0", {AF_INET, {IP4(0,0,0,0)}, 0},
84 {"0.0.0.0/0", {AF_INET, {IP4(0,0,0,0)}, 0},
85 CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK},
86 {"0.0.0.0/24", {AF_INET, {IP4(0,0,0,0)}, 24},
87 CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK},
88 {"192.168.1.0/24", {AF_INET, {IP4(192,168,1,0)}, 24},
89 CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK},
90 {"012.34.56.78/24", {AF_INET, {IP4(12,34,56,78)}, 24},
91 CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK},
92 {"34.56.78.90/1", {AF_INET, {IP4(34,56,78,90)}, 1},
93 CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK},
94 {"::", {AF_INET6, {IP6(0,0,0,0,0,0,0,0)}, 0},
96 {"::1", {AF_INET6, {IP6(0,0,0,0,0,0,0,1)}, 0},
98 {"::1/32", {AF_INET6, {IP6(0,0,0,0,0,0,0,1)}, 32},
99 CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
100 {"::/32", {AF_INET6, {IP6(0,0,0,0,0,0,0,0)}, 32},
101 CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
102 /* RFC5952 requests that only lowercase should be used */
103 {"1234:5678:90ab:cdef:4321:8765:BA09:FEDC", {AF_INET6,
104 {IP6(0x1234,0x5678,0x90AB,0xCDEF,0x4321,0x8765,0xBA09,0xFEDC)},
107 {"1234::1234/64", {AF_INET6,
108 {IP6(0x1234,0,0,0,0,0,0,0x1234)},
110 CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
111 {"1234::/64", {AF_INET6,
112 {IP6(0x1234,0,0,0,0,0,0,0)},
114 CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
115 {"1:1::1/32", {AF_INET6,
116 {IP6(1,1,0,0,0,0,0,1)},
118 CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
119 {"1:2:3:4::/64", {AF_INET6,
120 {IP6(1,2,3,4,0,0,0,0)},
122 CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
123 {"::ffff:192.168.1.0/64", {AF_INET6,
124 {IP6(0,0,0,0,0,0xFFFF,0xC0A8,0x100)},
126 CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
127 /* RFC5952 requests not using :: to skip one block of zeros*/
128 {"1::2:3:4:5:6:7", {AF_INET6,
129 {IP6(1,0,2,3,4,5,6,7)},
134 const char * ipaddr_garbage_addr4_strs[] = {
136 "192.168.1.0 garbage",
137 "192.168.1.0\0garbage",
138 "192.168.1.0#garbage",
139 "192.168.1.0\tgarbage",
140 "192.168.1.0\rgarbage",
141 "192.168.1.0\ngarbage",
143 #define IPv4_GARBAGE_ADDR IP4(192,168,1,0)
145 const char * ipaddr_garbage_addr6_strs[] = {
147 "1:2:3:4::8 garbage",
148 "1:2:3:4::8#garbage",
149 "1:2:3:4::8\0garbage",
150 "1:2:3:4::8\rgarbage",
151 "1:2:3:4::8\ngarbage",
152 "1:2:3:4::8\tgarbage",
154 #define IPv6_GARBAGE_ADDR {IP6(1,2,3,4,0,0,0,8)}
156 const char * ipaddr_garbage_network4_strs[] = {
158 "192.168.1.0/24 garbage",
159 "192.168.1.0/24\0garbage",
160 "192.168.1.0/24#garbage",
161 "192.168.1.0/24\tgarbage",
162 "192.168.1.0/24\rgarbage",
163 "192.168.1.0/24\ngarbage",
165 #define IPv4_GARBAGE_PREFIX 24
167 const char * ipaddr_garbage_network6_strs[] = {
169 "1:2:3:4::8/64 garbage",
170 "1:2:3:4::8/64#garbage",
171 "1:2:3:4::8/64\0garbage",
172 "1:2:3:4::8/64\rgarbage",
173 "1:2:3:4::8/64\ngarbage",
174 "1:2:3:4::8/64\tgarbage",
176 #define IPv6_GARBAGE_PREFIX 64
180 const char * ipaddr_invalid_strs[] = {
183 /* invalid numbers */
193 "256.123.123.123/24",
194 "255.256.123.123/24",
195 "255.255.256.123/24",
196 "255.255.255.256/24",
197 /* invalid network mask */
211 "123.123.123.123.123",
216 "123.123.123.123./24",
217 "123.123.123..123/24",
218 "123.123.123.123.123/24",
220 ".123.123.123.123/24",
221 /* invalid characters */
229 "123.123.123.123/4F",
236 "1:2:3:4:5:6:7:192.168.1.1",
237 "1234:192.168.1.1:ffff::",
238 "1:2:3:4:5:6:7:890ab",
239 "1:2:3:4:5:6:7890a:b",
240 "1:2:3:4:5:67890:a:b",
241 "1:2:3:4:56789:0:a:b",
242 "1:2:3:45678:9:0:a:b",
243 "1:2:34567:8:9:0:a:b",
244 "1:23456:7:8:9:0:a:b",
245 "12345:6:7:8:9:0:a:b",
255 "1::2:3:4:5:6:7:8/64",
257 /* invalid network mask */
258 "1:2:3:4:5:6:7:8/129",
259 "1:2:3:4:5:6:7:8/-1",
261 /* invalid characters */
267 "1234:1234:1234:1234:1234:1234:1234:1234:1234:1234:1234"
268 "random invalid text",
274 #define IPADDR_VALID_STRS_SIZE \
275 (sizeof(ipaddr_valid_strs) / sizeof(ipaddr_valid_strs[0]))
276 #define IPADDR_GARBAGE_ADDR4_STRS_SIZE \
277 (sizeof(ipaddr_garbage_addr4_strs) / sizeof(ipaddr_garbage_addr4_strs[0]))
278 #define IPADDR_GARBAGE_ADDR6_STRS_SIZE \
279 (sizeof(ipaddr_garbage_addr6_strs) / sizeof(ipaddr_garbage_addr6_strs[0]))
280 #define IPADDR_GARBAGE_NETWORK4_STRS_SIZE \
281 (sizeof(ipaddr_garbage_network4_strs) / sizeof(ipaddr_garbage_network4_strs[0]))
282 #define IPADDR_GARBAGE_NETWORK6_STRS_SIZE \
283 (sizeof(ipaddr_garbage_network6_strs) / sizeof(ipaddr_garbage_network6_strs[0]))
284 #define IPADDR_INVALID_STRS_SIZE \
285 (sizeof(ipaddr_invalid_strs) / sizeof(ipaddr_invalid_strs[0]))
288 dump_addr(cmdline_ipaddr_t addr)
290 switch (addr.family) {
293 printf(NIPQUAD_FMT " prefixlen=%u\n",
294 NIPQUAD(addr.addr.ipv4.s_addr), addr.prefixlen);
299 printf(NIP6_FMT " prefixlen=%u\n",
300 NIP6(addr.addr.ipv6), addr.prefixlen);
304 printf("Can't dump: unknown address family.\n");
311 is_addr_different(cmdline_ipaddr_t addr1, cmdline_ipaddr_t addr2)
313 if (addr1.family != addr2.family)
316 if (addr1.prefixlen != addr2.prefixlen)
319 switch (addr1.family) {
322 if (memcmp(&addr1.addr.ipv4, &addr2.addr.ipv4,
323 sizeof(struct in_addr)) != 0)
329 if (memcmp(&addr1.addr.ipv6, &addr2.addr.ipv6,
330 sizeof(struct in6_addr)) != 0)
334 /* thing that should not be */
342 can_parse_addr(unsigned addr_flags, unsigned test_flags)
344 if ((test_flags & addr_flags) == addr_flags) {
345 /* if we are not trying to parse network addresses */
346 if (test_flags < CMDLINE_IPADDR_NETWORK)
348 /* if this is a network address */
349 else if (addr_flags & CMDLINE_IPADDR_NETWORK)
356 test_parse_ipaddr_valid(void)
358 cmdline_parse_token_ipaddr_t token;
359 char buf[CMDLINE_TEST_BUFSIZE];
360 cmdline_ipaddr_t result;
365 /* cover all cases in help */
366 for (flags = 0x1; flags < 0x8; flags++) {
367 token.ipaddr_data.flags = flags;
369 memset(buf, 0, sizeof(buf));
371 if (cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
372 buf, sizeof(buf)) == -1) {
373 printf("Error: help rejected valid parameters!\n");
378 /* test valid strings */
379 for (i = 0; i < IPADDR_VALID_STRS_SIZE; i++) {
381 /* test each valid string against different flags */
382 for (flags = 1; flags < 0x8; flags++) {
385 if (flags == CMDLINE_IPADDR_NETWORK)
388 /* clear out everything */
389 memset(buf, 0, sizeof(buf));
390 memset(&result, 0, sizeof(result));
391 memset(&token, 0, sizeof(token));
393 token.ipaddr_data.flags = flags;
395 cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
398 ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
399 ipaddr_valid_strs[i].str, (void*)&result,
402 /* if should have passed, or should have failed */
404 (can_parse_addr(ipaddr_valid_strs[i].flags, flags))) {
405 printf("Error: unexpected behavior when parsing %s as %s!\n",
406 ipaddr_valid_strs[i].str, buf);
407 printf("Parsed result: ");
409 printf("Expected result: ");
410 dump_addr(ipaddr_valid_strs[i].addr);
414 is_addr_different(result, ipaddr_valid_strs[i].addr)) {
415 printf("Error: result mismatch when parsing %s as %s!\n",
416 ipaddr_valid_strs[i].str, buf);
417 printf("Parsed result: ");
419 printf("Expected result: ");
420 dump_addr(ipaddr_valid_strs[i].addr);
426 /* test garbage ipv4 address strings */
427 for (i = 0; i < IPADDR_GARBAGE_ADDR4_STRS_SIZE; i++) {
429 struct in_addr tmp = IPv4_GARBAGE_ADDR;
431 /* test each valid string against different flags */
432 for (flags = 1; flags < 0x8; flags++) {
435 if (flags == CMDLINE_IPADDR_NETWORK)
438 /* clear out everything */
439 memset(buf, 0, sizeof(buf));
440 memset(&result, 0, sizeof(result));
441 memset(&token, 0, sizeof(token));
443 token.ipaddr_data.flags = flags;
445 cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
448 ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
449 ipaddr_garbage_addr4_strs[i], (void*)&result,
452 /* if should have passed, or should have failed */
454 (can_parse_addr(CMDLINE_IPADDR_V4, flags))) {
455 printf("Error: unexpected behavior when parsing %s as %s!\n",
456 ipaddr_garbage_addr4_strs[i], buf);
460 memcmp(&result.addr.ipv4, &tmp, sizeof(tmp))) {
461 printf("Error: result mismatch when parsing %s as %s!\n",
462 ipaddr_garbage_addr4_strs[i], buf);
468 /* test garbage ipv6 address strings */
469 for (i = 0; i < IPADDR_GARBAGE_ADDR6_STRS_SIZE; i++) {
471 cmdline_ipaddr_t tmp = {.addr = IPv6_GARBAGE_ADDR};
473 /* test each valid string against different flags */
474 for (flags = 1; flags < 0x8; flags++) {
477 if (flags == CMDLINE_IPADDR_NETWORK)
480 /* clear out everything */
481 memset(buf, 0, sizeof(buf));
482 memset(&result, 0, sizeof(result));
483 memset(&token, 0, sizeof(token));
485 token.ipaddr_data.flags = flags;
487 cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
490 ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
491 ipaddr_garbage_addr6_strs[i], (void*)&result,
494 /* if should have passed, or should have failed */
496 (can_parse_addr(CMDLINE_IPADDR_V6, flags))) {
497 printf("Error: unexpected behavior when parsing %s as %s!\n",
498 ipaddr_garbage_addr6_strs[i], buf);
502 memcmp(&result.addr.ipv6, &tmp.addr.ipv6, sizeof(struct in6_addr))) {
503 printf("Error: result mismatch when parsing %s as %s!\n",
504 ipaddr_garbage_addr6_strs[i], buf);
511 /* test garbage ipv4 network strings */
512 for (i = 0; i < IPADDR_GARBAGE_NETWORK4_STRS_SIZE; i++) {
514 struct in_addr tmp = IPv4_GARBAGE_ADDR;
516 /* test each valid string against different flags */
517 for (flags = 1; flags < 0x8; flags++) {
520 if (flags == CMDLINE_IPADDR_NETWORK)
523 /* clear out everything */
524 memset(buf, 0, sizeof(buf));
525 memset(&result, 0, sizeof(result));
526 memset(&token, 0, sizeof(token));
528 token.ipaddr_data.flags = flags;
530 cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
533 ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
534 ipaddr_garbage_network4_strs[i], (void*)&result,
537 /* if should have passed, or should have failed */
539 (can_parse_addr(CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK, flags))) {
540 printf("Error: unexpected behavior when parsing %s as %s!\n",
541 ipaddr_garbage_network4_strs[i], buf);
545 memcmp(&result.addr.ipv4, &tmp, sizeof(tmp))) {
546 printf("Error: result mismatch when parsing %s as %s!\n",
547 ipaddr_garbage_network4_strs[i], buf);
553 /* test garbage ipv6 address strings */
554 for (i = 0; i < IPADDR_GARBAGE_NETWORK6_STRS_SIZE; i++) {
556 cmdline_ipaddr_t tmp = {.addr = IPv6_GARBAGE_ADDR};
558 /* test each valid string against different flags */
559 for (flags = 1; flags < 0x8; flags++) {
562 if (flags == CMDLINE_IPADDR_NETWORK)
565 /* clear out everything */
566 memset(buf, 0, sizeof(buf));
567 memset(&result, 0, sizeof(result));
568 memset(&token, 0, sizeof(token));
570 token.ipaddr_data.flags = flags;
572 cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
575 ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
576 ipaddr_garbage_network6_strs[i], (void*)&result,
579 /* if should have passed, or should have failed */
581 (can_parse_addr(CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK, flags))) {
582 printf("Error: unexpected behavior when parsing %s as %s!\n",
583 ipaddr_garbage_network6_strs[i], buf);
587 memcmp(&result.addr.ipv6, &tmp.addr.ipv6, sizeof(struct in6_addr))) {
588 printf("Error: result mismatch when parsing %s as %s!\n",
589 ipaddr_garbage_network6_strs[i], buf);
599 test_parse_ipaddr_invalid_data(void)
601 cmdline_parse_token_ipaddr_t token;
602 char buf[CMDLINE_TEST_BUFSIZE];
603 cmdline_ipaddr_t result;
608 memset(&result, 0, sizeof(result));
610 /* test invalid strings */
611 for (i = 0; i < IPADDR_INVALID_STRS_SIZE; i++) {
613 /* test each valid string against different flags */
614 for (flags = 1; flags < 0x8; flags++) {
617 if (flags == CMDLINE_IPADDR_NETWORK)
620 /* clear out everything */
621 memset(buf, 0, sizeof(buf));
622 memset(&token, 0, sizeof(token));
624 token.ipaddr_data.flags = flags;
626 cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
629 ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
630 ipaddr_invalid_strs[i], (void*)&result,
634 printf("Error: parsing %s as %s succeeded!\n",
635 ipaddr_invalid_strs[i], buf);
636 printf("Parsed result: ");
647 test_parse_ipaddr_invalid_param(void)
649 cmdline_parse_token_ipaddr_t token;
650 char buf[CMDLINE_TEST_BUFSIZE];
651 cmdline_ipaddr_t result;
653 snprintf(buf, sizeof(buf), "1.2.3.4");
654 token.ipaddr_data.flags = CMDLINE_IPADDR_V4;
657 if (cmdline_parse_ipaddr(NULL, buf, (void*)&result,
658 sizeof(result)) != -1) {
659 printf("Error: parser accepted invalid parameters!\n");
663 if (cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
664 NULL, (void*)&result, sizeof(result)) != -1) {
665 printf("Error: parser accepted invalid parameters!\n");
669 if (cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
670 "", (void*)&result, sizeof(result)) != -1) {
671 printf("Error: parser accepted invalid parameters!\n");
675 if (cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
676 buf, NULL, 0) == -1) {
677 printf("Error: parser rejected null result!\n");
682 if (cmdline_get_help_ipaddr(NULL, buf, 0) != -1) {
683 printf("Error: help accepted invalid parameters!\n");
687 if (cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
689 printf("Error: help accepted invalid parameters!\n");