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.29 $
   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 /*XXX the bug: tabs are also valid whitespace */    
 478 /*    while( *ips == ' ' ) { */
 479     while(isspace((int)*ips)) {
 480       ips++;
 481     }
 482     
 483     /* convert the second IP into a binary struct */
 484     if( (err=IP_addr_t2b( &(rangptr->end), ips, expf)) != IP_OK ) {
 485       /* die;  */ /* incorrect address format */
 486       return err;
 487     }
 488     
 489     
 490     
 491     return ip_rang_validate(rangptr);
 492   }
 493 }
 494 
 495 
 496 /**************************************************************************/
 497 /* accessor functions */
 498 
 499 /******** address **********/
 500 
 501 unsigned IP_addr_b2_space(ip_addr_t *addrptr) 
     /* [<][>][^][v][top][bottom][index][help] */
 502 {
 503   return addrptr->space;
 504 }
 505 
 506 unsigned IP_addr_b2v4_addr(ip_addr_t *addrptr) 
     /* [<][>][^][v][top][bottom][index][help] */
 507 {
 508   dieif( addrptr->space != IP_V4 );
 509   return addrptr->words[0];
 510 }
 511 /* ipv4 */
 512 
 513 ip_v6word_t IP_addr_b2v6_hi(ip_addr_t *addrptr) 
     /* [<][>][^][v][top][bottom][index][help] */
 514 {
 515   dieif( addrptr->space != IP_V6 );
 516   return (  (((ip_v6word_t) addrptr->words[0]) << 32)
 517           + (((ip_v6word_t) addrptr->words[1]) ));
 518 }
 519 
 520 ip_v6word_t IP_addr_b2v6_lo(ip_addr_t *addrptr) 
     /* [<][>][^][v][top][bottom][index][help] */
 521 {
 522   dieif( addrptr->space != IP_V6 );
 523   return (   (((ip_v6word_t) addrptr->words[2]) << 32)
 524            + (((ip_v6word_t) addrptr->words[3]) ));
 525 }
 526 
 527 /******** prefix **********/
 528 
 529 unsigned IP_pref_b2_space(ip_prefix_t *prefix) {
     /* [<][>][^][v][top][bottom][index][help] */
 530   return IP_addr_b2_space( &(prefix->ip) );
 531 }
 532 
 533 unsigned IP_pref_b2_len(ip_prefix_t *prefix) {
     /* [<][>][^][v][top][bottom][index][help] */
 534   return prefix->bits;
 535 }
 536 
 537 unsigned IP_pref_b2v4_addr(ip_prefix_t *prefix) {
     /* [<][>][^][v][top][bottom][index][help] */
 538   return IP_addr_b2v4_addr( &(prefix->ip) );
 539 }
 540 
 541 /* range */
 542 
 543 unsigned IP_rang_b2_space(ip_range_t *myrang) {
     /* [<][>][^][v][top][bottom][index][help] */
 544   /* hardwire to IPV4 for now */
 545   return IP_V4;
 546 }
 547 
 548 /* 
 549  * complex conversions (return void, set values through pointers *
 550  */
 551 void IP_addr_b2v4(ip_addr_t *addrptr, unsigned *address) {
     /* [<][>][^][v][top][bottom][index][help] */
 552   *address = IP_addr_b2v4_addr(addrptr);
 553 }
 554 
 555 void IP_pref_b2v4(ip_prefix_t *prefptr, 
     /* [<][>][^][v][top][bottom][index][help] */
 556                    unsigned int *prefix, 
 557                    unsigned int *prefix_length) 
 558 {
 559   *prefix        = IP_addr_b2v4_addr( &(prefptr->ip));
 560   *prefix_length = IP_pref_b2v4_len(prefptr);
 561 }
 562 
 563 
 564 
 565 void IP_pref_b2v6(ip_prefix_t *prefptr, 
     /* [<][>][^][v][top][bottom][index][help] */
 566                   ip_v6word_t *high, 
 567                   ip_v6word_t *low, 
 568                   unsigned int *prefix_length) 
 569 {
 570   *high          = IP_addr_b2v6_hi( &(prefptr->ip));
 571   *low           = IP_addr_b2v6_lo( &(prefptr->ip));
 572   *prefix_length = IP_pref_b2v6_len(prefptr);
 573 }
 574 
 575 
 576 void IP_rang_b2v4(ip_range_t *myrang,
     /* [<][>][^][v][top][bottom][index][help] */
 577                   unsigned *begin, 
 578                   unsigned *end)
 579 {
 580   *begin = IP_addr_b2v4_addr( &(myrang->begin));
 581   *end   = IP_addr_b2v4_addr( &(myrang->end));
 582 }
 583 
 584 
 585 
 586 /******** construct from raw values **********/
 587 
 588 /******** address **********/
 589 er_ret_t IP_addr_v4_mk(ip_addr_t *addrptr,
     /* [<][>][^][v][top][bottom][index][help] */
 590                        unsigned addrval) {
 591   addrptr->space = IP_V4;
 592   addrptr->words[0] = addrval;
 593   addrptr->words[1] = addrptr->words[2] = addrptr->words[3] = 0;
 594   
 595   /* no real possibility of checking the syntax */
 596   return IP_OK;
 597 }
 598 
 599 er_ret_t IP_addr_v6_mk(ip_addr_t *addrptr,
     /* [<][>][^][v][top][bottom][index][help] */
 600                        ip_v6word_t high,
 601                        ip_v6word_t low) {
 602   
 603   ip_v6word_t ff = 0xffffffff;
 604 
 605   addrptr->space = IP_V6;
 606   (addrptr->words[0]) =  (high >> 32) & ff;
 607   (addrptr->words[1]) =   high & ff ;
 608   (addrptr->words[2]) =  (low >> 32) & ff;
 609   (addrptr->words[3]) =   low  & ff;
 610 
 611   /* no real possibility of checking the syntax */
 612   return IP_OK;
 613 }
 614 
 615 /******** prefix **********/
 616 er_ret_t IP_pref_v4_mk(ip_prefix_t *prefix,
     /* [<][>][^][v][top][bottom][index][help] */
 617                        unsigned prefval, 
 618                        unsigned preflen) 
 619 {
 620   if( preflen > 32 ) {
 621     die;
 622   }
 623   IP_addr_v4_mk(&(prefix->ip), prefval);
 624   prefix->bits = preflen;
 625   
 626   IP_pref_bit_fix( prefix ); /* never produce inconsistent prefixes */
 627 
 628   return IP_OK;
 629 }
 630 
 631 /******** range **********/
 632 er_ret_t IP_rang_v4_mk(ip_range_t *rangptr, 
     /* [<][>][^][v][top][bottom][index][help] */
 633                        unsigned addrbegin,
 634                        unsigned addrend)
 635 {
 636   er_ret_t err;
 637 
 638   if( (err=IP_addr_v4_mk( &(rangptr->begin), addrbegin)) == IP_OK ) {
 639     err=IP_addr_v4_mk( &(rangptr->end), addrend);
 640   }
 641   return err;
 642 }
 643 
 644 /**************************************************************************/
 645 
 646 
 647 /**************************************************************************/
 648 /*+ a2v4 == functions to convert the ascii representation into binary, 
 649  *          and then set the unsigned values at the pointers provided.
 650  *          
 651  +*/
 652 
 653 /* Convert route string into numbers */
 654 /* ipv4 */
 655 er_ret_t 
 656 IP_pref_a2v4(char *avalue, ip_prefix_t *pref,
     /* [<][>][^][v][top][bottom][index][help] */
 657              unsigned *prefix, unsigned *prefix_length)
 658 {
 659   
 660   er_ret_t ret;
 661   
 662   if((ret = IP_pref_e2b(pref, avalue)) == IP_OK) {
 663     IP_pref_b2v4(pref, prefix, prefix_length);
 664   }
 665   return(ret);
 666 }
 667 
 668 /* ipv6 */
 669 er_ret_t 
 670 IP_pref_a2v6(char *avalue, ip_prefix_t *pref,
     /* [<][>][^][v][top][bottom][index][help] */
 671              ip_v6word_t *high, ip_v6word_t  *low,
 672              unsigned *prefix_length)
 673 {
 674   er_ret_t ret;
 675   
 676   if((ret = IP_pref_e2b(pref, avalue)) == IP_OK) {
 677     IP_pref_b2v6(pref, high, low, prefix_length);
 678   }
 679   return(ret);
 680 }
 681 
 682 /* Convert reverse domain string into numbers */
 683 er_ret_t 
 684 IP_revd_a2v4(char *avalue, ip_prefix_t *pref,
     /* [<][>][^][v][top][bottom][index][help] */
 685              unsigned int *prefix, unsigned int *prefix_length)
 686 {
 687   er_ret_t ret;
 688   
 689   if((ret = IP_revd_e2b(pref, avalue)) == IP_OK) {
 690     IP_pref_b2v4(pref, prefix, prefix_length);
 691   }
 692   return(ret);
 693 }
 694 
 695 /* Convert ip addr string into numbers */
 696 er_ret_t 
 697 IP_addr_a2v4(char *avalue,ip_addr_t *ipaddr, unsigned int *address)
     /* [<][>][^][v][top][bottom][index][help] */
 698 {
 699 er_ret_t ret;
 700 
 701  if((ret = IP_addr_e2b(ipaddr, avalue)) == IP_OK) {
 702    IP_addr_b2v4(ipaddr, address);
 703  }
 704  return(ret);
 705 }
 706 
 707 /* Convert inetnum attribute into numbers */
 708 er_ret_t 
 709 IP_rang_a2v4(char *rangstr, ip_range_t *myrang,
     /* [<][>][^][v][top][bottom][index][help] */
 710              unsigned int *begin_in, unsigned int *end_in)
 711 {
 712   er_ret_t ret;
 713   
 714   if( (ret=IP_rang_e2b(myrang, rangstr)) == IP_OK ) {
 715 #if 0    /* no IPv4 classful ranges anymore */
 716     if( IP_addr_e2b( &(myrang->begin), rangstr ) == IP_OK )
 717       if ((ret=IP_rang_classful( myrang , &(myrang->begin))) == IP_OK )
 718         ;
 719 #endif
 720     IP_rang_b2v4(myrang, begin_in, end_in);
 721   }
 722   
 723   return (ret);
 724 }
 725 
 726 
 727 /* *********************************************************************
 728    f2b - free numbers represented in ascii into a binary struct
 729 ********************************************************************* */
 730 
 731 er_ret_t
 732 IP_addr_f2b_v4(ip_addr_t *addrptr, char *adrstr) 
     /* [<][>][^][v][top][bottom][index][help] */
 733 {
 734   unsigned address;
 735 
 736   if( ut_dec_2_uns(adrstr, &address) < 0 ) {
 737     return IP_INVARG;
 738   }
 739   
 740   return IP_addr_v4_mk(addrptr, address);
 741 }
 742 
 743 er_ret_t
 744 IP_rang_f2b_v4(ip_range_t *rangptr, char *beginstr,  char *endstr) 
     /* [<][>][^][v][top][bottom][index][help] */
 745 {
 746   if(    IP_addr_f2b_v4( &(rangptr->begin), beginstr) != IP_OK
 747       || IP_addr_f2b_v4( &(rangptr->end),   endstr)   != IP_OK) {
 748     return IP_INVARG;
 749   }
 750   else {
 751     return IP_OK;
 752   }
 753 }
 754 
 755 er_ret_t
 756 IP_pref_f2b_v4(ip_prefix_t *prefptr, char *prefixstr, char *lengthstr) 
     /* [<][>][^][v][top][bottom][index][help] */
 757 {
 758   if( IP_addr_f2b_v4( &(prefptr->ip), prefixstr) != IP_OK 
 759       || ut_dec_2_uns(lengthstr, &(prefptr->bits) ) < 0
 760       || prefptr->bits > IP_sizebits(prefptr->ip.space)) {
 761     return IP_INVARG;
 762   }
 763   IP_pref_bit_fix(prefptr); /* never create broken binary prefixes. */
 764   return IP_OK;
 765 }
 766 
 767 
 768 er_ret_t
 769 IP_addr_f2b_v6(ip_addr_t *addrptr, char *msbstr, char *lsbstr )
     /* [<][>][^][v][top][bottom][index][help] */
 770 {
 771   ip_v6word_t high, low;
 772   
 773   if( sscanf(msbstr, "%llu", &high) < 1 ||
 774       sscanf(lsbstr, "%llu", &low)  < 1 ) {
 775     return IP_INVARG;
 776   }
 777  
 778   return IP_addr_v6_mk(addrptr, high, low);
 779 }
 780 
 781 
 782 er_ret_t
 783 IP_pref_f2b_v6(ip_prefix_t *prefptr, char *msbstr, char *lsbstr, char *lengthstr) 
     /* [<][>][^][v][top][bottom][index][help] */
 784 {
 785   if( IP_addr_f2b_v6( &(prefptr->ip), msbstr, lsbstr ) != IP_OK 
 786       || ut_dec_2_uns(lengthstr, &(prefptr->bits) ) < 0 
 787       || prefptr->bits > IP_sizebits(prefptr->ip.space)) {
 788     return IP_INVARG;
 789   }
 790   IP_pref_bit_fix(prefptr); /* never create broken binary prefixes. */
 791   return IP_OK;
 792 }
 793 
 794 
 795 /**************************************************************************/
 796 /*+ convert the socket's idea of address into a binary range struct. 
 797 
 798   space    select the address type (and consequently struct type)
 799 */
 800 
 801 er_ret_t
 802 IP_addr_s2b(ip_addr_t *addrptr, 
     /* [<][>][^][v][top][bottom][index][help] */
 803             void      *addr_in, 
 804             int       addr_len)
 805 {
 806   if( addr_len == sizeof(struct sockaddr_in) 
 807       && ((struct sockaddr_in *)addr_in)->sin_family == AF_INET ) {
 808     addrptr->space = IP_V4;
 809     addrptr->words[0] = 
 810       ntohl( ((struct sockaddr_in*)addr_in)->sin_addr.s_addr);
 811     
 812     /* set remaining limbs to zero */
 813     addrptr->words[1] = addrptr->words[2] = addrptr->words[3] = 0; 
 814     
 815   }
 816   else { /* unsupported family or invalid struct */
 817     die;
 818   }
 819   return IP_OK;
 820 }
 821 
 822 /**************************************************************************/
 823 /*+converts the IP binary address (binaddr) to a string (ascaddr) 
 824    of at most strmax characters. Independent of the result
 825    (success or failure) it messes up the string.
 826 +*/
 827 er_ret_t
 828 IP_addr_b2a( ip_addr_t *binaddr, char *ascaddr, unsigned strmax ) 
     /* [<][>][^][v][top][bottom][index][help] */
 829 {
 830   
 831   if(binaddr->space == IP_V4) {
 832     if (snprintf(ascaddr, strmax, "%d.%d.%d.%d",
 833                  ((binaddr->words[0]) & ((unsigned)0xff<<24))>>24,
 834                  ((binaddr->words[0]) & (0xff<<16))>>16,
 835                  ((binaddr->words[0]) & (0xff<<8))>>8,
 836                  ((binaddr->words[0]) & (0xff<<0))>>0
 837                  ) >= strmax) {
 838       /*die;  */ /* string too short */
 839       return IP_TOSHRT;
 840     }
 841   }
 842   else {
 843     /* IPv6 */
 844     unsigned tmpv6[4];
 845     int i;
 846 
 847     /* inet_* operates on network byte format numbers, so we need
 848         to prepare a tmp. data with it */
 849 
 850     for(i=0; i<4; i++) {
 851         tmpv6[i] = htonl(binaddr->words[i]);
 852     }
 853 
 854     if( inet_ntop(AF_INET6, tmpv6, ascaddr, strmax) 
 855         == NULL ) {
 856       return IP_TOSHRT;
 857     }
 858   }
 859   return IP_OK;
 860 }
 861 
 862 /**************************************************************************/
 863 
 864 /*+ convert a binary prefix back into ascii string at most strmax chars long 
 865 +*/
 866 er_ret_t
 867 IP_pref_b2a(ip_prefix_t *prefptr, char *ascaddr, unsigned strmax) 
     /* [<][>][^][v][top][bottom][index][help] */
 868 {
 869   int strl;
 870   er_ret_t err;
 871 
 872   if( (err=IP_addr_b2a (&(prefptr->ip), ascaddr, strmax)) != IP_OK) {
 873     /*die;  */ /* what the hell */
 874     return err;
 875   }
 876   strl = strlen(ascaddr);
 877   strmax -= strl;
 878 
 879   /* now strmax holds the space that is left */
 880 
 881   if( snprintf(ascaddr+strl, strmax, "/%d", prefptr->bits) >= strmax) {
 882     /* die;  */ /* error: string too short */
 883     return IP_TOSHRT;
 884   }
 885   return IP_OK;
 886 }
 887 
 888 
 889 
 890 /**************************************************************************/
 891 /*+ convert a binary range back into ascii string at most strmax chars long 
 892 +*/
 893 er_ret_t
 894 IP_rang_b2a(ip_range_t *rangptr, char *ascaddr, unsigned strmax) 
     /* [<][>][^][v][top][bottom][index][help] */
 895 {
 896   int strl=0;
 897   unsigned strleft;
 898   er_ret_t err;
 899 
 900   strleft = strmax - strl;
 901   if( (err=IP_addr_b2a (&(rangptr->begin), ascaddr, strleft)) != IP_OK) {
 902     return err;
 903   }
 904   strl = strlen(ascaddr);
 905   
 906   strleft = strmax - strl;
 907   if( strleft < 5 ) {
 908     return IP_TOSHRT; 
 909   }
 910   strcat( ascaddr, " - " );
 911   strl += 3;
 912 
 913   strleft = strmax - strl;
 914   if( (err=IP_addr_b2a (&(rangptr->end), ascaddr+strl, strleft)) != IP_OK) {
 915     return err;
 916   }
 917 
 918   return IP_OK;
 919 }
 920 
 921 /**************************************************************************/
 922 /*+ return the bitnum bit of the address, 
 923    COUNTING FROM THE TOP !!!!! , 
 924    starting with 0 for the *most significant bit*.
 925 +*/
 926 int
 927 IP_addr_bit_get(ip_addr_t *binaddr, unsigned bitnum) {
     /* [<][>][^][v][top][bottom][index][help] */
 928   int bitval;
 929   int w,c;
 930   
 931   /* avoid unnecessary division */
 932   if( binaddr->space == IP_V4 ) {
 933     w = 0;
 934     c = bitnum;
 935   }
 936   else {
 937     w = bitnum / 32;
 938     c = bitnum % 32;
 939   }
 940 
 941   bitval = (binaddr->words[w] & (0x80000000 >> (c)));
 942 
 943   return (bitval != 0);
 944 
 945 }
 946 
 947 /**************************************************************************/
 948 /*+ set the bitnum bit of the address to bitval, 
 949    COUNTING FROM THE TOP !!!!! , 
 950    starting with 0 for the *most significant bit*.
 951 +*/
 952 void
 953 IP_addr_bit_set(ip_addr_t *binaddr, unsigned bitnum, unsigned bitval) {
     /* [<][>][^][v][top][bottom][index][help] */
 954   int w,c;
 955   
 956   /* avoid unnecessary division */
 957   if( binaddr->space == IP_V4 ) {
 958     w = 0;
 959     c = bitnum;
 960   }
 961   else {
 962     w = bitnum / 32;
 963     c = bitnum % 32;
 964   }
 965 
 966   if ( bitval == 1 )
 967     
 968     binaddr->words[w] |= (0x80000000 >> (c));
 969   else
 970     binaddr->words[w] &=  ~(0x80000000 >> (c));
 971 }
 972 /**************************************************************************/
 973 
 974 /*+ this fixes a prefix by setting insignificant bits to 0 +*/
 975 void
 976 IP_pref_bit_fix( ip_prefix_t *prefix ) 
     /* [<][>][^][v][top][bottom][index][help] */
 977 {
 978 
 979   if( prefix->ip.space == IP_V4 ) {
 980     ip_limb_t mask = 0xffffffff;
 981     
 982     /* shorthand for ipv4 */
 983     
 984     /* Shifting out by 32 bits does NOT turn all bits into 0... */
 985     if( prefix->bits < 32 ) {
 986       prefix->ip.words[0] &= ~(mask >> prefix->bits);
 987     }
 988   }
 989   else {
 990     unsigned i;
 991     for(i=prefix->bits; i < IP_sizebits(prefix->ip.space) ; i++) {
 992       IP_addr_bit_set( & prefix->ip, i, 0);
 993     }
 994   }
 995 }
 996 
 997 
 998 /**************************************************************************/
 999 
