Source File ip/ip.c

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