modules/ip/ip.c

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. IP_sizebits
  2. ip_rang_validate
  3. IP_addr_t2b
  4. IP_pref_t2b
  5. IP_revd_t2b
  6. IP_rang_t2b
  7. IP_addr_b2_space
  8. IP_addr_b2v4_addr
  9. IP_addr_b2v6_hi
  10. IP_addr_b2v6_lo
  11. IP_pref_b2_space
  12. IP_pref_b2_len
  13. IP_pref_b2v4_addr
  14. IP_rang_b2_space
  15. IP_addr_b2v4
  16. IP_pref_b2v4
  17. IP_pref_b2v6
  18. IP_rang_b2v4
  19. IP_addr_v4_mk
  20. IP_addr_v6_mk
  21. IP_pref_v4_mk
  22. IP_rang_v4_mk
  23. IP_pref_a2v4
  24. IP_pref_a2v6
  25. IP_revd_a2v4
  26. IP_addr_a2v4
  27. IP_rang_a2v4
  28. IP_addr_f2b_v4
  29. IP_rang_f2b_v4
  30. IP_pref_f2b_v4
  31. IP_addr_f2b_v6
  32. IP_pref_f2b_v6
  33. IP_addr_s2b
  34. IP_addr_b2a
  35. IP_pref_b2a
  36. IP_rang_b2a
  37. IP_addr_bit_get
  38. IP_addr_bit_set
  39. IP_pref_bit_fix
  40. IP_addr_cmp
  41. IP_addr_in_pref
  42. IP_addr_in_rang
  43. IP_rang_span
  44. ad
  45. IP_rang_decomp
  46. IP_rang_encomp
  47. IP_pref_2_rang
  48. IP_rang_classful
  49. IP_smart_conv
  50. IP_smart_range

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

/* [<][>][^][v][top][bottom][index][help] */