]> git.ipfire.org Git - people/ms/network.git/blame - src/inetcalc.c
route: rename route to route static
[people/ms/network.git] / src / inetcalc.c
CommitLineData
13a6e69f
MT
1/*#############################################################################
2# #
3# IPFire.org - A linux based firewall #
4# Copyright (C) 2015 IPFire Network Development Team #
5# #
6# This program is free software: you can redistribute it and/or modify #
7# it under the terms of the GNU General Public License as published by #
8# the Free Software Foundation, either version 3 of the License, or #
9# (at your option) any later version. #
10# #
11# This program is distributed in the hope that it will be useful, #
12# but WITHOUT ANY WARRANTY; without even the implied warranty of #
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14# GNU General Public License for more details. #
15# #
16# You should have received a copy of the GNU General Public License #
17# along with this program. If not, see <http://www.gnu.org/licenses/>. #
18# #
19#############################################################################*/
20
21#include <assert.h>
22#include <arpa/inet.h>
23#include <errno.h>
24#include <getopt.h>
25#include <netinet/in.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <sys/socket.h>
30
31typedef struct ip_address {
32 int family;
cf3fb03c 33 struct in6_addr addr;
13a6e69f
MT
34 int prefix;
35} ip_address_t;
36
cf3fb03c
MT
37static struct in6_addr prefix_to_bitmask(int prefix) {
38 assert(prefix <= 128);
13a6e69f 39
cf3fb03c 40 struct in6_addr bitmask;
13a6e69f 41
cf3fb03c
MT
42 for (int i = 0; i < 16; i++)
43 bitmask.s6_addr[i] = 0;
44
45 for (int i = prefix, j = 0; i > 0; i -= 8, j++) {
46 if (i >= 8)
47 bitmask.s6_addr[j] = 0xff;
48 else
49 bitmask.s6_addr[j] = 0xff << (8 - i);
50 }
51
52 return bitmask;
13a6e69f
MT
53}
54
55static int bitmask_to_prefix(uint32_t bits) {
56 int prefix = 0;
57
58 // Count all ones until we find the first zero
59 while (bits & (1 << 31)) {
60 bits <<= 1;
61 prefix++;
62 }
63
64 // The remaining bits must all be zero
65 if (bits)
66 return -1;
67
68 return prefix;
69}
70
71static int ip_address_parse_subnet_mask(ip_address_t* ip, const char* prefix) {
72 struct in_addr mask;
73
74 int r = inet_pton(AF_INET, prefix, &mask.s_addr);
75 if (r != 1)
76 return 1;
77
78 uint32_t bits = ntohl(mask.s_addr);
79 ip->prefix = bitmask_to_prefix(bits);
80
81 return (ip->prefix < 0 || ip->prefix > 32);
82}
83
84static int ip_address_parse_prefix_cidr(ip_address_t* ip, const int family, const char* prefix) {
85 ip->prefix = 0;
86 while (*prefix) {
87 char p = *prefix++;
88
89 if (p >= '0' && p <= '9') {
90 ip->prefix *= 10;
91 ip->prefix += p - '0';
92 } else {
93 return 1;
94 }
95 }
96
97 switch (family) {
98 case AF_INET6:
99 return (ip->prefix < 0 || ip->prefix > 128);
100
101 case AF_INET:
102 return (ip->prefix < 0 || ip->prefix > 32);
103
104 default:
105 return 1;
106 }
107}
108
109static int ip_address_parse_prefix(ip_address_t* ip, const int family, const char* prefix) {
110 int r = ip_address_parse_prefix_cidr(ip, family, prefix);
111
112 if (r && family == AF_INET) {
113 r = ip_address_parse_subnet_mask(ip, prefix);
114 }
115
116 return r;
117}
118
9e244826
MT
119static int default_prefix(const int family) {
120 switch (family) {
121 case AF_INET6:
122 return 128;
123
124 case AF_INET:
125 return 32;
126
127 default:
128 return -1;
129 }
130}
131
13a6e69f
MT
132static int ip_address_parse_simple(ip_address_t* ip, const int family, const char* address) {
133 assert(family == AF_INET || family == AF_INET6);
134
135 size_t address_length = strlen(address);
136 char buffer[address_length + 1];
137 strncpy(buffer, address, sizeof(buffer));
138
139 // Search for a prefix or subnet mask
140 char* prefix = strchr(buffer, '/');
141 if (prefix) {
142 buffer[prefix - buffer] = '\0';
143 prefix++;
144 }
145
146 memset(&ip->addr, 0, sizeof(ip->addr));
147 int r = inet_pton(family, buffer, &ip->addr);
148
149 switch (r) {
150 // If parsing the IP address failed, we will return false
151 case 0:
152 return 1;
153
154 // If the IP address could be successfully parsed, we will
155 // save the address family and return true
156 case 1:
157 ip->family = family;
158 r = 0;
159 break;
160
161 default:
162 return r;
163 }
164
165 if (prefix)
166 r = ip_address_parse_prefix(ip, family, prefix);
167 else
9e244826 168 ip->prefix = default_prefix(family);
13a6e69f
MT
169
170 return r;
171}
172
173static int ip_address_parse(ip_address_t* ip, const int family, const char* address) {
174 static int families[] = { AF_INET, AF_INET6, 0 };
175
176 int r = 1;
177 int* f = families;
178 while (*f) {
179 if (family == AF_UNSPEC || family == *f) {
180 r = ip_address_parse_simple(ip, *f, address);
181
182 if (r == 0)
183 break;
184 }
185
186 f++;
187 }
188
189 return r;
190}
191
192static int ip_address_eq(const ip_address_t* a1, const ip_address_t* a2) {
193 if (a1->family != a2->family)
194 return 1;
195
44f177a9 196 if (!IN6_ARE_ADDR_EQUAL(&a1->addr, &a2->addr))
13a6e69f
MT
197 return 1;
198
199 if (a1->prefix != a2->prefix)
200 return 1;
201
202 return 0;
203}
204
205static int ip_address_gt(const ip_address_t* a1, const ip_address_t* a2) {
206 if (a1->family != a2->family || a1->prefix != a2->prefix)
207 return -1;
208
5439682d
MT
209 if (memcmp(&a1->addr.s6_addr, &a2->addr.s6_addr, sizeof(a1->addr.s6_addr)) > 0)
210 return 0;
13a6e69f
MT
211
212 return 1;
213}
214
9e244826
MT
215static int ip_address_ge(const ip_address_t* a1, const ip_address_t* a2) {
216 int r = ip_address_eq(a1, a2);
217 if (r <= 0)
218 return r;
219
220 return ip_address_gt(a1, a2);
221}
222
223static int ip_address_le(const ip_address_t* a1, const ip_address_t* a2) {
224 int r = ip_address_eq(a1, a2);
225 if (r <= 0)
226 return r;
227
228 return !ip_address_gt(a1, a2);
229}
230
13a6e69f
MT
231static int ip_address_format_string(char* buffer, size_t size, const ip_address_t* ip) {
232 assert(ip->family == AF_INET || ip->family == AF_INET6);
233
cf3fb03c 234 const char* p = inet_ntop(ip->family, &ip->addr.s6_addr, buffer, size);
13a6e69f
MT
235 if (!p)
236 return errno;
237
238 return 0;
239}
240
241static void ip_address_print(const ip_address_t* ip) {
242 char buffer[INET6_ADDRSTRLEN+4];
243
244 int r = ip_address_format_string(buffer, sizeof(buffer), ip);
245 if (r)
246 return;
247
248 if (ip->prefix >= 0) {
249 size_t len = strlen(buffer);
250 snprintf(buffer + len, sizeof(buffer) - len, "/%d", ip->prefix);
251 }
252
253 printf("%s\n", buffer);
254}
255
9e244826
MT
256static void ip_address_get_first_address(ip_address_t* first, const ip_address_t* network) {
257 assert(network->prefix >= 0);
13a6e69f 258
9e244826 259 struct in6_addr mask = prefix_to_bitmask(network->prefix);
13a6e69f 260
9e244826
MT
261 first->family = network->family;
262 first->prefix = default_prefix(network->family);
cf3fb03c
MT
263
264 for (int i = 0; i < 16; i++)
9e244826 265 first->addr.s6_addr[i] = network->addr.s6_addr[i] & mask.s6_addr[i];
13a6e69f
MT
266}
267
9e244826
MT
268static void ip_address_get_last_address(ip_address_t* last, const ip_address_t* network) {
269 assert(network->prefix >= 0);
13a6e69f 270
9e244826 271 struct in6_addr mask = prefix_to_bitmask(network->prefix);
13a6e69f 272
9e244826
MT
273 last->family = network->family;
274 last->prefix = default_prefix(network->family);
cf3fb03c
MT
275
276 for (int i = 0; i < 16; i++)
9e244826
MT
277 last->addr.s6_addr[i] = network->addr.s6_addr[i] | ~mask.s6_addr[i];
278}
279
280static void ip_address_make_network(ip_address_t* net, const ip_address_t* network) {
281 ip_address_get_first_address(net, network);
282
283 // Copy the prefix
284 net->prefix = network->prefix;
285}
286
287static void ip_address_make_broadcast(ip_address_t* broadcast, const ip_address_t* network) {
288 assert(network->family == AF_INET);
289
290 ip_address_get_last_address(broadcast, network);
291
292 // Copy the prefix
293 broadcast->prefix = network->prefix;
294}
295
296static int ip_address_is_subset(const ip_address_t* network1, const ip_address_t* network2) {
297 ip_address_t first1;
298 ip_address_t first2;
299 ip_address_t last1;
300 ip_address_t last2;
301
302 // Get the first address of the networks
303 ip_address_get_first_address(&first1, network1);
304 ip_address_get_first_address(&first2, network2);
305
306 // Get the highest address in both networks
307 ip_address_get_last_address(&last1, network1);
308 ip_address_get_last_address(&last2, network2);
309
310 // The start address must be in the network
311 if (ip_address_ge(&first1, &first2) == 0 && ip_address_le(&first1, &last2) == 0) {
312 // The end address must be in the network, too
313 if (ip_address_ge(&last1, &first2) == 0 && ip_address_le(&last1, &last2) == 0) {
314 return 0;
315 }
316 }
317
318 return 1;
13a6e69f
MT
319}
320
321static int action_check(const int family, const char* address) {
322 ip_address_t ip;
323
324 int r = ip_address_parse(&ip, family, address);
325 if (r)
326 return r;
327
9e244826
MT
328 // If the prefix is the host prefix this is a host address
329 if (ip.prefix == default_prefix(family))
330 return 0;
331
332 return 1;
13a6e69f
MT
333}
334
335static int action_equal(const int family, const char* addr1, const char* addr2) {
336 ip_address_t a1;
337 ip_address_t a2;
338 int r;
339
340 r = ip_address_parse(&a1, family, addr1);
341 if (r)
342 return 2;
343
344 r = ip_address_parse(&a2, family, addr2);
345 if (r)
346 return 2;
347
348 return ip_address_eq(&a1, &a2);
349}
350
351static int action_greater(const int family, const char* addr1, const char* addr2) {
352 ip_address_t a1;
353 ip_address_t a2;
354 int r;
355
356 r = ip_address_parse(&a1, family, addr1);
357 if (r)
358 return 2;
359
360 r = ip_address_parse(&a2, family, addr2);
361 if (r)
362 return 2;
363
364 return ip_address_gt(&a1, &a2);
365}
366
367static int action_format(const int family, const char* address) {
368 ip_address_t ip;
369
370 int r = ip_address_parse(&ip, family, address);
371 if (r)
372 return r;
373
374 ip_address_print(&ip);
375 return 0;
376}
377
378static int action_broadcast(const int family, const char* address) {
379 ip_address_t ip;
380 int r = ip_address_parse(&ip, family, address);
381 if (r) {
382 fprintf(stderr, "Invalid IP address: %s\n", address);
383 return r;
384 }
385
386 if (ip.family != AF_INET) {
387 fprintf(stderr, "This is only possible for IPv4\n");
388 return 1;
389 }
390
391 ip_address_t broadcast;
392 ip_address_make_broadcast(&broadcast, &ip);
393
394 ip_address_print(&broadcast);
395 return 0;
396}
397
398static int action_network(const int family, const char* address) {
399 ip_address_t ip;
400
401 int r = ip_address_parse(&ip, family, address);
402 if (r) {
403 fprintf(stderr, "Invalid IP address: %s\n", address);
404 return r;
405 }
406
407 ip_address_t network;
408 ip_address_make_network(&network, &ip);
409
410 ip_address_print(&network);
411 return 0;
412}
413
414static int action_prefix(const int family, const char* addr1, const char* addr2) {
415 int r;
416
417 ip_address_t network;
418 r = ip_address_parse(&network, family, addr1);
419 if (r)
420 return r;
421
422 ip_address_t broadcast;
423 r = ip_address_parse(&broadcast, family, addr2);
424 if (r)
425 return r;
426
427 r = ip_address_gt(&broadcast, &network);
428 if (r)
429 return r;
430
cf3fb03c
MT
431 struct in6_addr netmask;
432 for (int i = 0; i < 16; i++)
433 netmask.s6_addr[i] = network.addr.s6_addr[i] ^ broadcast.addr.s6_addr[i];
434
435 uint32_t mask = netmask.s6_addr[0] << 24 | netmask.s6_addr[1] << 16 |
436 netmask.s6_addr[2] << 8 | netmask.s6_addr[3];
437
13a6e69f
MT
438 int prefix = bitmask_to_prefix(~mask);
439 if (prefix < 0)
440 return 1;
441
442 printf("%d\n", prefix);
443 return 0;
444}
445
9e244826
MT
446static int action_subset(const int family, const char* address1, const char* address2) {
447 int r;
448 ip_address_t network1;
449 ip_address_t network2;
450
451 // Parse both networks and/or IP addresses
452 r = ip_address_parse(&network1, family, address1);
453 if (r)
454 return r;
455
456 r = ip_address_parse(&network2, family, address2);
457 if (r)
458 return r;
459
460 if (network1.family != network2.family) {
461 fprintf(stderr, "Address family of both arguments must match\n");
462 return -1;
463 }
464
465 return ip_address_is_subset(&network1, &network2);
466}
467
13a6e69f
MT
468enum actions {
469 AC_UNSPEC = 0,
470 AC_BROADCAST,
471 AC_CHECK,
472 AC_EQUAL,
473 AC_FORMAT,
474 AC_GREATER,
475 AC_NETWORK,
9e244826 476 AC_SUBSET,
13a6e69f
MT
477 AC_PREFIX,
478};
479
480static void set_action(int* action, int what) {
481 if (*action != AC_UNSPEC) {
482 printf("Another action has already been selected\n");
483 exit(1);
484 }
485
486 *action = what;
487}
488
489static struct option long_options[] = {
490 {"broadcast", no_argument, 0, 'b'},
491 {"check", no_argument, 0, 'c'},
492 {"equal", no_argument, 0, 'e'},
493 {"format", no_argument, 0, 'f'},
494 {"greater", no_argument, 0, 'g'},
495 {"ipv4-only", no_argument, 0, '4'},
496 {"ipv6-only", no_argument, 0, '6'},
497 {"network", no_argument, 0, 'n'},
498 {"prefix", no_argument, 0, 'p'},
9e244826 499 {"subset", no_argument, 0, 's'},
13a6e69f
MT
500 {"verbose", no_argument, 0, 'v'},
501 {0, 0, 0, 0}
502};
503
504int main(int argc, char** argv) {
505 int option_index = 0;
506 int required_arguments = 0;
507
508 int verbose = 0;
509 int action = AC_UNSPEC;
510 int family = AF_UNSPEC;
511
512 while (1) {
9e244826 513 int c = getopt_long(argc, argv, "46bcefgnpsv", long_options, &option_index);
13a6e69f
MT
514 if (c == -1)
515 break;
516
517 switch (c) {
518 case 0:
519 if (long_options[option_index].flag != 0)
520 break;
521
522 printf("option: %s", long_options[option_index].name);
523 if (optarg)
524 printf(" with arg %s", optarg);
525 printf("\n");
526 break;
527
528 case '4':
529 family = AF_INET;
530 break;
531
532 case '6':
533 family = AF_INET6;
534 break;
535
536 case 'b':
537 set_action(&action, AC_BROADCAST);
538 required_arguments = 1;
539 break;
540
541 case 'c':
542 set_action(&action, AC_CHECK);
543 required_arguments = 1;
544 break;
545
546 case 'e':
547 set_action(&action, AC_EQUAL);
548 required_arguments = 2;
549 break;
550
551 case 'f':
552 set_action(&action, AC_FORMAT);
553 required_arguments = 1;
554 break;
555
556 case 'g':
557 set_action(&action, AC_GREATER);
558 required_arguments = 2;
559 break;
560
561 case 'n':
562 set_action(&action, AC_NETWORK);
563 required_arguments = 1;
564 break;
565
566 case 'p':
567 set_action(&action, AC_PREFIX);
568 required_arguments = 2;
569 break;
570
9e244826
MT
571 case 's':
572 set_action(&action, AC_SUBSET);
573 required_arguments = 2;
574 break;
575
13a6e69f
MT
576 case 'v':
577 verbose = 1;
578 break;
579
580 case '?':
581 break;
582
583 default:
584 abort();
585 }
586 }
587
588 while (optind--) {
589 argc--;
590 argv++;
591 }
592
593 if (argc != required_arguments) {
594 fprintf(stderr, "Invalid number of arguments. Got %d, required %d.\n",
595 argc, required_arguments);
596 return 1;
597 }
598
599 if (verbose && family != AF_UNSPEC)
600 printf("Address family = %d\n", family);
601
602 int r = 0;
603
604 switch (action) {
605 case AC_UNSPEC:
606 printf("No action specified\n");
607 r = 1;
608 break;
609
610 case AC_BROADCAST:
611 r = action_broadcast(family, argv[0]);
612 break;
613
614 case AC_CHECK:
615 r = action_check(family, argv[0]);
616
617 if (verbose) {
618 if (r == 0)
619 printf("%s is a valid IP address\n", argv[0]);
620 else
621 printf("%s is not a valid IP address\n", argv[0]);
622 }
623 break;
624
625 case AC_EQUAL:
626 r = action_equal(family, argv[0], argv[1]);
627
628 if (verbose) {
629 if (r == 0)
630 printf("%s equals %s\n", argv[0], argv[1]);
631 else if (r == 2)
632 printf("Invalid IP address provided\n");
633 else
634 printf("%s does not equal %s\n", argv[0], argv[1]);
635 }
636 break;
637
638 case AC_FORMAT:
639 r = action_format(family, argv[0]);
640
641 if (verbose && r)
642 printf("Invalid IP address given\n");
643
644 break;
645
646 case AC_GREATER:
647 r = action_greater(family, argv[0], argv[1]);
648
649 if (verbose) {
650 if (r == 0)
651 printf("%s is greater than %s\n", argv[0], argv[1]);
652 else if (r == 2)
653 printf("Invalid IP address provided\n");
654 else
655 printf("%s is not greater than %s\n", argv[0], argv[1]);
656 }
657 break;
658
659 case AC_NETWORK:
660 r = action_network(family, argv[0]);
661 break;
662
9e244826
MT
663 case AC_SUBSET:
664 r = action_subset(family, argv[0], argv[1]);
665
666 if (verbose) {
667 if (r == 0)
668 printf("%s is a subset of %s\n", argv[0], argv[1]);
669 else if (r > 0)
670 printf("%s is not a subset of %s\n", argv[0], argv[1]);
671 }
672
673 break;
674
13a6e69f
MT
675 case AC_PREFIX:
676 r = action_prefix(family, argv[0], argv[1]);
677 break;
678 }
679
680 return r;
681}