]>
git.ipfire.org Git - people/stevee/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 typedef struct ip_address
{
37 static __uint128_t
prefix_to_bitmask(int prefix
) {
38 __uint128_t bitmask
= ~0;
40 for (int i
= 0; i
< 128 - prefix
; i
++)
46 static int bitmask_to_prefix(uint32_t bits
) {
49 // Count all ones until we find the first zero
50 while (bits
& (1 << 31)) {
55 // The remaining bits must all be zero
62 static int ip_address_parse_subnet_mask(ip_address_t
* ip
, const char* prefix
) {
65 int r
= inet_pton(AF_INET
, prefix
, &mask
.s_addr
);
69 uint32_t bits
= ntohl(mask
.s_addr
);
70 ip
->prefix
= bitmask_to_prefix(bits
);
72 return (ip
->prefix
< 0 || ip
->prefix
> 32);
75 static int ip_address_parse_prefix_cidr(ip_address_t
* ip
, const int family
, const char* prefix
) {
80 if (p
>= '0' && p
<= '9') {
82 ip
->prefix
+= p
- '0';
90 return (ip
->prefix
< 0 || ip
->prefix
> 128);
93 return (ip
->prefix
< 0 || ip
->prefix
> 32);
100 static int ip_address_parse_prefix(ip_address_t
* ip
, const int family
, const char* prefix
) {
101 int r
= ip_address_parse_prefix_cidr(ip
, family
, prefix
);
103 if (r
&& family
== AF_INET
) {
104 r
= ip_address_parse_subnet_mask(ip
, prefix
);
110 static int ip_address_parse_simple(ip_address_t
* ip
, const int family
, const char* address
) {
111 assert(family
== AF_INET
|| family
== AF_INET6
);
113 size_t address_length
= strlen(address
);
114 char buffer
[address_length
+ 1];
115 strncpy(buffer
, address
, sizeof(buffer
));
117 // Search for a prefix or subnet mask
118 char* prefix
= strchr(buffer
, '/');
120 buffer
[prefix
- buffer
] = '\0';
124 memset(&ip
->addr
, 0, sizeof(ip
->addr
));
125 int r
= inet_pton(family
, buffer
, &ip
->addr
);
128 // If parsing the IP address failed, we will return false
132 // If the IP address could be successfully parsed, we will
133 // save the address family and return true
144 r
= ip_address_parse_prefix(ip
, family
, prefix
);
151 static int ip_address_parse(ip_address_t
* ip
, const int family
, const char* address
) {
152 static int families
[] = { AF_INET
, AF_INET6
, 0 };
157 if (family
== AF_UNSPEC
|| family
== *f
) {
158 r
= ip_address_parse_simple(ip
, *f
, address
);
170 static int ip_address_eq(const ip_address_t
* a1
, const ip_address_t
* a2
) {
171 if (a1
->family
!= a2
->family
)
174 if (a1
->addr
!= a2
->addr
)
177 if (a1
->prefix
!= a2
->prefix
)
183 static int ip_address_gt(const ip_address_t
* a1
, const ip_address_t
* a2
) {
184 if (a1
->family
!= a2
->family
|| a1
->prefix
!= a2
->prefix
)
187 if (a1
->addr
> a2
->addr
)
193 static int ip_address_format_string(char* buffer
, size_t size
, const ip_address_t
* ip
) {
194 assert(ip
->family
== AF_INET
|| ip
->family
== AF_INET6
);
196 const char* p
= inet_ntop(ip
->family
, &ip
->addr
, buffer
, size
);
203 static void ip_address_print(const ip_address_t
* ip
) {
204 char buffer
[INET6_ADDRSTRLEN
+4];
206 int r
= ip_address_format_string(buffer
, sizeof(buffer
), ip
);
210 if (ip
->prefix
>= 0) {
211 size_t len
= strlen(buffer
);
212 snprintf(buffer
+ len
, sizeof(buffer
) - len
, "/%d", ip
->prefix
);
215 printf("%s\n", buffer
);
218 static void ip_address_make_network(ip_address_t
* net
, const ip_address_t
* ip
) {
219 assert(ip
->prefix
>= 0);
221 __uint128_t mask
= prefix_to_bitmask(ip
->prefix
);
223 net
->family
= ip
->family
;
224 net
->prefix
= ip
->prefix
;
225 net
->addr
= ip
->addr
& mask
;
228 static void ip_address_make_broadcast(ip_address_t
* broadcast
, const ip_address_t
* ip
) {
229 assert(ip
->family
== AF_INET
&& ip
->prefix
>= 0);
231 __uint128_t mask
= prefix_to_bitmask(ip
->prefix
);
233 broadcast
->family
= ip
->family
;
234 broadcast
->prefix
= ip
->prefix
;
235 broadcast
->addr
= ip
->addr
| ~mask
;
238 static int action_check(const int family
, const char* address
) {
241 int r
= ip_address_parse(&ip
, family
, address
);
246 return (ip
.prefix
>= 0);
249 static int action_equal(const int family
, const char* addr1
, const char* addr2
) {
254 r
= ip_address_parse(&a1
, family
, addr1
);
258 r
= ip_address_parse(&a2
, family
, addr2
);
262 return ip_address_eq(&a1
, &a2
);
265 static int action_greater(const int family
, const char* addr1
, const char* addr2
) {
270 r
= ip_address_parse(&a1
, family
, addr1
);
274 r
= ip_address_parse(&a2
, family
, addr2
);
278 return ip_address_gt(&a1
, &a2
);
281 static int action_format(const int family
, const char* address
) {
284 int r
= ip_address_parse(&ip
, family
, address
);
288 ip_address_print(&ip
);
292 static int action_broadcast(const int family
, const char* address
) {
294 int r
= ip_address_parse(&ip
, family
, address
);
296 fprintf(stderr
, "Invalid IP address: %s\n", address
);
300 if (ip
.family
!= AF_INET
) {
301 fprintf(stderr
, "This is only possible for IPv4\n");
305 ip_address_t broadcast
;
306 ip_address_make_broadcast(&broadcast
, &ip
);
308 ip_address_print(&broadcast
);
312 static int action_network(const int family
, const char* address
) {
315 int r
= ip_address_parse(&ip
, family
, address
);
317 fprintf(stderr
, "Invalid IP address: %s\n", address
);
321 ip_address_t network
;
322 ip_address_make_network(&network
, &ip
);
324 ip_address_print(&network
);
328 static int action_prefix(const int family
, const char* addr1
, const char* addr2
) {
331 ip_address_t network
;
332 r
= ip_address_parse(&network
, family
, addr1
);
336 ip_address_t broadcast
;
337 r
= ip_address_parse(&broadcast
, family
, addr2
);
341 r
= ip_address_gt(&broadcast
, &network
);
345 uint32_t mask
= ntohl(network
.addr
^ broadcast
.addr
);
346 int prefix
= bitmask_to_prefix(~mask
);
350 printf("%d\n", prefix
);
365 static void set_action(int* action
, int what
) {
366 if (*action
!= AC_UNSPEC
) {
367 printf("Another action has already been selected\n");
374 static struct option long_options
[] = {
375 {"broadcast", no_argument
, 0, 'b'},
376 {"check", no_argument
, 0, 'c'},
377 {"equal", no_argument
, 0, 'e'},
378 {"format", no_argument
, 0, 'f'},
379 {"greater", no_argument
, 0, 'g'},
380 {"ipv4-only", no_argument
, 0, '4'},
381 {"ipv6-only", no_argument
, 0, '6'},
382 {"network", no_argument
, 0, 'n'},
383 {"prefix", no_argument
, 0, 'p'},
384 {"verbose", no_argument
, 0, 'v'},
388 int main(int argc
, char** argv
) {
389 int option_index
= 0;
390 int required_arguments
= 0;
393 int action
= AC_UNSPEC
;
394 int family
= AF_UNSPEC
;
397 int c
= getopt_long(argc
, argv
, "46bcefgnpv", long_options
, &option_index
);
403 if (long_options
[option_index
].flag
!= 0)
406 printf("option: %s", long_options
[option_index
].name
);
408 printf(" with arg %s", optarg
);
421 set_action(&action
, AC_BROADCAST
);
422 required_arguments
= 1;
426 set_action(&action
, AC_CHECK
);
427 required_arguments
= 1;
431 set_action(&action
, AC_EQUAL
);
432 required_arguments
= 2;
436 set_action(&action
, AC_FORMAT
);
437 required_arguments
= 1;
441 set_action(&action
, AC_GREATER
);
442 required_arguments
= 2;
446 set_action(&action
, AC_NETWORK
);
447 required_arguments
= 1;
451 set_action(&action
, AC_PREFIX
);
452 required_arguments
= 2;
472 if (argc
!= required_arguments
) {
473 fprintf(stderr
, "Invalid number of arguments. Got %d, required %d.\n",
474 argc
, required_arguments
);
478 if (verbose
&& family
!= AF_UNSPEC
)
479 printf("Address family = %d\n", family
);
485 printf("No action specified\n");
490 r
= action_broadcast(family
, argv
[0]);
494 r
= action_check(family
, argv
[0]);
498 printf("%s is a valid IP address\n", argv
[0]);
500 printf("%s is not a valid IP address\n", argv
[0]);
505 r
= action_equal(family
, argv
[0], argv
[1]);
509 printf("%s equals %s\n", argv
[0], argv
[1]);
511 printf("Invalid IP address provided\n");
513 printf("%s does not equal %s\n", argv
[0], argv
[1]);
518 r
= action_format(family
, argv
[0]);
521 printf("Invalid IP address given\n");
526 r
= action_greater(family
, argv
[0], argv
[1]);
530 printf("%s is greater than %s\n", argv
[0], argv
[1]);
532 printf("Invalid IP address provided\n");
534 printf("%s is not greater than %s\n", argv
[0], argv
[1]);
539 r
= action_network(family
, argv
[0]);
543 r
= action_prefix(family
, argv
[0], argv
[1]);