1000 /*+ compares two IP addresses up to the bit # len, 
1001    returns 0 if equal, 1 if ptra greater, -1 if ptrb greater.
1002    
1003    It is the responsility of the caller to ensure that both addresses
1004    are from the same IP space.
1005 
1006    This is pretty slow; it is used in the searches of the radix tree,
1007    so it might be good to optimise this.
1008 +*/
1009 
1010 int 
1011 IP_addr_cmp(ip_addr_t *ptra, ip_addr_t *ptrb, unsigned len)
     /* [<][>][^][v][top][bottom][index][help] */
1012 {
1013   unsigned a,b,i;
1014 
1015   for(i=0; i<len; i++) {
1016     a=IP_addr_bit_get(ptra, i);
1017     b=IP_addr_bit_get(ptrb, i);
1018     if( a != b ) {
1019       if( a > b ) return 1;
1020       else return -1;
1021     }
1022   }
1023   return 0;
1024 }
1025 
1026 
1027 /*+ checks if an IP address is contained within the prefix 
1028   returns 1 if it is, 0 otherwise
1029 
1030   It is the responsility of the caller to ensure that both address
1031   and prefix are from the same IP space.
1032 +*/
1033 int 
1034 IP_addr_in_pref(ip_addr_t *ptra, ip_prefix_t *prefix)
     /* [<][>][^][v][top][bottom][index][help] */
