1 | /*************************************** 2 | $Revision: 1.11 $ 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 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 | 50 | /***************************************************************************/ 51 | /*+ return the max. length of bits per space 52 | 53 | Yes, it *could* be a macro - but as a function it can detect 54 | more programmer's errors. And will get inlined anyway. 55 | 56 | +*/ 57 | 58 | int IP_sizebits(ip_space_t spc_id) { 59 | switch (spc_id) { 60 | case IP_V4: 61 | return 32; 62 | case IP_V6: 63 | return 128; 64 | default: 65 | /* die; */ /* error: bad IP version specified */ 66 | return -1; 67 | } 68 | } 69 | 70 | /***************************************************************************/ 71 | /*+ 72 | ascii IP address to binary. 73 | In IP_EXPN mode IP will be treated as not-expanded. 74 | (missing octets will be set to 0, MSB will be set). 75 | In IP_PLAIN mode the routine will complain if it sees less octets. 76 | +*/ 77 | 78 | er_ret_t 79 | IP_addr_t2b(ip_addr_t *ipptr, char *addr, ip_exp_t expf) 80 | { 81 | if( index(addr, ':') == NULL ) { 82 | /* IPv4 */ 83 | char *dot; 84 | unsigned len, byte, result=0; 85 | char cpy[5]; 86 | int last = 0, dotsfound=0; 87 | int bytes=0; 88 | 89 | if( expf != IP_PLAIN && expf != IP_EXPN ) { 90 | return IP_INVARG; 91 | } 92 | 93 | do { 94 | if ( (dot = index (addr, '.')) == NULL) { 95 | dot = index (addr, '\0'); 96 | last = 1; 97 | } 98 | else { 99 | if( ++dotsfound > 3 ) { 100 | /* handle syntax ERROR - too many dots found */ 101 | return IP_INVIP4; 102 | } 103 | } 104 | 105 | if ((len = dot - addr) > 4) { 106 | /* syntax ERROR - too many digits between dots*/ 107 | return IP_INVIP4; 108 | } 109 | strncpy( cpy, addr, len ); 110 | cpy[len]=0; 111 | 112 | /* sscanf is waay too slow */ 113 | 114 | if( ut_dec_2_uns(cpy, &byte) < 0 ) { 115 | /* handle syntax ERROR - invalid characters found */ 116 | return IP_INVIP4; 117 | } 118 | 119 | 120 | if( byte > 255 ) { 121 | /* handle syntax ERROR - number between dots too high */ 122 | return IP_INVIP4; 123 | } 124 | 125 | result <<= 8; 126 | result += byte; 127 | bytes++; 128 | 129 | addr = dot + 1; 130 | } while (!last); 131 | 132 | if( expf == IP_PLAIN ) { 133 | if( bytes!=4 ) { 134 | return IP_INVIP4; 135 | } 136 | } 137 | else { 138 | while( bytes<4 ) { 139 | result <<= 8; 140 | bytes++; 141 | } 142 | } 143 | 144 | memset(ipptr, 0, sizeof(ip_addr_t)); 145 | ipptr->space = IP_V4; 146 | ipptr->words[0] = result; 147 | } 148 | else { 149 | /* IPv6 */ 150 | /* not yet implemented. Sorry. */ 151 | /* die; */ 152 | return IP_NO6YET; 153 | } 154 | return IP_OK; 155 | } 156 | 157 | /***************************************************************************/ 158 | 159 | /*+ converts a "IP/length" string into a binary prefix 160 | +*/ 161 | er_ret_t 162 | IP_pref_t2b(ip_prefix_t *prefptr, char *prefstr, ip_exp_t expf) 163 | { 164 | char ip[256]; 165 | char *slash, *trash; 166 | int len; 167 | er_ret_t err; 168 | 169 | if( expf != IP_PLAIN && expf != IP_EXPN ) { 170 | return IP_INVARG; 171 | } 172 | 173 | if( (slash=index(prefstr, '/')) == NULL ) { 174 | /* die; */ /* error: missing slash in prefix */ 175 | return IP_NOSLAS; 176 | } 177 | else { 178 | /* copy the IP part to another string, ERROR if 256 chars is not nough */ 179 | 180 | len = slash - prefstr; 181 | if( len > 255 ) { 182 | /* die; */ /* ERROR - ip address part of the string too long. */ 183 | return IP_ADTOLO; 184 | } 185 | strncpy(ip, prefstr, len); 186 | ip[len]=0; 187 | 188 | if( (err=IP_addr_t2b( &(prefptr->ip), ip, expf)) != IP_OK) { 189 | /* die; */ /* set error flag: incorrect address format */ 190 | return err; 191 | } 192 | 193 | /* stop at first non-digit */ 194 | for(trash = slash+1; isdigit(*trash) ; trash++); 195 | len = trash - (slash+1) ; 196 | if( len > 4 ) { 197 | /* die; */ /* ERROR - prefix length part of the string too long. */ 198 | return IP_PRTOLO; 199 | } 200 | strncpy(ip, slash+1, len); 201 | ip[len]=0; 202 | 203 | if( ut_dec_2_uns(ip, &prefptr->bits) < 0 ) { 204 | 205 | /* if( sscanf (slash+1, "%d", &(prefptr->bits)) < 1 ) { 206 | die; */ /* handle syntax ERROR invalid characters found */ 207 | return IP_INVPRF; 208 | } 209 | } 210 | /* sanitify the prefix - maybe some irrelevant bits are set */ 211 | /* never create broken binary prefixes. */ 212 | 213 | IP_pref_bit_fix(prefptr); 214 | 215 | return IP_OK; 216 | } 217 | 218 | /***************************************************************************/ 219 | 220 | /*+ convert a range string into a binary range struct. 221 | +*/ 222 | er_ret_t 223 | IP_rang_t2b(ip_range_t *rangptr, char *rangstr, ip_exp_t expf) 224 | { 225 | char *ips, *dash; 226 | er_ret_t err; 227 | 228 | if( expf != IP_PLAIN && expf != IP_EXPN ) { 229 | return IP_INVARG; 230 | } 231 | 232 | if( (dash=index(rangstr, '-')) == NULL ) { 233 | /* die; */ /* error: missing dash in range */ 234 | return IP_INVRAN; 235 | } 236 | else { 237 | /* copy the first IP */ 238 | if( (err = wr_calloc( (void*) &ips,1,dash - rangstr + 1)) != UT_OK ) { 239 | return err; 240 | } 241 | 242 | strncpy(ips, rangstr, dash - rangstr); 243 | 244 | /* convert the first IP into a binary struct */ 245 | err=IP_addr_t2b( &(rangptr->begin), ips, expf); 246 | 247 | /* check later */ /* set error flag: incorrect address format */ 248 | 249 | wr_free(ips); 250 | 251 | if( err != IP_OK ) { 252 | return err; 253 | } 254 | 255 | /* now find the other ip, skip the space */ 256 | ips=dash+1; 257 | while( *ips == ' ' ) { 258 | ips++; 259 | } 260 | 261 | /* convert the second IP into a binary struct */ 262 | if( (err=IP_addr_t2b( &(rangptr->end), ips, expf)) != IP_OK ) { 263 | /* die; */ /* incorrect address format */ 264 | return err; 265 | } 266 | 267 | if( rangptr->begin.space != rangptr->end.space ) { 268 | /* die; */ /* incompatible IP spaces */ 269 | return IP_INVRAN; 270 | } 271 | 272 | return IP_OK; 273 | } 274 | } 275 | 276 | /***************************************************************************/ 277 | /*+ convert the socket's idea of address into a binary range struct. 278 | 279 | space select the address type (and consequently struct type) 280 | */ 281 | 282 | er_ret_t 283 | IP_addr_s2b(ip_addr_t *addrptr, 284 | void *addr_in, 285 | int addr_len) 286 | { 287 | if( addr_len == sizeof(struct sockaddr_in) 288 | && ((struct sockaddr_in *)addr_in)->sin_family == AF_INET ) { 289 | addrptr->space = IP_V4; 290 | addrptr->words[0] = 291 | ntohl( ((struct sockaddr_in*)addr_in)->sin_addr.s_addr); 292 | 293 | addrptr->words[1] = addrptr->words[2] = addrptr->words[3] = 0; 294 | } 295 | else { /* unsupported family or invalid struct */ 296 | die; 297 | } 298 | return IP_OK; 299 | } 300 | 301 | 302 | /*+converts the IP binary address (binaddr) to a string (ascaddr) 303 | of at most strmax characters. Independent of the result 304 | (success or failure) it messes up the string. 305 | +*/ 306 | er_ret_t 307 | IP_addr_b2a( ip_addr_t *binaddr, char *ascaddr, int strmax ) 308 | { 309 | 310 | if(binaddr->space == IP_V4) { 311 | if (snprintf(ascaddr, strmax, "%d.%d.%d.%d", 312 | ((binaddr->words[0]) & ((unsigned)0xff<<24))>>24, 313 | ((binaddr->words[0]) & (0xff<<16))>>16, 314 | ((binaddr->words[0]) & (0xff<<8))>>8, 315 | ((binaddr->words[0]) & (0xff<<0))>>0 316 | ) >= strmax) { 317 | /*die; */ /* string too short */ 318 | return IP_TOSHRT; 319 | } 320 | 321 | #if 0 322 | char buf[5]; 323 | int mask; 324 | 325 | *ascaddr = '\0'; 326 | 327 | /* this is very inefficient - but maybe this is the way to go for IPv6 */ 328 | 329 | for(mask=24; mask >= 0; mask -= 8) { 330 | 331 | sprintf(buf, "%d%s", ((binaddr->words[0]) & 0xff<<mask)>>mask, 332 | mask==0 ? "" : "."); 333 | if( (strlen(buf)+strlen(ascaddr)) >= strmax ) { 334 | /* die; */ /* error: insufficient space */ 335 | return IP_TOSHRT; 336 | } 337 | else { 338 | strcat(ascaddr, buf); 339 | } 340 | } 341 | 342 | #endif 343 | 344 | } 345 | else { 346 | /* IPv6 */ 347 | /* not yet implemented. Sorry. */ 348 | /* die; */ 349 | return IP_NO6YET; 350 | } 351 | return IP_OK; 352 | } 353 | 354 | /***************************************************************************/ 355 | 356 | /*+ convert a binary prefix back into ascii string at most strmax chars long 357 | +*/ 358 | er_ret_t 359 | IP_pref_b2a(ip_prefix_t *prefptr, char *ascaddr, int strmax) 360 | { 361 | int strl; 362 | er_ret_t err; 363 | 364 | if( (err=IP_addr_b2a (&(prefptr->ip), ascaddr, strmax)) != IP_OK) { 365 | /*die; */ /* what the hell */ 366 | return err; 367 | } 368 | strl = strlen(ascaddr); 369 | strmax -= strl; 370 | 371 | /* now strmax holds the space that is left */ 372 | 373 | if( snprintf(ascaddr+strl, strmax, "/%d", prefptr->bits) >= strmax) { 374 | /* die; */ /* error: string too short */ 375 | return IP_TOSHRT; 376 | } 377 | return IP_OK; 378 | } 379 | 380 | 381 | 382 | /***************************************************************************/ 383 | /*+ convert a binary range back into ascii string at most strmax chars long 384 | +*/ 385 | er_ret_t 386 | IP_rang_b2a(ip_range_t *rangptr, char *ascaddr, int strmax) 387 | { 388 | int strl=0, strleft; 389 | er_ret_t err; 390 | 391 | strleft = strmax - strl; 392 | if( (err=IP_addr_b2a (&(rangptr->begin), ascaddr, strleft)) != IP_OK) { 393 | return err; 394 | } 395 | strl = strlen(ascaddr); 396 | 397 | strleft = strmax - strl; 398 | if( strleft < 5 ) { 399 | return IP_TOSHRT; 400 | } 401 | strcat( ascaddr, " - " ); 402 | strl += 3; 403 | 404 | strleft = strmax - strl; 405 | if( (err=IP_addr_b2a (&(rangptr->end), ascaddr+strl, strleft)) != IP_OK) { 406 | return err; 407 | } 408 | 409 | return IP_OK; 410 | } 411 | 412 | /***************************************************************************/ 413 | /*+ return the bitnum bit of the address, 414 | COUNTING FROM THE TOP !!!!! , 415 | starting with 0 for the *most significant bit*. 416 | +*/ 417 | int 418 | IP_addr_bit_get(ip_addr_t *binaddr, int bitnum) { 419 | register int bitval; 420 | 421 | /* IPv4 is easy... */ 422 | bitval = (binaddr->words[0] & (0x80000000 >> (bitnum))); 423 | 424 | return (bitval != 0); 425 | 426 | } 427 | 428 | /***************************************************************************/ 429 | /*+ set the bitnum bit of the address to bitval, 430 | COUNTING FROM THE TOP !!!!! , 431 | starting with 0 for the *most significant bit*. 432 | +*/ 433 | void 434 | IP_addr_bit_set(ip_addr_t *binaddr, int bitnum, int bitval) { 435 | 436 | /* IPv4 is easy... */ 437 | if ( bitval == 1 ) 438 | binaddr->words[0] |= (0x80000000 >> (bitnum)); 439 | else 440 | binaddr->words[0] &= ~(0x80000000 >> (bitnum)); 441 | } 442 | /***************************************************************************/ 443 | 444 | /*+ this fixes a prefix by setting insignificant bits to 0 +*/ 445 | void 446 | IP_pref_bit_fix( ip_prefix_t *prefix ) 447 | { 448 | 449 | unsigned mask=0xffffffff; 450 | 451 | /* shorthand for ipv4 */ 452 | 453 | /* Shifting out by 32 bits does NOT turn all bits into 0... */ 454 | if( prefix->bits < 32 ) { 455 | prefix->ip.words[0] &= ~(mask >> prefix->bits); 456 | } 457 | 458 | #if 0 459 | int i; 460 | for(i=prefix->bits; i < IP_sizebits(prefix->ip.space) ; i++) { 461 | IP_addr_bit_set( & prefix->ip, i, 0); 462 | } 463 | #endif 464 | 465 | 466 | } 467 | 468 | /***************************************************************************/ 469 | 470 | 471 | /*+ 472 | This is a hook function for use with g_list_foreach, to print a list 473 | of prefixes 474 | +*/ 475 | 476 | void ip_print_prefix(void *dataptr, void *junk) { 477 | char ascpref[IP_PREFSTR_MAX]; 478 | ip_prefix_t *binpref=dataptr; 479 | 480 | IP_pref_b2a( binpref, ascpref, IP_PREFSTR_MAX ); 481 | printf ("prefix: %s\n", ascpref); 482 | } 483 | 484 | 485 | /***************************************************************************/ 486 | 487 | /*+ compares two IP addresses up to the bit # len, 488 | returns 0 if equal, 1 if ptra greater, -1 if ptrb greater. 489 | 490 | It is the responsility of the caller to ensure that both addresses 491 | are from the same IP space. 492 | +*/ 493 | 494 | int 495 | IP_addr_cmp(ip_addr_t *ptra, ip_addr_t *ptrb, int len) 496 | { 497 | int a,b,i; 498 | 499 | for(i=0; i<len; i++) { 500 | a=IP_addr_bit_get(ptra, i); 501 | b=IP_addr_bit_get(ptrb, i); 502 | if( a != b ) { 503 | if( a > b ) return 1; 504 | else return -1; 505 | } 506 | } 507 | return 0; 508 | } 509 | 510 | 511 | 512 | 513 | 514 | /***************************************************************************/ 515 | 516 | /*+ 517 | this is a shorthand notation to pull out the first word of the address. 518 | it is defined for the scope od the following functions 519 | +*/ 520 | #define ad(which) (rangptr->which) 521 | 522 | /***************************************************************************/ 523 | /*+ calculate the span of a range == size - 1 +*/ 524 | 525 | ip_rangesize_t 526 | /* ottrey 30/12/1999 527 | IP_rang_span( ip_range_t *rangptr ) 528 | */ 529 | IP_rang_span( ip_range_t rangptr ) 530 | { 531 | /* IPv4: */ 532 | /* ottrey 30/12/1999 533 | return ad(end).words[0] - ad(begin).words[0]; 534 | */ 535 | return rangptr.end.words[0] - rangptr.begin.words[0]; 536 | } 537 | 538 | /***************************************************************************/ 539 | 540 | /*+ Decomposes a binary range into prefixes and appends them to the list. 541 | Allocates prefix structures and list elements, they must be freed after use. 542 | 543 | returns a bitmask of prefix lengths used. 544 | +*/ 545 | 546 | unsigned 547 | IP_rang_decomp(ip_range_t *rangptr, GList **preflist) 548 | { 549 | unsigned prefmask=0; 550 | register int slash=0; 551 | register unsigned c_dif, blk, ff; 552 | ip_range_t workrange; 553 | ip_addr_t workbegin; 554 | ip_addr_t workend; 555 | ip_prefix_t *prefptr; 556 | 557 | if( ad(begin).words[0] > ad(end).words[0] ) { /* has gone too far */ 558 | return 0; 559 | } 560 | 561 | if( ad(begin).words[0] == ad(end).words[0] ) { /* one IP, i.e. /32 for IPv4 */ 562 | prefmask |= 1; 563 | if( wr_calloc( (void **)& prefptr, sizeof(ip_prefix_t), 1) != UT_OK) { 564 | die; 565 | } 566 | prefptr->ip = ad(begin); 567 | prefptr->bits = 32; 568 | 569 | *preflist = g_list_append( *preflist, prefptr ); 570 | 571 | return prefmask; 572 | } 573 | 574 | c_dif = ad(end).words[0] - ad(begin).words[0]; 575 | 576 | /* initialize work vars */ 577 | 578 | workbegin = ad(begin); 579 | workend = ad(end); 580 | 581 | /* now find the biggest block fitting in this range */ 582 | /* i.e. the first 2^n number smaller than c_dif */ 583 | 584 | /* the loop would not work for /0 (some stupid queries may have that) */ 585 | /* so this must be checked for separately */ 586 | 587 | if( c_dif == 0xffffffff ) { 588 | /* they are already set to 0.0.0.0 - 255.255.255.255 */ 589 | /* leave them alone. */ 590 | blk = 0; 591 | slash = 0; 592 | } 593 | else { 594 | 595 | c_dif += 1; /* was not done earlier to protect from overflow */ 596 | 597 | for(slash=1; 598 | slash<32 && ((blk=((unsigned)0x80000000>>(slash-1))) & c_dif) == 0; 599 | slash++) {} 600 | 601 | /* clear all digits in a and b under the blk one. */ 602 | ff=blk-1; 603 | 604 | workbegin.words[0] = (workbegin.words[0] + ff) & ~ff; 605 | 606 | workend.words[0] = (workend.words[0] + 1) & ~ff; 607 | } 608 | 609 | if( workbegin.words[0] != workend.words[0] ) { 610 | prefmask |= blk; 611 | if( wr_malloc( (void **)& prefptr, sizeof(ip_prefix_t)) != UT_OK) { 612 | die; 613 | } 614 | prefptr->ip = workbegin; 615 | prefptr->bits = slash; 616 | 617 | *preflist = g_list_append( *preflist, prefptr ); 618 | } 619 | 620 | if( ad(begin).words[0] != workbegin.words[0] ) { 621 | workrange.begin = ad(begin); 622 | 623 | workbegin.words[0] -= 1; 624 | workrange.end = workbegin; 625 | 626 | prefmask |= IP_rang_decomp( &workrange, preflist ); 627 | } 628 | 629 | /* here we must protect from decomposition of */ 630 | /* 255.255.255.255 - 255.255.255.255 in case the range */ 631 | /* 0.0.0.0 - 255.255.255.255 is considered. Hence the slash>0 condition. */ 632 | 633 | if( workend.words[0] <= ad(end).words[0] && slash > 0) { 634 | workrange.begin = workend; 635 | workrange.end = ad(end); 636 | 637 | prefmask |= IP_rang_decomp( &workrange, preflist ); 638 | } 639 | 640 | return prefmask; 641 | } 642 | 643 | 644 | /***************************************************************************/ 645 | 646 | /*+ Similar name, slightly different code, totally different functionality. 647 | 648 | finds the smallest canonical block encompassing the whole given range, 649 | then MODIFIES the range pointed to by the argument 650 | so that it's equal to this block. 651 | 652 | returns a bitmask of prefix length used. 653 | +*/ 654 | 655 | unsigned 656 | IP_rang_encomp(ip_range_t *rangptr) 657 | { 658 | unsigned prefmask=0; 659 | int slash=0; 660 | unsigned c_dif, blk, ff, t_dif; 661 | ip_range_t workrange; 662 | ip_addr_t workbegin; 663 | ip_addr_t workend; 664 | 665 | c_dif = ad(end).words[0] - ad(begin).words[0]; 666 | 667 | /* now find the biggest block fitting in this range */ 668 | /* i.e. the first 2^n number smaller than c_dif */ 669 | 670 | /* the loop would not work for /0 (some stupid queries may have that) */ 671 | /* so this must be checked for separately */ 672 | 673 | if( c_dif > 0x80000000 ) { 674 | slash = 0; 675 | ff = 0xffffffff; 676 | blk = 0; 677 | 678 | workbegin = workend = ad(begin); 679 | workbegin.words[0] = 0; 680 | workend.words[0] = ff; 681 | } 682 | else { 683 | 684 | do { 685 | c_dif += 1; 686 | 687 | /* find the smallest block ENCOMPASSING c_dif. */ 688 | /* this implies a loop from the bottom up */ 689 | 690 | for(slash=32; 691 | slash>1 && (blk=((unsigned)0x80000000>>(slash-1))) < c_dif; 692 | slash--) {} 693 | 694 | ff=blk-1; 695 | 696 | /* clear all digits in workbegin under the blk one. */ 697 | 698 | workbegin = ad(begin); 699 | workbegin.words[0] = workbegin.words[0] & ~ff; 700 | 701 | /* see if it has not made the difference larger than blk, */ 702 | /* retry if so */ 703 | 704 | t_dif = c_dif; 705 | c_dif = ad(end).words[0] - workbegin.words[0]; 706 | 707 | } while( c_dif >= t_dif ); 708 | 709 | /* set the endpoint to workbegin + blocksize - 1 */ 710 | /* which amounts to + ff */ 711 | 712 | workend = ad(begin); 713 | workend.words[0] = workbegin.words[0] + ff; 714 | } 715 | 716 | 717 | /* set the range to new values */ 718 | 719 | rangptr->begin = workbegin; 720 | rangptr->end = workend; 721 | } 722 | 723 | /***************************************************************************/ 724 | /*+ sets a range equal to a prefix +*/ 725 | 726 | er_ret_t 727 | IP_pref_2_rang( ip_range_t *rangptr, ip_prefix_t *prefptr ) 728 | { 729 | ip_rangesize_t span; 730 | 731 | ad(begin) = ad(end) = prefptr->ip; 732 | 733 | if( prefptr->bits > 0 ) { 734 | span = (1 << (32 - prefptr->bits)) - 1 ; 735 | } 736 | else { 737 | span = 0xffffffff; 738 | } 739 | 740 | ad(end).words[0] += span; 741 | 742 | return IP_OK; 743 | } 744 | 745 | #undef ad 746 | 747 | /***************************************************************************/ 748 | 749 | /*+ 750 | This is to parse a classfull address into a range. 751 | 752 | Takes the address by pointer from addrptr and puts the result 753 | at rangptr. 754 | 755 | Throws error if the address does not fall into any of the 756 | classfull categories 757 | 758 | +*/ 759 | 760 | er_ret_t 761 | IP_rang_classful( ip_range_t *rangptr, ip_addr_t *addrptr) 762 | { 763 | int i; 764 | unsigned b[4]; 765 | 766 | if( addrptr->space != IP_V4 ) { 767 | /* it's IPv6. There are no classful ranges or anything like that. */ 768 | /* we accept only explicit ranges */ 769 | 770 | die; 771 | } 772 | 773 | rangptr->begin = *addrptr; 774 | rangptr->end.space = IP_V4; 775 | for(i=0; i<4; i++) { 776 | rangptr->end.words[i] = 0; 777 | } 778 | 779 | /* assume it's at least a valid IP. let's try different classes now */ 780 | 781 | /* we could have used a union here, but it would not work on */ 782 | /* low endians. So byte by byte copying to and from an array. */ 783 | 784 | for(i=0; i<4; i++) { 785 | b[i] = ( rangptr->begin.words[0] & (0xFF << i*8) ) >> i*8; 786 | } 787 | 788 | if( b[3] >= 1 && b[3] < 128 789 | && b[2] == 0 && b[1] == 0 && b[0] == 0 ) { 790 | b[2]=b[1]=b[0]=255; 791 | } 792 | else if( b[3] >= 128 && b[3] < 192 793 | && b[1] == 0 && b[0] == 0 ) { 794 | b[1]=b[0]=255; 795 | } 796 | else if( b[3] >= 192 && b[3] < 224 797 | && b[0] == 0 ) { 798 | b[0]=255; 799 | } 800 | else if( b[3] >= 224 && b[3] < 255 ) { 801 | /* just leave it, make it a /32, i.e. begin == end */ 802 | } 803 | else { 804 | /* Leave it and make it a /32 */ 805 | /* This is AGAINST the rule! but we have some junk */ 806 | /* so we have to compensate for it. */ 807 | } 808 | 809 | /* copy the (now - modified) bytes into the end of range */ 810 | for(i=0; i<4; i++) { 811 | rangptr->end.words[0] |= (b[i] << i*8); 812 | } 813 | 814 | return IP_OK; 815 | } 816 | 817 | 818 | /***************************************************************************/ 819 | /*+ 820 | Trying to be smart :-) and convert a query search term into prefix(es), 821 | regardless of whether specified as IP address, prefix or range. 822 | 823 | justcheck - if just checking the syntax (justcheck == 1), 824 | then the prefixes are freed before the function returns, 825 | otherwise it is the responsibility of the caller to free the list. 826 | 827 | +*/ 828 | 829 | er_ret_t 830 | IP_smart_conv(char *key, 831 | int justcheck, 832 | int encomp, 833 | GList **preflist, 834 | ip_exp_t expf) 835 | { 836 | int free_it; 837 | er_ret_t call_err, err=IP_OK; /* let's be optimistic :-) */ 838 | ip_prefix_t *querypref; 839 | 840 | /* if just checking the syntax (justcheck == 1), 841 | then free_it = 1, 842 | else 0, but may be modified later (in range conversion) 843 | */ 844 | 845 | free_it = justcheck; 846 | 847 | if( (call_err = wr_malloc( (void **) &querypref, sizeof(ip_prefix_t))) 848 | != UT_OK) { 849 | return call_err; 850 | } 851 | 852 | if( IP_pref_t2b(querypref, key, expf) == IP_OK ) { 853 | if( justcheck == 0) { 854 | *preflist = g_list_append(*preflist, querypref); 855 | } 856 | } 857 | else { 858 | /* not a prefix. */ 859 | /* Maybe an IP ? */ 860 | if( IP_addr_t2b( &(querypref->ip), key, expf) == IP_OK ) { 861 | 862 | /*convert to a /32 */ 863 | querypref->bits = 32; 864 | 865 | if( justcheck == 0) { 866 | *preflist = g_list_append(*preflist, querypref); 867 | } 868 | } 869 | else { 870 | /* hm, maybe a range then ? */ 871 | ip_range_t myrang; 872 | 873 | /* won't use the querypref anymore, mark it for freeing later */ 874 | free_it = 1; 875 | 876 | if( IP_rang_t2b(&myrang, key, expf) == IP_OK ) { 877 | /* Wow. Great. */ 878 | 879 | /* sometimes (exless match) we look for the first bigger(shorter) */ 880 | /* prefix containing this range. */ 881 | 882 | if( encomp ) { 883 | IP_rang_encomp(&myrang); 884 | } 885 | /* OK, now we can let the engine happily find that it's just one */ 886 | /* range */ 887 | 888 | if( justcheck == 0) { 889 | IP_rang_decomp(&myrang, preflist); 890 | } 891 | } 892 | else { 893 | err = IP_INVARG; /* "conversion error" */ 894 | } 895 | } 896 | } 897 | 898 | if( free_it ) { 899 | wr_free(querypref); 900 | } 901 | 902 | return err; 903 | } 904 | 905 | 906 | #ifdef MODULE_TEST 907 | #include "ip_test.c" 908 | #endif