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