1    | /***************************************
2    |   $Revision: 1.11 $
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[5];
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  | /* ottrey 30/12/1999
527  | IP_rang_span( ip_range_t *rangptr )
528  | */
529  | IP_rang_span( ip_range_t rangptr )
530  | {
531  |   /* IPv4: */
532  |   /* ottrey 30/12/1999
533  |   return ad(end).words[0] - ad(begin).words[0];
534  |   */
535  |   return rangptr.end.words[0] - rangptr.begin.words[0];
536  | }
537  | 
538  | /***************************************************************************/
539  | 
540  | /*+ Decomposes a binary range into prefixes and appends them to the list.
541  |    Allocates prefix structures and list elements, they must be freed after use.
542  | 
543  |    returns a bitmask of prefix lengths used.
544  | +*/
545  | 
546  | unsigned
547  | IP_rang_decomp(ip_range_t *rangptr, GList **preflist)
548  | {
549  | unsigned            prefmask=0;
550  | register int        slash=0;
551  | register unsigned   c_dif, blk, ff;
552  | ip_range_t  workrange;
553  | ip_addr_t   workbegin;
554  | ip_addr_t   workend;
555  | ip_prefix_t *prefptr;
556  | 
557  |   if( ad(begin).words[0] > ad(end).words[0] ) {   /* has gone too far */
558  |     return 0; 
559  |   }
560  | 
561  |   if( ad(begin).words[0] == ad(end).words[0] ) {  /* one IP, i.e. /32 for IPv4 */
562  |     prefmask |= 1;
563  |     if(  wr_calloc( (void **)& prefptr, sizeof(ip_prefix_t), 1) != UT_OK) {
564  |       die;
565  |     }
566  |     prefptr->ip = ad(begin);
567  |     prefptr->bits = 32;
568  | 
569  |     *preflist = g_list_append( *preflist, prefptr );
570  | 
571  |     return prefmask;
572  |   }
573  |   
574  |   c_dif = ad(end).words[0] - ad(begin).words[0];
575  |   
576  |   /* initialize work vars */
577  | 
578  |   workbegin = ad(begin);
579  |   workend = ad(end);
580  |  
581  |   /* now find the biggest block fitting in this range */
582  |   /* i.e. the first 2^n number smaller than c_dif */
583  | 
584  |   /* the loop would not work for /0 (some stupid queries may have that) */
585  |   /* so this must be checked for separately */
586  | 
587  |   if( c_dif == 0xffffffff ) {
588  |     /* they are already set to 0.0.0.0 - 255.255.255.255 */
589  |     /* leave them alone.  */
590  |     blk = 0;
591  |     slash = 0;
592  |   }
593  |   else {
594  | 
595  |     c_dif += 1;     /* was not done earlier to protect from overflow */
596  | 
597  |     for(slash=1; 
598  | 	slash<32 && ((blk=((unsigned)0x80000000>>(slash-1))) & c_dif) == 0; 
599  | 	slash++) {}
600  | 
601  |     /* clear all digits in a and b under the blk one. */
602  |     ff=blk-1;
603  | 
604  |     workbegin.words[0] = (workbegin.words[0] + ff) & ~ff;
605  |     
606  |     workend.words[0] = (workend.words[0] + 1) & ~ff;
607  |   }
608  |   
609  |   if( workbegin.words[0] != workend.words[0] ) {
610  |     prefmask |= blk;
611  |     if(  wr_malloc( (void **)& prefptr, sizeof(ip_prefix_t)) != UT_OK) {
612  |       die;
613  |     }
614  |     prefptr->ip = workbegin;
615  |     prefptr->bits = slash;
616  |     
617  |     *preflist = g_list_append( *preflist, prefptr );
618  |   }
619  | 
620  |   if( ad(begin).words[0] != workbegin.words[0] ) {
621  |     workrange.begin = ad(begin);
622  | 
623  |     workbegin.words[0] -= 1;
624  |     workrange.end   = workbegin;
625  | 
626  |     prefmask |= IP_rang_decomp( &workrange, preflist );
627  |   }
628  |   
629  |   /* here we must protect from decomposition of  */
630  |   /* 255.255.255.255 - 255.255.255.255 in case the range */
631  |   /* 0.0.0.0 - 255.255.255.255 is considered. Hence the slash>0 condition. */
632  | 
633  |   if( workend.words[0] <= ad(end).words[0] && slash > 0) {
634  |     workrange.begin = workend;
635  |     workrange.end   = ad(end);
636  | 
637  |     prefmask |= IP_rang_decomp( &workrange, preflist );
638  |   }
639  |   
640  |   return prefmask;
641  | }
642  | 
643  | 
644  | /***************************************************************************/
645  | 
646  | /*+ Similar name, slightly different code, totally different functionality.
647  | 
648  |    finds the smallest canonical block encompassing the whole given range, 
649  |    then MODIFIES the range pointed to by the argument 
650  |    so that it's equal to this block.
651  | 
652  |    returns a bitmask of prefix length used.
653  | +*/
654  | 
655  | unsigned
656  | IP_rang_encomp(ip_range_t *rangptr)
657  | {
658  |   unsigned    prefmask=0;
659  |   int         slash=0;
660  |   unsigned    c_dif, blk, ff, t_dif;
661  |   ip_range_t  workrange;
662  |   ip_addr_t   workbegin;
663  |   ip_addr_t   workend;
664  |   
665  |   c_dif = ad(end).words[0] - ad(begin).words[0];
666  | 
667  |   /* now find the biggest block fitting in this range */
668  |   /* i.e. the first 2^n number smaller than c_dif */
669  | 
670  |   /* the loop would not work for /0 (some stupid queries may have that) */
671  |   /* so this must be checked for separately */
672  | 
673  |   if( c_dif > 0x80000000 ) {
674  |     slash = 0;
675  |     ff = 0xffffffff;
676  |     blk = 0;
677  | 
678  |     workbegin = workend = ad(begin);
679  |     workbegin.words[0] = 0;
680  |     workend.words[0] = ff;
681  |   }
682  |   else {
683  |     
684  |     do {
685  |       c_dif += 1;
686  |       
687  |       /* find the smallest block ENCOMPASSING c_dif. */
688  |       /* this implies a loop from the bottom up */
689  |       
690  |       for(slash=32; 
691  | 	  slash>1 && (blk=((unsigned)0x80000000>>(slash-1))) < c_dif; 
692  | 	  slash--) {}
693  |       
694  |       ff=blk-1;
695  |       
696  |       /* clear all digits in workbegin under the blk one. */
697  |       
698  |       workbegin = ad(begin);
699  |       workbegin.words[0] = workbegin.words[0] & ~ff;
700  |     
701  |       /* see if it has not made the difference larger than blk,  */
702  |       /* retry if so */
703  |       
704  |       t_dif = c_dif;
705  |       c_dif = ad(end).words[0] - workbegin.words[0];
706  |       
707  |     } while( c_dif >= t_dif );
708  |     
709  |     /* set the endpoint to workbegin + blocksize - 1 */
710  |     /* which amounts to + ff */
711  |     
712  |     workend = ad(begin);
713  |     workend.words[0] = workbegin.words[0] + ff;
714  |   }
715  | 
716  | 
717  |     /* set the range to new values */
718  |   
719  |     rangptr->begin = workbegin;
720  |     rangptr->end   = workend;
721  | }
722  | 
723  | /***************************************************************************/
724  | /*+ sets a range equal to a prefix +*/
725  | 
726  | er_ret_t
727  | IP_pref_2_rang( ip_range_t *rangptr, ip_prefix_t *prefptr )
728  | {
729  |   ip_rangesize_t span;
730  | 
731  |   ad(begin) = ad(end) = prefptr->ip;
732  |   
733  |   if( prefptr->bits > 0 ) {
734  |     span = (1 << (32 - prefptr->bits)) - 1 ;
735  |   }
736  |   else {
737  |     span = 0xffffffff;
738  |   }
739  |   
740  |   ad(end).words[0] += span;
741  |   
742  |   return IP_OK;
743  | }
744  | 
745  | #undef ad
746  | 
747  | /***************************************************************************/
748  | 
749  | /*+ 
750  |    This is to parse a classfull address into a range.
751  | 
752  |    Takes the address by pointer from addrptr and puts the result
753  |    at rangptr. 
754  | 
755  |    Throws error if the address does not fall into any of the 
756  |    classfull categories 
757  | 
758  | +*/
759  | 
760  | er_ret_t
761  | IP_rang_classful( ip_range_t *rangptr, ip_addr_t *addrptr)
762  | {
763  | int i;
764  | unsigned b[4];
765  | 
766  |   if( addrptr->space != IP_V4 ) {
767  |     /* it's IPv6. There are no classful ranges or anything like that. */
768  |     /* we accept only explicit ranges */
769  | 
770  |     die;
771  |   }
772  |   
773  |   rangptr->begin = *addrptr;
774  |   rangptr->end.space = IP_V4;
775  |   for(i=0; i<4; i++) {
776  |     rangptr->end.words[i] = 0;
777  |   }
778  |   
779  |   /* assume it's at least a valid IP. let's try different classes now */
780  | 	      
781  |   /* we could have used a union here, but it would not work on */
782  |   /* low endians. So byte by byte copying to and from an array. */
783  |   
784  |   for(i=0; i<4; i++) {
785  |     b[i] = ( rangptr->begin.words[0] & (0xFF << i*8) ) >> i*8;
786  |   }
787  |   
788  |   if( b[3] >= 1 && b[3] < 128 
789  |       && b[2] == 0 && b[1] == 0 && b[0] == 0 ) {
790  |     b[2]=b[1]=b[0]=255;
791  |   }
792  |   else if( b[3] >= 128 && b[3] < 192 
793  | 	   && b[1] == 0 && b[0] == 0 ) {
794  |     b[1]=b[0]=255;
795  |   }
796  |   else if( b[3] >= 192 && b[3] < 224 
797  | 	   &&  b[0] == 0 ) {
798  |     b[0]=255;
799  |   }
800  |   else if( b[3] >= 224 && b[3] < 255 ) {
801  |     /* just leave it, make it a /32, i.e. begin == end */
802  |   }
803  |   else {
804  |     /* Leave it and make it a /32 */
805  |     /* This is AGAINST the rule! but we have some junk  */
806  |     /* so we have to compensate for it. */
807  |   }
808  |   
809  |   /* copy the (now - modified) bytes into the end of range */
810  |   for(i=0; i<4; i++) {
811  |     rangptr->end.words[0] |= (b[i] << i*8);
812  |   }
813  |   
814  |   return IP_OK;
815  | }
816  | 
817  | 
818  | /***************************************************************************/
819  | /*+ 
820  |   Trying to be smart :-) and convert a query search term into prefix(es),
821  |   regardless of whether specified as IP address, prefix or range.
822  |  
823  |   justcheck - if just checking the syntax (justcheck == 1), 
824  |      then the prefixes are freed before the function returns,
825  |      otherwise it is the responsibility of the caller to free the list.
826  | 
827  | +*/
828  | 
829  | er_ret_t
830  | IP_smart_conv(char *key, 
831  | 	      int justcheck, 
832  | 	      int encomp, 
833  | 	      GList **preflist, 
834  | 	      ip_exp_t expf)
835  | {
836  |   int free_it;
837  |   er_ret_t call_err, err=IP_OK;      /* let's be optimistic :-) */
838  |   ip_prefix_t *querypref;
839  | 
840  |   /* if just checking the syntax (justcheck == 1), 
841  |      then free_it = 1, 
842  |      else 0, but may be modified later (in range conversion)
843  |   */
844  | 
845  |   free_it = justcheck;
846  |   
847  |   if( (call_err = wr_malloc( (void **) &querypref, sizeof(ip_prefix_t))) 
848  |       != UT_OK) {
849  |     return call_err;
850  |   }
851  |   
852  |   if( IP_pref_t2b(querypref, key, expf) == IP_OK ) {
853  |     if( justcheck == 0) {
854  |       *preflist = g_list_append(*preflist, querypref);
855  |     }
856  |   } 
857  |   else {
858  |     /* not a prefix.  */
859  |     /* Maybe an IP ? */
860  |     if( IP_addr_t2b( &(querypref->ip), key, expf) == IP_OK ) {
861  | 
862  |       /*convert to a /32 */
863  |       querypref->bits = 32;
864  | 
865  |       if( justcheck == 0) {
866  | 	*preflist = g_list_append(*preflist, querypref);
867  |       }
868  |     }
869  |     else {    
870  |       /* hm, maybe a range then ? */
871  |       ip_range_t myrang;
872  |       
873  |       /* won't use the querypref anymore, mark it for freeing later */
874  |       free_it = 1;
875  |       
876  |       if( IP_rang_t2b(&myrang, key, expf) == IP_OK ) {
877  | 	/* Wow. Great.  */
878  | 	
879  | 	/* sometimes (exless match) we look for the first bigger(shorter)  */
880  | 	/* prefix containing this range. */
881  | 	
882  | 	if( encomp ) {
883  | 	  IP_rang_encomp(&myrang);
884  | 	}
885  | 	/* OK, now we can let the engine happily find that it's just one */
886  | 	/* range */
887  | 	
888  | 	if( justcheck == 0) {
889  | 	  IP_rang_decomp(&myrang, preflist);
890  | 	}
891  |       }
892  |       else {
893  | 	err = IP_INVARG; /* "conversion error" */
894  |       }
895  |     }
896  |   }
897  |   
898  |   if( free_it ) {
899  |     wr_free(querypref);
900  |   }
901  |   
902  |   return err;
903  | }
904  | 
905  | 
906  | #ifdef MODULE_TEST
907  | #include "ip_test.c"
908  | #endif