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

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