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");