1035 {
1036   return (IP_addr_cmp( ptra, & prefix->ip, prefix->bits) == 0);
1037 }
1038 
1039 /*+ checks if an IP address is contained within the range
1040   returns 1 if it is, 0 otherwise
1041 
1042   It is the responsility of the caller to ensure that both address
1043   and range are from the same IP space.
1044   
1045   works only for IPv4
1046 +*/
1047 
1048 int IP_addr_in_rang(ip_addr_t *ptra, ip_range_t *rangptr)
     /* [<][>][^][v][top][bottom][index][help] */
1049 {
1050 /*  if( rangptr->end.space == IP_V4 ) {
1051     return (  rangptr->begin.words[0]  <=  ptra->words[0]
1052               && rangptr->end.words[0]  >=  ptra->words[0] );
1053   }
1054   else {
1055 */
1056     return( IP_addr_cmp(ptra, &rangptr->begin, 
1057                         IP_sizebits(rangptr->end.space)) >= 0 /* adr >= begin */
1058             && IP_addr_cmp(ptra, &rangptr->end, 
1059                            IP_sizebits(rangptr->end.space)) <= 0  /* adr <= end */
1060             );
1061 /*  }*/
1062 }
1063 
1064 /**************************************************************************/
1065 
1066 /*+ calculate the span of a range == size - 1 +*/
1067 
1068 ip_rangesize_t 
1069 IP_rang_span( ip_range_t *rangptr )
     /* [<][>][^][v][top][bottom][index][help] */
