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