]>
git.ipfire.org Git - network.git/blob - src/inetcalc.c
1 /*#############################################################################
3 # IPFire.org - A linux based firewall #
4 # Copyright (C) 2015 IPFire Network Development Team #
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. #
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. #
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/>. #
19 #############################################################################*/
22 #include <arpa/inet.h>
25 #include <netinet/in.h>
29 #include <sys/socket.h>
31 #include <network/libnetwork.h>
33 typedef struct ip_address
{
39 static struct in6_addr
prefix_to_bitmask(int prefix
) {
40 assert(prefix
<= 128);
42 struct in6_addr bitmask
;
44 for (int i
= 0; i
< 16; i
++)
45 bitmask
.s6_addr
[i
] = 0;
47 for (int i
= prefix
, j
= 0; i
> 0; i
-= 8, j
++) {
49 bitmask
.s6_addr
[j
] = 0xff;
51 bitmask
.s6_addr
[j
] = 0xff << (8 - i
);
57 static int bitmask_to_prefix(uint32_t bits
) {
60 // Count all ones until we find the first zero
61 while (bits
& (1 << 31)) {
66 // The remaining bits must all be zero
73 static int ip_address_parse_subnet_mask(ip_address_t
* ip
, const char* prefix
) {
76 int r
= inet_pton(AF_INET
, prefix
, &mask
.s_addr
);
80 uint32_t bits
= ntohl(mask
.s_addr
);
81 ip
->prefix
= bitmask_to_prefix(bits
);
83 return (ip
->prefix
< 0 || ip
->prefix
> 32);
86 static int ip_address_parse_prefix_cidr(ip_address_t
* ip
, const int family
, const char* prefix
) {
91 if (p
>= '0' && p
<= '9') {
93 ip
->prefix
+= p
- '0';
101 return (ip
->prefix
< 0 || ip
->prefix
> 128);
104 return (ip
->prefix
< 0 || ip
->prefix
> 32);
111 static 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
);
114 if (r
&& family
== AF_INET
) {
115 r
= ip_address_parse_subnet_mask(ip
, prefix
);
121 static int default_prefix(const int family
) {
134 static int ip_address_parse_simple(ip_address_t
* ip
, const int family
, const char* address
) {
135 assert(family
== AF_INET
|| family
== AF_INET6
);
137 size_t address_length
= strlen(address
);
138 char buffer
[address_length
+ 1];
139 strncpy(buffer
, address
, sizeof(buffer
));
141 // Search for a prefix or subnet mask
142 char* prefix
= strchr(buffer
, '/');
144 buffer
[prefix
- buffer
] = '\0';
148 memset(&ip
->addr
, 0, sizeof(ip
->addr
));
149 int r
= inet_pton(family
, buffer
, &ip
->addr
);
152 // If parsing the IP address failed, we will return false
156 // If the IP address could be successfully parsed, we will
157 // save the address family and return true
168 r
= ip_address_parse_prefix(ip
, family
, prefix
);
170 ip
->prefix
= default_prefix(family
);
175 static int ip_address_parse(ip_address_t
* ip
, const int family
, const char* address
) {
176 static int families
[] = { AF_INET
, AF_INET6
, 0 };
181 if (family
== AF_UNSPEC
|| family
== *f
) {
182 r
= ip_address_parse_simple(ip
, *f
, address
);
194 static int ip_address_eq(const ip_address_t
* a1
, const ip_address_t
* a2
) {
195 if (a1
->family
!= a2
->family
)
198 if (!IN6_ARE_ADDR_EQUAL(&a1
->addr
, &a2
->addr
))
201 if (a1
->prefix
!= a2
->prefix
)
207 static int ip_address_gt(const ip_address_t
* a1
, const ip_address_t
* a2
) {
208 if (a1
->family
!= a2
->family
|| a1
->prefix
!= a2
->prefix
)
211 if (memcmp(&a1
->addr
.s6_addr
, &a2
->addr
.s6_addr
, sizeof(a1
->addr
.s6_addr
)) > 0)
217 static int ip_address_ge(const ip_address_t
* a1
, const ip_address_t
* a2
) {
218 int r
= ip_address_eq(a1
, a2
);
222 return ip_address_gt(a1
, a2
);
225 static int ip_address_le(const ip_address_t
* a1
, const ip_address_t
* a2
) {
226 int r
= ip_address_eq(a1
, a2
);
230 return !ip_address_gt(a1
, a2
);
233 static 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
);
236 const char* p
= inet_ntop(ip
->family
, &ip
->addr
.s6_addr
, buffer
, size
);
243 static void ip_address_print(const ip_address_t
* ip
) {
244 char buffer
[INET6_ADDRSTRLEN
+4];
246 int r
= ip_address_format_string(buffer
, sizeof(buffer
), ip
);
250 int address_prefix
= default_prefix(ip
->family
);
252 // Only print prefix when it is not the default one
253 if (ip
->prefix
!= address_prefix
) {
254 size_t len
= strlen(buffer
);
255 snprintf(buffer
+ len
, sizeof(buffer
) - len
, "/%d", ip
->prefix
);
258 printf("%s\n", buffer
);
261 static void ip_address_get_first_address(ip_address_t
* first
, const ip_address_t
* network
) {
262 assert(network
->prefix
>= 0);
264 struct in6_addr mask
= prefix_to_bitmask(network
->prefix
);
266 first
->family
= network
->family
;
267 first
->prefix
= default_prefix(network
->family
);
269 for (int i
= 0; i
< 16; i
++)
270 first
->addr
.s6_addr
[i
] = network
->addr
.s6_addr
[i
] & mask
.s6_addr
[i
];
273 static void ip_address_get_last_address(ip_address_t
* last
, const ip_address_t
* network
) {
274 assert(network
->prefix
>= 0);
276 struct in6_addr mask
= prefix_to_bitmask(network
->prefix
);
278 last
->family
= network
->family
;
279 last
->prefix
= default_prefix(network
->family
);
281 for (int i
= 0; i
< 16; i
++)
282 last
->addr
.s6_addr
[i
] = network
->addr
.s6_addr
[i
] | ~mask
.s6_addr
[i
];
285 static void ip_address_make_network(ip_address_t
* net
, const ip_address_t
* network
) {
286 ip_address_get_first_address(net
, network
);
289 net
->prefix
= network
->prefix
;
292 static void ip_address_make_broadcast(ip_address_t
* broadcast
, const ip_address_t
* network
) {
293 assert(network
->family
== AF_INET
);
295 ip_address_get_last_address(broadcast
, network
);
298 broadcast
->prefix
= network
->prefix
;
301 static int ip_address_is_subset(const ip_address_t
* network1
, const ip_address_t
* network2
) {
307 // Get the first address of the networks
308 ip_address_get_first_address(&first1
, network1
);
309 ip_address_get_first_address(&first2
, network2
);
311 // Get the highest address in both networks
312 ip_address_get_last_address(&last1
, network1
);
313 ip_address_get_last_address(&last2
, network2
);
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) {
326 static int action_check(const int family
, const char* address
) {
329 int r
= ip_address_parse(&ip
, family
, address
);
333 // If the prefix is the host prefix this is a host address
334 if (ip
.prefix
== default_prefix(family
))
340 static int action_equal(const int family
, const char* addr1
, const char* addr2
) {
345 r
= ip_address_parse(&a1
, family
, addr1
);
349 r
= ip_address_parse(&a2
, family
, addr2
);
353 return ip_address_eq(&a1
, &a2
);
356 static int action_greater(const int family
, const char* addr1
, const char* addr2
) {
361 r
= ip_address_parse(&a1
, family
, addr1
);
365 r
= ip_address_parse(&a2
, family
, addr2
);
369 return ip_address_gt(&a1
, &a2
);
372 static int action_format(const int family
, const char* address
) {
375 int r
= ip_address_parse(&ip
, family
, address
);
379 ip_address_print(&ip
);
383 static int action_broadcast(const int family
, const char* address
) {
385 int r
= ip_address_parse(&ip
, family
, address
);
387 fprintf(stderr
, "Invalid IP address: %s\n", address
);
391 if (ip
.family
!= AF_INET
) {
392 fprintf(stderr
, "This is only possible for IPv4\n");
396 ip_address_t broadcast
;
397 ip_address_make_broadcast(&broadcast
, &ip
);
399 ip_address_print(&broadcast
);
403 static int action_network(const int family
, const char* address
) {
406 int r
= ip_address_parse(&ip
, family
, address
);
408 fprintf(stderr
, "Invalid IP address: %s\n", address
);
412 ip_address_t network
;
413 ip_address_make_network(&network
, &ip
);
415 ip_address_print(&network
);
419 static int action_prefix(const int family
, const char* addr1
, const char* addr2
) {
422 ip_address_t network
;
423 r
= ip_address_parse(&network
, family
, addr1
);
427 ip_address_t broadcast
;
428 r
= ip_address_parse(&broadcast
, family
, addr2
);
432 r
= ip_address_gt(&broadcast
, &network
);
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
];
440 uint32_t mask
= netmask
.s6_addr
[0] << 24 | netmask
.s6_addr
[1] << 16 |
441 netmask
.s6_addr
[2] << 8 | netmask
.s6_addr
[3];
443 int prefix
= bitmask_to_prefix(~mask
);
447 printf("%d\n", prefix
);
451 static int action_subset(const int family
, const char* address1
, const char* address2
) {
453 ip_address_t network1
;
454 ip_address_t network2
;
456 // Parse both networks and/or IP addresses
457 r
= ip_address_parse(&network1
, family
, address1
);
461 r
= ip_address_parse(&network2
, family
, address2
);
465 if (network1
.family
!= network2
.family
) {
466 fprintf(stderr
, "Address family of both arguments must match\n");
470 return ip_address_is_subset(&network1
, &network2
);
485 static void set_action(int* action
, int what
) {
486 if (*action
!= AC_UNSPEC
) {
487 printf("Another action has already been selected\n");
494 static 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'},
504 {"subset", no_argument
, 0, 's'},
505 {"verbose", no_argument
, 0, 'v'},
509 int main(int argc
, char** argv
) {
510 int option_index
= 0;
511 int required_arguments
= 0;
514 int action
= AC_UNSPEC
;
515 int family
= AF_UNSPEC
;
518 int c
= getopt_long(argc
, argv
, "46bcefgnpsviV", long_options
, &option_index
);
524 if (long_options
[option_index
].flag
!= 0)
527 printf("option: %s", long_options
[option_index
].name
);
529 printf(" with arg %s", optarg
);
542 set_action(&action
, AC_BROADCAST
);
543 required_arguments
= 1;
547 set_action(&action
, AC_CHECK
);
548 required_arguments
= 1;
552 set_action(&action
, AC_EQUAL
);
553 required_arguments
= 2;
557 set_action(&action
, AC_FORMAT
);
558 required_arguments
= 1;
562 set_action(&action
, AC_GREATER
);
563 required_arguments
= 2;
567 set_action(&action
, AC_NETWORK
);
568 required_arguments
= 1;
572 set_action(&action
, AC_PREFIX
);
573 required_arguments
= 2;
577 set_action(&action
, AC_SUBSET
);
578 required_arguments
= 2;
586 printf("%s\n", network_version());
603 if (argc
!= required_arguments
) {
604 fprintf(stderr
, "Invalid number of arguments. Got %d, required %d.\n",
605 argc
, required_arguments
);
609 if (verbose
&& family
!= AF_UNSPEC
)
610 printf("Address family = %d\n", family
);
616 printf("No action specified\n");
621 r
= action_broadcast(family
, argv
[0]);
625 r
= action_check(family
, argv
[0]);
629 printf("%s is a valid IP address\n", argv
[0]);
631 printf("%s is not a valid IP address\n", argv
[0]);
636 r
= action_equal(family
, argv
[0], argv
[1]);
640 printf("%s equals %s\n", argv
[0], argv
[1]);
642 printf("Invalid IP address provided\n");
644 printf("%s does not equal %s\n", argv
[0], argv
[1]);
649 r
= action_format(family
, argv
[0]);
652 printf("Invalid IP address given\n");
657 r
= action_greater(family
, argv
[0], argv
[1]);
661 printf("%s is greater than %s\n", argv
[0], argv
[1]);
663 printf("Invalid IP address provided\n");
665 printf("%s is not greater than %s\n", argv
[0], argv
[1]);
670 r
= action_network(family
, argv
[0]);
674 r
= action_subset(family
, argv
[0], argv
[1]);
678 printf("%s is a subset of %s\n", argv
[0], argv
[1]);
680 printf("%s is not a subset of %s\n", argv
[0], argv
[1]);
686 r
= action_prefix(family
, argv
[0], argv
[1]);