Source File modules/ip/ip.c

    1    | /***************************************
    2    |   $Revision: 1.9 $
    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
    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   |
    50   | /***************************************************************************/
    51   | /*+ return the max. length of bits per space
    52   |
    53   |    Yes, it *could* be a macro - but as a function it can detect
    54   |    more programmer's errors. And will get inlined anyway.
    55   |
    56   | +*/
    57   |
    58   | int IP_sizebits(ip_space_t spc_id) {
    59   |   switch (spc_id) {
    60   |   case IP_V4:
    61   |     return 32;
    62   |   case IP_V6:
    63   |     return 128;
    64   |   default:
    65   |     /*    die; */ /* error: bad IP version specified */
    66   |     return -1;
    67   |   }
    68   | }
    69   |
    70   | /***************************************************************************/
    71   | /*+
    72   |    ascii IP address to binary.
    73   |    In IP_EXPN mode IP will be treated as not-expanded.
    74   |    (missing octets will be set to 0, MSB will be set).
    75   |    In IP_PLAIN mode the routine will complain if it sees less octets.
    76   | +*/
    77   |
    78   | er_ret_t
    79   | IP_addr_t2b(ip_addr_t *ipptr, char *addr, ip_exp_t expf)
    80   | {
    81   |   if( index(addr, ':') == NULL ) {
    82   |     /* IPv4 */
    83   |     char *dot;
    84   |     unsigned len, byte, result=0;
    85   |     char cpy[4];
    86   |     int last = 0, dotsfound=0;
    87   |     int bytes=0;
    88   |
    89   |     if( expf != IP_PLAIN && expf != IP_EXPN ) {
    90   |       return IP_INVARG;
    91   |     }
    92   |
    93   |     do {
    94   |       if ( (dot = index (addr, '.')) == NULL) {
    95   | 	dot = index (addr, '\0');
    96   | 	last = 1;
    97   |       }
    98   |       else {
    99   | 	if( ++dotsfound > 3 ) {
    100  | 	  /* handle syntax ERROR - too many dots found */
    101  | 	  return IP_INVIP4;
    102  | 	}
    103  |       }
    104  |
    105  |       if ((len = dot - addr) > 4) {
    106  | 	/* syntax ERROR - too many digits between dots*/
    107  | 	return IP_INVIP4;
    108  |       }
    109  |       strncpy( cpy, addr, len );
    110  |       cpy[len]=0;
    111  |
    112  |       /* sscanf is waay too slow */
    113  |
    114  |       if( ut_dec_2_uns(cpy, &byte) < 0 ) {
    115  | 	/* handle syntax ERROR - invalid characters found */
    116  | 	return IP_INVIP4;
    117  |       }
    118  |
    119  |
    120  |       if( byte > 255 ) {
    121  | 	/* handle syntax ERROR - number between dots too high */
    122  | 	return IP_INVIP4;
    123  |       }
    124  |
    125  |       result <<= 8;
    126  |       result += byte;
    127  |       bytes++;
    128  |
    129  |       addr = dot + 1;
    130  |     } while (!last);
    131  |
    132  |     if( expf == IP_PLAIN ) {
    133  |       if( bytes!=4 ) {
    134  | 	return IP_INVIP4;
    135  |       }
    136  |     }
    137  |     else {
    138  |       while( bytes<4 ) {
    139  | 	result <<= 8;
    140  | 	bytes++;
    141  |       }
    142  |     }
    143  |
    144  |     memset(ipptr, 0, sizeof(ip_addr_t));
    145  |     ipptr->space = IP_V4;
    146  |     ipptr->words[0] = result;
    147  |   }
    148  |   else {
    149  |     /* IPv6 */
    150  |     /* not yet implemented. Sorry. */
    151  |     /*    die; */
    152  |     return  IP_NO6YET;
    153  |   }
    154  |   return IP_OK;
    155  | }
    156  |
    157  | /***************************************************************************/
    158  |
    159  | /*+ converts a "IP/length" string into a binary prefix
    160  | +*/
    161  | er_ret_t
    162  | IP_pref_t2b(ip_prefix_t *prefptr, char *prefstr, ip_exp_t expf)
    163  | {
    164  |   char ip[256];
    165  |   char *slash, *trash;
    166  |   int len;
    167  |   er_ret_t err;
    168  |
    169  |   if( expf != IP_PLAIN && expf != IP_EXPN ) {
    170  |     return IP_INVARG;
    171  |   }
    172  |
    173  |   if( (slash=index(prefstr, '/')) == NULL ) {
    174  |     /* die;  */ /* error: missing slash in prefix */
    175  |     return    IP_NOSLAS;
    176  |   }
    177  |   else {
    178  |     /* copy the IP part to another string, ERROR if 256 chars is not nough */
    179  |
    180  |     len = slash - prefstr;
    181  |     if( len > 255 ) {
    182  |       /* die;  */ /* ERROR - ip address part of the string too long. */
    183  |       return  IP_ADTOLO;
    184  |     }
    185  |     strncpy(ip, prefstr, len);
    186  |     ip[len]=0;
    187  |
    188  |     if( (err=IP_addr_t2b( &(prefptr->ip), ip, expf)) != IP_OK) {
    189  |       /* die;   */ /* set error flag: incorrect address format */
    190  |       return err;
    191  |     }
    192  |
    193  |     /* stop at first non-digit */
    194  |     for(trash = slash+1; isdigit(*trash) ; trash++);
    195  |     len = trash - (slash+1) ;
    196  |     if( len > 4 ) {
    197  |       /* die; */ /* ERROR - prefix length part of the string too long. */
    198  |       return IP_PRTOLO;
    199  |     }
    200  |     strncpy(ip, slash+1, len);
    201  |     ip[len]=0;
    202  |
    203  |     if( ut_dec_2_uns(ip, &prefptr->bits) < 0 ) {
    204  |
    205  |       /*    if( sscanf (slash+1, "%d", &(prefptr->bits)) < 1 ) {
    206  |             die; */ /* handle syntax ERROR invalid characters found */
    207  |       return IP_INVPRF;
    208  |     }
    209  |   }
    210  |   /* sanitify the prefix - maybe some irrelevant bits are set */
    211  |   /* never create broken binary prefixes. */
    212  |
    213  |   IP_pref_bit_fix(prefptr);
    214  |
    215  |   return IP_OK;
    216  | }
    217  |
    218  | /***************************************************************************/
    219  |
    220  | /*+ convert a range string into a binary range struct.
    221  | +*/
    222  | er_ret_t
    223  | IP_rang_t2b(ip_range_t *rangptr, char *rangstr, ip_exp_t expf)
    224  | {
    225  |   char *ips, *dash;
    226  |   er_ret_t err;
    227  |
    228  |   if( expf != IP_PLAIN && expf != IP_EXPN ) {
    229  |     return IP_INVARG;
    230  |   }
    231  |
    232  |   if( (dash=index(rangstr, '-')) == NULL ) {
    233  |     /*    die;  */ /* error: missing dash in range */
    234  |     return IP_INVRAN;
    235  |   }
    236  |   else {
    237  |     /* copy the first IP */
    238  |     if( (err = wr_calloc( (void*) &ips,1,dash - rangstr + 1)) != UT_OK ) {
    239  |       return err;
    240  |     }
    241  |
    242  |     strncpy(ips, rangstr, dash - rangstr);
    243  |
    244  |     /* convert the first IP into a binary struct */
    245  |     err=IP_addr_t2b( &(rangptr->begin), ips, expf);
    246  |
    247  |     /* check later */ /* set error flag: incorrect address format */
    248  |
    249  |     wr_free(ips);
    250  |
    251  |     if( err != IP_OK ) {
    252  |       return err;
    253  |     }
    254  |
    255  |     /* now find the other ip, skip the space */
    256  |     ips=dash+1;
    257  |     while( *ips == ' ' ) {
    258  |       ips++;
    259  |     }
    260  |
    261  |     /* convert the second IP into a binary struct */
    262  |     if( (err=IP_addr_t2b( &(rangptr->end), ips, expf)) != IP_OK ) {
    263  |       /* die;  */ /* incorrect address format */
    264  |       return err;
    265  |     }
    266  |
    267  |     if( rangptr->begin.space != rangptr->end.space ) {
    268  |       /* die;  */ /* incompatible IP spaces */
    269  |       return IP_INVRAN;
    270  |     }
    271  |
    272  |     return IP_OK;
    273  |   }
    274  | }
    275  |
    276  | /***************************************************************************/
    277  | /*+ convert the socket's idea of address into a binary range struct.
    278  |
    279  |   space    select the address type (and consequently struct type)
    280  | */
    281  |
    282  | er_ret_t
    283  | IP_addr_s2b(ip_addr_t *addrptr,
    284  | 	    void      *addr_in,
    285  | 	    int       addr_len)
    286  | {
    287  |   if( addr_len == sizeof(struct sockaddr_in)
    288  |       && ((struct sockaddr_in *)addr_in)->sin_family == AF_INET ) {
    289  |     addrptr->space = IP_V4;
    290  |     addrptr->words[0] =
    291  |       ntohl( ((struct sockaddr_in*)addr_in)->sin_addr.s_addr);
    292  |
    293  |     addrptr->words[1] = addrptr->words[2] = addrptr->words[3] = 0;
    294  |   }
    295  |   else { /* unsupported family or invalid struct */
    296  |     die;
    297  |   }
    298  |   return IP_OK;
    299  | }
    300  |
    301  |
    302  | /*+converts the IP binary address (binaddr) to a string (ascaddr)
    303  |    of at most strmax characters. Independent of the result
    304  |    (success or failure) it messes up the string.
    305  | +*/
    306  | er_ret_t
    307  | IP_addr_b2a( ip_addr_t *binaddr, char *ascaddr, int strmax )
    308  | {
    309  |
    310  |   if(binaddr->space == IP_V4) {
    311  |     if (snprintf(ascaddr, strmax, "%d.%d.%d.%d",
    312  | 		 ((binaddr->words[0]) & ((unsigned)0xff<<24))>>24,
    313  | 		 ((binaddr->words[0]) & (0xff<<16))>>16,
    314  | 		 ((binaddr->words[0]) & (0xff<<8))>>8,
    315  | 		 ((binaddr->words[0]) & (0xff<<0))>>0
    316  | 		 ) >= strmax) {
    317  |       /*die;  */ /* string too short */
    318  |       return IP_TOSHRT;
    319  |     }
    320  |
    321  | #if 0
    322  |     char buf[5];
    323  |     int mask;
    324  |
    325  |     *ascaddr = '\0';
    326  |
    327  |     /* this is very inefficient - but maybe this is the way to go for IPv6 */
    328  |
    329  |     for(mask=24; mask >= 0; mask -= 8) {
    330  |
    331  |       sprintf(buf, "%d%s", ((binaddr->words[0]) & 0xff<<mask)>>mask,
    332  | 	      mask==0 ? "" : ".");
    333  |       if( (strlen(buf)+strlen(ascaddr)) >= strmax ) {
    334  | 	/* die;  */ /* error: insufficient space */
    335  | 	return IP_TOSHRT;
    336  |       }
    337  |       else {
    338  | 	strcat(ascaddr, buf);
    339  |       }
    340  |     }
    341  |
    342  | #endif
    343  |
    344  |   }
    345  |   else {
    346  |     /* IPv6 */
    347  |     /* not yet implemented. Sorry. */
    348  |     /* die; */
    349  |     return    IP_NO6YET;
    350  |   }
    351  |   return IP_OK;
    352  | }
    353  |
    354  | /***************************************************************************/
    355  |
    356  | /*+ convert a binary prefix back into ascii string at most strmax chars long
    357  | +*/
    358  | er_ret_t
    359  | IP_pref_b2a(ip_prefix_t *prefptr, char *ascaddr, int strmax)
    360  | {
    361  |   int strl;
    362  |   er_ret_t err;
    363  |
    364  |   if( (err=IP_addr_b2a (&(prefptr->ip), ascaddr, strmax)) != IP_OK) {
    365  |     /*die;  */ /* what the hell */
    366  |     return err;
    367  |   }
    368  |   strl = strlen(ascaddr);
    369  |   strmax -= strl;
    370  |
    371  |   /* now strmax holds the space that is left */
    372  |
    373  |   if( snprintf(ascaddr+strl, strmax, "/%d", prefptr->bits) >= strmax) {
    374  |     /* die;  */ /* error: string too short */
    375  |     return IP_TOSHRT;
    376  |   }
    377  |   return IP_OK;
    378  | }
    379  |
    380  |
    381  |
    382  | /***************************************************************************/
    383  | /*+ convert a binary range back into ascii string at most strmax chars long
    384  | +*/
    385  | er_ret_t
    386  | IP_rang_b2a(ip_range_t *rangptr, char *ascaddr, int strmax)
    387  | {
    388  |   int strl=0, strleft;
    389  |   er_ret_t err;
    390  |
    391  |   strleft = strmax - strl;
    392  |   if( (err=IP_addr_b2a (&(rangptr->begin), ascaddr, strleft)) != IP_OK) {
    393  |     return err;
    394  |   }
    395  |   strl = strlen(ascaddr);
    396  |
    397  |   strleft = strmax - strl;
    398  |   if( strleft < 5 ) {
    399  |     return IP_TOSHRT;
    400  |   }
    401  |   strcat( ascaddr, " - " );
    402  |   strl += 3;
    403  |
    404  |   strleft = strmax - strl;
    405  |   if( (err=IP_addr_b2a (&(rangptr->end), ascaddr+strl, strleft)) != IP_OK) {
    406  |     return err;
    407  |   }
    408  |
    409  |   return IP_OK;
    410  | }
    411  |
    412  | /***************************************************************************/
    413  | /*+ return the bitnum bit of the address,
    414  |    COUNTING FROM THE TOP !!!!! ,
    415  |    starting with 0 for the *most significant bit*.
    416  | +*/
    417  | int
    418  | IP_addr_bit_get(ip_addr_t *binaddr, int bitnum) {
    419  |   register int bitval;
    420  |
    421  |   /* IPv4 is easy... */
    422  |   bitval = (binaddr->words[0] & (0x80000000 >> (bitnum)));
    423  |
    424  |   return (bitval != 0);
    425  |
    426  | }
    427  |
    428  | /***************************************************************************/
    429  | /*+ set the bitnum bit of the address to bitval,
    430  |    COUNTING FROM THE TOP !!!!! ,
    431  |    starting with 0 for the *most significant bit*.
    432  | +*/
    433  | void
    434  | IP_addr_bit_set(ip_addr_t *binaddr, int bitnum, int bitval) {
    435  |
    436  |   /* IPv4 is easy... */
    437  |   if ( bitval == 1 )
    438  |     binaddr->words[0] |= (0x80000000 >> (bitnum));
    439  |   else
    440  |     binaddr->words[0] &=  ~(0x80000000 >> (bitnum));
    441  | }
    442  | /***************************************************************************/
    443  |
    444  | /*+ this fixes a prefix by setting insignificant bits to 0 +*/
    445  | void
    446  | IP_pref_bit_fix( ip_prefix_t *prefix )
    447  | {
    448  |
    449  | unsigned mask=0xffffffff;
    450  |
    451  | /* shorthand for ipv4 */
    452  |
    453  | /* Shifting out by 32 bits does NOT turn all bits into 0... */
    454  |  if( prefix->bits < 32 ) {
    455  |    prefix->ip.words[0] &= ~(mask >> prefix->bits);
    456  |  }
    457  |
    458  | #if 0
    459  |  int i;
    460  |  for(i=prefix->bits; i < IP_sizebits(prefix->ip.space) ; i++) {
    461  |    IP_addr_bit_set( & prefix->ip, i, 0);
    462  |  }
    463  | #endif
    464  |
    465  |
    466  | }
    467  |
    468  | /***************************************************************************/
    469  |
    470  |
    471  | /*+
    472  |   This is a hook function for use with g_list_foreach, to print a list
    473  |   of prefixes
    474  | +*/
    475  |
    476  | void ip_print_prefix(void *dataptr, void *junk) {
    477  |   char ascpref[IP_PREFSTR_MAX];
    478  |   ip_prefix_t *binpref=dataptr;
    479  |
    480  |   IP_pref_b2a( binpref, ascpref, IP_PREFSTR_MAX );
    481  |   printf ("prefix: %s\n", ascpref);
    482  | }
    483  |
    484  |
    485  | /***************************************************************************/
    486  |
    487  | /*+ compares two IP addresses up to the bit # len,
    488  |    returns 0 if equal, 1 if ptra greater, -1 if ptrb greater.
    489  |
    490  |    It is the responsility of the caller to ensure that both addresses
    491  |    are from the same IP space.
    492  | +*/
    493  |
    494  | int
    495  | IP_addr_cmp(ip_addr_t *ptra, ip_addr_t *ptrb, int len)
    496  | {
    497  |   int a,b,i;
    498  |
    499  |   for(i=0; i<len; i++) {
    500  |     a=IP_addr_bit_get(ptra, i);
    501  |     b=IP_addr_bit_get(ptrb, i);
    502  |     if( a != b ) {
    503  |       if( a > b ) return 1;
    504  |       else return -1;
    505  |     }
    506  |   }
    507  |   return 0;
    508  | }
    509  |
    510  |
    511  |
    512  |
    513  |
    514  | /***************************************************************************/
    515  |
    516  | /*+
    517  | this is a shorthand notation to pull out the first word of the address.
    518  | it is defined for the scope od the following functions
    519  | +*/
    520  | #define ad(which) (rangptr->which)
    521  |
    522  | /***************************************************************************/
    523  | /*+ calculate the span of a range == size - 1 +*/
    524  |
    525  | ip_rangesize_t
    526  | IP_rang_span( ip_range_t *rangptr )
    527  | {
    528  |   /* IPv4: */
    529  |   return ad(end).words[0] - ad(begin).words[0];
    530  | }
    531  |
    532  | /***************************************************************************/
    533  |
    534  | /*+ Decomposes a binary range into prefixes and appends them to the list.
    535  |    Allocates prefix structures and list elements, they must be freed after use.
    536  |
    537  |    returns a bitmask of prefix lengths used.
    538  | +*/
    539  |
    540  | unsigned
    541  | IP_rang_decomp(ip_range_t *rangptr, GList **preflist)
    542  | {
    543  | unsigned            prefmask=0;
    544  | register int        slash=0;
    545  | register unsigned   c_dif, blk, ff;
    546  | ip_range_t  workrange;
    547  | ip_addr_t   workbegin;
    548  | ip_addr_t   workend;
    549  | ip_prefix_t *prefptr;
    550  |
    551  |   if( ad(begin).words[0] > ad(end).words[0] ) {   /* has gone too far */
    552  |     return 0;
    553  |   }
    554  |
    555  |   if( ad(begin).words[0] == ad(end).words[0] ) {  /* one IP, i.e. /32 for IPv4 */
    556  |     prefmask |= 1;
    557  |     if(  wr_calloc( (void **)& prefptr, sizeof(ip_prefix_t), 1) != UT_OK) {
    558  |       die;
    559  |     }
    560  |     prefptr->ip = ad(begin);
    561  |     prefptr->bits = 32;
    562  |
    563  |     *preflist = g_list_append( *preflist, prefptr );
    564  |
    565  |     return prefmask;
    566  |   }
    567  |
    568  |   c_dif = ad(end).words[0] - ad(begin).words[0];
    569  |
    570  |   /* initialize work vars */
    571  |
    572  |   workbegin = ad(begin);
    573  |   workend = ad(end);
    574  |
    575  |   /* now find the biggest block fitting in this range */
    576  |   /* i.e. the first 2^n number smaller than c_dif */
    577  |
    578  |   /* the loop would not work for /0 (some stupid queries may have that) */
    579  |   /* so this must be checked for separately */
    580  |
    581  |   if( c_dif == 0xffffffff ) {
    582  |     /* they are already set to 0.0.0.0 - 255.255.255.255 */
    583  |     /* leave them alone.  */
    584  |     blk = 0;
    585  |     slash = 0;
    586  |   }
    587  |   else {
    588  |
    589  |     c_dif += 1;     /* was not done earlier to protect from overflow */
    590  |
    591  |     for(slash=1;
    592  | 	slash<32 && ((blk=((unsigned)0x80000000>>(slash-1))) & c_dif) == 0;
    593  | 	slash++) {}
    594  |
    595  |     /* clear all digits in a and b under the blk one. */
    596  |     ff=blk-1;
    597  |
    598  |     workbegin.words[0] = (workbegin.words[0] + ff) & ~ff;
    599  |
    600  |     workend.words[0] = (workend.words[0] + 1) & ~ff;
    601  |   }
    602  |
    603  |   if( workbegin.words[0] != workend.words[0] ) {
    604  |     prefmask |= blk;
    605  |     if(  wr_malloc( (void **)& prefptr, sizeof(ip_prefix_t)) != UT_OK) {
    606  |       die;
    607  |     }
    608  |     prefptr->ip = workbegin;
    609  |     prefptr->bits = slash;
    610  |
    611  |     *preflist = g_list_append( *preflist, prefptr );
    612  |   }
    613  |
    614  |   if( ad(begin).words[0] != workbegin.words[0] ) {
    615  |     workrange.begin = ad(begin);
    616  |
    617  |     workbegin.words[0] -= 1;
    618  |     workrange.end   = workbegin;
    619  |
    620  |     prefmask |= IP_rang_decomp( &workrange, preflist );
    621  |   }
    622  |
    623  |   /* here we must protect from decomposition of  */
    624  |   /* 255.255.255.255 - 255.255.255.255 in case the range */
    625  |   /* 0.0.0.0 - 255.255.255.255 is considered. Hence the slash>0 condition. */
    626  |
    627  |   if( workend.words[0] <= ad(end).words[0] && slash > 0) {
    628  |     workrange.begin = workend;
    629  |     workrange.end   = ad(end);
    630  |
    631  |     prefmask |= IP_rang_decomp( &workrange, preflist );
    632  |   }
    633  |
    634  |   return prefmask;
    635  | }
    636  |
    637  |
    638  | /***************************************************************************/
    639  |
    640  | /*+ Similar name, slightly different code, totally different functionality.
    641  |
    642  |    finds the smallest canonical block encompassing the whole given range,
    643  |    then MODIFIES the range pointed to by the argument
    644  |    so that it's equal to this block.
    645  |
    646  |    returns a bitmask of prefix length used.
    647  | +*/
    648  |
    649  | unsigned
    650  | IP_rang_encomp(ip_range_t *rangptr)
    651  | {
    652  |   unsigned    prefmask=0;
    653  |   int         slash=0;
    654  |   unsigned    c_dif, blk, ff, t_dif;
    655  |   ip_range_t  workrange;
    656  |   ip_addr_t   workbegin;
    657  |   ip_addr_t   workend;
    658  |
    659  |   c_dif = ad(end).words[0] - ad(begin).words[0];
    660  |
    661  |   /* now find the biggest block fitting in this range */
    662  |   /* i.e. the first 2^n number smaller than c_dif */
    663  |
    664  |   /* the loop would not work for /0 (some stupid queries may have that) */
    665  |   /* so this must be checked for separately */
    666  |
    667  |   if( c_dif > 0x80000000 ) {
    668  |     slash = 0;
    669  |     ff = 0xffffffff;
    670  |     blk = 0;
    671  |
    672  |     workbegin = workend = ad(begin);
    673  |     workbegin.words[0] = 0;
    674  |     workend.words[0] = ff;
    675  |   }
    676  |   else {
    677  |
    678  |     do {
    679  |       c_dif += 1;
    680  |
    681  |       /* find the smallest block ENCOMPASSING c_dif. */
    682  |       /* this implies a loop from the bottom up */
    683  |
    684  |       for(slash=32;
    685  | 	  slash>1 && (blk=((unsigned)0x80000000>>(slash-1))) < c_dif;
    686  | 	  slash--) {}
    687  |
    688  |       ff=blk-1;
    689  |
    690  |       /* clear all digits in workbegin under the blk one. */
    691  |
    692  |       workbegin = ad(begin);
    693  |       workbegin.words[0] = workbegin.words[0] & ~ff;
    694  |
    695  |       /* see if it has not made the difference larger than blk,  */
    696  |       /* retry if so */
    697  |
    698  |       t_dif = c_dif;
    699  |       c_dif = ad(end).words[0] - workbegin.words[0];
    700  |
    701  |     } while( c_dif >= t_dif );
    702  |
    703  |     /* set the endpoint to workbegin + blocksize - 1 */
    704  |     /* which amounts to + ff */
    705  |
    706  |     workend = ad(begin);
    707  |     workend.words[0] = workbegin.words[0] + ff;
    708  |   }
    709  |
    710  |
    711  |     /* set the range to new values */
    712  |
    713  |     rangptr->begin = workbegin;
    714  |     rangptr->end   = workend;
    715  | }
    716  |
    717  | /***************************************************************************/
    718  | /*+ sets a range equal to a prefix +*/
    719  |
    720  | er_ret_t
    721  | IP_pref_2_rang( ip_range_t *rangptr, ip_prefix_t *prefptr )
    722  | {
    723  |   ip_rangesize_t span;
    724  |
    725  |   ad(begin) = ad(end) = prefptr->ip;
    726  |
    727  |   if( prefptr->bits > 0 ) {
    728  |     span = (1 << (32 - prefptr->bits)) - 1 ;
    729  |   }
    730  |   else {
    731  |     span = 0xffffffff;
    732  |   }
    733  |
    734  |   ad(end).words[0] += span;
    735  |
    736  |   return IP_OK;
    737  | }
    738  |
    739  | #undef ad
    740  |
    741  | /***************************************************************************/
    742  |
    743  | /*+
    744  |    This is to parse a classfull address into a range.
    745  |
    746  |    Takes the address by pointer from addrptr and puts the result
    747  |    at rangptr.
    748  |
    749  |    Throws error if the address does not fall into any of the
    750  |    classfull categories
    751  |
    752  | +*/
    753  |
    754  | er_ret_t
    755  | IP_rang_classful( ip_range_t *rangptr, ip_addr_t *addrptr)
    756  | {
    757  | int i;
    758  | unsigned b[4];
    759  |
    760  |   if( addrptr->space != IP_V4 ) {
    761  |     /* it's IPv6. There are no classful ranges or anything like that. */
    762  |     /* we accept only explicit ranges */
    763  |
    764  |     die;
    765  |   }
    766  |
    767  |   rangptr->begin = *addrptr;
    768  |   rangptr->end.space = IP_V4;
    769  |   for(i=0; i<4; i++) {
    770  |     rangptr->end.words[i] = 0;
    771  |   }
    772  |
    773  |   /* assume it's at least a valid IP. let's try different classes now */
    774  |
    775  |   /* we could have used a union here, but it would not work on */
    776  |   /* low endians. So byte by byte copying to and from an array. */
    777  |
    778  |   for(i=0; i<4; i++) {
    779  |     b[i] = ( rangptr->begin.words[0] & (0xFF << i*8) ) >> i*8;
    780  |   }
    781  |
    782  |   if( b[3] >= 1 && b[3] < 128
    783  |       && b[2] == 0 && b[1] == 0 && b[0] == 0 ) {
    784  |     b[2]=b[1]=b[0]=255;
    785  |   }
    786  |   else if( b[3] >= 128 && b[3] < 192
    787  | 	   && b[1] == 0 && b[0] == 0 ) {
    788  |     b[1]=b[0]=255;
    789  |   }
    790  |   else if( b[3] >= 192 && b[3] < 224
    791  | 	   &&  b[0] == 0 ) {
    792  |     b[0]=255;
    793  |   }
    794  |   else if( b[3] >= 224 && b[3] < 255 ) {
    795  |     /* just leave it, make it a /32, i.e. begin == end */
    796  |   }
    797  |   else {
    798  |     /* Leave it and make it a /32 */
    799  |     /* This is AGAINST the rule! but we have some junk  */
    800  |     /* so we have to compensate for it. */
    801  |   }
    802  |
    803  |   /* copy the (now - modified) bytes into the end of range */
    804  |   for(i=0; i<4; i++) {
    805  |     rangptr->end.words[0] |= (b[i] << i*8);
    806  |   }
    807  |
    808  |   return IP_OK;
    809  | }
    810  |
    811  |
    812  | /***************************************************************************/
    813  | /*+
    814  |   Trying to be smart :-) and convert a query search term into prefix(es),
    815  |   regardless of whether specified as IP address, prefix or range.
    816  |
    817  |   justcheck - if just checking the syntax (justcheck == 1),
    818  |      then the prefixes are freed before the function returns,
    819  |      otherwise it is the responsibility of the caller to free the list.
    820  |
    821  | +*/
    822  |
    823  | er_ret_t
    824  | IP_smart_conv(char *key,
    825  | 	      int justcheck,
    826  | 	      int encomp,
    827  | 	      GList **preflist,
    828  | 	      ip_exp_t expf)
    829  | {
    830  |   int free_it;
    831  |   er_ret_t call_err, err=IP_OK;      /* let's be optimistic :-) */
    832  |   ip_prefix_t *querypref;
    833  |
    834  |   /* if just checking the syntax (justcheck == 1),
    835  |      then free_it = 1,
    836  |      else 0, but may be modified later (in range conversion)
    837  |   */
    838  |
    839  |   free_it = justcheck;
    840  |
    841  |   if( (call_err = wr_malloc( (void **) &querypref, sizeof(ip_prefix_t)))
    842  |       != UT_OK) {
    843  |     return call_err;
    844  |   }
    845  |
    846  |   if( IP_pref_t2b(querypref, key, expf) == IP_OK ) {
    847  |     if( justcheck == 0) {
    848  |       *preflist = g_list_append(*preflist, querypref);
    849  |     }
    850  |   }
    851  |   else {
    852  |     /* not a prefix.  */
    853  |     /* Maybe an IP ? */
    854  |     if( IP_addr_t2b( &(querypref->ip), key, expf) == IP_OK ) {
    855  |
    856  |       /*convert to a /32 */
    857  |       querypref->bits = 32;
    858  |
    859  |       if( justcheck == 0) {
    860  | 	*preflist = g_list_append(*preflist, querypref);
    861  |       }
    862  |     }
    863  |     else {
    864  |       /* hm, maybe a range then ? */
    865  |       ip_range_t myrang;
    866  |
    867  |       /* won't use the querypref anymore, mark it for freeing later */
    868  |       free_it = 1;
    869  |
    870  |       if( IP_rang_t2b(&myrang, key, expf) == IP_OK ) {
    871  | 	/* Wow. Great.  */
    872  |
    873  | 	/* sometimes (exless match) we look for the first bigger(shorter)  */
    874  | 	/* prefix containing this range. */
    875  |
    876  | 	if( encomp ) {
    877  | 	  IP_rang_encomp(&myrang);
    878  | 	}
    879  | 	/* OK, now we can let the engine happily find that it's just one */
    880  | 	/* range */
    881  |
    882  | 	if( justcheck == 0) {
    883  | 	  IP_rang_decomp(&myrang, preflist);
    884  | 	}
    885  |       }
    886  |       else {
    887  | 	err = IP_INVARG; /* "conversion error" */
    888  |       }
    889  |     }
    890  |   }
    891  |
    892  |   if( free_it ) {
    893  |     wr_free(querypref);
    894  |   }
    895  |
    896  |   return err;
    897  | }
    898  |
    899  |
    900  | #ifdef MODULE_TEST
    901  | #include "ip_test.c"
    902  | #endif