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