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 {"34.56.78.90/1", {AF_INET, {IP4(34,56,78,90)}, 1},
91 CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK},
92 {"::", {AF_INET6, {IP6(0,0,0,0,0,0,0,0)}, 0},
94 {"::1", {AF_INET6, {IP6(0,0,0,0,0,0,0,1)}, 0},
96 {"::1/32", {AF_INET6, {IP6(0,0,0,0,0,0,0,1)}, 32},
97 CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
98 {"::/32", {AF_INET6, {IP6(0,0,0,0,0,0,0,0)}, 32},
99 CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
100 /* RFC5952 requests that only lowercase should be used */
101 {"1234:5678:90ab:cdef:4321:8765:BA09:FEDC", {AF_INET6,
102 {IP6(0x1234,0x5678,0x90AB,0xCDEF,0x4321,0x8765,0xBA09,0xFEDC)},
105 {"1234::1234/64", {AF_INET6,
106 {IP6(0x1234,0,0,0,0,0,0,0x1234)},
108 CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
109 {"1234::/64", {AF_INET6,
110 {IP6(0x1234,0,0,0,0,0,0,0)},
112 CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
113 {"1:1::1/32", {AF_INET6,
114 {IP6(1,1,0,0,0,0,0,1)},
116 CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
117 {"1:2:3:4::/64", {AF_INET6,
118 {IP6(1,2,3,4,0,0,0,0)},
120 CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
121 {"::ffff:192.168.1.0/64", {AF_INET6,
122 {IP6(0,0,0,0,0,0xFFFF,0xC0A8,0x100)},
124 CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
125 /* RFC5952 requests not using :: to skip one block of zeros*/
126 {"1::2:3:4:5:6:7", {AF_INET6,
127 {IP6(1,0,2,3,4,5,6,7)},
132 const char * ipaddr_garbage_addr4_strs[] = {
134 "192.168.1.0 garbage",
135 "192.168.1.0\0garbage",
136 "192.168.1.0#garbage",
137 "192.168.1.0\tgarbage",
138 "192.168.1.0\rgarbage",
139 "192.168.1.0\ngarbage",
141 #define IPv4_GARBAGE_ADDR IP4(192,168,1,0)
143 const char * ipaddr_garbage_addr6_strs[] = {
145 "1:2:3:4::8 garbage",
146 "1:2:3:4::8#garbage",
147 "1:2:3:4::8\0garbage",
148 "1:2:3:4::8\rgarbage",
149 "1:2:3:4::8\ngarbage",
150 "1:2:3:4::8\tgarbage",
152 #define IPv6_GARBAGE_ADDR {IP6(1,2,3,4,0,0,0,8)}
154 const char * ipaddr_garbage_network4_strs[] = {
156 "192.168.1.0/24 garbage",
157 "192.168.1.0/24\0garbage",
158 "192.168.1.0/24#garbage",
159 "192.168.1.0/24\tgarbage",
160 "192.168.1.0/24\rgarbage",
161 "192.168.1.0/24\ngarbage",
163 #define IPv4_GARBAGE_PREFIX 24
165 const char * ipaddr_garbage_network6_strs[] = {
167 "1:2:3:4::8/64 garbage",
168 "1:2:3:4::8/64#garbage",
169 "1:2:3:4::8/64\0garbage",
170 "1:2:3:4::8/64\rgarbage",
171 "1:2:3:4::8/64\ngarbage",
172 "1:2:3:4::8/64\tgarbage",
174 #define IPv6_GARBAGE_PREFIX 64
178 const char * ipaddr_invalid_strs[] = {
181 /* invalid numbers */
191 "256.123.123.123/24",
192 "255.256.123.123/24",
193 "255.255.256.123/24",
194 "255.255.255.256/24",
195 /* invalid network mask */
209 "123.123.123.123.123",
214 "123.123.123.123./24",
215 "123.123.123..123/24",
216 "123.123.123.123.123/24",
218 ".123.123.123.123/24",
219 /* invalid characters */
227 "123.123.123.123/4F",
234 "1:2:3:4:5:6:7:192.168.1.1",
235 "1234:192.168.1.1:ffff::",
236 "1:2:3:4:5:6:7:890ab",
237 "1:2:3:4:5:6:7890a:b",
238 "1:2:3:4:5:67890:a:b",
239 "1:2:3:4:56789:0:a:b",
240 "1:2:3:45678:9:0:a:b",
241 "1:2:34567:8:9:0:a:b",
242 "1:23456:7:8:9:0:a:b",
243 "12345:6:7:8:9:0:a:b",
253 "1::2:3:4:5:6:7:8/64",
255 /* invalid network mask */
256 "1:2:3:4:5:6:7:8/129",
257 "1:2:3:4:5:6:7:8/-1",
259 /* invalid characters */
265 "1234:1234:1234:1234:1234:1234:1234:1234:1234:1234:1234"
266 "random invalid text",
272 #define IPADDR_VALID_STRS_SIZE \
273 (sizeof(ipaddr_valid_strs) / sizeof(ipaddr_valid_strs[0]))
274 #define IPADDR_GARBAGE_ADDR4_STRS_SIZE \
275 (sizeof(ipaddr_garbage_addr4_strs) / sizeof(ipaddr_garbage_addr4_strs[0]))
276 #define IPADDR_GARBAGE_ADDR6_STRS_SIZE \
277 (sizeof(ipaddr_garbage_addr6_strs) / sizeof(ipaddr_garbage_addr6_strs[0]))
278 #define IPADDR_GARBAGE_NETWORK4_STRS_SIZE \
279 (sizeof(ipaddr_garbage_network4_strs) / sizeof(ipaddr_garbage_network4_strs[0]))
280 #define IPADDR_GARBAGE_NETWORK6_STRS_SIZE \
281 (sizeof(ipaddr_garbage_network6_strs) / sizeof(ipaddr_garbage_network6_strs[0]))
282 #define IPADDR_INVALID_STRS_SIZE \
283 (sizeof(ipaddr_invalid_strs) / sizeof(ipaddr_invalid_strs[0]))
286 dump_addr(cmdline_ipaddr_t addr)
288 switch (addr.family) {
291 printf(NIPQUAD_FMT " prefixlen=%u\n",
292 NIPQUAD(addr.addr.ipv4.s_addr), addr.prefixlen);
297 printf(NIP6_FMT " prefixlen=%u\n",
298 NIP6(addr.addr.ipv6), addr.prefixlen);
302 printf("Can't dump: unknown address family.\n");
309 is_addr_different(cmdline_ipaddr_t addr1, cmdline_ipaddr_t addr2)
311 if (addr1.family != addr2.family)
314 if (addr1.prefixlen != addr2.prefixlen)
317 switch (addr1.family) {
320 if (memcmp(&addr1.addr.ipv4, &addr2.addr.ipv4,
321 sizeof(struct in_addr)) != 0)
327 if (memcmp(&addr1.addr.ipv6, &addr2.addr.ipv6,
328 sizeof(struct in6_addr)) != 0)
332 /* thing that should not be */
340 can_parse_addr(unsigned addr_flags, unsigned test_flags)
342 if ((test_flags & addr_flags) == addr_flags) {
343 /* if we are not trying to parse network addresses */
344 if (test_flags < CMDLINE_IPADDR_NETWORK)
346 /* if this is a network address */
347 else if (addr_flags & CMDLINE_IPADDR_NETWORK)
354 test_parse_ipaddr_valid(void)
356 cmdline_parse_token_ipaddr_t token;
357 char buf[CMDLINE_TEST_BUFSIZE];
358 cmdline_ipaddr_t result;
363 /* cover all cases in help */
364 for (flags = 0x1; flags < 0x8; flags++) {
365 token.ipaddr_data.flags = flags;
367 memset(buf, 0, sizeof(buf));
369 if (cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
370 buf, sizeof(buf)) == -1) {
371 printf("Error: help rejected valid parameters!\n");
376 /* test valid strings */
377 for (i = 0; i < IPADDR_VALID_STRS_SIZE; i++) {
379 /* test each valid string against different flags */
380 for (flags = 1; flags < 0x8; flags++) {
383 if (flags == CMDLINE_IPADDR_NETWORK)
386 /* clear out everything */
387 memset(buf, 0, sizeof(buf));
388 memset(&result, 0, sizeof(result));
389 memset(&token, 0, sizeof(token));
391 token.ipaddr_data.flags = flags;
393 cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
396 ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
397 ipaddr_valid_strs[i].str, (void*)&result,
400 /* if should have passed, or should have failed */
402 (can_parse_addr(ipaddr_valid_strs[i].flags, flags))) {
403 printf("Error: unexpected behavior when parsing %s as %s!\n",
404 ipaddr_valid_strs[i].str, buf);
405 printf("Parsed result: ");
407 printf("Expected result: ");
408 dump_addr(ipaddr_valid_strs[i].addr);
412 is_addr_different(result, ipaddr_valid_strs[i].addr)) {
413 printf("Error: result mismatch when parsing %s as %s!\n",
414 ipaddr_valid_strs[i].str, buf);
415 printf("Parsed result: ");
417 printf("Expected result: ");
418 dump_addr(ipaddr_valid_strs[i].addr);
424 /* test garbage ipv4 address strings */
425 for (i = 0; i < IPADDR_GARBAGE_ADDR4_STRS_SIZE; i++) {
427 struct in_addr tmp = IPv4_GARBAGE_ADDR;
429 /* test each valid string against different flags */
430 for (flags = 1; flags < 0x8; flags++) {
433 if (flags == CMDLINE_IPADDR_NETWORK)
436 /* clear out everything */
437 memset(buf, 0, sizeof(buf));
438 memset(&result, 0, sizeof(result));
439 memset(&token, 0, sizeof(token));
441 token.ipaddr_data.flags = flags;
443 cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
446 ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
447 ipaddr_garbage_addr4_strs[i], (void*)&result,
450 /* if should have passed, or should have failed */
452 (can_parse_addr(CMDLINE_IPADDR_V4, flags))) {
453 printf("Error: unexpected behavior when parsing %s as %s!\n",
454 ipaddr_garbage_addr4_strs[i], buf);
458 memcmp(&result.addr.ipv4, &tmp, sizeof(tmp))) {
459 printf("Error: result mismatch when parsing %s as %s!\n",
460 ipaddr_garbage_addr4_strs[i], buf);
466 /* test garbage ipv6 address strings */
467 for (i = 0; i < IPADDR_GARBAGE_ADDR6_STRS_SIZE; i++) {
469 cmdline_ipaddr_t tmp = {.addr = IPv6_GARBAGE_ADDR};
471 /* test each valid string against different flags */
472 for (flags = 1; flags < 0x8; flags++) {
475 if (flags == CMDLINE_IPADDR_NETWORK)
478 /* clear out everything */
479 memset(buf, 0, sizeof(buf));
480 memset(&result, 0, sizeof(result));
481 memset(&token, 0, sizeof(token));
483 token.ipaddr_data.flags = flags;
485 cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
488 ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
489 ipaddr_garbage_addr6_strs[i], (void*)&result,
492 /* if should have passed, or should have failed */
494 (can_parse_addr(CMDLINE_IPADDR_V6, flags))) {
495 printf("Error: unexpected behavior when parsing %s as %s!\n",
496 ipaddr_garbage_addr6_strs[i], buf);
500 memcmp(&result.addr.ipv6, &tmp.addr.ipv6, sizeof(struct in6_addr))) {
501 printf("Error: result mismatch when parsing %s as %s!\n",
502 ipaddr_garbage_addr6_strs[i], buf);
509 /* test garbage ipv4 network strings */
510 for (i = 0; i < IPADDR_GARBAGE_NETWORK4_STRS_SIZE; i++) {
512 struct in_addr tmp = IPv4_GARBAGE_ADDR;
514 /* test each valid string against different flags */
515 for (flags = 1; flags < 0x8; flags++) {
518 if (flags == CMDLINE_IPADDR_NETWORK)
521 /* clear out everything */
522 memset(buf, 0, sizeof(buf));
523 memset(&result, 0, sizeof(result));
524 memset(&token, 0, sizeof(token));
526 token.ipaddr_data.flags = flags;
528 cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
531 ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
532 ipaddr_garbage_network4_strs[i], (void*)&result,
535 /* if should have passed, or should have failed */
537 (can_parse_addr(CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK, flags))) {
538 printf("Error: unexpected behavior when parsing %s as %s!\n",
539 ipaddr_garbage_network4_strs[i], buf);
543 memcmp(&result.addr.ipv4, &tmp, sizeof(tmp))) {
544 printf("Error: result mismatch when parsing %s as %s!\n",
545 ipaddr_garbage_network4_strs[i], buf);
551 /* test garbage ipv6 address strings */
552 for (i = 0; i < IPADDR_GARBAGE_NETWORK6_STRS_SIZE; i++) {
554 cmdline_ipaddr_t tmp = {.addr = IPv6_GARBAGE_ADDR};
556 /* test each valid string against different flags */
557 for (flags = 1; flags < 0x8; flags++) {
560 if (flags == CMDLINE_IPADDR_NETWORK)
563 /* clear out everything */
564 memset(buf, 0, sizeof(buf));
565 memset(&result, 0, sizeof(result));
566 memset(&token, 0, sizeof(token));
568 token.ipaddr_data.flags = flags;
570 cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
573 ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
574 ipaddr_garbage_network6_strs[i], (void*)&result,
577 /* if should have passed, or should have failed */
579 (can_parse_addr(CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK, flags))) {
580 printf("Error: unexpected behavior when parsing %s as %s!\n",
581 ipaddr_garbage_network6_strs[i], buf);
585 memcmp(&result.addr.ipv6, &tmp.addr.ipv6, sizeof(struct in6_addr))) {
586 printf("Error: result mismatch when parsing %s as %s!\n",
587 ipaddr_garbage_network6_strs[i], buf);
597 test_parse_ipaddr_invalid_data(void)
599 cmdline_parse_token_ipaddr_t token;
600 char buf[CMDLINE_TEST_BUFSIZE];
601 cmdline_ipaddr_t result;
606 memset(&result, 0, sizeof(result));
608 /* test invalid strings */
609 for (i = 0; i < IPADDR_INVALID_STRS_SIZE; i++) {
611 /* test each valid string against different flags */
612 for (flags = 1; flags < 0x8; flags++) {
615 if (flags == CMDLINE_IPADDR_NETWORK)
618 /* clear out everything */
619 memset(buf, 0, sizeof(buf));
620 memset(&token, 0, sizeof(token));
622 token.ipaddr_data.flags = flags;
624 cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
627 ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
628 ipaddr_invalid_strs[i], (void*)&result,
632 printf("Error: parsing %s as %s succeeded!\n",
633 ipaddr_invalid_strs[i], buf);
634 printf("Parsed result: ");
645 test_parse_ipaddr_invalid_param(void)
647 cmdline_parse_token_ipaddr_t token;
648 char buf[CMDLINE_TEST_BUFSIZE];
649 cmdline_ipaddr_t result;
651 snprintf(buf, sizeof(buf), "1.2.3.4");
652 token.ipaddr_data.flags = CMDLINE_IPADDR_V4;
655 if (cmdline_parse_ipaddr(NULL, buf, (void*)&result,
656 sizeof(result)) != -1) {
657 printf("Error: parser accepted invalid parameters!\n");
661 if (cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
662 NULL, (void*)&result, sizeof(result)) != -1) {
663 printf("Error: parser accepted invalid parameters!\n");
667 if (cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
668 "", (void*)&result, sizeof(result)) != -1) {
669 printf("Error: parser accepted invalid parameters!\n");
673 if (cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
674 buf, NULL, 0) == -1) {
675 printf("Error: parser rejected null result!\n");
680 if (cmdline_get_help_ipaddr(NULL, buf, 0) != -1) {
681 printf("Error: help accepted invalid parameters!\n");
685 if (cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
687 printf("Error: help accepted invalid parameters!\n");