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 |