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