modules/ip/ip.c

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

DEFINITIONS

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. IP_rang_decomp
  45. IP_rang_encomp
  46. IP_pref_2_rang
  47. IP_rang_classful
  48. IP_smart_conv
  49. IP_smart_range

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

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