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