1 | /*************************************** 2 | $Revision: 1.22 $ 3 | 4 | IP handling (ip). ip.c - conversions between ascii and binary forms 5 | of IP addresses, prefixes and ranges. 6 | 7 | various operations on binary forms. 8 | 9 | Status: NOT REVUED, TESTED, COMPLETE 10 | 11 | Design and implementation by: Marek Bukowy 12 | 13 | ******************/ /****************** 14 | Copyright (c) 1999 RIPE NCC 15 | 16 | All Rights Reserved 17 | 18 | Permission to use, copy, modify, and distribute this software and its 19 | documentation for any purpose and without fee is hereby granted, 20 | provided that the above copyright notice appear in all copies and that 21 | both that copyright notice and this permission notice appear in 22 | supporting documentation, and that the name of the author not be 23 | used in advertising or publicity pertaining to distribution of the 24 | software without specific, written prior permission. 25 | 26 | THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 27 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL 28 | AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY 29 | DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 30 | AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 31 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 32 | ***************************************/ 33 | 34 | #define IP_IMPL 35 | #include <iproutines.h> 36 | #include <string.h> 37 | #include <stdio.h> 38 | #include <erroutines.h> 39 | 40 | #include <ctype.h> 41 | #include <memwrap.h> 42 | 43 | #include <numconv.h> 44 | #include <stubs.h> 45 | 46 | #include <sys/socket.h> 47 | #include <netinet/in.h> 48 | 49 | #include <inet6def.h> 50 | 51 | /**************************************************************************/ 52 | /*+ return the max. length of bits per space 53 | 54 | Yes, it *could* be a macro - but as a function it can detect 55 | more programmer's errors. And will get inlined anyway. 56 | 57 | +*/ 58 | 59 | int IP_sizebits(ip_space_t spc_id) { 60 | switch (spc_id) { 61 | case IP_V4: 62 | return 32; 63 | case IP_V6: 64 | return 128; 65 | default: 66 | /* die; */ /* error: bad IP version specified */ 67 | return -1; 68 | } 69 | } 70 | 71 | static 72 | er_ret_t 73 | ip_rang_validate(ip_range_t *rangptr) 74 | { 75 | if( rangptr->begin.space != rangptr->end.space ) { 76 | /* die; */ /* incompatible IP spaces */ 77 | return IP_INVRAN; 78 | } 79 | 80 | /* XXX IPv6 missing */ 81 | if( rangptr->begin.space == IP_V4 ) { 82 | if( rangptr->begin.words[0] > rangptr->end.words[0] ) { 83 | return IP_INVRAN; 84 | } 85 | } 86 | 87 | return IP_OK; 88 | } 89 | /**************************************************************************/ 90 | /*+ 91 | ascii IP address to binary. 92 | 93 | In IP_EXPN mode IP will be "expanded" 94 | (missing octets will be set to 0, MSB's will be set). 95 | In IP_PLAIN mode the routine will complain if it sees less octets. 96 | 97 | why not use the standard inet_blabla routine ? 98 | it's because if some octets are missing, we make the address zero-padded 99 | (unlike the inet_blabla, which puts zeros in the middle). We also want 100 | to control the expansion with a flag. 101 | 102 | +*/ 103 | 104 | er_ret_t 105 | IP_addr_t2b(ip_addr_t *ipptr, char *addr, ip_exp_t expf) 106 | { 107 | if( index(addr, ':') == NULL ) { 108 | /* IPv4 */ 109 | char *dot=addr; 110 | unsigned len, byte, result=0; 111 | char cpy[4]; 112 | int last = 0, dotsfound=0; 113 | int bytes=0; 114 | 115 | if( expf != IP_PLAIN && expf != IP_EXPN ) { 116 | return IP_INVARG; 117 | } 118 | 119 | do { 120 | char *olddot = dot+1; 121 | /* dot should point to the "end of this number", not necessarily a dot */ 122 | 123 | if ( (dot = index (addr, '.')) == NULL) { 124 | /* after the ip it can contain lots of junk spaces */ 125 | while( *olddot != 0 && ! isspace(* (unsigned char *) olddot) ) { 126 | olddot++; 127 | } 128 | dot = olddot; 129 | last = 1; 130 | } 131 | else { 132 | if( ++dotsfound > 3 ) { 133 | /* handle syntax ERROR - too many dots found */ 134 | return IP_INVIP4; 135 | } 136 | } 137 | 138 | if ((len = dot - addr) > 3) { 139 | /* syntax ERROR - too many digits in an octet */ 140 | return IP_INVIP4; 141 | } 142 | strncpy( cpy, addr, len ); 143 | cpy[len]=0; 144 | 145 | /* sscanf is waay too slow */ 146 | 147 | if( ut_dec_2_uns(cpy, &byte) < 0 ) { 148 | /* handle syntax ERROR - invalid characters found */ 149 | return IP_INVIP4; 150 | } 151 | 152 | 153 | if( byte > 255 ) { 154 | /* handle syntax ERROR - number between dots too high */ 155 | return IP_INVIP4; 156 | } 157 | 158 | result <<= 8; 159 | result += byte; 160 | bytes++; 161 | 162 | addr = dot + 1; 163 | } while (!last); 164 | 165 | if( expf == IP_PLAIN ) { 166 | if( bytes!=4 ) { 167 | return IP_INVIP4; 168 | } 169 | } 170 | else { 171 | while( bytes<4 ) { 172 | result <<= 8; 173 | bytes++; 174 | } 175 | } 176 | 177 | memset(ipptr, 0, sizeof(ip_addr_t)); 178 | ipptr->space = IP_V4; 179 | ipptr->words[0] = result; 180 | } 181 | else { 182 | /* IPv6 */ 183 | #define _IPV6_LENGTH 128 184 | char addrcpy[_IPV6_LENGTH]; 185 | char *ch, *start; 186 | 187 | strncpy(addrcpy, addr, _IPV6_LENGTH-1); 188 | addrcpy[_IPV6_LENGTH-1] = 0; 189 | 190 | /* get rid of superfluous whitespaces */ 191 | /* leading... */ 192 | for( ch = start = addrcpy ; *ch != 0; ch++ ) { 193 | if( isspace( (int) *ch) ) { 194 | start++; 195 | } 196 | else { 197 | break; 198 | } 199 | } 200 | 201 | /* and trailing */ 202 | while( *ch != 0 ) { 203 | if( isspace( (int) *ch) ) { 204 | *ch = 0; 205 | break; 206 | } 207 | ch++; 208 | } 209 | 210 | if( inet_pton(AF_INET6, start, (ipptr->words)) == 0 ) { 211 | return IP_NO6YET; 212 | } 213 | 214 | ipptr->space = IP_V6; 215 | 216 | #undef _IPV6_LENGTH 217 | } 218 | return IP_OK; 219 | } 220 | 221 | /**************************************************************************/ 222 | 223 | /*+ converts a "IP/length" string into a binary prefix 224 | 225 | 226 | 227 | +*/ 228 | 229 | er_ret_t 230 | IP_pref_t2b(ip_prefix_t *prefptr, char *prefstr, ip_exp_t expf) 231 | { 232 | char ip[256]; 233 | char *trash; 234 | char *slash; 235 | int len; 236 | er_ret_t err; 237 | 238 | if( expf != IP_PLAIN && expf != IP_EXPN ) { 239 | return IP_INVARG; 240 | } 241 | 242 | if( (slash=index(prefstr, '/')) == NULL ) { 243 | /* die; */ /* error: missing slash in prefix */ 244 | return IP_NOSLAS; 245 | } 246 | else { 247 | /* copy the IP part to another string, ERROR if 256 chars not enough */ 248 | 249 | len = slash - prefstr; 250 | if( len > 255 ) { 251 | /* die; */ /* ERROR - ip address part of the string too long. */ 252 | return IP_ADTOLO; 253 | } 254 | strncpy(ip, prefstr, len); 255 | ip[len]=0; 256 | 257 | if( (err=IP_addr_t2b( &(prefptr->ip), ip, expf)) != IP_OK) { 258 | /* die; */ /* set error flag: incorrect address format */ 259 | return err; 260 | } 261 | 262 | /* stop at first non-digit */ 263 | for(trash = slash+1; 264 | isdigit(* (unsigned char*) trash); /* cast for stupid gcc */ 265 | trash++) 266 | ; 267 | len = trash - (slash+1) ; 268 | if( len > 4 ) { 269 | /* die; */ /* ERROR - prefix length part of the string too long. */ 270 | return IP_PRTOLO; 271 | } 272 | strncpy(ip, slash+1, len); 273 | ip[len]=0; 274 | 275 | if( ut_dec_2_uns(ip, &prefptr->bits) < 0 276 | || prefptr->bits > IP_sizebits(prefptr->ip.space)) 277 | { 278 | /* if( sscanf (slash+1, "%d", &(prefptr->bits)) < 1 ) { 279 | die; */ /* handle syntax ERROR invalid characters found */ 280 | return IP_INVPRF; 281 | } 282 | } 283 | /* sanitify the prefix - maybe some irrelevant bits are set */ 284 | /* never create broken binary prefixes. */ 285 | 286 | IP_pref_bit_fix(prefptr); 287 | 288 | return IP_OK; 289 | } 290 | 291 | /**************************************************************************/ 292 | 293 | /*+ converts an inaddr/ip6int string into a binary prefix. 294 | no distinction is made with respect to "expand" argument. 295 | +*/ 296 | er_ret_t 297 | IP_revd_t2b(ip_prefix_t *prefptr, char *prefstr, ip_exp_t expf) 298 | { 299 | char ip[256], temp[256]; 300 | char *arpa; 301 | int len, octets=0, goon=1; 302 | char *dot; 303 | er_ret_t err; 304 | 305 | dieif( expf != IP_PLAIN && expf != IP_EXPN ); 306 | 307 | if( (arpa=strstr(prefstr, ".in-addr.arpa")) == NULL ) { 308 | 309 | #if 0 /* XXX not yet implemented */ 310 | if( (arpa=strstr(prefstr, ".ip6.int")) != NULL ) { 311 | /* ipv6 */ 312 | } 313 | #endif 314 | 315 | return IP_NOREVD; 316 | } 317 | else { 318 | /* copy the IP part to another string, ERROR if 256 chars not enough */ 319 | len = arpa - prefstr; 320 | if( len > 255 ) { 321 | /* die; */ /* ERROR - ip address part of the string too long. */ 322 | return IP_ADTOLO; 323 | } 324 | strncpy(temp, prefstr, len); 325 | temp[len]=0; 326 | 327 | /* now : get the octets reversed one by one. */ 328 | ip[0]=0; /* init */ 329 | do { 330 | if( (dot = strrchr( temp, '.' )) == NULL ) { 331 | goon = 0; 332 | dot = temp; 333 | } 334 | 335 | strcat(ip, dot + ( goon ) ); 336 | octets++; 337 | 338 | /* add a dot, unless that was the last octet */ 339 | if( goon ) { 340 | strcat(ip, "."); 341 | } 342 | 343 | *dot = 0; 344 | 345 | } while( goon ); 346 | 347 | if( (err=IP_addr_t2b( &(prefptr->ip), ip, IP_EXPN)) != IP_OK) { 348 | /* die; */ /* set error flag: incorrect address format */ 349 | return err; 350 | } 351 | 352 | prefptr->bits = octets * 8; 353 | } 354 | return IP_OK; 355 | } 356 | 357 | /**************************************************************************/ 358 | 359 | /*+ convert a range string into a binary range struct. 360 | +*/ 361 | er_ret_t 362 | IP_rang_t2b(ip_range_t *rangptr, char *rangstr, ip_exp_t expf) 363 | { 364 | char *ips, *dash; 365 | er_ret_t err; 366 | 367 | if( expf != IP_PLAIN && expf != IP_EXPN ) { 368 | return IP_INVARG; 369 | } 370 | 371 | if( (dash=index(rangstr, '-')) == NULL ) { 372 | /* die; */ /* error: missing dash in range */ 373 | return IP_INVRAN; 374 | } 375 | else { 376 | /* copy the first IP */ 377 | if( (err = wr_calloc( (void*) &ips,1,dash - rangstr + 1)) != UT_OK ) { 378 | return err; 379 | } 380 | 381 | strncpy(ips, rangstr, dash - rangstr); 382 | 383 | /* convert the first IP into a binary struct */ 384 | err=IP_addr_t2b( &(rangptr->begin), ips, expf); 385 | 386 | /* check later */ /* set error flag: incorrect address format */ 387 | 388 | wr_free(ips); 389 | 390 | if( err != IP_OK ) { 391 | return err; 392 | } 393 | 394 | /* now find the other ip, skip the space */ 395 | ips=dash+1; 396 | while( *ips == ' ' ) { 397 | ips++; 398 | } 399 | 400 | /* convert the second IP into a binary struct */ 401 | if( (err=IP_addr_t2b( &(rangptr->end), ips, expf)) != IP_OK ) { 402 | /* die; */ /* incorrect address format */ 403 | return err; 404 | } 405 | 406 | 407 | 408 | return ip_rang_validate(rangptr); 409 | } 410 | } 411 | 412 | 413 | /**************************************************************************/ 414 | /* accessor functions */ 415 | 416 | /******** address **********/ 417 | 418 | unsigned IP_addr_b2_space(ip_addr_t *addrptr) 419 | { 420 | return addrptr->space; 421 | } 422 | 423 | unsigned IP_addr_b2v4_addr(ip_addr_t *addrptr) 424 | { 425 | dieif( addrptr->space != IP_V4 ); 426 | return addrptr->words[0]; 427 | } 428 | /* ipv4 */ 429 | 430 | ip_v6word_t IP_addr_b2v6_hi(ip_addr_t *addrptr) 431 | { 432 | dieif( addrptr->space != IP_V6 ); 433 | return ( (((ip_v6word_t) addrptr->words[0]) << 32) 434 | + (((ip_v6word_t) addrptr->words[1]) )); 435 | } 436 | 437 | ip_v6word_t IP_addr_b2v6_lo(ip_addr_t *addrptr) 438 | { 439 | dieif( addrptr->space != IP_V6 ); 440 | return ( (((ip_v6word_t) addrptr->words[2]) << 32) 441 | + (((ip_v6word_t) addrptr->words[3]) )); 442 | } 443 | 444 | /******** prefix **********/ 445 | 446 | unsigned IP_pref_b2_space(ip_prefix_t *prefix) { 447 | return IP_addr_b2_space( &(prefix->ip) ); 448 | } 449 | 450 | unsigned IP_pref_b2_len(ip_prefix_t *prefix) { 451 | return prefix->bits; 452 | } 453 | 454 | unsigned IP_pref_b2v4_addr(ip_prefix_t *prefix) { 455 | return IP_addr_b2v4_addr( &(prefix->ip) ); 456 | } 457 | 458 | /* range */ 459 | 460 | unsigned IP_rang_b2_space(ip_range_t *myrang) { 461 | /* hardwire to IPV4 for now */ 462 | return IP_V4; 463 | } 464 | 465 | /* 466 | * complex conversions (return void, set values through pointers * 467 | */ 468 | void IP_addr_b2v4(ip_addr_t *addrptr, unsigned *address) { 469 | *address = IP_addr_b2v4_addr(addrptr); 470 | } 471 | 472 | void IP_pref_b2v4(ip_prefix_t *prefptr, 473 | unsigned int *prefix, 474 | unsigned int *prefix_length) 475 | { 476 | *prefix = IP_addr_b2v4_addr( &(prefptr->ip)); 477 | *prefix_length = IP_pref_b2v4_len(prefptr); 478 | } 479 | 480 | 481 | 482 | void IP_pref_b2v6(ip_prefix_t *prefptr, 483 | ip_v6word_t *high, 484 | ip_v6word_t *low, 485 | unsigned int *prefix_length) 486 | { 487 | *high = IP_addr_b2v6_hi( &(prefptr->ip)); 488 | *low = IP_addr_b2v6_lo( &(prefptr->ip)); 489 | *prefix_length = IP_pref_b2v6_len(prefptr); 490 | } 491 | 492 | 493 | void IP_rang_b2v4(ip_range_t *myrang, 494 | unsigned *begin, 495 | unsigned *end) 496 | { 497 | *begin = IP_addr_b2v4_addr( &(myrang->begin)); 498 | *end = IP_addr_b2v4_addr( &(myrang->end)); 499 | } 500 | 501 | 502 | 503 | /******** construct from raw values **********/ 504 | 505 | /******** address **********/ 506 | er_ret_t IP_addr_v4_mk(ip_addr_t *addrptr, 507 | unsigned addrval) { 508 | addrptr->space = IP_V4; 509 | addrptr->words[0] = addrval; 510 | addrptr->words[1] = addrptr->words[2] = addrptr->words[3] = 0; 511 | 512 | /* no real possibility of checking the syntax */ 513 | return IP_OK; 514 | } 515 | 516 | er_ret_t IP_addr_v6_mk(ip_addr_t *addrptr, 517 | ip_v6word_t high, 518 | ip_v6word_t low) { 519 | 520 | ip_v6word_t ff = 0xffffffff; 521 | 522 | addrptr->space = IP_V6; 523 | (addrptr->words[0]) = (high >> 32) & ff; 524 | (addrptr->words[1]) = high & ff ; 525 | (addrptr->words[2]) = (low >> 32) & ff; 526 | (addrptr->words[3]) = low & ff; 527 | 528 | /* no real possibility of checking the syntax */ 529 | return IP_OK; 530 | } 531 | 532 | /******** prefix **********/ 533 | er_ret_t IP_pref_v4_mk(ip_prefix_t *prefix, 534 | unsigned prefval, 535 | unsigned preflen) 536 | { 537 | if( preflen > 32 ) { 538 | die; 539 | } 540 | IP_addr_v4_mk(&(prefix->ip), prefval); 541 | prefix->bits = preflen; 542 | 543 | IP_pref_bit_fix( prefix ); /* never produce inconsistent prefixes */ 544 | 545 | return IP_OK; 546 | } 547 | 548 | /******** range **********/ 549 | er_ret_t IP_rang_v4_mk(ip_range_t *rangptr, 550 | unsigned addrbegin, 551 | unsigned addrend) 552 | { 553 | er_ret_t err; 554 | 555 | if( (err=IP_addr_v4_mk( &(rangptr->begin), addrbegin)) == IP_OK ) { 556 | err=IP_addr_v4_mk( &(rangptr->end), addrend); 557 | } 558 | return err; 559 | } 560 | 561 | /**************************************************************************/ 562 | 563 | 564 | /**************************************************************************/ 565 | /*+ a2v4 == functions to convert the ascii representation into binary, 566 | * and then set the unsigned values at the pointers provided. 567 | * 568 | +*/ 569 | 570 | /* Convert route string into numbers */ 571 | /* ipv4 */ 572 | er_ret_t 573 | IP_pref_a2v4(char *avalue, ip_prefix_t *pref, 574 | unsigned *prefix, unsigned *prefix_length) 575 | { 576 | 577 | er_ret_t ret; 578 | 579 | if((ret = IP_pref_e2b(pref, avalue)) == IP_OK) { 580 | IP_pref_b2v4(pref, prefix, prefix_length); 581 | } 582 | return(ret); 583 | } 584 | 585 | /* ipv6 */ 586 | er_ret_t 587 | IP_pref_a2v6(char *avalue, ip_prefix_t *pref, 588 | ip_v6word_t *high, ip_v6word_t *low, 589 | unsigned *prefix_length) 590 | { 591 | er_ret_t ret; 592 | 593 | if((ret = IP_pref_e2b(pref, avalue)) == IP_OK) { 594 | IP_pref_b2v6(pref, high, low, prefix_length); 595 | } 596 | return(ret); 597 | } 598 | 599 | /* Convert reverse domain string into numbers */ 600 | er_ret_t 601 | IP_revd_a2v4(char *avalue, ip_prefix_t *pref, 602 | unsigned int *prefix, unsigned int *prefix_length) 603 | { 604 | er_ret_t ret; 605 | 606 | if((ret = IP_revd_e2b(pref, avalue)) == IP_OK) { 607 | IP_pref_b2v4(pref, prefix, prefix_length); 608 | } 609 | return(ret); 610 | } 611 | 612 | /* Convert ip addr string into numbers */ 613 | er_ret_t 614 | IP_addr_a2v4(char *avalue,ip_addr_t *ipaddr, unsigned int *address) 615 | { 616 | er_ret_t ret; 617 | 618 | if((ret = IP_addr_e2b(ipaddr, avalue)) == IP_OK) { 619 | IP_addr_b2v4(ipaddr, address); 620 | } 621 | return(ret); 622 | } 623 | 624 | /* Convert inetnum attribute into numbers */ 625 | er_ret_t 626 | IP_rang_a2v4(char *rangstr, ip_range_t *myrang, 627 | unsigned int *begin_in, unsigned int *end_in) 628 | { 629 | er_ret_t ret; 630 | 631 | if( (ret=IP_rang_e2b(myrang, rangstr)) == IP_OK ) { 632 | #if 0 /* no IPv4 classful ranges anymore */ 633 | if( IP_addr_e2b( &(myrang->begin), rangstr ) == IP_OK ) 634 | if ((ret=IP_rang_classful( myrang , &(myrang->begin))) == IP_OK ) 635 | ; 636 | #endif 637 | IP_rang_b2v4(myrang, begin_in, end_in); 638 | } 639 | 640 | return (ret); 641 | } 642 | 643 | 644 | /* ********************************************************************* 645 | f2b - free numbers represented in ascii into a binary struct 646 | ********************************************************************* */ 647 | 648 | er_ret_t 649 | IP_addr_f2b_v4(ip_addr_t *addrptr, char *adrstr) 650 | { 651 | unsigned address; 652 | 653 | if( ut_dec_2_uns(adrstr, &address) < 0 ) { 654 | return IP_INVARG; 655 | } 656 | 657 | return IP_addr_v4_mk(addrptr, address); 658 | } 659 | 660 | er_ret_t 661 | IP_rang_f2b_v4(ip_range_t *rangptr, char *beginstr, char *endstr) 662 | { 663 | if( IP_addr_f2b_v4( &(rangptr->begin), beginstr) != IP_OK 664 | || IP_addr_f2b_v4( &(rangptr->end), endstr) != IP_OK) { 665 | return IP_INVARG; 666 | } 667 | else { 668 | return IP_OK; 669 | } 670 | } 671 | 672 | er_ret_t 673 | IP_pref_f2b_v4(ip_prefix_t *prefptr, char *prefixstr, char *lengthstr) 674 | { 675 | if( IP_addr_f2b_v4( &(prefptr->ip), prefixstr) != IP_OK 676 | || ut_dec_2_uns(lengthstr, &(prefptr->bits) ) < 0 677 | || prefptr->bits > IP_sizebits(prefptr->ip.space)) { 678 | return IP_INVARG; 679 | } 680 | IP_pref_bit_fix(prefptr); /* never create broken binary prefixes. */ 681 | return IP_OK; 682 | } 683 | 684 | 685 | er_ret_t 686 | IP_addr_f2b_v6(ip_addr_t *addrptr, char *msbstr, char *lsbstr ) 687 | { 688 | ip_v6word_t high, low; 689 | 690 | if( sscanf(msbstr, "%llu", &high) < 1 || 691 | sscanf(lsbstr, "%llu", &low) < 1 ) { 692 | return IP_INVARG; 693 | } 694 | 695 | return IP_addr_v6_mk(addrptr, high, low); 696 | } 697 | 698 | 699 | er_ret_t 700 | IP_pref_f2b_v6(ip_prefix_t *prefptr, char *msbstr, char *lsbstr, char *lengthstr) 701 | { 702 | if( IP_addr_f2b_v6( &(prefptr->ip), msbstr, lsbstr ) != IP_OK 703 | || ut_dec_2_uns(lengthstr, &(prefptr->bits) ) < 0 704 | || prefptr->bits > IP_sizebits(prefptr->ip.space)) { 705 | return IP_INVARG; 706 | } 707 | IP_pref_bit_fix(prefptr); /* never create broken binary prefixes. */ 708 | return IP_OK; 709 | } 710 | 711 | 712 | /**************************************************************************/ 713 | /*+ convert the socket's idea of address into a binary range struct. 714 | 715 | space select the address type (and consequently struct type) 716 | */ 717 | 718 | er_ret_t 719 | IP_addr_s2b(ip_addr_t *addrptr, 720 | void *addr_in, 721 | int addr_len) 722 | { 723 | if( addr_len == sizeof(struct sockaddr_in) 724 | && ((struct sockaddr_in *)addr_in)->sin_family == AF_INET ) { 725 | addrptr->space = IP_V4; 726 | addrptr->words[0] = 727 | ntohl( ((struct sockaddr_in*)addr_in)->sin_addr.s_addr); 728 | 729 | /* set remaining limbs to zero */ 730 | addrptr->words[1] = addrptr->words[2] = addrptr->words[3] = 0; 731 | 732 | } 733 | else { /* unsupported family or invalid struct */ 734 | die; 735 | } 736 | return IP_OK; 737 | } 738 | 739 | /**************************************************************************/ 740 | /*+converts the IP binary address (binaddr) to a string (ascaddr) 741 | of at most strmax characters. Independent of the result 742 | (success or failure) it messes up the string. 743 | +*/ 744 | er_ret_t 745 | IP_addr_b2a( ip_addr_t *binaddr, char *ascaddr, int strmax ) 746 | { 747 | 748 | if(binaddr->space == IP_V4) { 749 | if (snprintf(ascaddr, strmax, "%d.%d.%d.%d", 750 | ((binaddr->words[0]) & ((unsigned)0xff<<24))>>24, 751 | ((binaddr->words[0]) & (0xff<<16))>>16, 752 | ((binaddr->words[0]) & (0xff<<8))>>8, 753 | ((binaddr->words[0]) & (0xff<<0))>>0 754 | ) >= strmax) { 755 | /*die; */ /* string too short */ 756 | return IP_TOSHRT; 757 | } 758 | } 759 | else { 760 | /* IPv6 */ 761 | 762 | if( inet_ntop(AF_INET6, &(binaddr->words[0]), ascaddr, strmax) 763 | == NULL ) { 764 | return IP_TOSHRT; 765 | } 766 | 767 | /* not yet implemented. Sorry. */ 768 | /* die; */ 769 | /*return IP_NO6YET;*/ 770 | } 771 | return IP_OK; 772 | } 773 | 774 | /**************************************************************************/ 775 | 776 | /*+ convert a binary prefix back into ascii string at most strmax chars long 777 | +*/ 778 | er_ret_t 779 | IP_pref_b2a(ip_prefix_t *prefptr, char *ascaddr, int strmax) 780 | { 781 | int strl; 782 | er_ret_t err; 783 | 784 | if( (err=IP_addr_b2a (&(prefptr->ip), ascaddr, strmax)) != IP_OK) { 785 | /*die; */ /* what the hell */ 786 | return err; 787 | } 788 | strl = strlen(ascaddr); 789 | strmax -= strl; 790 | 791 | /* now strmax holds the space that is left */ 792 | 793 | if( snprintf(ascaddr+strl, strmax, "/%d", prefptr->bits) >= strmax) { 794 | /* die; */ /* error: string too short */ 795 | return IP_TOSHRT; 796 | } 797 | return IP_OK; 798 | } 799 | 800 | 801 | 802 | /**************************************************************************/ 803 | /*+ convert a binary range back into ascii string at most strmax chars long 804 | +*/ 805 | er_ret_t 806 | IP_rang_b2a(ip_range_t *rangptr, char *ascaddr, int strmax) 807 | { 808 | int strl=0, strleft; 809 | er_ret_t err; 810 | 811 | strleft = strmax - strl; 812 | if( (err=IP_addr_b2a (&(rangptr->begin), ascaddr, strleft)) != IP_OK) { 813 | return err; 814 | } 815 | strl = strlen(ascaddr); 816 | 817 | strleft = strmax - strl; 818 | if( strleft < 5 ) { 819 | return IP_TOSHRT; 820 | } 821 | strcat( ascaddr, " - " ); 822 | strl += 3; 823 | 824 | strleft = strmax - strl; 825 | if( (err=IP_addr_b2a (&(rangptr->end), ascaddr+strl, strleft)) != IP_OK) { 826 | return err; 827 | } 828 | 829 | return IP_OK; 830 | } 831 | 832 | /**************************************************************************/ 833 | /*+ return the bitnum bit of the address, 834 | COUNTING FROM THE TOP !!!!! , 835 | starting with 0 for the *most significant bit*. 836 | +*/ 837 | int 838 | IP_addr_bit_get(ip_addr_t *binaddr, int bitnum) { 839 | int bitval; 840 | int w,c; 841 | 842 | /* avoid unnecessary division */ 843 | if( binaddr->space == IP_V4 ) { 844 | w = 0; 845 | c = bitnum; 846 | } 847 | else { 848 | w = bitnum / 32; 849 | c = bitnum % 32; 850 | } 851 | 852 | bitval = (binaddr->words[w] & (0x80000000 >> (c))); 853 | 854 | return (bitval != 0); 855 | 856 | } 857 | 858 | /**************************************************************************/ 859 | /*+ set the bitnum bit of the address to bitval, 860 | COUNTING FROM THE TOP !!!!! , 861 | starting with 0 for the *most significant bit*. 862 | +*/ 863 | void 864 | IP_addr_bit_set(ip_addr_t *binaddr, int bitnum, int bitval) { 865 | int w,c; 866 | 867 | /* avoid unnecessary division */ 868 | if( binaddr->space == IP_V4 ) { 869 | w = 0; 870 | c = bitnum; 871 | } 872 | else { 873 | w = bitnum / 32; 874 | c = bitnum % 32; 875 | } 876 | 877 | if ( bitval == 1 ) 878 | 879 | binaddr->words[w] |= (0x80000000 >> (c)); 880 | else 881 | binaddr->words[w] &= ~(0x80000000 >> (c)); 882 | } 883 | /**************************************************************************/ 884 | 885 | /*+ this fixes a prefix by setting insignificant bits to 0 +*/ 886 | void 887 | IP_pref_bit_fix( ip_prefix_t *prefix ) 888 | { 889 | 890 | if( prefix->ip.space == IP_V4 ) { 891 | ip_limb_t mask = 0xffffffff; 892 | 893 | /* shorthand for ipv4 */ 894 | 895 | /* Shifting out by 32 bits does NOT turn all bits into 0... */ 896 | if( prefix->bits < 32 ) { 897 | prefix->ip.words[0] &= ~(mask >> prefix->bits); 898 | } 899 | } 900 | else { 901 | int i; 902 | for(i=prefix->bits; i < IP_sizebits(prefix->ip.space) ; i++) { 903 | IP_addr_bit_set( & prefix->ip, i, 0); 904 | } 905 | } 906 | } 907 | 908 | 909 | /**************************************************************************/ 910 | 911 | /*+ compares two IP addresses up to the bit # len, 912 | returns 0 if equal, 1 if ptra greater, -1 if ptrb greater. 913 | 914 | It is the responsility of the caller to ensure that both addresses 915 | are from the same IP space. 916 | 917 | This is pretty slow; it is used in the searches of the radix tree, 918 | so it might be good to optimise this. 919 | +*/ 920 | 921 | int 922 | IP_addr_cmp(ip_addr_t *ptra, ip_addr_t *ptrb, int len) 923 | { 924 | int a,b,i; 925 | 926 | for(i=0; i<len; i++) { 927 | a=IP_addr_bit_get(ptra, i); 928 | b=IP_addr_bit_get(ptrb, i); 929 | if( a != b ) { 930 | if( a > b ) return 1; 931 | else return -1; 932 | } 933 | } 934 | return 0; 935 | } 936 | 937 | 938 | /*+ checks if an IP address is contained within the prefix 939 | returns 1 if it is, 0 otherwise 940 | 941 | It is the responsility of the caller to ensure that both address 942 | and prefix are from the same IP space. 943 | +*/ 944 | int 945 | IP_addr_in_pref(ip_addr_t *ptra, ip_prefix_t *prefix) 946 | { 947 | return (IP_addr_cmp( ptra, & prefix->ip, prefix->bits) == 0); 948 | } 949 | 950 | /*+ checks if an IP address is contained within the range 951 | returns 1 if it is, 0 otherwise 952 | 953 | It is the responsility of the caller to ensure that both address 954 | and range are from the same IP space. 955 | 956 | works only for IPv4 957 | +*/ 958 | 959 | int IP_addr_in_rang(ip_addr_t *ptra, ip_range_t *rangptr) 960 | { 961 | /* if( rangptr->end.space == IP_V4 ) { 962 | return ( rangptr->begin.words[0] <= ptra->words[0] 963 | && rangptr->end.words[0] >= ptra->words[0] ); 964 | } 965 | else { 966 | */ 967 | return( IP_addr_cmp(ptra, &rangptr->begin, 968 | IP_sizebits(rangptr->end.space)) >= 0 /* adr >= begin */ 969 | && IP_addr_cmp(ptra, &rangptr->end, 970 | IP_sizebits(rangptr->end.space)) <= 0 /* adr <= end */ 971 | ); 972 | /* }*/ 973 | } 974 | 975 | /**************************************************************************/ 976 | 977 | /*+ calculate the span of a range == size - 1 +*/ 978 | 979 | ip_rangesize_t 980 | IP_rang_span( ip_range_t *rangptr ) 981 | { 982 | /* IPv4: */ 983 | dieif( rangptr->end.space != IP_V4 ); 984 | 985 | return rangptr->end.words[0] - rangptr->begin.words[0]; 986 | } 987 | 988 | 989 | /**************************************************************************/ 990 | 991 | /*+ 992 | this is a shorthand notation to pull out the first word of the address. 993 | it is defined for the scope od the following functions 994 | +*/ 995 | #define ad(which) (rangptr->which) 996 | 997 | /**************************************************************************/ 998 | /*+ Decomposes a binary range into prefixes and appends them to the list. 999 | Allocates prefix structures and list elements, they must be freed 1000 | after use. 1001 | 1002 | returns a bitmask of prefix lengths used. 1003 | +*/ 1004 | unsigned 1005 | IP_rang_decomp(ip_range_t *rangptr, GList **preflist) 1006 | { 1007 | unsigned prefmask=0; 1008 | register int slash=0; 1009 | register unsigned c_dif, blk, ff; 1010 | ip_range_t workrange; 1011 | ip_addr_t workbegin; 1012 | ip_addr_t workend; 1013 | ip_prefix_t *prefptr; 1014 | 1015 | dieif( rangptr->begin.space != IP_V4 ); 1016 | 1017 | if( ad(begin).words[0] > ad(end).words[0] ) { /* has gone too far */ 1018 | return 0; 1019 | } 1020 | 1021 | if( ad(begin).words[0] == ad(end).words[0] ) { /* an IP == a /32 (IPv4) */ 1022 | prefmask |= 1; 1023 | if( wr_calloc( (void **)& prefptr, sizeof(ip_prefix_t), 1) != UT_OK) { 1024 | die; 1025 | } 1026 | prefptr->ip = ad(begin); 1027 | prefptr->bits = 32; 1028 | 1029 | *preflist = g_list_append( *preflist, prefptr ); 1030 | 1031 | return prefmask; 1032 | } 1033 | 1034 | c_dif = ad(end).words[0] - ad(begin).words[0]; 1035 | 1036 | /* initialize work vars */ 1037 | 1038 | workbegin = ad(begin); 1039 | workend = ad(end); 1040 | 1041 | /* now find the biggest block fitting in this range */ 1042 | /* i.e. the first 2^n number smaller than c_dif */ 1043 | 1044 | /* the loop would not work for /0 (some stupid queries may have that) */ 1045 | /* so this must be checked for separately */ 1046 | 1047 | if( c_dif == 0xffffffff ) { 1048 | /* they are already set to 0.0.0.0 - 255.255.255.255 */ 1049 | /* leave them alone. */ 1050 | blk = 0; 1051 | slash = 0; 1052 | } 1053 | else { 1054 | 1055 | c_dif += 1; /* was not done earlier to protect from overflow */ 1056 | 1057 | for(slash=1; 1058 | slash<32 && ((blk=((unsigned)0x80000000>>(slash-1))) & c_dif) == 0; 1059 | slash++) {} 1060 | 1061 | /* clear all digits in a and b under the blk one. */ 1062 | ff=blk-1; 1063 | 1064 | workbegin.words[0] = (workbegin.words[0] + ff) & ~ff; 1065 | 1066 | workend.words[0] = (workend.words[0] + 1) & ~ff; 1067 | } 1068 | 1069 | if( workbegin.words[0] != workend.words[0] ) { 1070 | prefmask |= blk; 1071 | if( wr_malloc( (void **)& prefptr, sizeof(ip_prefix_t)) != UT_OK) { 1072 | die; 1073 | } 1074 | prefptr->ip = workbegin; 1075 | prefptr->bits = slash; 1076 | 1077 | *preflist = g_list_append( *preflist, prefptr ); 1078 | } 1079 | 1080 | if( ad(begin).words[0] != workbegin.words[0] ) { 1081 | workrange.begin = ad(begin); 1082 | 1083 | workbegin.words[0] -= 1; 1084 | workrange.end = workbegin; 1085 | 1086 | prefmask |= IP_rang_decomp( &workrange, preflist ); 1087 | } 1088 | 1089 | /* here we must protect from decomposition of 1090 | * 255.255.255.255 - 255.255.255.255 in case the range 1091 | * 0.0.0.0 - 255.255.255.255 is considered. Hence the slash>0 condition. 1092 | */ 1093 | 1094 | if( workend.words[0] <= ad(end).words[0] && slash > 0) { 1095 | workrange.begin = workend; 1096 | workrange.end = ad(end); 1097 | 1098 | prefmask |= IP_rang_decomp( &workrange, preflist ); 1099 | } 1100 | 1101 | return prefmask; 1102 | 1103 | } 1104 | 1105 | 1106 | /***************************************************************************/ 1107 | 1108 | /*+ Similar name, slightly different code, totally different functionality. 1109 | 1110 | finds the smallest canonical block encompassing the whole given range, 1111 | then MODIFIES the range pointed to by the argument 1112 | so that it's equal to this block. 1113 | 1114 | +*/ 1115 | 1116 | void IP_rang_encomp(ip_range_t *rangptr) 1117 | { 1118 | int slash=0; 1119 | unsigned c_dif, blk, ff, t_dif; 1120 | ip_addr_t workbegin; 1121 | ip_addr_t workend; 1122 | 1123 | dieif( rangptr->begin.space != IP_V4 ); 1124 | 1125 | c_dif = ad(end).words[0] - ad(begin).words[0]; 1126 | 1127 | /* now find the biggest block fitting in this range */ 1128 | /* i.e. the first 2^n number smaller than c_dif */ 1129 | 1130 | /* the loop would not work for /0 (some stupid queries may have that) */ 1131 | /* so this must be checked for separately */ 1132 | 1133 | if( c_dif > 0x80000000 ) { 1134 | slash = 0; 1135 | ff = 0xffffffff; 1136 | blk = 0; 1137 | 1138 | workbegin = workend = ad(begin); 1139 | workbegin.words[0] = 0; 1140 | workend.words[0] = ff; 1141 | } 1142 | else { 1143 | 1144 | do { 1145 | c_dif += 1; 1146 | 1147 | /* find the smallest block ENCOMPASSING c_dif. */ 1148 | /* this implies a loop from the bottom up */ 1149 | 1150 | for(slash=32; 1151 | slash>1 && (blk=((unsigned)0x80000000>>(slash-1))) < c_dif; 1152 | slash--) {} 1153 | 1154 | ff=blk-1; 1155 | 1156 | /* clear all digits in workbegin under the blk one. */ 1157 | 1158 | workbegin = ad(begin); 1159 | workbegin.words[0] = workbegin.words[0] & ~ff; 1160 | 1161 | /* see if it has not made the difference larger than blk, */ 1162 | /* retry if so */ 1163 | 1164 | t_dif = c_dif; 1165 | c_dif = ad(end).words[0] - workbegin.words[0]; 1166 | 1167 | } while( c_dif >= t_dif ); 1168 | 1169 | /* set the endpoint to workbegin + blocksize - 1 */ 1170 | /* which amounts to + ff */ 1171 | 1172 | workend = ad(begin); 1173 | workend.words[0] = workbegin.words[0] + ff; 1174 | } 1175 | 1176 | 1177 | /* set the range to new values */ 1178 | 1179 | rangptr->begin = workbegin; 1180 | rangptr->end = workend; 1181 | } 1182 | 1183 | /***************************************************************************/ 1184 | /*+ sets a range equal to a prefix +*/ 1185 | 1186 | er_ret_t 1187 | IP_pref_2_rang( ip_range_t *rangptr, ip_prefix_t *prefptr ) 1188 | { 1189 | ip_rangesize_t span; 1190 | int shift; 1191 | int i; 1192 | 1193 | ad(begin) = ad(end) = prefptr->ip; 1194 | 1195 | /* IPv6 is a bit more complicated, as four words are involved */ 1196 | 1197 | /* additional problem: shifting right by >=32 is equal to shifting by 0, 1198 | so it does not change any bits */ 1199 | /* solution: don't touch those words */ 1200 | 1201 | for(i=0; i<4; i++) { 1202 | 1203 | if( prefptr->bits < 32*(1+i) ) { 1204 | shift = prefptr->bits < 32 + (i-1) * 32 1205 | ? 0 : (prefptr->bits % 32) ; 1206 | ad(end).words[i] |= (0xffffffffU >> shift); 1207 | } 1208 | 1209 | if( prefptr->ip.space == IP_V4) { 1210 | break; /* do only first word for IPv4 */ 1211 | } 1212 | } 1213 | return IP_OK; 1214 | } 1215 | 1216 | #undef ad 1217 | 1218 | /***************************************************************************/ 1219 | 1220 | /*+ 1221 | This is to parse a classfull address into a range. 1222 | 1223 | Takes the address by pointer from addrptr and puts the result 1224 | at rangptr. 1225 | 1226 | Throws error if the address does not fall into any of the 1227 | classfull categories 1228 | 1229 | +*/ 1230 | 1231 | er_ret_t 1232 | IP_rang_classful( ip_range_t *rangptr, ip_addr_t *addrptr) 1233 | { 1234 | int i; 1235 | unsigned b[4]; 1236 | 1237 | if( addrptr->space != IP_V4 ) { 1238 | /* it's IPv6. There are no classful ranges or anything like that. */ 1239 | die; 1240 | } 1241 | 1242 | rangptr->begin = *addrptr; 1243 | rangptr->end.space = IP_V4; 1244 | 1245 | /* initisalise end to zero */ 1246 | for(i=0; i<IPLIMBNUM; i++) { 1247 | rangptr->end.words[i] = 0; 1248 | } 1249 | 1250 | /* assume it's at least a valid IP. let's try different classes now */ 1251 | 1252 | /* we could have used a union here, but it would not work on */ 1253 | /* low endians. So byte by byte copying to and from an array. */ 1254 | 1255 | for(i=0; i<4; i++) { 1256 | b[i] = ( rangptr->begin.words[0] & (0xFF << i*8) ) >> i*8; 1257 | } 1258 | 1259 | if( b[3] >= 1 && b[3] < 128 1260 | && b[2] == 0 && b[1] == 0 && b[0] == 0 ) { 1261 | b[2]=b[1]=b[0]=255; 1262 | } 1263 | else if( b[3] >= 128 && b[3] < 192 1264 | && b[1] == 0 && b[0] == 0 ) { 1265 | b[1]=b[0]=255; 1266 | } 1267 | else if( b[3] >= 192 && b[3] < 224 1268 | && b[0] == 0 ) { 1269 | b[0]=255; 1270 | } 1271 | else if( b[3] >= 224 && b[3] < 255 ) { 1272 | /* just leave it, make it a /32, i.e. begin == end */ 1273 | /* EMPTY */; 1274 | } 1275 | else { 1276 | /* Leave it and make it a /32 */ 1277 | /* This is AGAINST the rule! but we have some junk */ 1278 | /* so we have to compensate for it. */ 1279 | /* EMPTY */; 1280 | } 1281 | 1282 | /* copy the (now - modified) bytes into the end of range */ 1283 | for(i=0; i<4; i++) { 1284 | rangptr->end.words[0] |= (b[i] << i*8); 1285 | } 1286 | 1287 | return IP_OK; 1288 | } 1289 | 1290 | 1291 | /***************************************************************************/ 1292 | /*+ 1293 | Trying to be smart :-) and convert a query search term into prefix(es), 1294 | regardless of whether specified as IP address, prefix or range. 1295 | 1296 | justcheck - if just checking the syntax (justcheck == 1), 1297 | then the prefixes are freed before the function returns, 1298 | otherwise it is the responsibility of the caller to free the list. 1299 | 1300 | XXX must make sure all memory is freed if INVARG is returned 1301 | 1302 | +*/ 1303 | 1304 | er_ret_t 1305 | IP_smart_conv(char *key, 1306 | int justcheck, 1307 | int encomp, 1308 | GList **preflist, 1309 | ip_exp_t expf, 1310 | ip_keytype_t *keytype 1311 | ) 1312 | { 1313 | int free_it; 1314 | er_ret_t call_err, err=IP_OK; /* let's be optimistic :-) */ 1315 | ip_prefix_t *querypref; 1316 | 1317 | /* if just checking the syntax (justcheck == 1), 1318 | then free_it = 1, 1319 | else 0, but may be modified later (in range conversion) 1320 | */ 1321 | 1322 | free_it = justcheck; 1323 | 1324 | if( (call_err = wr_malloc( (void **) &querypref, sizeof(ip_prefix_t))) 1325 | != UT_OK) { 1326 | return call_err; 1327 | } 1328 | 1329 | if( IP_pref_t2b(querypref, key, expf) == IP_OK ) { 1330 | *keytype = IPK_PREFIX; 1331 | 1332 | if( justcheck == 0) { 1333 | *preflist = g_list_append(*preflist, querypref); 1334 | } 1335 | } 1336 | else { 1337 | /* not a prefix. */ 1338 | /* Maybe an IP ? */ 1339 | if( IP_addr_t2b( &(querypref->ip), key, expf) == IP_OK ) { 1340 | 1341 | *keytype = IPK_IP; 1342 | 1343 | /*convert to a /32 or /128*/ 1344 | querypref->bits = IP_sizebits(querypref->ip.space); 1345 | 1346 | if( justcheck == 0) { 1347 | *preflist = g_list_append(*preflist, querypref); 1348 | } 1349 | } 1350 | else { 1351 | /* hm, maybe a range then ? */ 1352 | ip_range_t myrang; 1353 | 1354 | /* won't use the querypref anymore, mark it for freeing later */ 1355 | free_it = 1; 1356 | 1357 | if( IP_rang_t2b(&myrang, key, expf) == IP_OK ) { 1358 | /* Wow. Great. */ 1359 | 1360 | *keytype = IPK_RANGE; 1361 | 1362 | /* sometimes (exless match) we look for the first bigger(shorter) */ 1363 | /* prefix containing this range. */ 1364 | 1365 | if( encomp ) { 1366 | IP_rang_encomp(&myrang); 1367 | } 1368 | /* OK, now we can let the engine happily find that there's just one */ 1369 | /* prefix in range */ 1370 | 1371 | if( justcheck == 0) { 1372 | IP_rang_decomp(&myrang, preflist); 1373 | } 1374 | } 1375 | else { 1376 | *keytype = IPK_UNDEF; 1377 | err = IP_INVARG; /* "conversion error" */ 1378 | } 1379 | } 1380 | } 1381 | 1382 | if( free_it ) { 1383 | wr_free(querypref); 1384 | } 1385 | 1386 | return err; 1387 | } 1388 | 1389 | 1390 | /* convert whatever comes into a range */ 1391 | er_ret_t 1392 | IP_smart_range(char *key, 1393 | ip_range_t *rangptr, 1394 | ip_exp_t expf, 1395 | ip_keytype_t *keytype 1396 | ) 1397 | { 1398 | er_ret_t err=IP_OK; 1399 | GList *preflist = NULL; 1400 | 1401 | /* first : is it a range ? */ 1402 | 1403 | if( (err = IP_rang_t2b(rangptr, key, expf)) == IP_OK ) { 1404 | *keytype = IPK_RANGE; 1405 | } 1406 | else { 1407 | /* OK, this must be possible to convert it to prefix and from there 1408 | to a range. */ 1409 | if( (err = IP_smart_conv(key, 0, 0, &preflist, expf, keytype)) 1410 | == IP_OK ) { 1411 | 1412 | dieif( g_list_length(preflist) != 1 ); 1413 | 1414 | dieif(IP_pref_2_rang( rangptr, g_list_first(preflist)->data ) != IP_OK ); 1415 | } 1416 | } 1417 | 1418 | wr_clear_list( &preflist ); 1419 | 1420 | return err; 1421 | } 1422 |