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

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