1070 {
1071   /* IPv4: */
1072   dieif( rangptr->end.space != IP_V4 );
1073   
1074   return rangptr->end.words[0] - rangptr->begin.words[0];
1075 }
1076 
1077 
1078 /**************************************************************************/
1079 
1080 /*+ 
1081 this is a shorthand notation to pull out the first word of the address.
1082 it is defined for the scope od the following functions
1083 +*/
1084 #define ad(which) (rangptr->which)
     /* [<][>][^][v][top][bottom][index][help] */
1085 
1086 /**************************************************************************/
1087 /*+ Decomposes a binary range into prefixes and appends them to the list.
1088    Allocates prefix structures and list elements, they must be freed 
1089    after use.
1090 
1091    returns a bitmask of prefix lengths used.
1092 +*/
1093 unsigned
1094 IP_rang_decomp(ip_range_t *rangptr, GList **preflist)
     /* [<][>][^][v][top][bottom][index][help] */
1095 {
1096 unsigned            prefmask=0;
1097 register int        slash=0;
1098 register unsigned   c_dif, blk, ff;
1099 ip_range_t  workrange;
1100 ip_addr_t   workbegin;
1101 ip_addr_t   workend;
1102 ip_prefix_t *prefptr;
1103 
1104  dieif( rangptr->begin.space != IP_V4 );
1105  
1106  if( ad(begin).words[0] > ad(end).words[0] ) {   /* has gone too far */
1107    return 0; 
1108  }
1109  
1110  if( ad(begin).words[0] == ad(end).words[0] ) { /* an IP == a /32 (IPv4) */
1111    prefmask |= 1;
1112    if(  wr_calloc( (void **)& prefptr, sizeof(ip_prefix_t), 1) != UT_OK) {
1113      die;
1114    }
1115    prefptr->ip = ad(begin);
1116    prefptr->bits = 32;
1117    
1118    *preflist = g_list_append( *preflist, prefptr );
1119    
1120    return prefmask;
1121  }
1122  
1123   c_dif = ad(end).words[0] - ad(begin).words[0];
1124   
1125   /* initialize work vars */
1126   
1127   workbegin = ad(begin);
1128   workend = ad(end);
1129   
1130   /* now find the biggest block fitting in this range */
1131   /* i.e. the first 2^n number smaller than c_dif */
1132   
1133   /* the loop would not work for /0 (some stupid queries may have that) */
1134   /* so this must be checked for separately */
1135   
1136   if( c_dif == 0xffffffff ) {
1137     /* they are already set to 0.0.0.0 - 255.255.255.255 */
1138     /* leave them alone.  */
1139     blk = 0;
1140     slash = 0;
1141   }
1142   else {
1143     
1144     c_dif += 1;     /* was not done earlier to protect from overflow */
1145 
1146     for(slash=1; 
1147         slash<32 && ((blk=((unsigned)0x80000000>>(slash-1))) & c_dif) == 0; 
1148         slash++) {}
1149 
1150     /* clear all digits in a and b under the blk one. */
1151     ff=blk-1;
1152 
1153     workbegin.words[0] = (workbegin.words[0] + ff) & ~ff;
1154     
1155     workend.words[0] = (workend.words[0] + 1) & ~ff;
1156   }
1157   
1158   if( workbegin.words[0] != workend.words[0] ) {
1159     prefmask |= blk;
1160     if(  wr_malloc( (void **)& prefptr, sizeof(ip_prefix_t)) != UT_OK) {
1161       die;
1162     }
1163     prefptr->ip = workbegin;
1164     prefptr->bits = slash;
1165     
1166     *preflist = g_list_append( *preflist, prefptr );
1167   }
1168 
1169   if( ad(begin).words[0] != workbegin.words[0] ) {
1170     workrange.begin = ad(begin);
1171 
1172     workbegin.words[0] -= 1;
1173     workrange.end   = workbegin;
1174 
1175     prefmask |= IP_rang_decomp( &workrange, preflist );
1176   }
1177   
1178   /* here we must protect from decomposition of  
1179    * 255.255.255.255 - 255.255.255.255 in case the range 
1180    * 0.0.0.0 - 255.255.255.255 is considered. Hence the slash>0 condition. 
1181    */
1182   
1183   if( workend.words[0] <= ad(end).words[0] && slash > 0) {
1184     workrange.begin = workend;
1185     workrange.end   = ad(end);
1186 
1187     prefmask |= IP_rang_decomp( &workrange, preflist );
1188   }
1189   
1190   return prefmask;
1191  
1192 }
1193 
1194 
1195 /***************************************************************************/
1196 
1197 /*+ Similar name, slightly different code, totally different functionality.
1198 
1199    finds the smallest canonical block encompassing the whole given range, 
1200    then MODIFIES the range pointed to by the argument 
1201    so that it's equal to this block.
1202 
1203 +*/
1204 
1205 void IP_rang_encomp(ip_range_t *rangptr)
     /* [<][>][^][v][top][bottom][index][help] */
