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

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