kernel: fq_codel: dont reinit flow state
[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 (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 }