]> git.ipfire.org Git - people/ms/network.git/blob - src/inetcalc.c
wpa_supplicant: Add ctrl_interface
[people/ms/network.git] / src / inetcalc.c
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
31 typedef struct ip_address {
32 int family;
33 struct in6_addr addr;
34 int prefix;
35 } ip_address_t;
36
37 static struct in6_addr prefix_to_bitmask(int prefix) {
38 assert(prefix <= 128);
39
40 struct in6_addr bitmask;
41
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;
53 }
54
55 static 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
71 static 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
84 static 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
109 static 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
119 static 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
132 static 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
168 ip->prefix = default_prefix(family);
169
170 return r;
171 }
172
173 static 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
192 static int ip_address_eq(const ip_address_t* a1, const ip_address_t* a2) {
193 if (a1->family != a2->family)
194 return 1;
195
196 if (!IN6_ARE_ADDR_EQUAL(&a1->addr, &a2->addr))
197 return 1;
198
199 if (a1->prefix != a2->prefix)
200 return 1;
201
202 return 0;
203 }
204
205 static 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
209 if (memcmp(&a1->addr.s6_addr, &a2->addr.s6_addr, sizeof(a1->addr.s6_addr)) > 0)
210 return 0;
211
212 return 1;
213 }
214
215 static 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
223 static 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
231 static 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
234 const char* p = inet_ntop(ip->family, &ip->addr.s6_addr, buffer, size);
235 if (!p)
236 return errno;
237
238 return 0;
239 }
240
241 static 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 int address_prefix = default_prefix(ip->family);
249
250 // Only print prefix when it is not the default one
251 if (ip->prefix != address_prefix) {
252 size_t len = strlen(buffer);
253 snprintf(buffer + len, sizeof(buffer) - len, "/%d", ip->prefix);
254 }
255
256 printf("%s\n", buffer);
257 }
258
259 static void ip_address_get_first_address(ip_address_t* first, const ip_address_t* network) {
260 assert(network->prefix >= 0);
261
262 struct in6_addr mask = prefix_to_bitmask(network->prefix);
263
264 first->family = network->family;
265 first->prefix = default_prefix(network->family);
266
267 for (int i = 0; i < 16; i++)
268 first->addr.s6_addr[i] = network->addr.s6_addr[i] & mask.s6_addr[i];
269 }
270
271 static void ip_address_get_last_address(ip_address_t* last, const ip_address_t* network) {
272 assert(network->prefix >= 0);
273
274 struct in6_addr mask = prefix_to_bitmask(network->prefix);
275
276 last->family = network->family;
277 last->prefix = default_prefix(network->family);
278
279 for (int i = 0; i < 16; i++)
280 last->addr.s6_addr[i] = network->addr.s6_addr[i] | ~mask.s6_addr[i];
281 }
282
283 static void ip_address_make_network(ip_address_t* net, const ip_address_t* network) {
284 ip_address_get_first_address(net, network);
285
286 // Copy the prefix
287 net->prefix = network->prefix;
288 }
289
290 static void ip_address_make_broadcast(ip_address_t* broadcast, const ip_address_t* network) {
291 assert(network->family == AF_INET);
292
293 ip_address_get_last_address(broadcast, network);
294
295 // Copy the prefix
296 broadcast->prefix = network->prefix;
297 }
298
299 static int ip_address_is_subset(const ip_address_t* network1, const ip_address_t* network2) {
300 ip_address_t first1;
301 ip_address_t first2;
302 ip_address_t last1;
303 ip_address_t last2;
304
305 // Get the first address of the networks
306 ip_address_get_first_address(&first1, network1);
307 ip_address_get_first_address(&first2, network2);
308
309 // Get the highest address in both networks
310 ip_address_get_last_address(&last1, network1);
311 ip_address_get_last_address(&last2, network2);
312
313 // The start address must be in the network
314 if (ip_address_ge(&first1, &first2) == 0 && ip_address_le(&first1, &last2) == 0) {
315 // The end address must be in the network, too
316 if (ip_address_ge(&last1, &first2) == 0 && ip_address_le(&last1, &last2) == 0) {
317 return 0;
318 }
319 }
320
321 return 1;
322 }
323
324 static int action_check(const int family, const char* address) {
325 ip_address_t ip;
326
327 int r = ip_address_parse(&ip, family, address);
328 if (r)
329 return r;
330
331 // If the prefix is the host prefix this is a host address
332 if (ip.prefix == default_prefix(family))
333 return 0;
334
335 return 1;
336 }
337
338 static int action_equal(const int family, const char* addr1, const char* addr2) {
339 ip_address_t a1;
340 ip_address_t a2;
341 int r;
342
343 r = ip_address_parse(&a1, family, addr1);
344 if (r)
345 return 2;
346
347 r = ip_address_parse(&a2, family, addr2);
348 if (r)
349 return 2;
350
351 return ip_address_eq(&a1, &a2);
352 }
353
354 static int action_greater(const int family, const char* addr1, const char* addr2) {
355 ip_address_t a1;
356 ip_address_t a2;
357 int r;
358
359 r = ip_address_parse(&a1, family, addr1);
360 if (r)
361 return 2;
362
363 r = ip_address_parse(&a2, family, addr2);
364 if (r)
365 return 2;
366
367 return ip_address_gt(&a1, &a2);
368 }
369
370 static int action_format(const int family, const char* address) {
371 ip_address_t ip;
372
373 int r = ip_address_parse(&ip, family, address);
374 if (r)
375 return r;
376
377 ip_address_print(&ip);
378 return 0;
379 }
380
381 static int action_broadcast(const int family, const char* address) {
382 ip_address_t ip;
383 int r = ip_address_parse(&ip, family, address);
384 if (r) {
385 fprintf(stderr, "Invalid IP address: %s\n", address);
386 return r;
387 }
388
389 if (ip.family != AF_INET) {
390 fprintf(stderr, "This is only possible for IPv4\n");
391 return 1;
392 }
393
394 ip_address_t broadcast;
395 ip_address_make_broadcast(&broadcast, &ip);
396
397 ip_address_print(&broadcast);
398 return 0;
399 }
400
401 static int action_network(const int family, const char* address) {
402 ip_address_t ip;
403
404 int r = ip_address_parse(&ip, family, address);
405 if (r) {
406 fprintf(stderr, "Invalid IP address: %s\n", address);
407 return r;
408 }
409
410 ip_address_t network;
411 ip_address_make_network(&network, &ip);
412
413 ip_address_print(&network);
414 return 0;
415 }
416
417 static int action_prefix(const int family, const char* addr1, const char* addr2) {
418 int r;
419
420 ip_address_t network;
421 r = ip_address_parse(&network, family, addr1);
422 if (r)
423 return r;
424
425 ip_address_t broadcast;
426 r = ip_address_parse(&broadcast, family, addr2);
427 if (r)
428 return r;
429
430 r = ip_address_gt(&broadcast, &network);
431 if (r)
432 return r;
433
434 struct in6_addr netmask;
435 for (int i = 0; i < 16; i++)
436 netmask.s6_addr[i] = network.addr.s6_addr[i] ^ broadcast.addr.s6_addr[i];
437
438 uint32_t mask = netmask.s6_addr[0] << 24 | netmask.s6_addr[1] << 16 |
439 netmask.s6_addr[2] << 8 | netmask.s6_addr[3];
440
441 int prefix = bitmask_to_prefix(~mask);
442 if (prefix < 0)
443 return 1;
444
445 printf("%d\n", prefix);
446 return 0;
447 }
448
449 static int action_subset(const int family, const char* address1, const char* address2) {
450 int r;
451 ip_address_t network1;
452 ip_address_t network2;
453
454 // Parse both networks and/or IP addresses
455 r = ip_address_parse(&network1, family, address1);
456 if (r)
457 return r;
458
459 r = ip_address_parse(&network2, family, address2);
460 if (r)
461 return r;
462
463 if (network1.family != network2.family) {
464 fprintf(stderr, "Address family of both arguments must match\n");
465 return -1;
466 }
467
468 return ip_address_is_subset(&network1, &network2);
469 }
470
471 enum actions {
472 AC_UNSPEC = 0,
473 AC_BROADCAST,
474 AC_CHECK,
475 AC_EQUAL,
476 AC_FORMAT,
477 AC_GREATER,
478 AC_NETWORK,
479 AC_SUBSET,
480 AC_PREFIX,
481 };
482
483 static void set_action(int* action, int what) {
484 if (*action != AC_UNSPEC) {
485 printf("Another action has already been selected\n");
486 exit(1);
487 }
488
489 *action = what;
490 }
491
492 static struct option long_options[] = {
493 {"broadcast", no_argument, 0, 'b'},
494 {"check", no_argument, 0, 'c'},
495 {"equal", no_argument, 0, 'e'},
496 {"format", no_argument, 0, 'f'},
497 {"greater", no_argument, 0, 'g'},
498 {"ipv4-only", no_argument, 0, '4'},
499 {"ipv6-only", no_argument, 0, '6'},
500 {"network", no_argument, 0, 'n'},
501 {"prefix", no_argument, 0, 'p'},
502 {"subset", no_argument, 0, 's'},
503 {"verbose", no_argument, 0, 'v'},
504 {0, 0, 0, 0}
505 };
506
507 int main(int argc, char** argv) {
508 int option_index = 0;
509 int required_arguments = 0;
510
511 int verbose = 0;
512 int action = AC_UNSPEC;
513 int family = AF_UNSPEC;
514
515 while (1) {
516 int c = getopt_long(argc, argv, "46bcefgnpsv", long_options, &option_index);
517 if (c == -1)
518 break;
519
520 switch (c) {
521 case 0:
522 if (long_options[option_index].flag != 0)
523 break;
524
525 printf("option: %s", long_options[option_index].name);
526 if (optarg)
527 printf(" with arg %s", optarg);
528 printf("\n");
529 break;
530
531 case '4':
532 family = AF_INET;
533 break;
534
535 case '6':
536 family = AF_INET6;
537 break;
538
539 case 'b':
540 set_action(&action, AC_BROADCAST);
541 required_arguments = 1;
542 break;
543
544 case 'c':
545 set_action(&action, AC_CHECK);
546 required_arguments = 1;
547 break;
548
549 case 'e':
550 set_action(&action, AC_EQUAL);
551 required_arguments = 2;
552 break;
553
554 case 'f':
555 set_action(&action, AC_FORMAT);
556 required_arguments = 1;
557 break;
558
559 case 'g':
560 set_action(&action, AC_GREATER);
561 required_arguments = 2;
562 break;
563
564 case 'n':
565 set_action(&action, AC_NETWORK);
566 required_arguments = 1;
567 break;
568
569 case 'p':
570 set_action(&action, AC_PREFIX);
571 required_arguments = 2;
572 break;
573
574 case 's':
575 set_action(&action, AC_SUBSET);
576 required_arguments = 2;
577 break;
578
579 case 'v':
580 verbose = 1;
581 break;
582
583 case '?':
584 break;
585
586 default:
587 abort();
588 }
589 }
590
591 while (optind--) {
592 argc--;
593 argv++;
594 }
595
596 if (argc != required_arguments) {
597 fprintf(stderr, "Invalid number of arguments. Got %d, required %d.\n",
598 argc, required_arguments);
599 return 1;
600 }
601
602 if (verbose && family != AF_UNSPEC)
603 printf("Address family = %d\n", family);
604
605 int r = 0;
606
607 switch (action) {
608 case AC_UNSPEC:
609 printf("No action specified\n");
610 r = 1;
611 break;
612
613 case AC_BROADCAST:
614 r = action_broadcast(family, argv[0]);
615 break;
616
617 case AC_CHECK:
618 r = action_check(family, argv[0]);
619
620 if (verbose) {
621 if (r == 0)
622 printf("%s is a valid IP address\n", argv[0]);
623 else
624 printf("%s is not a valid IP address\n", argv[0]);
625 }
626 break;
627
628 case AC_EQUAL:
629 r = action_equal(family, argv[0], argv[1]);
630
631 if (verbose) {
632 if (r == 0)
633 printf("%s equals %s\n", argv[0], argv[1]);
634 else if (r == 2)
635 printf("Invalid IP address provided\n");
636 else
637 printf("%s does not equal %s\n", argv[0], argv[1]);
638 }
639 break;
640
641 case AC_FORMAT:
642 r = action_format(family, argv[0]);
643
644 if (verbose && r)
645 printf("Invalid IP address given\n");
646
647 break;
648
649 case AC_GREATER:
650 r = action_greater(family, argv[0], argv[1]);
651
652 if (verbose) {
653 if (r == 0)
654 printf("%s is greater than %s\n", argv[0], argv[1]);
655 else if (r == 2)
656 printf("Invalid IP address provided\n");
657 else
658 printf("%s is not greater than %s\n", argv[0], argv[1]);
659 }
660 break;
661
662 case AC_NETWORK:
663 r = action_network(family, argv[0]);
664 break;
665
666 case AC_SUBSET:
667 r = action_subset(family, argv[0], argv[1]);
668
669 if (verbose) {
670 if (r == 0)
671 printf("%s is a subset of %s\n", argv[0], argv[1]);
672 else if (r > 0)
673 printf("%s is not a subset of %s\n", argv[0], argv[1]);
674 }
675
676 break;
677
678 case AC_PREFIX:
679 r = action_prefix(family, argv[0], argv[1]);
680 break;
681 }
682
683 return r;
684 }