1206 {
1207   int         slash=0;
1208   unsigned    c_dif, blk, ff, t_dif;
1209   ip_addr_t   workbegin;
1210   ip_addr_t   workend;
1211 
1212   dieif( rangptr->begin.space != IP_V4 );
1213 
1214     c_dif = ad(end).words[0] - ad(begin).words[0];
1215     
1216     /* now find the biggest block fitting in this range */
1217     /* i.e. the first 2^n number smaller than c_dif */
1218     
1219     /* the loop would not work for /0 (some stupid queries may have that) */
1220     /* so this must be checked for separately */
1221     
1222     if( c_dif > 0x80000000 ) {
1223       slash = 0;
1224       ff = 0xffffffff;
1225       blk = 0;
1226       
1227       workbegin = workend = ad(begin);
1228       workbegin.words[0] = 0;
1229       workend.words[0] = ff;
1230     }
1231     else {
1232       
1233       do {
1234         c_dif += 1;
1235         
1236         /* find the smallest block ENCOMPASSING c_dif. */
1237         /* this implies a loop from the bottom up */
1238         
1239         for(slash=32; 
1240             slash>1 && (blk=((unsigned)0x80000000>>(slash-1))) < c_dif; 
1241             slash--) {}
1242         
1243         ff=blk-1;
1244         
1245         /* clear all digits in workbegin under the blk one. */
1246         
1247         workbegin = ad(begin);
1248         workbegin.words[0] = workbegin.words[0] & ~ff;
1249         
1250         /* see if it has not made the difference larger than blk,  */
1251         /* retry if so */
1252         
1253         t_dif = c_dif;
1254         c_dif = ad(end).words[0] - workbegin.words[0];
1255         
1256       } while( c_dif >= t_dif );
1257       
1258       /* set the endpoint to workbegin + blocksize - 1 */
1259       /* which amounts to + ff */
1260       
1261       workend = ad(begin);
1262       workend.words[0] = workbegin.words[0] + ff;
1263     }
1264     
1265     
1266     /* set the range to new values */
1267     
1268     rangptr->begin = workbegin;
1269     rangptr->end   = workend;
1270 }
1271 
1272 /***************************************************************************/
1273 /*+ sets a range equal to a prefix +*/
1274 
1275 er_ret_t
1276 IP_pref_2_rang( ip_range_t *rangptr, ip_prefix_t *prefptr )
     /* [<][>][^][v][top][bottom][index][help] */
