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

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