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

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