1277 {
1278   int shift;
1279   int i;
1280     
1281   ad(begin) = ad(end) = prefptr->ip;
1282   
1283   /* IPv6 is a bit more complicated, as four words are involved */
1284   
1285   /* additional problem: shifting right by >=32 is equal to shifting by 0,
1286      so it does not change any bits */
1287   /* solution: don't touch those words */
1288   
1289   for(i=0; i<4; i++) {
1290     
1291     if( prefptr->bits < 32*(1+i) ) {
1292       shift = prefptr->bits < 32 + (i-1) * 32 
1293         ? 0 : (prefptr->bits % 32) ;
1294       ad(end).words[i] |= (0xffffffffU >> shift);
1295     }
1296     
1297     if( prefptr->ip.space == IP_V4) {
1298       break; /* do only first word for IPv4 */
1299     }   
1300   }
1301   return IP_OK;
1302 }
1303 
1304 #undef ad
1305 
1306 /***************************************************************************/
1307 
1308 /*+ 
1309    This is to parse a classfull address into a range.
1310 
1311    Takes the address by pointer from addrptr and puts the result
1312    at rangptr. 
1313 
1314    Throws error if the address does not fall into any of the 
1315    classfull categories 
1316 
1317 +*/
1318 
1319 er_ret_t
1320 IP_rang_classful( ip_range_t *rangptr, ip_addr_t *addrptr)
     /* [<][>][^][v][top][bottom][index][help] */
