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

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