d22594bd765ce7e5a7ac67d5bdde3ee96ad5fed3
[openwrt/openwrt.git] / package / network / utils / 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 (printed)
228 qprintf(" ");
229
230 if ((b->prefix >= a->prefix) && (net1 == net2))
231 {
232 qprintf("1");
233 return true;
234 }
235 else
236 {
237 qprintf("0");
238 return false;
239 }
240 }
241
242 static bool cidr_netmask4(struct cidr *a)
243 {
244 struct cidr *n = cidr_clone(a);
245
246 n->addr.v4.s_addr = htonl(~((1 << (32 - n->prefix)) - 1));
247 n->prefix = 32;
248
249 return true;
250 }
251
252 static bool cidr_private4(struct cidr *a)
253 {
254 uint32_t x = ntohl(a->addr.v4.s_addr);
255
256 if (printed)
257 qprintf(" ");
258
259 if (((x >= 0x0A000000) && (x <= 0x0AFFFFFF)) ||
260 ((x >= 0xAC100000) && (x <= 0xAC1FFFFF)) ||
261 ((x >= 0xC0A80000) && (x <= 0xC0A8FFFF)))
262 {
263 qprintf("1");
264 return true;
265 }
266 else
267 {
268 qprintf("0");
269 return false;
270 }
271 }
272
273 static bool cidr_linklocal4(struct cidr *a)
274 {
275 uint32_t x = ntohl(a->addr.v4.s_addr);
276
277 if (printed)
278 qprintf(" ");
279
280 if ((x >= 0xA9FE0000) && (x <= 0xA9FEFFFF))
281 {
282 qprintf("1");
283 return true;
284 }
285 else
286 {
287 qprintf("0");
288 return false;
289 }
290 }
291
292 static bool cidr_prev4(struct cidr *a, struct cidr *b)
293 {
294 struct cidr *n = cidr_clone(a);
295
296 n->prefix = b->prefix;
297 n->addr.v4.s_addr -= htonl(1 << (32 - b->prefix));
298
299 return true;
300 }
301
302 static bool cidr_next4(struct cidr *a, struct cidr *b)
303 {
304 struct cidr *n = cidr_clone(a);
305
306 n->prefix = b->prefix;
307 n->addr.v4.s_addr += htonl(1 << (32 - b->prefix));
308
309 return true;
310 }
311
312 static bool cidr_6to4(struct cidr *a)
313 {
314 struct cidr *n = cidr_clone(a);
315 uint32_t x = a->addr.v4.s_addr;
316
317 memset(&n->addr.v6.s6_addr, 0, sizeof(n->addr.v6.s6_addr));
318
319 n->family = AF_INET6;
320 n->prefix = 48;
321
322 n->addr.v6.s6_addr[0] = 0x20;
323 n->addr.v6.s6_addr[1] = 0x02;
324 n->addr.v6.s6_addr[2] = (x >> 24);
325 n->addr.v6.s6_addr[3] = (x >> 16) & 0xFF;
326 n->addr.v6.s6_addr[4] = (x >> 8) & 0xFF;
327 n->addr.v6.s6_addr[5] = x & 0xFF;
328
329 return true;
330 }
331
332 static bool cidr_print4(struct cidr *a)
333 {
334 char *p;
335
336 if (!a || (a->family != AF_INET))
337 return false;
338
339 if (!(p = (char *)inet_ntop(AF_INET, &a->addr.v4, a->buf.v4, sizeof(a->buf.v4))))
340 return false;
341
342 if (printed)
343 qprintf(" ");
344
345 qprintf("%s", p);
346
347 if (a->prefix < 32)
348 qprintf("/%u", a->prefix);
349
350 cidr_pop(a);
351
352 return true;
353 }
354
355
356 static struct cidr * cidr_parse6(const char *s)
357 {
358 char *p = NULL, *r;
359 struct cidr *addr = malloc(sizeof(struct cidr));
360
361 if (!addr || (strlen(s) >= sizeof(addr->buf.v6)))
362 goto err;
363
364 snprintf(addr->buf.v4, sizeof(addr->buf.v6), "%s", s);
365
366 addr->family = AF_INET6;
367
368 if ((p = strchr(addr->buf.v4, '/')) != NULL)
369 {
370 *p++ = 0;
371
372 addr->prefix = strtoul(p, &r, 10);
373
374 if ((p == r) || (*r != 0) || (addr->prefix > 128))
375 goto err;
376 }
377 else
378 {
379 addr->prefix = 128;
380 }
381
382 if (p == addr->buf.v4+1)
383 memset(&addr->addr.v6, 0, sizeof(addr->addr.v6));
384 else if (inet_pton(AF_INET6, addr->buf.v4, &addr->addr.v6) != 1)
385 goto err;
386
387 return addr;
388
389 err:
390 if (addr)
391 free(addr);
392
393 return NULL;
394 }
395
396 static bool cidr_add6(struct cidr *a, struct cidr *b)
397 {
398 uint8_t idx = 15, carry = 0, overflow = 0;
399
400 struct cidr *n = cidr_clone(a);
401 struct in6_addr *x = &n->addr.v6;
402 struct in6_addr *y = &b->addr.v6;
403
404 if ((a->family != AF_INET6) || (b->family != AF_INET6))
405 return false;
406
407 do {
408 overflow = !!((x->s6_addr[idx] + y->s6_addr[idx] + carry) >= 256);
409 x->s6_addr[idx] += y->s6_addr[idx] + carry;
410 carry = overflow;
411 }
412 while (idx-- > 0);
413
414 if (carry)
415 {
416 fprintf(stderr, "overflow during 'add'\n");
417 return false;
418 }
419
420 return true;
421 }
422
423 static bool cidr_sub6(struct cidr *a, struct cidr *b)
424 {
425 uint8_t idx = 15, carry = 0, underflow = 0;
426
427 struct cidr *n = cidr_clone(a);
428 struct in6_addr *x = &n->addr.v6;
429 struct in6_addr *y = &b->addr.v6;
430
431 if ((n->family != AF_INET6) || (b->family != AF_INET6))
432 return false;
433
434 do {
435 underflow = !!((x->s6_addr[idx] - y->s6_addr[idx] - carry) < 0);
436 x->s6_addr[idx] -= y->s6_addr[idx] + carry;
437 carry = underflow;
438 }
439 while (idx-- > 0);
440
441 if (carry)
442 {
443 fprintf(stderr, "underflow during 'sub'\n");
444 return false;
445 }
446
447 return true;
448 }
449
450 static bool cidr_prev6(struct cidr *a, struct cidr *b)
451 {
452 uint8_t idx, carry = 1, underflow = 0;
453 struct cidr *n = cidr_clone(a);
454 struct in6_addr *x = &n->addr.v6;
455
456 if (b->prefix == 0)
457 {
458 fprintf(stderr, "underflow during 'prev'\n");
459 return false;
460 }
461
462 idx = (b->prefix - 1) / 8;
463
464 do {
465 underflow = !!((x->s6_addr[idx] - carry) < 0);
466 x->s6_addr[idx] -= carry;
467 carry = underflow;
468 }
469 while (idx-- > 0);
470
471 if (carry)
472 {
473 fprintf(stderr, "underflow during 'prev'\n");
474 return false;
475 }
476
477 n->prefix = b->prefix;
478
479 return true;
480 }
481
482 static bool cidr_next6(struct cidr *a, struct cidr *b)
483 {
484 uint8_t idx, carry = 1, overflow = 0;
485 struct cidr *n = cidr_clone(a);
486 struct in6_addr *x = &n->addr.v6;
487
488 if (b->prefix == 0)
489 {
490 fprintf(stderr, "overflow during 'next'\n");
491 return false;
492 }
493
494 idx = (b->prefix - 1) / 8;
495
496 do {
497 overflow = !!((x->s6_addr[idx] + carry) >= 256);
498 x->s6_addr[idx] += carry;
499 carry = overflow;
500 }
501 while (idx-- > 0);
502
503 if (carry)
504 {
505 fprintf(stderr, "overflow during 'next'\n");
506 return false;
507 }
508
509 n->prefix = b->prefix;
510
511 return true;
512 }
513
514 static bool cidr_network6(struct cidr *a)
515 {
516 uint8_t i;
517 struct cidr *n = cidr_clone(a);
518
519 for (i = 0; i < (128 - n->prefix) / 8; i++)
520 n->addr.v6.s6_addr[15-i] = 0;
521
522 if ((128 - n->prefix) % 8)
523 n->addr.v6.s6_addr[15-i] &= ~((1 << ((128 - n->prefix) % 8)) - 1);
524
525 return true;
526 }
527
528 static bool cidr_contains6(struct cidr *a, struct cidr *b)
529 {
530 struct cidr *n = cidr_clone(a);
531 struct in6_addr *x = &n->addr.v6;
532 struct in6_addr *y = &b->addr.v6;
533 uint8_t i = (128 - n->prefix) / 8;
534 uint8_t m = ~((1 << ((128 - n->prefix) % 8)) - 1);
535 uint8_t net1 = x->s6_addr[15-i] & m;
536 uint8_t net2 = y->s6_addr[15-i] & m;
537
538 if (printed)
539 qprintf(" ");
540
541 if ((b->prefix >= n->prefix) && (net1 == net2) &&
542 ((i == 15) || !memcmp(&x->s6_addr, &y->s6_addr, 15-i)))
543 {
544 qprintf("1");
545 return true;
546 }
547 else
548 {
549 qprintf("0");
550 return false;
551 }
552 }
553
554 static bool cidr_linklocal6(struct cidr *a)
555 {
556 if (printed)
557 qprintf(" ");
558
559 if ((a->addr.v6.s6_addr[0] == 0xFE) &&
560 (a->addr.v6.s6_addr[1] >= 0x80) &&
561 (a->addr.v6.s6_addr[1] <= 0xBF))
562 {
563 qprintf("1");
564 return true;
565 }
566 else
567 {
568 qprintf("0");
569 return false;
570 }
571 }
572
573 static bool cidr_ula6(struct cidr *a)
574 {
575 if (printed)
576 qprintf(" ");
577
578 if ((a->addr.v6.s6_addr[0] >= 0xFC) &&
579 (a->addr.v6.s6_addr[0] <= 0xFD))
580 {
581 qprintf("1");
582 return true;
583 }
584 else
585 {
586 qprintf("0");
587 return false;
588 }
589 }
590
591 static bool cidr_print6(struct cidr *a)
592 {
593 char *p;
594
595 if (!a || (a->family != AF_INET6))
596 return NULL;
597
598 if (!(p = (char *)inet_ntop(AF_INET6, &a->addr.v6, a->buf.v6, sizeof(a->buf.v6))))
599 return false;
600
601 if (printed)
602 qprintf(" ");
603
604 qprintf("%s", p);
605
606 if (a->prefix < 128)
607 qprintf("/%u", a->prefix);
608
609 cidr_pop(a);
610
611 return true;
612 }
613
614
615 static struct cidr * cidr_parse(const char *op, const char *s, int af_hint)
616 {
617 char *r;
618 struct cidr *a;
619
620 uint8_t i;
621 uint32_t sum = strtoul(s, &r, 0);
622
623 if ((r > s) && (*r == 0))
624 {
625 a = malloc(sizeof(struct cidr));
626
627 if (!a)
628 return NULL;
629
630 if (af_hint == AF_INET)
631 {
632 a->family = AF_INET;
633 a->prefix = sum;
634 a->addr.v4.s_addr = htonl(sum);
635 }
636 else
637 {
638 a->family = AF_INET6;
639 a->prefix = sum;
640
641 for (i = 0; i <= 15; i++)
642 {
643 a->addr.v6.s6_addr[15-i] = sum % 256;
644 sum >>= 8;
645 }
646 }
647
648 return a;
649 }
650
651 if (strchr(s, ':'))
652 a = cidr_parse6(s);
653 else
654 a = cidr_parse4(s);
655
656 if (!a)
657 return NULL;
658
659 if (a->family != af_hint)
660 {
661 fprintf(stderr, "attempt to '%s' %s with %s address\n",
662 op,
663 (af_hint == AF_INET) ? "ipv4" : "ipv6",
664 (af_hint != AF_INET) ? "ipv4" : "ipv6");
665 exit(4);
666 }
667
668 return a;
669 }
670
671 static bool cidr_howmany(struct cidr *a, struct cidr *b)
672 {
673 if (printed)
674 qprintf(" ");
675
676 if (b->prefix < a->prefix)
677 qprintf("0");
678 else
679 qprintf("%u", 1 << (b->prefix - a->prefix));
680
681 return true;
682 }
683
684 static bool cidr_prefix(struct cidr *a, struct cidr *b)
685 {
686 a->prefix = b->prefix;
687 return true;
688 }
689
690 static bool cidr_quiet(struct cidr *a)
691 {
692 quiet = true;
693 return true;
694 }
695
696
697 struct op ops[] = {
698 { .name = "add",
699 .desc = "Add argument to base address",
700 .f4.a2 = cidr_add4,
701 .f6.a2 = cidr_add6 },
702
703 { .name = "sub",
704 .desc = "Substract argument from base address",
705 .f4.a2 = cidr_sub4,
706 .f6.a2 = cidr_sub6 },
707
708 { .name = "next",
709 .desc = "Advance base address to next prefix of given size",
710 .f4.a2 = cidr_next4,
711 .f6.a2 = cidr_next6 },
712
713 { .name = "prev",
714 .desc = "Lower base address to previous prefix of give size",
715 .f4.a2 = cidr_prev4,
716 .f6.a2 = cidr_prev6 },
717
718 { .name = "network",
719 .desc = "Turn base address into network address",
720 .f4.a1 = cidr_network4,
721 .f6.a1 = cidr_network6 },
722
723 { .name = "broadcast",
724 .desc = "Turn base address into broadcast address",
725 .f4.a1 = cidr_broadcast4 },
726
727 { .name = "prefix",
728 .desc = "Set the prefix of base address to argument",
729 .f4.a2 = cidr_prefix,
730 .f6.a2 = cidr_prefix },
731
732 { .name = "netmask",
733 .desc = "Calculate netmask of base address",
734 .f4.a1 = cidr_netmask4 },
735
736 { .name = "6to4",
737 .desc = "Calculate 6to4 prefix of given ipv4-address",
738 .f4.a1 = cidr_6to4 },
739
740 { .name = "howmany",
741 .desc = "Print amount of righ-hand prefixes that fit into base address",
742 .f4.a2 = cidr_howmany,
743 .f6.a2 = cidr_howmany },
744
745 { .name = "contains",
746 .desc = "Print '1' if argument fits into base address or '0' if not",
747 .f4.a2 = cidr_contains4,
748 .f6.a2 = cidr_contains6 },
749
750 { .name = "private",
751 .desc = "Print '1' if base address is in RFC1918 private space or '0' "
752 "if not",
753 .f4.a1 = cidr_private4 },
754
755 { .name = "linklocal",
756 .desc = "Print '1' if base address is in 169.254.0.0/16 or FE80::/10 "
757 "link local space or '0' if not",
758 .f4.a1 = cidr_linklocal4,
759 .f6.a1 = cidr_linklocal6 },
760
761 { .name = "ula",
762 .desc = "Print '1' if base address is in FC00::/7 unique local address "
763 "(ULA) space or '0' if not",
764 .f6.a1 = cidr_ula6 },
765
766 { .name = "quiet",
767 .desc = "Suppress output, useful for test operation where the result can "
768 "be inferred from the exit code",
769 .f4.a1 = cidr_quiet,
770 .f6.a1 = cidr_quiet },
771
772 { .name = "pop",
773 .desc = "Pop intermediate result from stack",
774 .f4.a1 = cidr_pop,
775 .f6.a1 = cidr_pop },
776
777 { .name = "print",
778 .desc = "Print intermediate result and pop it from stack, invoked "
779 "implicitely at the end of calculation if no intermediate prints "
780 "happened",
781 .f4.a1 = cidr_print4,
782 .f6.a1 = cidr_print6 },
783 };
784
785 static void usage(const char *prog)
786 {
787 int i;
788
789 fprintf(stderr,
790 "\n"
791 "Usage:\n\n"
792 " %s {base address} operation [argument] "
793 "[operation [argument] ...]\n\n"
794 "Operations:\n\n",
795 prog);
796
797 for (i = 0; i < sizeof(ops) / sizeof(ops[0]); i++)
798 {
799 if (ops[i].f4.a2 || ops[i].f6.a2)
800 {
801 fprintf(stderr, " %s %s\n",
802 ops[i].name,
803 (ops[i].f4.a2 && ops[i].f6.a2) ? "{ipv4/ipv6/amount}" :
804 (ops[i].f6.a2 ? "{ipv6/amount}" : "{ipv4/amount}"));
805 }
806 else
807 {
808 fprintf(stderr, " %s\n", ops[i].name);
809 }
810
811 fprintf(stderr, " %s.\n", ops[i].desc);
812
813 if ((ops[i].f4.a1 && ops[i].f6.a1) || (ops[i].f4.a2 && ops[i].f6.a2))
814 fprintf(stderr, " Applicable to ipv4- and ipv6-addresses.\n\n");
815 else if (ops[i].f6.a2 || ops[i].f6.a1)
816 fprintf(stderr, " Only applicable to ipv6-addresses.\n\n");
817 else
818 fprintf(stderr, " Only applicable to ipv4-addresses.\n\n");
819 }
820
821 fprintf(stderr,
822 "Examples:\n\n"
823 " Calculate a DHCP range:\n\n"
824 " $ %s 192.168.1.1/255.255.255.0 network add 100 print add 150 print\n"
825 " 192.168.1.100\n"
826 " 192.168.1.250\n\n"
827 " Count number of prefixes:\n\n"
828 " $ %s 2001:0DB8:FDEF::/48 howmany ::/64\n"
829 " 65536\n\n",
830 prog, prog);
831
832 exit(1);
833 }
834
835 static bool runop(char ***arg, int *status)
836 {
837 int i;
838 char *arg1 = **arg;
839 char *arg2 = *(*arg+1);
840 struct cidr *a = stack;
841 struct cidr *b = NULL;
842
843 if (!arg1)
844 return false;
845
846 for (i = 0; i < sizeof(ops) / sizeof(ops[0]); i++)
847 {
848 if (!strcmp(ops[i].name, arg1))
849 {
850 if (ops[i].f4.a2 || ops[i].f6.a2)
851 {
852 if (!arg2)
853 {
854 fprintf(stderr, "'%s' requires an argument\n",
855 ops[i].name);
856
857 *status = 2;
858 return false;
859 }
860
861 b = cidr_parse(ops[i].name, arg2, a->family);
862
863 if (!b)
864 {
865 fprintf(stderr, "invalid address argument for '%s'\n",
866 ops[i].name);
867
868 *status = 3;
869 return false;
870 }
871
872 *arg += 2;
873
874 if (((a->family == AF_INET) && !ops[i].f4.a2) ||
875 ((a->family == AF_INET6) && !ops[i].f6.a2))
876 {
877 fprintf(stderr, "'%s' not supported for %s addresses\n",
878 ops[i].name,
879 (a->family == AF_INET) ? "ipv4" : "ipv6");
880
881 *status = 5;
882 return false;
883 }
884
885 *status = !((a->family == AF_INET) ? ops[i].f4.a2(a, b)
886 : ops[i].f6.a2(a, b));
887
888 return true;
889 }
890 else
891 {
892 *arg += 1;
893
894 if (((a->family == AF_INET) && !ops[i].f4.a1) ||
895 ((a->family == AF_INET6) && !ops[i].f6.a1))
896 {
897 fprintf(stderr, "'%s' not supported for %s addresses\n",
898 ops[i].name,
899 (a->family == AF_INET) ? "ipv4" : "ipv6");
900
901 *status = 5;
902 return false;
903 }
904
905 *status = !((a->family == AF_INET) ? ops[i].f4.a1(a)
906 : ops[i].f6.a1(a));
907
908 return true;
909 }
910 }
911 }
912
913 return false;
914 }
915
916 int main(int argc, char **argv)
917 {
918 int status = 0;
919 char **arg = argv+2;
920 struct cidr *a;
921
922 if (argc < 3)
923 usage(argv[0]);
924
925 a = strchr(argv[1], ':') ? cidr_parse6(argv[1]) : cidr_parse4(argv[1]);
926
927 if (!a)
928 usage(argv[0]);
929
930 cidr_push(a);
931
932 while (runop(&arg, &status));
933
934 if (*arg)
935 {
936 fprintf(stderr, "unknown operation '%s'\n", *arg);
937 exit(6);
938 }
939
940 if (!printed && (status < 2))
941 {
942 if (stack->family == AF_INET)
943 cidr_print4(stack);
944 else
945 cidr_print6(stack);
946 }
947
948 qprintf("\n");
949
950 exit(status);
951 }