1321 {
1322 int i;
1323 unsigned b[4];
1324 
1325   if( addrptr->space != IP_V4 ) {
1326     /* it's IPv6. There are no classful ranges or anything like that. */
1327     die;
1328   }
1329   
1330   rangptr->begin = *addrptr;
1331   rangptr->end.space = IP_V4;
1332 
1333   /* initisalise end to zero */
1334   for(i=0; i<IPLIMBNUM; i++) {
1335     rangptr->end.words[i] = 0;
1336   }
1337   
1338   /* assume it's at least a valid IP. let's try different classes now */
1339               
1340   /* we could have used a union here, but it would not work on */
1341   /* low endians. So byte by byte copying to and from an array. */
1342   
1343   for(i=0; i<4; i++) {
1344     b[i] = ( rangptr->begin.words[0] & (0xFF << i*8) ) >> i*8;
1345   }
1346   
1347   if( b[3] >= 1 && b[3] < 128 
1348       && b[2] == 0 && b[1] == 0 && b[0] == 0 ) {
1349     b[2]=b[1]=b[0]=255;
1350   }
1351   else if( b[3] >= 128 && b[3] < 192 
1352            && b[1] == 0 && b[0] == 0 ) {
1353     b[1]=b[0]=255;
1354   }
1355   else if( b[3] >= 192 && b[3] < 224 
1356            &&  b[0] == 0 ) {
1357     b[0]=255;
1358   }
1359   else if( b[3] >= 224 && b[3] < 255 ) {
1360     /* just leave it, make it a /32, i.e. begin == end */
1361     /* EMPTY */;
1362   }
1363   else {
1364     /* Leave it and make it a /32 */
1365     /* This is AGAINST the rule! but we have some junk  */
1366     /* so we have to compensate for it. */
1367     /* EMPTY */;
1368   }
1369   
1370   /* copy the (now - modified) bytes into the end of range */
1371   for(i=0; i<4; i++) {
1372     rangptr->end.words[0] |= (b[i] << i*8);
1373   }
1374   
1375   return IP_OK;
1376 }
1377 
1378 
1379 /***************************************************************************/
1380 /*+ 
1381   Trying to be smart :-) and convert a query search term into prefix(es),
1382   regardless of whether specified as IP address, prefix or range.
1383  
1384   justcheck - if just checking the syntax (justcheck == 1), 
1385      then the prefixes are freed before the function returns,
1386      otherwise it is the responsibility of the caller to free the list.
1387      
1388 +*/
1389 
1390 er_ret_t
1391 IP_smart_conv(char *key, 
     /* [<][>][^][v][top][bottom][index][help] */
1392               int justcheck, 
1393               int encomp, 
1394               GList **preflist, 
1395               ip_exp_t expf,
1396               ip_keytype_t *keytype
1397               )
1398 {
1399   int free_it;
1400   er_ret_t call_err, err=IP_OK;      /* let's be optimistic :-) */
1401   ip_prefix_t *querypref;
1402 
1403   /* if just checking the syntax (justcheck == 1), 
1404      then free_it = 1, 
1405      else 0, but may be modified later (in range conversion)
1406   */
1407 
1408   free_it = justcheck;
1409   
1410   if( (call_err = wr_malloc( (void **) &querypref, sizeof(ip_prefix_t))) 
1411       != UT_OK) {
1412     return call_err;
1413   }
1414   
1415   if( IP_pref_t2b(querypref, key, expf) == IP_OK ) {
1416     *keytype = IPK_PREFIX;
1417 
1418     if( justcheck == 0) {
1419       *preflist = g_list_append(*preflist, querypref);
1420     }
1421   } 
1422   else {
1423     /* not a prefix.  */
1424     /* Maybe an IP ? */
1425     if( IP_addr_t2b( &(querypref->ip), key, expf) == IP_OK ) {
1426       
1427       *keytype = IPK_IP;
1428 
1429       /*convert to a /32 or /128*/
1430       querypref->bits =  IP_sizebits(querypref->ip.space);
1431 
1432       if( justcheck == 0) {
1433         *preflist = g_list_append(*preflist, querypref);
1434       }
1435     }
1436     else {    
1437       /* hm, maybe a range then ? */
1438       ip_range_t myrang;
1439       
1440       /* won't use the querypref anymore, mark it for freeing later */
1441       free_it = 1;
1442       
1443       if( IP_rang_t2b(&myrang, key, expf) == IP_OK ) {
1444         /* Wow. Great.  */
1445         
1446         *keytype = IPK_RANGE;
1447 
1448         /* sometimes (exless match) we look for the first bigger(shorter)  */
1449         /* prefix containing this range. */
1450         
1451         if( encomp ) {
1452           IP_rang_encomp(&myrang);
1453         }
1454         /* OK, now we can let the engine happily find that there's just one */
1455         /* prefix in range */
1456         
1457         if( justcheck == 0) {
1458           IP_rang_decomp(&myrang, preflist);
1459         }
1460       }
1461       else {
1462         *keytype = IPK_UNDEF;
1463         err = IP_INVARG; /* "conversion error" */
1464       }
1465     }
1466   }
1467   
1468   if( free_it ) {
1469     wr_free(querypref);
1470   }
1471   
1472   return err;
1473 }
1474 
1475 
1476 /* convert whatever comes into a range */
1477 er_ret_t
1478 IP_smart_range(char *key,
     /* [<][>][^][v][top][bottom][index][help] */
1479                ip_range_t *rangptr, 
1480                ip_exp_t expf,
1481                ip_keytype_t *keytype
1482                )
1483 {
1484   er_ret_t  err=IP_OK;  
1485   GList    *preflist = NULL;
1486 
1487   /* first : is it a range ? */
1488 
1489   if( (err = IP_rang_t2b(rangptr, key, expf)) == IP_OK ) {
1490       *keytype = IPK_RANGE;
1491   }
1492   else {
1493       /* OK, this must be possible to convert it to prefix and from there
1494          to a range. */
1495       if( (err = IP_smart_conv(key, 0, 0, &preflist, expf, keytype)) 
1496           == IP_OK ) {
1497           
1498           dieif( g_list_length(preflist) != 1 );
1499           
1500           dieif(IP_pref_2_rang( rangptr, g_list_first(preflist)->data ) != IP_OK );
1501       }
1502   }
1503   
1504   wr_clear_list( &preflist );
1505 
1506   return err;
1507 }
1508 

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