1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2014 Intel Corporation
8 #include <netinet/in.h>
10 #include <sys/socket.h>
13 #include <rte_string_fns.h>
15 #include <cmdline_parse.h>
16 #include <cmdline_parse_ipaddr.h>
18 #include "test_cmdline.h"
20 #define IP4(a,b,c,d) {((uint32_t)(((a) & 0xff)) | \
21 (((b) & 0xff) << 8) | \
22 (((c) & 0xff) << 16) | \
26 (((x & 0xFF) << 8) | ((x & 0xFF00) >> 8))
28 /* create IPv6 address, swapping bytes where needed */
30 # define s6_addr16 __u6_addr.__u6_addr16
32 #define IP6(a,b,c,d,e,f,g,h) .ipv6 = \
34 {U16_SWAP(a),U16_SWAP(b),U16_SWAP(c),U16_SWAP(d),\
35 U16_SWAP(e),U16_SWAP(f),U16_SWAP(g),U16_SWAP(h)}}
37 /** these are defined in netinet/in.h but not present in linux headers */
40 #define NIPQUAD_FMT "%u.%u.%u.%u"
41 #define NIPQUAD(addr) \
42 (unsigned)((unsigned char *)&addr)[0], \
43 (unsigned)((unsigned char *)&addr)[1], \
44 (unsigned)((unsigned char *)&addr)[2], \
45 (unsigned)((unsigned char *)&addr)[3]
47 #define NIP6_FMT "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x"
49 (unsigned)((addr).s6_addr[0]), \
50 (unsigned)((addr).s6_addr[1]), \
51 (unsigned)((addr).s6_addr[2]), \
52 (unsigned)((addr).s6_addr[3]), \
53 (unsigned)((addr).s6_addr[4]), \
54 (unsigned)((addr).s6_addr[5]), \
55 (unsigned)((addr).s6_addr[6]), \
56 (unsigned)((addr).s6_addr[7]), \
57 (unsigned)((addr).s6_addr[8]), \
58 (unsigned)((addr).s6_addr[9]), \
59 (unsigned)((addr).s6_addr[10]), \
60 (unsigned)((addr).s6_addr[11]), \
61 (unsigned)((addr).s6_addr[12]), \
62 (unsigned)((addr).s6_addr[13]), \
63 (unsigned)((addr).s6_addr[14]), \
64 (unsigned)((addr).s6_addr[15])
72 cmdline_ipaddr_t addr;
76 const struct ipaddr_str ipaddr_valid_strs[] = {
77 {"0.0.0.0", {AF_INET, {IP4(0,0,0,0)}, 0},
79 {"0.0.0.0/0", {AF_INET, {IP4(0,0,0,0)}, 0},
80 CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK},
81 {"0.0.0.0/24", {AF_INET, {IP4(0,0,0,0)}, 24},
82 CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK},
83 {"192.168.1.0/24", {AF_INET, {IP4(192,168,1,0)}, 24},
84 CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK},
85 {"34.56.78.90/1", {AF_INET, {IP4(34,56,78,90)}, 1},
86 CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK},
87 {"::", {AF_INET6, {IP6(0,0,0,0,0,0,0,0)}, 0},
89 {"::1", {AF_INET6, {IP6(0,0,0,0,0,0,0,1)}, 0},
91 {"::1/32", {AF_INET6, {IP6(0,0,0,0,0,0,0,1)}, 32},
92 CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
93 {"::/32", {AF_INET6, {IP6(0,0,0,0,0,0,0,0)}, 32},
94 CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
95 /* RFC5952 requests that only lowercase should be used */
96 {"1234:5678:90ab:cdef:4321:8765:BA09:FEDC", {AF_INET6,
97 {IP6(0x1234,0x5678,0x90AB,0xCDEF,0x4321,0x8765,0xBA09,0xFEDC)},
100 {"1234::1234/64", {AF_INET6,
101 {IP6(0x1234,0,0,0,0,0,0,0x1234)},
103 CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
104 {"1234::/64", {AF_INET6,
105 {IP6(0x1234,0,0,0,0,0,0,0)},
107 CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
108 {"1:1::1/32", {AF_INET6,
109 {IP6(1,1,0,0,0,0,0,1)},
111 CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
112 {"1:2:3:4::/64", {AF_INET6,
113 {IP6(1,2,3,4,0,0,0,0)},
115 CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
116 {"::ffff:192.168.1.0/64", {AF_INET6,
117 {IP6(0,0,0,0,0,0xFFFF,0xC0A8,0x100)},
119 CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK},
120 /* RFC5952 requests not using :: to skip one block of zeros*/
121 {"1::2:3:4:5:6:7", {AF_INET6,
122 {IP6(1,0,2,3,4,5,6,7)},
127 const char * ipaddr_garbage_addr4_strs[] = {
129 "192.168.1.0 garbage",
130 "192.168.1.0\0garbage",
131 "192.168.1.0#garbage",
132 "192.168.1.0\tgarbage",
133 "192.168.1.0\rgarbage",
134 "192.168.1.0\ngarbage",
136 #define IPv4_GARBAGE_ADDR IP4(192,168,1,0)
138 const char * ipaddr_garbage_addr6_strs[] = {
140 "1:2:3:4::8 garbage",
141 "1:2:3:4::8#garbage",
142 "1:2:3:4::8\0garbage",
143 "1:2:3:4::8\rgarbage",
144 "1:2:3:4::8\ngarbage",
145 "1:2:3:4::8\tgarbage",
147 #define IPv6_GARBAGE_ADDR {IP6(1,2,3,4,0,0,0,8)}
149 const char * ipaddr_garbage_network4_strs[] = {
151 "192.168.1.0/24 garbage",
152 "192.168.1.0/24\0garbage",
153 "192.168.1.0/24#garbage",
154 "192.168.1.0/24\tgarbage",
155 "192.168.1.0/24\rgarbage",
156 "192.168.1.0/24\ngarbage",
158 #define IPv4_GARBAGE_PREFIX 24
160 const char * ipaddr_garbage_network6_strs[] = {
162 "1:2:3:4::8/64 garbage",
163 "1:2:3:4::8/64#garbage",
164 "1:2:3:4::8/64\0garbage",
165 "1:2:3:4::8/64\rgarbage",
166 "1:2:3:4::8/64\ngarbage",
167 "1:2:3:4::8/64\tgarbage",
169 #define IPv6_GARBAGE_PREFIX 64
173 const char * ipaddr_invalid_strs[] = {
176 /* invalid numbers */
186 "256.123.123.123/24",
187 "255.256.123.123/24",
188 "255.255.256.123/24",
189 "255.255.255.256/24",
190 /* invalid network mask */
204 "123.123.123.123.123",
209 "123.123.123.123./24",
210 "123.123.123..123/24",
211 "123.123.123.123.123/24",
213 ".123.123.123.123/24",
214 /* invalid characters */
222 "123.123.123.123/4F",
229 "1:2:3:4:5:6:7:192.168.1.1",
230 "1234:192.168.1.1:ffff::",
231 "1:2:3:4:5:6:7:890ab",
232 "1:2:3:4:5:6:7890a:b",
233 "1:2:3:4:5:67890:a:b",
234 "1:2:3:4:56789:0:a:b",
235 "1:2:3:45678:9:0:a:b",
236 "1:2:34567:8:9:0:a:b",
237 "1:23456:7:8:9:0:a:b",
238 "12345:6:7:8:9:0:a:b",
248 "1::2:3:4:5:6:7:8/64",
250 /* invalid network mask */
251 "1:2:3:4:5:6:7:8/129",
252 "1:2:3:4:5:6:7:8/-1",
254 /* invalid characters */
260 "1234:1234:1234:1234:1234:1234:1234:1234:1234:1234:1234"
261 "random invalid text",
267 #define IPADDR_VALID_STRS_SIZE \
268 (sizeof(ipaddr_valid_strs) / sizeof(ipaddr_valid_strs[0]))
269 #define IPADDR_GARBAGE_ADDR4_STRS_SIZE \
270 (sizeof(ipaddr_garbage_addr4_strs) / sizeof(ipaddr_garbage_addr4_strs[0]))
271 #define IPADDR_GARBAGE_ADDR6_STRS_SIZE \
272 (sizeof(ipaddr_garbage_addr6_strs) / sizeof(ipaddr_garbage_addr6_strs[0]))
273 #define IPADDR_GARBAGE_NETWORK4_STRS_SIZE \
274 (sizeof(ipaddr_garbage_network4_strs) / sizeof(ipaddr_garbage_network4_strs[0]))
275 #define IPADDR_GARBAGE_NETWORK6_STRS_SIZE \
276 (sizeof(ipaddr_garbage_network6_strs) / sizeof(ipaddr_garbage_network6_strs[0]))
277 #define IPADDR_INVALID_STRS_SIZE \
278 (sizeof(ipaddr_invalid_strs) / sizeof(ipaddr_invalid_strs[0]))
281 dump_addr(cmdline_ipaddr_t addr)
283 switch (addr.family) {
286 printf(NIPQUAD_FMT " prefixlen=%u\n",
287 NIPQUAD(addr.addr.ipv4.s_addr), addr.prefixlen);
292 printf(NIP6_FMT " prefixlen=%u\n",
293 NIP6(addr.addr.ipv6), addr.prefixlen);
297 printf("Can't dump: unknown address family.\n");
304 is_addr_different(cmdline_ipaddr_t addr1, cmdline_ipaddr_t addr2)
306 if (addr1.family != addr2.family)
309 if (addr1.prefixlen != addr2.prefixlen)
312 switch (addr1.family) {
315 if (memcmp(&addr1.addr.ipv4, &addr2.addr.ipv4,
316 sizeof(struct in_addr)) != 0)
322 if (memcmp(&addr1.addr.ipv6, &addr2.addr.ipv6,
323 sizeof(struct in6_addr)) != 0)
327 /* thing that should not be */
335 can_parse_addr(unsigned addr_flags, unsigned test_flags)
337 if ((test_flags & addr_flags) == addr_flags) {
338 /* if we are not trying to parse network addresses */
339 if (test_flags < CMDLINE_IPADDR_NETWORK)
341 /* if this is a network address */
342 else if (addr_flags & CMDLINE_IPADDR_NETWORK)
349 test_parse_ipaddr_valid(void)
351 cmdline_parse_token_ipaddr_t token;
352 char buf[CMDLINE_TEST_BUFSIZE];
353 cmdline_ipaddr_t result;
358 /* cover all cases in help */
359 for (flags = 0x1; flags < 0x8; flags++) {
360 token.ipaddr_data.flags = flags;
362 memset(buf, 0, sizeof(buf));
364 if (cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
365 buf, sizeof(buf)) == -1) {
366 printf("Error: help rejected valid parameters!\n");
371 /* test valid strings */
372 for (i = 0; i < IPADDR_VALID_STRS_SIZE; i++) {
374 /* test each valid string against different flags */
375 for (flags = 1; flags < 0x8; flags++) {
378 if (flags == CMDLINE_IPADDR_NETWORK)
381 /* clear out everything */
382 memset(buf, 0, sizeof(buf));
383 memset(&result, 0, sizeof(result));
384 memset(&token, 0, sizeof(token));
386 token.ipaddr_data.flags = flags;
388 cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
391 ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
392 ipaddr_valid_strs[i].str, (void*)&result,
395 /* if should have passed, or should have failed */
397 (can_parse_addr(ipaddr_valid_strs[i].flags, flags))) {
398 printf("Error: unexpected behavior when parsing %s as %s!\n",
399 ipaddr_valid_strs[i].str, buf);
400 printf("Parsed result: ");
402 printf("Expected result: ");
403 dump_addr(ipaddr_valid_strs[i].addr);
407 is_addr_different(result, ipaddr_valid_strs[i].addr)) {
408 printf("Error: result mismatch when parsing %s as %s!\n",
409 ipaddr_valid_strs[i].str, buf);
410 printf("Parsed result: ");
412 printf("Expected result: ");
413 dump_addr(ipaddr_valid_strs[i].addr);
419 /* test garbage ipv4 address strings */
420 for (i = 0; i < IPADDR_GARBAGE_ADDR4_STRS_SIZE; i++) {
422 struct in_addr tmp = IPv4_GARBAGE_ADDR;
424 /* test each valid string against different flags */
425 for (flags = 1; flags < 0x8; flags++) {
428 if (flags == CMDLINE_IPADDR_NETWORK)
431 /* clear out everything */
432 memset(buf, 0, sizeof(buf));
433 memset(&result, 0, sizeof(result));
434 memset(&token, 0, sizeof(token));
436 token.ipaddr_data.flags = flags;
438 cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
441 ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
442 ipaddr_garbage_addr4_strs[i], (void*)&result,
445 /* if should have passed, or should have failed */
447 (can_parse_addr(CMDLINE_IPADDR_V4, flags))) {
448 printf("Error: unexpected behavior when parsing %s as %s!\n",
449 ipaddr_garbage_addr4_strs[i], buf);
453 memcmp(&result.addr.ipv4, &tmp, sizeof(tmp))) {
454 printf("Error: result mismatch when parsing %s as %s!\n",
455 ipaddr_garbage_addr4_strs[i], buf);
461 /* test garbage ipv6 address strings */
462 for (i = 0; i < IPADDR_GARBAGE_ADDR6_STRS_SIZE; i++) {
464 cmdline_ipaddr_t tmp = {.addr = IPv6_GARBAGE_ADDR};
466 /* test each valid string against different flags */
467 for (flags = 1; flags < 0x8; flags++) {
470 if (flags == CMDLINE_IPADDR_NETWORK)
473 /* clear out everything */
474 memset(buf, 0, sizeof(buf));
475 memset(&result, 0, sizeof(result));
476 memset(&token, 0, sizeof(token));
478 token.ipaddr_data.flags = flags;
480 cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
483 ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
484 ipaddr_garbage_addr6_strs[i], (void*)&result,
487 /* if should have passed, or should have failed */
489 (can_parse_addr(CMDLINE_IPADDR_V6, flags))) {
490 printf("Error: unexpected behavior when parsing %s as %s!\n",
491 ipaddr_garbage_addr6_strs[i], buf);
495 memcmp(&result.addr.ipv6, &tmp.addr.ipv6, sizeof(struct in6_addr))) {
496 printf("Error: result mismatch when parsing %s as %s!\n",
497 ipaddr_garbage_addr6_strs[i], buf);
504 /* test garbage ipv4 network strings */
505 for (i = 0; i < IPADDR_GARBAGE_NETWORK4_STRS_SIZE; i++) {
507 struct in_addr tmp = IPv4_GARBAGE_ADDR;
509 /* test each valid string against different flags */
510 for (flags = 1; flags < 0x8; flags++) {
513 if (flags == CMDLINE_IPADDR_NETWORK)
516 /* clear out everything */
517 memset(buf, 0, sizeof(buf));
518 memset(&result, 0, sizeof(result));
519 memset(&token, 0, sizeof(token));
521 token.ipaddr_data.flags = flags;
523 cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
526 ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
527 ipaddr_garbage_network4_strs[i], (void*)&result,
530 /* if should have passed, or should have failed */
532 (can_parse_addr(CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK, flags))) {
533 printf("Error: unexpected behavior when parsing %s as %s!\n",
534 ipaddr_garbage_network4_strs[i], buf);
538 memcmp(&result.addr.ipv4, &tmp, sizeof(tmp))) {
539 printf("Error: result mismatch when parsing %s as %s!\n",
540 ipaddr_garbage_network4_strs[i], buf);
546 /* test garbage ipv6 address strings */
547 for (i = 0; i < IPADDR_GARBAGE_NETWORK6_STRS_SIZE; i++) {
549 cmdline_ipaddr_t tmp = {.addr = IPv6_GARBAGE_ADDR};
551 /* test each valid string against different flags */
552 for (flags = 1; flags < 0x8; flags++) {
555 if (flags == CMDLINE_IPADDR_NETWORK)
558 /* clear out everything */
559 memset(buf, 0, sizeof(buf));
560 memset(&result, 0, sizeof(result));
561 memset(&token, 0, sizeof(token));
563 token.ipaddr_data.flags = flags;
565 cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
568 ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
569 ipaddr_garbage_network6_strs[i], (void*)&result,
572 /* if should have passed, or should have failed */
574 (can_parse_addr(CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK, flags))) {
575 printf("Error: unexpected behavior when parsing %s as %s!\n",
576 ipaddr_garbage_network6_strs[i], buf);
580 memcmp(&result.addr.ipv6, &tmp.addr.ipv6, sizeof(struct in6_addr))) {
581 printf("Error: result mismatch when parsing %s as %s!\n",
582 ipaddr_garbage_network6_strs[i], buf);
592 test_parse_ipaddr_invalid_data(void)
594 cmdline_parse_token_ipaddr_t token;
595 char buf[CMDLINE_TEST_BUFSIZE];
596 cmdline_ipaddr_t result;
601 memset(&result, 0, sizeof(result));
603 /* test invalid strings */
604 for (i = 0; i < IPADDR_INVALID_STRS_SIZE; i++) {
606 /* test each valid string against different flags */
607 for (flags = 1; flags < 0x8; flags++) {
610 if (flags == CMDLINE_IPADDR_NETWORK)
613 /* clear out everything */
614 memset(buf, 0, sizeof(buf));
615 memset(&token, 0, sizeof(token));
617 token.ipaddr_data.flags = flags;
619 cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
622 ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
623 ipaddr_invalid_strs[i], (void*)&result,
627 printf("Error: parsing %s as %s succeeded!\n",
628 ipaddr_invalid_strs[i], buf);
629 printf("Parsed result: ");
640 test_parse_ipaddr_invalid_param(void)
642 cmdline_parse_token_ipaddr_t token;
643 char buf[CMDLINE_TEST_BUFSIZE];
644 cmdline_ipaddr_t result;
646 snprintf(buf, sizeof(buf), "1.2.3.4");
647 token.ipaddr_data.flags = CMDLINE_IPADDR_V4;
650 if (cmdline_parse_ipaddr(NULL, buf, (void*)&result,
651 sizeof(result)) != -1) {
652 printf("Error: parser accepted invalid parameters!\n");
656 if (cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
657 NULL, (void*)&result, sizeof(result)) != -1) {
658 printf("Error: parser accepted invalid parameters!\n");
662 if (cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
663 "", (void*)&result, sizeof(result)) != -1) {
664 printf("Error: parser accepted invalid parameters!\n");
668 if (cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token,
669 buf, NULL, 0) == -1) {
670 printf("Error: parser rejected null result!\n");
675 if (cmdline_get_help_ipaddr(NULL, buf, 0) != -1) {
676 printf("Error: help accepted invalid parameters!\n");
680 if (cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token,
682 printf("Error: help accepted invalid parameters!\n");