aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/netcalc.c
diff options
context:
space:
mode:
authorDavid M. Syzdek <david@syzdek.net>2021-10-06 01:30:25 -0800
committerDavid M. Syzdek <david@syzdek.net>2021-10-06 01:32:28 -0800
commit7ca6ec8abb90fb1bc4d2d37166dd107b2718a58d (patch)
tree81b8d50bebf3b31d8d2cf206bff12551d2a8570a /src/netcalc.c
parent7529d42f1f420a9a1cc98bd0f46cb4b8988fe486 (diff)
downloaddmstools-7ca6ec8abb90fb1bc4d2d37166dd107b2718a58d.tar.gz
dmstools-7ca6ec8abb90fb1bc4d2d37166dd107b2718a58d.tar.bz2
dmstools-7ca6ec8abb90fb1bc4d2d37166dd107b2718a58d.tar.xz
dmstools-7ca6ec8abb90fb1bc4d2d37166dd107b2718a58d.zip
netcalc: refactoring to support IPv6 networks
Diffstat (limited to 'src/netcalc.c')
-rw-r--r--src/netcalc.c1035
1 files changed, 887 insertions, 148 deletions
diff --git a/src/netcalc.c b/src/netcalc.c
index 2a0a744..6cb389f 100644
--- a/src/netcalc.c
+++ b/src/netcalc.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * DMS Tools and Utilities 2 * DMS Tools and Utilities
3 * Copyright (C) 2011 David M. Syzdek <david@syzdek.net>. 3 * Copyright (C) 2011, 2021 David M. Syzdek <david@syzdek.net>.
4 * 4 *
5 * @SYZDEK_LICENSE_HEADER_START@ 5 * @SYZDEK_LICENSE_HEADER_START@
6 * 6 *
@@ -61,9 +61,9 @@
61#include "common.h" 61#include "common.h"
62#endif 62#endif
63 63
64#include <assert.h>
64#include <stdio.h> 65#include <stdio.h>
65#include <getopt.h> 66#include <getopt.h>
66#include <arpa/inet.h>
67#include <string.h> 67#include <string.h>
68#include <inttypes.h> 68#include <inttypes.h>
69#include <stdlib.h> 69#include <stdlib.h>
@@ -96,7 +96,45 @@
96#endif 96#endif
97 97
98 98
99#define NETCALC_OPT_ALL_NETWORKS 0x0001 99#define NETCALC_ALL_NETWORKS 0x0001
100#define NETCALC_IPV6_EXPAND 0x0002
101#define NETCALC_IPV6_FULL 0x0004
102#define NETCALC_NO_MAP 0x0008
103
104#define NETCALC_INET 4
105#define NETCALC_INET6 6
106
107
108/////////////////
109// //
110// Datatypes //
111// //
112/////////////////
113
114typedef struct _netcalc_ip netcalc_ip;
115typedef struct _netcalc netcalc;
116
117struct _netcalc_ip
118{
119 uint32_t addr[8];
120};
121
122
123struct _netcalc
124{
125 int32_t cidr;
126 int32_t cidr_limit;
127 int32_t cidr_incr;
128 int32_t family;
129 uint64_t opts;
130 size_t count;
131 netcalc_ip * lower;
132 netcalc_ip * upper;
133 int len_netmask;
134 int len_broadcast;
135 int len_network;
136 int len_wildmask;
137};
100 138
101 139
102////////////////// 140//////////////////
@@ -105,20 +143,140 @@
105// // 143// //
106////////////////// 144//////////////////
107 145
108// converts IPv4 to string 146int
109const char * netcalc_ipv4tostr(uint64_t ipv4); 147netcalc_init(
148 netcalc ** cnfp );
149
150
151void
152netcalc_free(
153 netcalc * cnfi );
154
155
156int
157netcalc_ip_cmp(
158 netcalc_ip * ip1,
159 netcalc_ip * ip2 );
160
161
162void
163netcalc_ip_free(
164 netcalc_ip * ip );
165
166
167int
168netcalc_ip_parse(
169 netcalc * cnf,
170 netcalc_ip ** ipp,
171 const char * str );
172
173
174int
175netcalc_ip_parse_ipv4(
176 netcalc * cnf,
177 netcalc_ip * ip,
178 char * str );
179
180
181int
182netcalc_ip_parse_ipv4_str(
183 netcalc * cnf,
184 netcalc_ip * ip,
185 char * str );
186
187
188int
189netcalc_ip_parse_ipv6(
190 netcalc * cnf,
191 netcalc_ip * ip,
192 char * str );
193
194
195int netcalc_ip_string(
196 netcalc * cnf,
197 netcalc_ip * ip,
198 char * str,
199 size_t size );
200
201
202int netcalc_ip_string_ipv4(
203 netcalc * cnf,
204 netcalc_ip * ip,
205 char * str,
206 size_t size );
207
208
209int netcalc_ip_string_ipv6(
210 netcalc * cnf,
211 netcalc_ip * ip,
212 char * str,
213 size_t size );
214
215
216int
217netcalc_ip_parse_ipv6_mapped_ipv4(
218 netcalc * cnf,
219 netcalc_ip * ip,
220 char * node );
221
222
223void
224netcalc_net_broadcast_r(
225 netcalc_ip * broadcast,
226 netcalc_ip * ip,
227 int32_t cidr );
228
229
230int
231netcalc_net_cmp(
232 netcalc_ip * ip1,
233 netcalc_ip * ip2,
234 int32_t cidr );
235
236
237void
238netcalc_net_netmask_r(
239 netcalc_ip * netmask,
240 int32_t cidr );
241
242
243void
244netcalc_net_network_r(
245 netcalc_ip * network,
246 netcalc_ip * ip,
247 int32_t cidr );
248
249
250void
251netcalc_net_wildmask_r(
252 netcalc_ip * wildmask,
253 int32_t cidr );
254
255
256void
257netcalc_print_ip(
258 netcalc * cnf,
259 netcalc_ip * ip,
260 int32_t cidr,
261 int header );
110 262
111// tests if string represents an IP address
112int netcalc_is_ipv4 PARAMS((const char * str, uint64_t * ipp, uint64_t * cidrp));
113 263
114// displays usage 264// displays usage
115void netcalc_usage PARAMS((void)); 265void
266netcalc_usage( void );
267
116 268
117// displays version information 269// displays version information
118void netcalc_version PARAMS((void)); 270void
271netcalc_version( void );
272
119 273
120// main statement 274// main statement
121int main PARAMS((int argc, char * argv[])); 275int
276main(
277 int argc,
278 char * argv[] );
279
122 280
123char buff[1024]; 281char buff[1024];
124 282
@@ -129,83 +287,613 @@ char buff[1024];
129// // 287// //
130///////////////// 288/////////////////
131 289
132/// converts IPv4 to string 290
133const char * netcalc_ipv4tostr(uint64_t ipv4) 291void netcalc_free( netcalc * cnf )
292{
293 if (!(cnf))
294 return;
295
296 bzero(cnf, sizeof(netcalc));
297 free(cnf);
298
299 return;
300}
301
302
303int netcalc_init( netcalc ** cnfp )
134{ 304{
135 int c; 305 assert(cnfp != NULL);
136 int offset; 306
137 offset = 0; 307 if ((*cnfp = malloc(sizeof(netcalc))) == NULL)
138 for(c = 0; c < 4; c++) 308 {
139 offset += snprintf(&buff[offset], 1024-offset, "%" PRIu64 ".", ((ipv4 >> (24 - (8*c)))&0xff) ); 309 fprintf(stderr, "%s: out of virtual memory\n", PROGRAM_NAME);
140 buff[offset-1] = '\0'; 310 return(1);
141 return(buff); 311 };
312 bzero(*cnfp, sizeof(netcalc));
313
314 (*cnfp)->cidr = 128;
315 (*cnfp)->cidr_limit = -1;
316 (*cnfp)->cidr_incr = -1;
317 (*cnfp)->family = NETCALC_INET;
318
319 (*cnfp)->len_netmask = 7;
320 (*cnfp)->len_network = 7;
321 (*cnfp)->len_wildmask = 8;
322 (*cnfp)->len_broadcast = 9;
323
324 return(0);
142} 325}
143 326
144 327
145/// tests if string represents an IP address 328int netcalc_ip_cmp( netcalc_ip * ip1, netcalc_ip * ip2 )
146int netcalc_is_ipv4(const char * str, uint64_t * ipv4_ptr, uint64_t * cidrp)
147{ 329{
148 int c; 330 int pos;
149 int value; 331 assert(ip1 != NULL);
150 uint64_t ipv4; 332 assert(ip2 != NULL);
151 char * ptr; 333 for(pos = 0; ((pos < 7) && (ip1->addr[pos] == ip2->addr[pos])); pos++);
334 if (ip1->addr[pos] < ip2->addr[pos])
335 return(-1);
336 if (ip1->addr[pos] > ip2->addr[pos])
337 return(1);
338 return(0);
339}
340
152 341
153 // reset IP address buffer 342void netcalc_ip_free( netcalc_ip * ip )
154 if ((ipv4_ptr)) 343{
155 *ipv4_ptr = 0; 344 if (!(ip))
345 return;
346 bzero(ip, sizeof(netcalc_ip));
347 free(ip);
348 return;
349}
350
351
352int netcalc_ip_parse( netcalc * cnf, netcalc_ip ** ipp, const char * ipstr )
353{
354 int rc;
355 netcalc_ip * ip;
356 char * ptr;
357 char * endptr;
358 int32_t cidr;
359 char * str;
156 360
157 // reset initial IP address 361 assert(cnf != NULL);
158 ipv4 = 0;
159 ptr = NULL;
160 362
161 // loops through octets 363 // allocate memory
162 for(c = 0; c < 4; c++) 364 if ((ip = malloc(sizeof(netcalc_ip))) == NULL)
163 { 365 {
164 // reads number from string 366 fprintf(stderr, "%s: out of virtual memory\n", PROGRAM_NAME);
165 ptr = NULL; 367 return(1);
166 value = (int)strtol(str, &ptr, 10); 368 };
369 if ((str = strdup(ipstr)) == NULL)
370 {
371 netcalc_ip_free(ip);
372 fprintf(stderr, "%s: out of virtual memory\n", PROGRAM_NAME);
373 return(1);
374 };
167 375
168 // exits if string is not a number or IP address 376 // parses CIDR
169 if (!(ptr)) 377 cidr = -1;
378 if ((ptr = strrchr(str, '/')) != NULL)
379 {
380 ptr[0] = '\0';
381 cidr = (int32_t)strtol(&ptr[1], &endptr, 0);
382 if ((endptr[0] != '\0') || (&ptr[1] == endptr))
383 {
384 fprintf(stderr, "%s: invalid CIDR\n", PROGRAM_NAME);
385 free(str);
170 return(1); 386 return(1);
171 if ((ptr[0] != '.') && (ptr[0] != '\0') && (ptr[0] != '/')) 387 };
388 };
389
390 // parses string
391 if ((ptr = strchr(str, ':')) == NULL)
392 {
393 // verifies cidr
394 if ((cidr < -1) || (cidr > 32))
395 {
396 fprintf(stderr, "%s: invalid CIDR\n", PROGRAM_NAME);
397 free(str);
398 return(1);
399 };
400
401 // normalizes CIDR for IPv6
402 if (cidr >= 0)
403 cidr += 128 - 32;
404
405 // parse string
406 if ((rc = netcalc_ip_parse_ipv4(cnf, ip, str)) != 0)
407 {
408 netcalc_ip_free(ip);
409 free(str);
410 return(1);
411 };
412 } else {
413 // verifies cidr
414 if ((cidr < -1) || (cidr > 128))
415 {
416 fprintf(stderr, "%s: invalid CIDR\n", PROGRAM_NAME);
417 free(str);
172 return(1); 418 return(1);
419 };
173 420
174 // exits if number is out of bounds for IPv4 octet 421 // parses string
175 if ((value < 0) || (value > 255)) 422 if ((rc = netcalc_ip_parse_ipv6(cnf, ip, str)) != 0)
423 {
424 netcalc_ip_free(ip);
425 free(str);
176 return(1); 426 return(1);
427 };
428 };
177 429
178 // adds number to IPv4 address and moves position within string 430 // normalizes CIDR
179 ipv4 = ((ipv4 << 8) | (((uint64_t)value) & 0xFF)); 431 if ((cnf->cidr > cidr) && (cidr != -1))
180 str = &ptr[1]; 432 cnf->cidr = cidr;
433
434 // frees resources
435 free(str);
436
437 *ipp = ip;
438
439 return(0);
440}
441
442
443int netcalc_ip_parse_ipv4( netcalc * cnf, netcalc_ip * ip, char * str )
444{
445 assert(cnf != NULL);
446 assert(ip != NULL);
447
448 ip->addr[5] = 0xffff;
449
450 // parses IPv4 string
451 return(netcalc_ip_parse_ipv4_str(cnf, ip, str));
452}
453
454
455int netcalc_ip_parse_ipv4_str( netcalc * cnf, netcalc_ip * ip, char * str )
456{
457 uint32_t addr;
458 uint32_t octet;
459 int pos;
460 char * ptr;
461 char * endptr;
462 char * nodes[4];
181 463
182 // finishes up if at end of string 464 assert(cnf != NULL);
183 if ((ptr[0] == '\0') || (ptr[1] == '\0')) 465 assert(ip != NULL);
466 assert(str != NULL);
467
468 // set state
469 addr = 0;
470
471 // splits octets
472 for(pos = 0; (pos < 3); pos++)
473 {
474 nodes[pos] = str;
475 if ((ptr = strchr(str, '.')) == NULL)
184 { 476 {
185 ipv4 = ipv4 << ((3 - c) * 8); 477 fprintf(stderr, "%s: invalid IPv4 address\n", PROGRAM_NAME);
186 if ((ipv4_ptr)) 478 return(1);
187 *ipv4_ptr = ipv4;
188 return(0);
189 }; 479 };
480 ptr[0] = '\0';
481 str = &ptr[1];
482 };
483 nodes[pos] = str;
190 484
191 // process CIDR 485 // parses octets
192 if (ptr[0] == '/') 486 for(pos = 0; (pos < 4); pos++)
487 {
488 octet = (uint32_t)strtoul(nodes[pos], &endptr, 10);
489 if ((nodes[pos] == endptr) || (endptr[0] != '\0') || (octet > 255))
193 { 490 {
194 value = (int)strtol(&ptr[1], &ptr, 10); 491 fprintf(stderr, "%s: invalid IPv4 address\n", PROGRAM_NAME);
195 if (!(ptr)) 492 return(1);
196 return(1);
197 if (ptr[0] != '\0')
198 return(1);
199 if ((value < 0) || (value > 32))
200 return(1);
201 if ((cidrp))
202 *cidrp = value;
203 return(0);
204 }; 493 };
494 addr = (addr << 8) | (octet & 0xff);
205 }; 495 };
206 496
207 // if we made it here, then the string is not an IPv4 address 497 // stores address data
208 return(1); 498 ip->addr[6] = (addr >> 16) & 0xffff;
499 ip->addr[7] = (addr >> 0) & 0xffff;
500
501 return(0);
502}
503
504
505int netcalc_ip_parse_ipv6( netcalc * cnf, netcalc_ip * ip, char * str)
506{
507 int pos;
508 int rev;
509 int compress;
510 char * nodes[9];
511 char * ptr;
512 char * endptr;
513
514 assert(cnf != NULL);
515 assert(ip != NULL);
516
517 cnf->family = NETCALC_INET6;
518
519 // verifies zero compression
520 compress = 0;
521 for(pos = 1; (pos < (int)strlen(str)); pos++)
522 if ((str[pos-0] == ':') && (str[pos-1] == ':'))
523 compress++;
524 if (compress > 1)
525 {
526 fprintf(stderr, "%s:%i: invalid IPv6 address\n", PROGRAM_NAME, __LINE__);
527 return(1);
528 };
529
530 // set state
531 bzero(nodes, sizeof(nodes));
532
533 // splits octets
534 for(pos = 0; ((pos < 8) && (str[0] != ':') && ((ptr = strchr(str, ':')) != NULL)); pos++)
535 {
536 nodes[pos] = str;
537 str = &ptr[1];
538 ptr[0] = '\0';
539 };
540 for(rev = 7; ((rev > 0) && ((ptr = strrchr(str, ':')) != NULL)); rev--)
541 {
542 ptr[0] = '\0';
543 nodes[rev] = &ptr[1];
544 if ((rev == 7) && ((strchr(nodes[rev], '.'))))
545 rev--;
546 };
547 nodes[rev] = str;
548 if (rev < pos)
549 {
550 fprintf(stderr, "%s:%i: invalid IPv6 address\n", PROGRAM_NAME, __LINE__);
551 return(1);
552 };
553
554 // converts string to numeric data
555 for(pos = 0; (pos < 8); pos++)
556 {
557 if (!(nodes[pos]))
558 continue;
559 if (!(nodes[pos][0]))
560 continue;
561 ip->addr[pos] = (uint32_t)strtoul(nodes[pos], &endptr, 16);
562 if ((pos == 7) && (endptr[0] == '.'))
563 return(netcalc_ip_parse_ipv6_mapped_ipv4(cnf, ip, nodes[7]));
564 if ( (nodes[pos] == endptr) || (endptr[0] != '\0') || (ip->addr[pos] > 0xffff) )
565 {
566 fprintf(stderr, "%s:%i: invalid IPv6 address\n", PROGRAM_NAME, __LINE__);
567 return(1);
568 };
569 };
570
571 return(0);
572}
573
574
575int netcalc_ip_parse_ipv6_mapped_ipv4( netcalc * cnf, netcalc_ip * ip, char * node )
576{
577 int pos;
578
579 assert(cnf != NULL);
580 assert(ip != NULL);
581 assert(node != NULL);
582
583 // verify syntax
584 for(pos = 0; (pos < 5); pos++)
585 {
586 if (ip->addr[pos] != 0)
587 {
588 fprintf(stderr, "%s:%i: invalid IPv6 address\n", PROGRAM_NAME, __LINE__);
589 return(1);
590 };
591 };
592 if (ip->addr[5] != 0xffff)
593 {
594 fprintf(stderr, "%s:%i: invalid IPv6 address\n", PROGRAM_NAME, __LINE__);
595 return(1);
596 };
597
598 return(netcalc_ip_parse_ipv4_str(cnf, ip, node));
599}
600
601
602int netcalc_ip_string( netcalc * cnf, netcalc_ip * ip, char * str, size_t size )
603{
604 if (cnf->family == NETCALC_INET)
605 return(netcalc_ip_string_ipv4(cnf, ip, str, size));
606 return(netcalc_ip_string_ipv6(cnf, ip, str, size));
607}
608
609
610int netcalc_ip_string_ipv4( netcalc * cnf, netcalc_ip * ip, char * str, size_t size )
611{
612 assert(cnf != NULL);
613 assert(ip != NULL);
614 assert(str != NULL);
615 assert(size > 0);
616 snprintf(
617 str,
618 size,
619 "%i.%i.%i.%i",
620 (ip->addr[6] >> 8),
621 (ip->addr[6] & 0xff),
622 (ip->addr[7] >> 8),
623 (ip->addr[7] & 0xff)
624 );
625 return(0);
626}
627
628
629int netcalc_ip_string_ipv6( netcalc * cnf, netcalc_ip * ip, char * str, size_t size )
630{
631 char b[32];
632 char * ptr;
633 int ipv4mapped;
634 int padding;
635 int pos;
636 int zero_offset;
637 int zero_len;
638 int offset;
639
640 assert(cnf != NULL);
641 assert(ip != NULL);
642 assert(str != NULL);
643 assert(size > 0);
644
645 // set state
646 str[0] = '\0';
647
648 // calculates zero compression
649 zero_offset = 0;
650 zero_len = 0;
651 for(pos = 0; (pos < 8); pos++)
652 {
653 if (ip->addr[pos] == 0)
654 {
655 offset = pos;
656 while((ip->addr[pos] == 0) && (pos < 8))
657 pos++;
658 if ((pos - offset) > zero_len)
659 {
660 zero_offset = offset;
661 zero_len = pos - offset;
662 };
663 };
664 };
665
666 // determines if IPv4 mapped address
667 ipv4mapped = (zero_offset == 0) ? 1 : 0;
668 ipv4mapped = (zero_len == 5) ? ipv4mapped : 0;
669 ipv4mapped = (ip->addr[5] == 0xffff) ? ipv4mapped : 0;
670 ipv4mapped = (!(cnf->opts & NETCALC_NO_MAP)) ? ipv4mapped : 0;
671
672 // prints full IP address
673 if ((cnf->opts & NETCALC_IPV6_FULL) != 0)
674 {
675 if ((ipv4mapped))
676 {
677 snprintf(
678 str,
679 size,
680 "0:0:0:0:0:ffff:%i.%i.%i.%i",
681 (ip->addr[6] >> 8),
682 (ip->addr[6] & 0xff),
683 (ip->addr[7] >> 8),
684 (ip->addr[7] & 0xff)
685 );
686 } else {
687 padding = (cnf->opts & NETCALC_IPV6_EXPAND) ? 4 : 0;
688 for(pos = 0; (pos < 7); pos++)
689 {
690 snprintf(b, sizeof(b), "%0*x:", padding, ip->addr[pos]);
691 strncat(str, b, size);
692 };
693 snprintf(b, sizeof(b), "%0*x", padding, ip->addr[7]);
694 strncat(str, b, size);
695 };
696 return(0);
697 };
698
699 // prints IPv4 mapped address
700 if ((ipv4mapped))
701 {
702 snprintf(
703 str,
704 size,
705 "::ffff:%i.%i.%i.%i",
706 (ip->addr[6] >> 8),
707 (ip->addr[6] & 0xff),
708 (ip->addr[7] >> 8),
709 (ip->addr[7] & 0xff)
710 );
711 return(0);
712 };
713
714 // prints IPv6 prefix
715 for(pos = 0; (pos < 8); pos++)
716 {
717 if ((pos == zero_offset) && (zero_len > 1))
718 {
719 strncat(str, ((pos == 0) ? "::" : ":"), size);
720 pos += zero_len - 1;
721 if (pos > 6)
722 strncat(str, ":", size);
723 } else {
724 snprintf(b, sizeof(b), "%x:", ip->addr[pos]);
725 strncat(str, b, size);
726 };
727 };
728 ptr = strrchr(str, ':');
729 ptr[0] = '\0';
730
731 return(0);
732}
733
734
735void netcalc_net_broadcast_r( netcalc_ip * broadcast, netcalc_ip * ip, int32_t cidr )
736{
737 int pos;
738 netcalc_ip wildmask;
739 netcalc_net_wildmask_r(&wildmask, cidr);
740 for(pos = 0; (pos < 8); pos++)
741 broadcast->addr[pos] = ip->addr[pos] | wildmask.addr[pos];
742 return;
743}
744
745
746int netcalc_net_cmp( netcalc_ip * a, netcalc_ip * b, int32_t cidr )
747{
748 int i;
749 netcalc_ip m;
750
751 assert(a != NULL);
752 assert(b != NULL);
753
754 netcalc_net_netmask_r(&m, cidr);
755
756 for(i = 0; ( (i < 7) && ((a->addr[i]&m.addr[i]) == (b->addr[i]&m.addr[i])) ); i++);
757
758 if ( (a->addr[i] & m.addr[i]) < (b->addr[i] & m.addr[i]) )
759 return(-1);
760
761 if ( (a->addr[i] & m.addr[i]) > (b->addr[i] & m.addr[i]) )
762 return(1);
763
764 return(0);
765}
766
767
768void netcalc_net_netmask_r( netcalc_ip * netmask, int32_t cidr )
769{
770 int32_t pos;
771 bzero(netmask, sizeof(netcalc_ip));
772 for(pos = 0; (pos < (cidr / 16)); pos++)
773 netmask->addr[pos] = 0xffff;
774 for(cidr %= 16; (cidr > 0); cidr--)
775 {
776 netmask->addr[pos] |= 0x10000;
777 netmask->addr[pos] >>= 1;
778 };
779 return;
780}
781
782
783void netcalc_net_network_r( netcalc_ip * network, netcalc_ip * ip, int32_t cidr )
784{
785 int pos;
786 netcalc_ip netmask;
787 netcalc_net_netmask_r(&netmask, cidr);
788 for(pos = 0; (pos < 8); pos++)
789 network->addr[pos] = ip->addr[pos] & netmask.addr[pos];
790 return;
791}
792
793
794void netcalc_net_wildmask_r( netcalc_ip * wildmask, int32_t cidr )
795{
796 int32_t pos;
797 netcalc_net_netmask_r(wildmask, cidr);
798 for(pos = 0; (pos < 8); pos++)
799 wildmask->addr[pos] = (~wildmask->addr[pos] & 0xffff);
800 return;
801}
802
803
804void netcalc_print_ip( netcalc * cnf, netcalc_ip * ip, int32_t cidr, int header )
805{
806 int pos;
807 netcalc_ip netmask;
808 netcalc_ip broadcast;
809 netcalc_ip network;
810 netcalc_ip wildmask;
811 char str_netmask[56];
812 char str_broadcast[56];
813 char str_network[56];
814 char str_wildmask[56];
815 char str_subnets[128];
816 uint64_t count;
817
818 if ((ip))
819 {
820 netcalc_net_netmask_r( &netmask, cidr );
821 netcalc_net_wildmask_r( &wildmask, cidr );
822 netcalc_net_network_r( &network, ip, cidr );
823 netcalc_net_broadcast_r( &broadcast, ip, cidr );
824 netcalc_ip_string( cnf, &netmask, str_netmask, sizeof(str_netmask) );
825 netcalc_ip_string( cnf, &wildmask, str_wildmask, sizeof(str_wildmask) );
826 netcalc_ip_string( cnf, &network, str_network, sizeof(str_network) );
827 netcalc_ip_string( cnf, &broadcast, str_broadcast, sizeof(str_broadcast) );
828 };
829
830 // network count
831 if (cnf->cidr_incr >= cnf->cidr)
832 {
833 count = 1;
834 for(pos = 0; (pos < (cnf->cidr_incr - cnf->cidr)); pos++)
835 count *= 2;
836 } else {
837 count = 0;
838 };
839
840 // print IPv4 information
841 if (cnf->family == NETCALC_INET)
842 {
843 if ((header))
844 {
845 snprintf(str_subnets, sizeof(str_subnets), "/%" PRIu32 "s", (cnf->cidr_incr + 32 - 128));
846 // prints field names
847 printf("%-15s", "Network");
848 printf(" %-15s", "Broadcast");
849 printf(" %-15s", "Netmask");
850 printf(" %-15s", "Wildcard");
851 printf(" %-4s", "CIDR");
852 printf(" %s", str_subnets);
853 printf("\n");
854 return;
855 };
856 printf("%-15s", str_network);
857 printf(" %-15s", str_broadcast);
858 printf(" %-15s", str_netmask);
859 printf(" %-15s", str_wildmask);
860 printf(" %-4i", cidr + 32 - 128);
861 printf(" %" PRIu64, count);
862 printf("\n");
863 return;
864 };
865
866 cnf->len_netmask = (cnf->len_netmask < (int)strlen(str_netmask)) ? (int)strlen(str_netmask) : cnf->len_netmask;
867 cnf->len_network = (cnf->len_network < (int)strlen(str_network)) ? (int)strlen(str_network) : cnf->len_network;
868 cnf->len_wildmask = (cnf->len_wildmask < (int)strlen(str_wildmask)) ? (int)strlen(str_wildmask) : cnf->len_wildmask;
869 cnf->len_broadcast = (cnf->len_broadcast < (int)strlen(str_broadcast)) ? (int)strlen(str_broadcast) : cnf->len_broadcast;
870
871 // print IPv6 information
872 if ((header))
873 {
874 snprintf(str_subnets, sizeof(str_subnets), "/%" PRIu32 "s", cnf->cidr_incr);
875 // prints field names
876 printf("%-*s", cnf->len_network, "Network");
877 printf(" %-*s", cnf->len_broadcast, "Broadcast");
878 printf(" %-*s", cnf->len_netmask, "Netmask");
879 printf(" %-*s", cnf->len_wildmask, "Wildcard");
880 printf(" %-4s", "CIDR");
881 printf(" %s", str_subnets);
882 printf("\n");
883 return;
884 };
885 printf("%-*s", cnf->len_network, str_network);
886 printf(" %-*s", cnf->len_broadcast, str_broadcast);
887 printf(" %-*s", cnf->len_netmask, str_netmask);
888 printf(" %-*s", cnf->len_wildmask, str_wildmask);
889 printf(" %-4i", cidr);
890 if ((cnf->cidr_incr >= cnf->cidr) && ((cnf->cidr_incr - cnf->cidr) < 64))
891 printf(" %" PRIu64, count);
892 else
893 printf(" n/a");
894 printf("\n");
895
896 return;
209} 897}
210 898
211 899
@@ -214,10 +902,13 @@ void netcalc_usage(void)
214{ 902{
215 printf("Usage: %s [OPTIONS] address1 address2 ... addressN\n", PROGRAM_NAME); 903 printf("Usage: %s [OPTIONS] address1 address2 ... addressN\n", PROGRAM_NAME);
216 printf(" -a display all matching networks\n"); 904 printf(" -a display all matching networks\n");
217 printf(" -c num requested network size in CIDR notation\n"); 905 printf(" -c cidr requested network size in CIDR notation\n");
906 printf(" -f print full IPv6 notation (do not compress zeros)\n");
218 printf(" -h, --help print this help and exit\n"); 907 printf(" -h, --help print this help and exit\n");
219 printf(" -i num requested network size in amount of IP addresses\n"); 908 printf(" -i cidr increment size of network list\n");
909 printf(" -m do not display IPv4 mapped addresses\n");
220 printf(" -V, --version print version number and exit\n"); 910 printf(" -V, --version print version number and exit\n");
911 printf(" -x print IPv6 expanded notation (print leading zeros)\n");
221 printf("\n"); 912 printf("\n");
222 printf("Report bugs to <%s>.\n", PACKAGE_BUGREPORT); 913 printf("Report bugs to <%s>.\n", PACKAGE_BUGREPORT);
223 return; 914 return;
@@ -243,19 +934,12 @@ void netcalc_version(void)
243int main(int argc, char * argv[]) 934int main(int argc, char * argv[])
244{ 935{
245 int c; 936 int c;
246 int opt; 937 int rc;
247 int opt_index; 938 int opt_index;
248 uint64_t cidr; 939 netcalc * cnf;
249 uint64_t opt_cidr_high; 940 netcalc_ip * ip;
250 uint64_t opt_ip_count; 941
251 uint64_t ipv4; 942 static char short_opt[] = "6ac:fhi:mVx";
252 uint64_t ipv4_low;
253 uint64_t ipv4_high;
254 uint64_t network;
255 uint64_t broadcast;
256 uint64_t netmask;
257
258 static char short_opt[] = "ac:hi:V";
259 static struct option long_opt[] = 943 static struct option long_opt[] =
260 { 944 {
261 {"help", no_argument, 0, 'h'}, 945 {"help", no_argument, 0, 'h'},
@@ -263,10 +947,8 @@ int main(int argc, char * argv[])
263 {NULL, 0, 0, 0 } 947 {NULL, 0, 0, 0 }
264 }; 948 };
265 949
266 // set defaults 950 if ((rc = netcalc_init(&cnf)) != 0)
267 opt = 0; 951 return(1);
268 opt_cidr_high = 33;
269 opt_ip_count = 0;
270 952
271 while((c = getopt_long(argc, argv, short_opt, long_opt, &opt_index)) != -1) 953 while((c = getopt_long(argc, argv, short_opt, long_opt, &opt_index)) != -1)
272 { 954 {
@@ -274,29 +956,68 @@ int main(int argc, char * argv[])
274 { 956 {
275 case -1: /* no more arguments */ 957 case -1: /* no more arguments */
276 case 0: /* long options toggles */ 958 case 0: /* long options toggles */
277 break; 959 break;
960
961 case '6':
962 cnf->family = NETCALC_INET6;
963 break;
964
278 case 'a': 965 case 'a':
279 opt = opt | NETCALC_OPT_ALL_NETWORKS; 966 cnf->opts |= NETCALC_ALL_NETWORKS;
280 break; 967 cnf->len_wildmask = 39;
968 cnf->len_broadcast = 39;
969 break;
970
281 case 'c': 971 case 'c':
282 opt_cidr_high = strtoll(optarg, NULL, 0); 972 cnf->cidr_limit = (int32_t)strtol(optarg, NULL, 0);
283 break; 973 if ((cnf->cidr_limit < 0) || (cnf->cidr_limit > 128))
974 {
975 fprintf(stderr, "%s: invalid CIDR\n", PROGRAM_NAME);
976 netcalc_free(cnf);
977 return(1);
978 };
979 break;
980
981 case 'f':
982 cnf->opts |= NETCALC_IPV6_FULL;
983 break;
984
284 case 'h': 985 case 'h':
285 netcalc_usage(); 986 netcalc_usage();
286 return(0); 987 return(0);
988
287 case 'i': 989 case 'i':
288 opt_ip_count = strtoll(optarg, NULL, 0); 990 cnf->cidr_incr = (int32_t)strtol(optarg, NULL, 0);
289 break; 991 if ((cnf->cidr_incr < 0) || (cnf->cidr_incr > 128))
992 {
993 fprintf(stderr, "%s: invalid CIDR\n", PROGRAM_NAME);
994 netcalc_free(cnf);
995 return(1);
996 };
997 break;
998
999 case 'm':
1000 cnf->opts |= NETCALC_NO_MAP;
1001 break;
1002
290 case 'V': 1003 case 'V':
291 netcalc_version(); 1004 netcalc_version();
292 return(0); 1005 return(0);
1006
1007 case 'x':
1008 cnf->opts |= NETCALC_IPV6_EXPAND;
1009 cnf->opts |= NETCALC_IPV6_FULL;
1010 cnf->opts |= NETCALC_NO_MAP;
1011 break;
1012
293 case '?': 1013 case '?':
294 fprintf(stderr, "Try `%s --help' for more information.\n", PROGRAM_NAME); 1014 fprintf(stderr, "Try `%s --help' for more information.\n", PROGRAM_NAME);
295 return(1); 1015 return(1);
1016
296 default: 1017 default:
297 fprintf(stderr, "%s: unrecognized option `--%c'\n", PROGRAM_NAME, c); 1018 fprintf(stderr, "%s: unrecognized option `--%c'\n", PROGRAM_NAME, c);
298 fprintf(stderr, "Try `%s --help' for more information.\n", PROGRAM_NAME); 1019 fprintf(stderr, "Try `%s --help' for more information.\n", PROGRAM_NAME);
299 return(1); 1020 return(1);
300 }; 1021 };
301 }; 1022 };
302 1023
@@ -307,71 +1028,89 @@ int main(int argc, char * argv[])
307 return(1); 1028 return(1);
308 }; 1029 };
309 1030
310 // determines the high and low IP address in the list
311 ipv4_high = 0;
312 ipv4_low = 0;
313 for(c = optind; c < argc; c++) 1031 for(c = optind; c < argc; c++)
314 { 1032 {
315 if (netcalc_is_ipv4(argv[c], &ipv4, &opt_cidr_high)) 1033 if ((rc = netcalc_ip_parse(cnf, &ip, argv[c])) != 0)
316 { 1034 {
317 printf("%s: invalid IPv4 address: %s\n", PROGRAM_NAME, argv[c]); 1035 netcalc_free(cnf);
318 return(1); 1036 return(1);
319 }; 1037 };
320 if (c == optind) 1038
1039 // initialize bounds
1040 if (!(cnf->lower))
1041 {
1042 if ((cnf->lower = malloc(sizeof(netcalc_ip))) == NULL)
1043 {
1044 fprintf(stderr, "%s: out of virtual memory\n", PROGRAM_NAME);
1045 netcalc_ip_free(ip);
1046 netcalc_free(cnf);
1047 return(1);
1048 };
1049 memcpy(cnf->lower, ip, sizeof(netcalc_ip));
1050 };
1051 if (!(cnf->upper))
1052 {
1053 if ((cnf->upper = malloc(sizeof(netcalc_ip))) == NULL)
1054 {
1055 fprintf(stderr, "%s: out of virtual memory\n", PROGRAM_NAME);
1056 netcalc_ip_free(ip);
1057 netcalc_free(cnf);
1058 return(1);
1059 };
1060 memcpy(cnf->upper, ip, sizeof(netcalc_ip));
1061 };
1062
1063 // updates bounds
1064 if (netcalc_ip_cmp(ip, cnf->lower) < 0)
321 { 1065 {
322 ipv4_low = ipv4; 1066 netcalc_ip_free(cnf->lower);
323 ipv4_high = ipv4; 1067 cnf->lower = ip;
1068 } else if (netcalc_ip_cmp(ip, cnf->upper) > 0) {
1069 netcalc_ip_free(cnf->upper);
1070 cnf->upper = ip;
1071 } else {
1072 netcalc_ip_free(ip);
324 }; 1073 };
325 if (ipv4 < ipv4_low)
326 ipv4_low = ipv4;
327 if (ipv4 > ipv4_high)
328 ipv4_high = ipv4;
329 }; 1074 };
330 1075
331 // calculates the smallest network which matches criteria 1076 if (cnf->family == NETCALC_INET)
332 cidr = 32LL;
333 netmask = 0x00;
334 while ( ((~netmask & ipv4_high) != (~netmask & ipv4_low)) ||
335 ((opt_cidr_high < cidr)) ||
336 (((uint64_t)opt_ip_count > (netmask+1))) )
337 { 1077 {
338 netmask = (netmask << 1) | 0x01; 1078 cnf->cidr_limit = ((cnf->cidr_limit == -1) ? 32 : cnf->cidr_limit) + 128 - 32;
339 cidr--; 1079 cnf->cidr_incr = ((cnf->cidr_incr == -1) ? 32 : cnf->cidr_incr) + 128 - 32;
1080 cnf->cidr = (cnf->cidr < cnf->cidr_limit) ? cnf->cidr : cnf->cidr_limit;
1081 } else {
1082 cnf->cidr_limit = (cnf->cidr_limit == -1) ? 64 : cnf->cidr_limit;
1083 cnf->cidr_incr = (cnf->cidr_incr == -1) ? 64 : cnf->cidr_incr;
1084 cnf->cidr = (cnf->cidr < cnf->cidr_limit) ? cnf->cidr : cnf->cidr_limit;
340 }; 1085 };
341 netmask = ~netmask;
342 network = netmask & ipv4_high;
343
344 // prints field names
345 printf("%-18s", "Network");
346 printf("%-8s", "CIDR");
347 printf("%-18s", "Netmask");
348 printf("%-18s", "Broadcast");
349 printf("%s", "IP Count");
350 printf("\n");
351 1086
352 // prints list of matching networks 1087 // calculate inclusive CIDR
353 while(cidr >= 0) 1088 while ((rc = netcalc_net_cmp(cnf->lower, cnf->upper, cnf->cidr)) != 0)
354 { 1089 cnf->cidr--;
355 // calculates network and broadcast
356 network = network & netmask;
357 broadcast = network | (~netmask);
358
359 // prints information
360 printf("%-18s", netcalc_ipv4tostr(network));
361 printf("%-8" PRIu64, cidr);
362 printf("%-18s", netcalc_ipv4tostr(netmask));
363 printf("%-18s", netcalc_ipv4tostr(broadcast));
364 printf("%" PRIu64, (~netmask + 1));
365 printf("\n");
366 1090
367 // moves to next netmask/cidr 1091 // print header
368 if (!(opt & NETCALC_OPT_ALL_NETWORKS)) 1092 netcalc_print_ip(cnf, cnf->lower, cnf->cidr, 1);
369 return(0); 1093 netcalc_print_ip(cnf, cnf->lower, cnf->cidr, 0);
370 netmask = ~((~netmask << 1) | 0x01); 1094
371 cidr--; 1095 // print all matching subnets
1096 if ((cnf->opts & NETCALC_ALL_NETWORKS))
1097 {
1098 if (cnf->family == NETCALC_INET6)
1099 {
1100 while(cnf->cidr > 0)
1101 {
1102 cnf->cidr--;
1103 netcalc_print_ip(cnf, cnf->lower, cnf->cidr, 0);
1104 };
1105 } else {
1106 while(cnf->cidr > (128-32))
1107 {
1108 cnf->cidr--;
1109 netcalc_print_ip(cnf, cnf->lower, cnf->cidr, 0);
1110 };
1111 };
372 }; 1112 };
373 1113
374 // Okay, time to rest after a job well done
375 return(0); 1114 return(0);
376} 1115}
377 1116