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