18013136b120474c6cb2b23c716fa38b20db743d
[openwrt/openwrt.git] / package / owipcalc / src / owipcalc.c
1 /*
2 * owipcalc - OpenWrt IP Calculator
3 *
4 * Copyright (C) 2012 Jo-Philipp Wich <jow@openwrt.org>
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 #include <stdio.h>
20 #include <stdint.h>
21 #include <stdbool.h>
22 #include <stdlib.h>
23
24 #include <string.h>
25 #include <unistd.h>
26
27 #include <arpa/inet.h>
28
29
30 struct cidr {
31 uint8_t family;
32 uint32_t prefix;
33 union {
34 struct in_addr v4;
35 struct in6_addr v6;
36 } addr;
37 union {
38 char v4[sizeof("255.255.255.255/255.255.255.255 ")];
39 char v6[sizeof("FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:255.255.255.255/128 ")];
40 } buf;
41 struct cidr *next;
42 };
43
44 struct op {
45 const char *name;
46 const char *desc;
47 struct {
48 bool (*a1)(struct cidr *a);
49 bool (*a2)(struct cidr *a, struct cidr *b);
50 } f4;
51 struct {
52 bool (*a1)(struct cidr *a);
53 bool (*a2)(struct cidr *a, struct cidr *b);
54 } f6;
55 };
56
57
58 static bool quiet = false;
59 static bool printed = false;
60
61 static struct cidr *stack = NULL;
62
63 #define qprintf(...) \
64 do { \
65 if (!quiet) printf(__VA_ARGS__); \
66 printed = true; \
67 } while(0)
68
69 static void cidr_push(struct cidr *a)
70 {
71 if (a)
72 {
73 a->next = stack;
74 stack = a;
75 }
76 }
77
78 static bool cidr_pop(struct cidr *a)
79 {
80 struct cidr *old = stack;
81
82 if (old)
83 {
84 stack = stack->next;
85 free(old);
86
87 return true;
88 }
89
90 return false;
91 }
92
93 static struct cidr * cidr_clone(struct cidr *a)
94 {
95 struct cidr *b = malloc(sizeof(*b));
96
97 if (!b)
98 {
99 fprintf(stderr, "out of memory\n");
100 exit(255);
101 }
102
103 memcpy(b, a, sizeof(*b));
104 cidr_push(b);
105
106 return b;
107 }
108
109
110 static struct cidr * cidr_parse4(const char *s)
111 {
112 char *p = NULL, *r;
113 struct in_addr mask;
114 struct cidr *addr = malloc(sizeof(struct cidr));
115
116 if (!addr || (strlen(s) >= sizeof(addr->buf.v4)))
117 goto err;
118
119 snprintf(addr->buf.v4, sizeof(addr->buf.v4), "%s", s);
120
121 addr->family = AF_INET;
122
123 if ((p = strchr(addr->buf.v4, '/')) != NULL)
124 {
125 *p++ = 0;
126
127 if (strchr(p, '.') != NULL)
128 {
129 if (inet_pton(AF_INET, p, &mask) != 1)
130 goto err;
131
132 for (addr->prefix = 0; mask.s_addr; mask.s_addr >>= 1)
133 addr->prefix += (mask.s_addr & 1);
134 }
135 else
136 {
137 addr->prefix = strtoul(p, &r, 10);
138
139 if ((p == r) || (*r != 0) || (addr->prefix > 32))
140 goto err;
141 }
142 }
143 else
144 {
145 addr->prefix = 32;
146 }
147
148 if (p == addr->buf.v4+1)
149 memset(&addr->addr.v4, 0, sizeof(addr->addr.v4));
150 else if (inet_pton(AF_INET, addr->buf.v4, &addr->addr.v4) != 1)
151 goto err;
152
153 return addr;
154
155 err:
156 if (addr)
157 free(addr);
158
159 return NULL;
160 }
161
162 static bool cidr_add4(struct cidr *a, struct cidr *b)
163 {
164 uint32_t x = ntohl(a->addr.v4.s_addr);
165 uint32_t y = ntohl(b->addr.v4.s_addr);
166
167 struct cidr *n = cidr_clone(a);
168
169 if ((n->family != AF_INET) || (b->family != AF_INET))
170 return false;
171
172 if ((uint32_t)(x + y) < x)
173 {
174 fprintf(stderr, "overflow during 'add'\n");
175 return false;
176 }
177
178 n->addr.v4.s_addr = htonl(x + y);
179 return true;
180 }
181
182 static bool cidr_sub4(struct cidr *a, struct cidr *b)
183 {
184 uint32_t x = ntohl(a->addr.v4.s_addr);
185 uint32_t y = ntohl(b->addr.v4.s_addr);
186
187 struct cidr *n = cidr_clone(a);
188
189 if ((n->family != AF_INET) || (b->family != AF_INET))
190 return false;
191
192 if ((uint32_t)(x - y) > x)
193 {
194 fprintf(stderr, "underflow during 'sub'\n");
195 return false;
196 }
197
198 n->addr.v4.s_addr = htonl(x - y);
199 return true;
200 }
201
202 static bool cidr_network4(struct cidr *a)
203 {
204 struct cidr *n = cidr_clone(a);
205
206 n->addr.v4.s_addr &= htonl(~((1 << (32 - n->prefix)) - 1));
207 n->prefix = 32;
208
209 return true;
210 }
211
212 static bool cidr_broadcast4(struct cidr *a)
213 {
214 struct cidr *n = cidr_clone(a);
215
216 n->addr.v4.s_addr |= htonl(((1 << (32 - n->prefix)) - 1));
217 n->prefix = 32;
218
219 return true;
220 }
221
222 static bool cidr_contains4(struct cidr *a, struct cidr *b)
223 {
224 uint32_t net1 = a->addr.v4.s_addr & htonl(~((1 << (32 - a->prefix)) - 1));
225 uint32_t net2 = b->addr.v4.s_addr & htonl(~((1 << (32 - a->prefix)) - 1));
226
227 if ((b->prefix >= a->prefix) && (net1 == net2))
228 {
229 qprintf("1\n");
230 return true;
231 }
232 else
233 {
234 qprintf("0\n");
235 return false;
236 }
237 }
238
239 static bool cidr_netmask4(struct cidr *a)
240 {
241 struct cidr *n = cidr_clone(a);
242
243 n->addr.v4.s_addr = htonl(~((1 << (32 - n->prefix)) - 1));
244 n->prefix = 32;
245
246 return true;
247 }
248
249 static bool cidr_private4(struct cidr *a)
250 {
251 uint32_t x = ntohl(a->addr.v4.s_addr);
252
253 if (((x >= 0x0A000000) && (x <= 0x0AFFFFFF)) ||
254 ((x >= 0xAC100000) && (x <= 0xAC1FFFFF)) ||
255 ((x >= 0xC0A80000) && (x <= 0xC0A8FFFF)))
256 {
257 qprintf("1\n");
258 return true;
259 }
260 else
261 {
262 qprintf("0\n");
263 return false;
264 }
265 }
266
267 static bool cidr_linklocal4(struct cidr *a)
268 {
269 uint32_t x = ntohl(a->addr.v4.s_addr);
270
271 if ((x >= 0xA9FE0000) && (x <= 0xA9FEFFFF))
272 {
273 qprintf("1\n");
274 return true;
275 }
276 else
277 {
278 qprintf("0\n");
279 return false;
280 }
281 }
282
283 static bool cidr_prev4(struct cidr *a, struct cidr *b)
284 {
285 struct cidr *n = cidr_clone(a);
286
287 n->prefix = b->prefix;
288 n->addr.v4.s_addr -= htonl(1 << (32 - b->prefix));
289
290 return true;
291 }
292
293 static bool cidr_next4(struct cidr *a, struct cidr *b)
294 {
295 struct cidr *n = cidr_clone(a);
296
297 n->prefix = b->prefix;
298 n->addr.v4.s_addr += htonl(1 << (32 - b->prefix));
299
300 return true;
301 }
302
303 static bool cidr_6to4(struct cidr *a)
304 {
305 struct cidr *n = cidr_clone(a);
306 uint32_t x = a->addr.v4.s_addr;
307
308 memset(&n->addr.v6.s6_addr, 0, sizeof(n->addr.v6.s6_addr));
309
310 n->family = AF_INET6;
311 n->prefix = 48;
312
313 n->addr.v6.s6_addr[0] = 0x20;
314 n->addr.v6.s6_addr[1] = 0x02;
315 n->addr.v6.s6_addr[2] = (x >> 24);
316 n->addr.v6.s6_addr[3] = (x >> 16) & 0xFF;
317 n->addr.v6.s6_addr[4] = (x >> 8) & 0xFF;
318 n->addr.v6.s6_addr[5] = x & 0xFF;
319
320 return true;
321 }
322
323 static bool cidr_print4(struct cidr *a)
324 {
325 char *p;
326
327 if (!a || (a->family != AF_INET))
328 return false;
329
330 if (!(p = (char *)inet_ntop(AF_INET, &a->addr.v4, a->buf.v4, sizeof(a->buf.v4))))
331 return false;
332
333 if (printed)
334 qprintf(" ");
335
336 qprintf("%s", p);
337
338 if (a->prefix < 32)
339 qprintf("/%u", a->prefix);
340
341 cidr_pop(a);
342
343 return true;
344 }
345
346
347 static struct cidr * cidr_parse6(const char *s)
348 {
349 char *p = NULL, *r;
350 struct cidr *addr = malloc(sizeof(struct cidr));
351
352 if (!addr || (strlen(s) >= sizeof(addr->buf.v6)))
353 goto err;
354
355 snprintf(addr->buf.v4, sizeof(addr->buf.v6), "%s", s);
356
357 addr->family = AF_INET6;
358
359 if ((p = strchr(addr->buf.v4, '/')) != NULL)
360 {
361 *p++ = 0;
362
363 addr->prefix = strtoul(p, &r, 10);
364
365 if ((p == r) || (*r != 0) || (addr->prefix > 128))
366 goto err;
367 }
368 else
369 {
370 addr->prefix = 128;
371 }
372
373 if (p == addr->buf.v4+1)
374 memset(&addr->addr.v6, 0, sizeof(addr->addr.v6));
375 else if (inet_pton(AF_INET6, addr->buf.v4, &addr->addr.v6) != 1)
376 goto err;
377
378 return addr;
379
380 err:
381 if (addr)
382 free(addr);
383
384 return NULL;
385 }
386
387 static bool cidr_add6(struct cidr *a, struct cidr *b)
388 {
389 uint8_t idx = 15, carry = 0, overflow = 0;
390
391 struct cidr *n = cidr_clone(a);
392 struct in6_addr *x = &n->addr.v6;
393 struct in6_addr *y = &b->addr.v6;
394
395 if ((a->family != AF_INET6) || (b->family != AF_INET6))
396 return false;
397
398 do {
399 overflow = !!((x->s6_addr[idx] + y->s6_addr[idx] + carry) >= 256);
400 x->s6_addr[idx] += y->s6_addr[idx] + carry;
401 carry = overflow;
402 }
403 while (idx-- > 0);
404
405 if (carry)
406 {
407 fprintf(stderr, "overflow during 'add'\n");
408 return false;
409 }
410
411 return true;
412 }
413
414 static bool cidr_sub6(struct cidr *a, struct cidr *b)
415 {
416 uint8_t idx = 15, carry = 0, underflow = 0;
417
418 struct cidr *n = cidr_clone(a);
419 struct in6_addr *x = &n->addr.v6;
420 struct in6_addr *y = &b->addr.v6;
421
422 if ((n->family != AF_INET6) || (b->family != AF_INET6))
423 return false;
424
425 do {
426 underflow = !!((x->s6_addr[idx] - y->s6_addr[idx] - carry) < 0);
427 x->s6_addr[idx] -= y->s6_addr[idx] + carry;
428 carry = underflow;
429 }
430 while (idx-- > 0);
431
432 if (carry)
433 {
434 fprintf(stderr, "underflow during 'sub'\n");
435 return false;
436 }
437
438 return true;
439 }
440
441 static bool cidr_prev6(struct cidr *a, struct cidr *b)
442 {
443 uint8_t idx, carry = 1, underflow = 0;
444 struct cidr *n = cidr_clone(a);
445 struct in6_addr *x = &n->addr.v6;
446
447 if (b->prefix == 0)
448 {
449 fprintf(stderr, "underflow during 'prev'\n");
450 return false;
451 }
452
453 idx = (b->prefix - 1) / 8;
454
455 do {
456 underflow = !!((x->s6_addr[idx] - carry) < 0);
457 x->s6_addr[idx] -= carry;
458 carry = underflow;
459 }
460 while (idx-- > 0);
461
462 if (carry)
463 {
464 fprintf(stderr, "underflow during 'prev'\n");
465 return false;
466 }
467
468 n->prefix = b->prefix;
469
470 return true;
471 }
472
473 static bool cidr_next6(struct cidr *a, struct cidr *b)
474 {
475 uint8_t idx, carry = 1, overflow = 0;
476 struct cidr *n = cidr_clone(a);
477 struct in6_addr *x = &n->addr.v6;
478
479 if (b->prefix == 0)
480 {
481 fprintf(stderr, "overflow during 'next'\n");
482 return false;
483 }
484
485 idx = (b->prefix - 1) / 8;
486
487 do {
488 overflow = !!((x->s6_addr[idx] + carry) >= 256);
489 x->s6_addr[idx] += carry;
490 carry = overflow;
491 }
492 while (idx-- > 0);
493
494 if (carry)
495 {
496 fprintf(stderr, "overflow during 'next'\n");
497 return false;
498 }
499
500 n->prefix = b->prefix;
501
502 return true;
503 }
504
505 static bool cidr_network6(struct cidr *a)
506 {
507 uint8_t i;
508 struct cidr *n = cidr_clone(a);
509
510 for (i = 0; i < (128 - n->prefix) / 8; i++)
511 n->addr.v6.s6_addr[15-i] = 0;
512
513 if ((128 - n->prefix) % 8)
514 n->addr.v6.s6_addr[15-i] &= ~((1 << ((128 - n->prefix) % 8)) - 1);
515
516 return true;
517 }
518
519 static bool cidr_contains6(struct cidr *a, struct cidr *b)
520 {
521 struct cidr *n = cidr_clone(a);
522 struct in6_addr *x = &n->addr.v6;
523 struct in6_addr *y = &b->addr.v6;
524 uint8_t i = (128 - n->prefix) / 8;
525 uint8_t m = ~((1 << ((128 - n->prefix) % 8)) - 1);
526 uint8_t net1 = x->s6_addr[15-i] & m;
527 uint8_t net2 = y->s6_addr[15-i] & m;
528
529 if ((b->prefix >= n->prefix) && (net1 == net2) &&
530 ((i == 15) || !memcmp(&x->s6_addr, &y->s6_addr, 15-i)))
531 {
532 qprintf("1\n");
533 return true;
534 }
535 else
536 {
537 qprintf("0\n");
538 return false;
539 }
540 }
541
542 static bool cidr_linklocal6(struct cidr *a)
543 {
544 if ((a->addr.v6.s6_addr[0] == 0xFE) &&
545 (a->addr.v6.s6_addr[1] >= 0x80) &&
546 (a->addr.v6.s6_addr[1] <= 0xBF))
547 {
548 qprintf("1\n");
549 return true;
550 }
551 else
552 {
553 qprintf("0\n");
554 return false;
555 }
556 }
557
558 static bool cidr_ula6(struct cidr *a)
559 {
560 if ((a->addr.v6.s6_addr[0] >= 0xFC) &&
561 (a->addr.v6.s6_addr[0] <= 0xFD))
562 {
563 qprintf("1\n");
564 return true;
565 }
566 else
567 {
568 qprintf("0\n");
569 return false;
570 }
571 }
572
573 static bool cidr_print6(struct cidr *a)
574 {
575 char *p;
576
577 if (!a || (a->family != AF_INET6))
578 return NULL;
579
580 if (!(p = (char *)inet_ntop(AF_INET6, &a->addr.v6, a->buf.v6, sizeof(a->buf.v6))))
581 return false;
582
583 if (printed)
584 qprintf(" ");
585
586 qprintf("%s", p);
587
588 if (a->prefix < 128)
589 qprintf("/%u", a->prefix);
590
591 cidr_pop(a);
592
593 return true;
594 }
595
596
597 static struct cidr * cidr_parse(const char *op, const char *s, int af_hint)
598 {
599 char *r;
600 struct cidr *a;
601
602 uint8_t i;
603 uint32_t sum = strtoul(s, &r, 0);
604
605 if ((r > s) && (*r == 0))
606 {
607 a = malloc(sizeof(struct cidr));
608
609 if (!a)
610 return NULL;
611
612 if (af_hint == AF_INET)
613 {
614 a->family = AF_INET;
615 a->prefix = sum;
616 a->addr.v4.s_addr = htonl(sum);
617 }
618 else
619 {
620 a->family = AF_INET6;
621 a->prefix = sum;
622
623 for (i = 0; i <= 15; i++)
624 {
625 a->addr.v6.s6_addr[15-i] = sum % 256;
626 sum >>= 8;
627 }
628 }
629
630 return a;
631 }
632
633 if (strchr(s, ':'))
634 a = cidr_parse6(s);
635 else
636 a = cidr_parse4(s);
637
638 if (!a)
639 return NULL;
640
641 if (a->family != af_hint)
642 {
643 fprintf(stderr, "attempt to '%s' %s with %s address\n",
644 op,
645 (af_hint == AF_INET) ? "ipv4" : "ipv6",
646 (af_hint != AF_INET) ? "ipv4" : "ipv6");
647 exit(4);
648 }
649
650 return a;
651 }
652
653 static bool cidr_howmany(struct cidr *a, struct cidr *b)
654 {
655 if (b->prefix < a->prefix)
656 qprintf("0\n");
657 else
658 qprintf("%u\n", 1 << (b->prefix - a->prefix));
659
660 return true;
661 }
662
663 static bool cidr_prefix(struct cidr *a, struct cidr *b)
664 {
665 a->prefix = b->prefix;
666 return true;
667 }
668
669 static bool cidr_quiet(struct cidr *a)
670 {
671 quiet = true;
672 return true;
673 }
674
675
676 struct op ops[] = {
677 { .name = "add",
678 .desc = "Add argument to base address",
679 .f4.a2 = cidr_add4,
680 .f6.a2 = cidr_add6 },
681
682 { .name = "sub",
683 .desc = "Substract argument from base address",
684 .f4.a2 = cidr_sub4,
685 .f6.a2 = cidr_sub6 },
686
687 { .name = "next",
688 .desc = "Advance base address to next prefix of given size",
689 .f4.a2 = cidr_next4,
690 .f6.a2 = cidr_next6 },
691
692 { .name = "prev",
693 .desc = "Lower base address to previous prefix of give size",
694 .f4.a2 = cidr_prev4,
695 .f6.a2 = cidr_prev6 },
696
697 { .name = "network",
698 .desc = "Turn base address into network address",
699 .f4.a1 = cidr_network4,
700 .f6.a1 = cidr_network6 },
701
702 { .name = "broadcast",
703 .desc = "Turn base address into broadcast address",
704 .f4.a1 = cidr_broadcast4 },
705
706 { .name = "prefix",
707 .desc = "Set the prefix of base address to argument",
708 .f4.a2 = cidr_prefix,
709 .f6.a2 = cidr_prefix },
710
711 { .name = "netmask",
712 .desc = "Calculate netmask of base address",
713 .f4.a1 = cidr_netmask4 },
714
715 { .name = "6to4",
716 .desc = "Calculate 6to4 prefix of given ipv4-address",
717 .f4.a1 = cidr_6to4 },
718
719 { .name = "howmany",
720 .desc = "Print amount of righ-hand prefixes that fit into base address",
721 .f4.a2 = cidr_howmany,
722 .f6.a2 = cidr_howmany },
723
724 { .name = "contains",
725 .desc = "Print '1' if argument fits into base address or '0' if not",
726 .f4.a2 = cidr_contains4,
727 .f6.a2 = cidr_contains6 },
728
729 { .name = "private",
730 .desc = "Print '1' if base address is in RFC1918 private space or '0' "
731 "if not",
732 .f4.a1 = cidr_private4 },
733
734 { .name = "linklocal",
735 .desc = "Print '1' if base address is in 169.254.0.0/16 or FE80::/10 "
736 "link local space or '0' if not",
737 .f4.a1 = cidr_linklocal4,
738 .f6.a1 = cidr_linklocal6 },
739
740 { .name = "ula",
741 .desc = "Print '1' if base address is in FC00::/7 unique local address "
742 "(ULA) space or '0' if not",
743 .f6.a1 = cidr_ula6 },
744
745 { .name = "quiet",
746 .desc = "Suppress output, useful for test operation where the result can "
747 "be inferred from the exit code",
748 .f4.a1 = cidr_quiet,
749 .f6.a1 = cidr_quiet },
750
751 { .name = "pop",
752 .desc = "Pop intermediate result from stack",
753 .f4.a1 = cidr_pop,
754 .f6.a1 = cidr_pop },
755
756 { .name = "print",
757 .desc = "Print intermediate result and pop it from stack, invoked "
758 "implicitely at the end of calculation if no intermediate prints "
759 "happened",
760 .f4.a1 = cidr_print4,
761 .f6.a1 = cidr_print6 },
762 };
763
764 static void usage(const char *prog)
765 {
766 int i;
767
768 fprintf(stderr,
769 "\n"
770 "Usage:\n\n"
771 " %s {base address} operation [argument] "
772 "[operation [argument] ...]\n\n"
773 "Operations:\n\n",
774 prog);
775
776 for (i = 0; i < sizeof(ops) / sizeof(ops[0]); i++)
777 {
778 if (ops[i].f4.a2 || ops[i].f6.a2)
779 {
780 fprintf(stderr, " %s %s\n",
781 ops[i].name,
782 (ops[i].f4.a2 && ops[i].f6.a2) ? "{ipv4/ipv6/amount}" :
783 (ops[i].f6.a2 ? "{ipv6/amount}" : "{ipv4/amount}"));
784 }
785 else
786 {
787 fprintf(stderr, " %s\n", ops[i].name);
788 }
789
790 fprintf(stderr, " %s.\n", ops[i].desc);
791
792 if ((ops[i].f4.a1 && ops[i].f6.a1) || (ops[i].f4.a2 && ops[i].f6.a2))
793 fprintf(stderr, " Applicable to ipv4- and ipv6-addresses.\n\n");
794 else if (ops[i].f6.a2 || ops[i].f6.a1)
795 fprintf(stderr, " Only applicable to ipv6-addresses.\n\n");
796 else
797 fprintf(stderr, " Only applicable to ipv4-addresses.\n\n");
798 }
799
800 fprintf(stderr,
801 "Examples:\n\n"
802 " Calculate a DHCP range:\n\n"
803 " $ %s 192.168.1.1/255.255.255.0 network add 100 print add 150 print\n"
804 " 192.168.1.100\n"
805 " 192.168.1.250\n\n"
806 " Count number of prefixes:\n\n"
807 " $ %s 2001:0DB8:FDEF::/48 howmany ::/64\n"
808 " 65536\n\n",
809 prog, prog);
810
811 exit(1);
812 }
813
814 static bool runop(char ***arg, int *status)
815 {
816 int i;
817 char *arg1 = **arg;
818 char *arg2 = *(*arg+1);
819 struct cidr *a = stack;
820 struct cidr *b = NULL;
821
822 if (!arg1)
823 return false;
824
825 for (i = 0; i < sizeof(ops) / sizeof(ops[0]); i++)
826 {
827 if (!strcmp(ops[i].name, arg1))
828 {
829 if (ops[i].f4.a2 || ops[i].f6.a2)
830 {
831 if (!arg2)
832 {
833 fprintf(stderr, "'%s' requires an argument\n",
834 ops[i].name);
835
836 *status = 2;
837 return false;
838 }
839
840 b = cidr_parse(ops[i].name, arg2, a->family);
841
842 if (!b)
843 {
844 fprintf(stderr, "invalid address argument for '%s'\n",
845 ops[i].name);
846
847 *status = 3;
848 return false;
849 }
850
851 *arg += 2;
852
853 if (((a->family == AF_INET) && !ops[i].f4.a2) ||
854 ((a->family == AF_INET6) && !ops[i].f6.a2))
855 {
856 fprintf(stderr, "'%s' not supported for %s addresses\n",
857 ops[i].name,
858 (a->family == AF_INET) ? "ipv4" : "ipv6");
859
860 *status = 5;
861 return false;
862 }
863
864 *status = !((a->family == AF_INET) ? ops[i].f4.a2(a, b)
865 : ops[i].f6.a2(a, b));
866
867 return true;
868 }
869 else
870 {
871 *arg += 1;
872
873 if (((a->family == AF_INET) && !ops[i].f4.a1) ||
874 ((a->family == AF_INET6) && !ops[i].f6.a1))
875 {
876 fprintf(stderr, "'%s' not supported for %s addresses\n",
877 ops[i].name,
878 (a->family == AF_INET) ? "ipv4" : "ipv6");
879
880 *status = 5;
881 return false;
882 }
883
884 *status = !((a->family == AF_INET) ? ops[i].f4.a1(a)
885 : ops[i].f6.a1(a));
886
887 return true;
888 }
889 }
890 }
891
892 return false;
893 }
894
895 int main(int argc, char **argv)
896 {
897 int status = 0;
898 char **arg = argv+2;
899 struct cidr *a;
900
901 if (argc < 3)
902 usage(argv[0]);
903
904 a = strchr(argv[1], ':') ? cidr_parse6(argv[1]) : cidr_parse4(argv[1]);
905
906 if (!a)
907 usage(argv[0]);
908
909 cidr_push(a);
910
911 while (runop(&arg, &status));
912
913 if (*arg)
914 {
915 fprintf(stderr, "unknown operation '%s'\n", *arg);
916 exit(6);
917 }
918
919 if (!printed && (status < 2))
920 {
921 if (stack->family == AF_INET)
922 cidr_print4(stack);
923 else
924 cidr_print6(stack);
925 }
926
927 qprintf("\n");
928
929 exit(status);
930 }