diff options
| author | David M. Syzdek <david@syzdek.net> | 2021-10-06 01:30:25 -0800 |
|---|---|---|
| committer | David M. Syzdek <david@syzdek.net> | 2021-10-06 01:32:28 -0800 |
| commit | 7ca6ec8abb90fb1bc4d2d37166dd107b2718a58d (patch) | |
| tree | 81b8d50bebf3b31d8d2cf206bff12551d2a8570a | |
| parent | 7529d42f1f420a9a1cc98bd0f46cb4b8988fe486 (diff) | |
| download | dmstools-7ca6ec8abb90fb1bc4d2d37166dd107b2718a58d.tar.gz dmstools-7ca6ec8abb90fb1bc4d2d37166dd107b2718a58d.tar.bz2 dmstools-7ca6ec8abb90fb1bc4d2d37166dd107b2718a58d.tar.xz dmstools-7ca6ec8abb90fb1bc4d2d37166dd107b2718a58d.zip | |
netcalc: refactoring to support IPv6 networks
| -rw-r--r-- | src/netcalc.c | 1035 |
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 | |||
| 114 | typedef struct _netcalc_ip netcalc_ip; | ||
| 115 | typedef struct _netcalc netcalc; | ||
| 116 | |||
| 117 | struct _netcalc_ip | ||
| 118 | { | ||
| 119 | uint32_t addr[8]; | ||
| 120 | }; | ||
| 121 | |||
| 122 | |||
| 123 | struct _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 | 146 | int |
| 109 | const char * netcalc_ipv4tostr(uint64_t ipv4); | 147 | netcalc_init( |
| 148 | netcalc ** cnfp ); | ||
| 149 | |||
| 150 | |||
| 151 | void | ||
| 152 | netcalc_free( | ||
| 153 | netcalc * cnfi ); | ||
| 154 | |||
| 155 | |||
| 156 | int | ||
| 157 | netcalc_ip_cmp( | ||
| 158 | netcalc_ip * ip1, | ||
| 159 | netcalc_ip * ip2 ); | ||
| 160 | |||
| 161 | |||
| 162 | void | ||
| 163 | netcalc_ip_free( | ||
| 164 | netcalc_ip * ip ); | ||
| 165 | |||
| 166 | |||
| 167 | int | ||
| 168 | netcalc_ip_parse( | ||
| 169 | netcalc * cnf, | ||
| 170 | netcalc_ip ** ipp, | ||
| 171 | const char * str ); | ||
| 172 | |||
| 173 | |||
| 174 | int | ||
| 175 | netcalc_ip_parse_ipv4( | ||
| 176 | netcalc * cnf, | ||
| 177 | netcalc_ip * ip, | ||
| 178 | char * str ); | ||
| 179 | |||
| 180 | |||
| 181 | int | ||
| 182 | netcalc_ip_parse_ipv4_str( | ||
| 183 | netcalc * cnf, | ||
| 184 | netcalc_ip * ip, | ||
| 185 | char * str ); | ||
| 186 | |||
| 187 | |||
| 188 | int | ||
| 189 | netcalc_ip_parse_ipv6( | ||
| 190 | netcalc * cnf, | ||
| 191 | netcalc_ip * ip, | ||
| 192 | char * str ); | ||
| 193 | |||
| 194 | |||
| 195 | int netcalc_ip_string( | ||
| 196 | netcalc * cnf, | ||
| 197 | netcalc_ip * ip, | ||
| 198 | char * str, | ||
| 199 | size_t size ); | ||
| 200 | |||
| 201 | |||
| 202 | int netcalc_ip_string_ipv4( | ||
| 203 | netcalc * cnf, | ||
| 204 | netcalc_ip * ip, | ||
| 205 | char * str, | ||
| 206 | size_t size ); | ||
| 207 | |||
| 208 | |||
| 209 | int netcalc_ip_string_ipv6( | ||
| 210 | netcalc * cnf, | ||
| 211 | netcalc_ip * ip, | ||
| 212 | char * str, | ||
| 213 | size_t size ); | ||
| 214 | |||
| 215 | |||
| 216 | int | ||
| 217 | netcalc_ip_parse_ipv6_mapped_ipv4( | ||
| 218 | netcalc * cnf, | ||
| 219 | netcalc_ip * ip, | ||
| 220 | char * node ); | ||
| 221 | |||
| 222 | |||
| 223 | void | ||
| 224 | netcalc_net_broadcast_r( | ||
| 225 | netcalc_ip * broadcast, | ||
| 226 | netcalc_ip * ip, | ||
| 227 | int32_t cidr ); | ||
| 228 | |||
| 229 | |||
| 230 | int | ||
| 231 | netcalc_net_cmp( | ||
| 232 | netcalc_ip * ip1, | ||
| 233 | netcalc_ip * ip2, | ||
| 234 | int32_t cidr ); | ||
| 235 | |||
| 236 | |||
| 237 | void | ||
| 238 | netcalc_net_netmask_r( | ||
| 239 | netcalc_ip * netmask, | ||
| 240 | int32_t cidr ); | ||
| 241 | |||
| 242 | |||
| 243 | void | ||
| 244 | netcalc_net_network_r( | ||
| 245 | netcalc_ip * network, | ||
| 246 | netcalc_ip * ip, | ||
| 247 | int32_t cidr ); | ||
| 248 | |||
| 249 | |||
| 250 | void | ||
| 251 | netcalc_net_wildmask_r( | ||
| 252 | netcalc_ip * wildmask, | ||
| 253 | int32_t cidr ); | ||
| 254 | |||
| 255 | |||
| 256 | void | ||
| 257 | netcalc_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 | ||
| 112 | int netcalc_is_ipv4 PARAMS((const char * str, uint64_t * ipp, uint64_t * cidrp)); | ||
| 113 | 263 | ||
| 114 | // displays usage | 264 | // displays usage |
| 115 | void netcalc_usage PARAMS((void)); | 265 | void |
| 266 | netcalc_usage( void ); | ||
| 267 | |||
| 116 | 268 | ||
| 117 | // displays version information | 269 | // displays version information |
| 118 | void netcalc_version PARAMS((void)); | 270 | void |
| 271 | netcalc_version( void ); | ||
| 272 | |||
| 119 | 273 | ||
| 120 | // main statement | 274 | // main statement |
| 121 | int main PARAMS((int argc, char * argv[])); | 275 | int |
| 276 | main( | ||
| 277 | int argc, | ||
| 278 | char * argv[] ); | ||
| 279 | |||
| 122 | 280 | ||
| 123 | char buff[1024]; | 281 | char buff[1024]; |
| 124 | 282 | ||
| @@ -129,83 +287,613 @@ char buff[1024]; | |||
| 129 | // // | 287 | // // |
| 130 | ///////////////// | 288 | ///////////////// |
| 131 | 289 | ||
| 132 | /// converts IPv4 to string | 290 | |
| 133 | const char * netcalc_ipv4tostr(uint64_t ipv4) | 291 | void 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 | |||
| 303 | int 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 | 328 | int netcalc_ip_cmp( netcalc_ip * ip1, netcalc_ip * ip2 ) |
| 146 | int 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 | 342 | void 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 | |||
| 352 | int 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 | |||
| 443 | int 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 | |||
| 455 | int 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 | |||
| 505 | int 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 | |||
| 575 | int 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 | |||
| 602 | int 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 | |||
| 610 | int 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 | |||
| 629 | int 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 | |||
| 735 | void 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 | |||
| 746 | int 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 | |||
| 768 | void 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 | |||
| 783 | void 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 | |||
| 794 | void 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 | |||
| 804 | void 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) | |||
| 243 | int main(int argc, char * argv[]) | 934 | int 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 | ||
