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

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