1 | /***************************************
2 | $Revision: 1.11 $
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
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 |
50 | /***************************************************************************/
51 | /*+ return the max. length of bits per space
52 |
53 | Yes, it *could* be a macro - but as a function it can detect
54 | more programmer's errors. And will get inlined anyway.
55 |
56 | +*/
57 |
58 | int IP_sizebits(ip_space_t spc_id) {
59 | switch (spc_id) {
60 | case IP_V4:
61 | return 32;
62 | case IP_V6:
63 | return 128;
64 | default:
65 | /* die; */ /* error: bad IP version specified */
66 | return -1;
67 | }
68 | }
69 |
70 | /***************************************************************************/
71 | /*+
72 | ascii IP address to binary.
73 | In IP_EXPN mode IP will be treated as not-expanded.
74 | (missing octets will be set to 0, MSB will be set).
75 | In IP_PLAIN mode the routine will complain if it sees less octets.
76 | +*/
77 |
78 | er_ret_t
79 | IP_addr_t2b(ip_addr_t *ipptr, char *addr, ip_exp_t expf)
80 | {
81 | if( index(addr, ':') == NULL ) {
82 | /* IPv4 */
83 | char *dot;
84 | unsigned len, byte, result=0;
85 | char cpy[5];
86 | int last = 0, dotsfound=0;
87 | int bytes=0;
88 |
89 | if( expf != IP_PLAIN && expf != IP_EXPN ) {
90 | return IP_INVARG;
91 | }
92 |
93 | do {
94 | if ( (dot = index (addr, '.')) == NULL) {
95 | dot = index (addr, '\0');
96 | last = 1;
97 | }
98 | else {
99 | if( ++dotsfound > 3 ) {
100 | /* handle syntax ERROR - too many dots found */
101 | return IP_INVIP4;
102 | }
103 | }
104 |
105 | if ((len = dot - addr) > 4) {
106 | /* syntax ERROR - too many digits between dots*/
107 | return IP_INVIP4;
108 | }
109 | strncpy( cpy, addr, len );
110 | cpy[len]=0;
111 |
112 | /* sscanf is waay too slow */
113 |
114 | if( ut_dec_2_uns(cpy, &byte) < 0 ) {
115 | /* handle syntax ERROR - invalid characters found */
116 | return IP_INVIP4;
117 | }
118 |
119 |
120 | if( byte > 255 ) {
121 | /* handle syntax ERROR - number between dots too high */
122 | return IP_INVIP4;
123 | }
124 |
125 | result <<= 8;
126 | result += byte;
127 | bytes++;
128 |
129 | addr = dot + 1;
130 | } while (!last);
131 |
132 | if( expf == IP_PLAIN ) {
133 | if( bytes!=4 ) {
134 | return IP_INVIP4;
135 | }
136 | }
137 | else {
138 | while( bytes<4 ) {
139 | result <<= 8;
140 | bytes++;
141 | }
142 | }
143 |
144 | memset(ipptr, 0, sizeof(ip_addr_t));
145 | ipptr->space = IP_V4;
146 | ipptr->words[0] = result;
147 | }
148 | else {
149 | /* IPv6 */
150 | /* not yet implemented. Sorry. */
151 | /* die; */
152 | return IP_NO6YET;
153 | }
154 | return IP_OK;
155 | }
156 |
157 | /***************************************************************************/
158 |
159 | /*+ converts a "IP/length" string into a binary prefix
160 | +*/
161 | er_ret_t
162 | IP_pref_t2b(ip_prefix_t *prefptr, char *prefstr, ip_exp_t expf)
163 | {
164 | char ip[256];
165 | char *slash, *trash;
166 | int len;
167 | er_ret_t err;
168 |
169 | if( expf != IP_PLAIN && expf != IP_EXPN ) {
170 | return IP_INVARG;
171 | }
172 |
173 | if( (slash=index(prefstr, '/')) == NULL ) {
174 | /* die; */ /* error: missing slash in prefix */
175 | return IP_NOSLAS;
176 | }
177 | else {
178 | /* copy the IP part to another string, ERROR if 256 chars is not nough */
179 |
180 | len = slash - prefstr;
181 | if( len > 255 ) {
182 | /* die; */ /* ERROR - ip address part of the string too long. */
183 | return IP_ADTOLO;
184 | }
185 | strncpy(ip, prefstr, len);
186 | ip[len]=0;
187 |
188 | if( (err=IP_addr_t2b( &(prefptr->ip), ip, expf)) != IP_OK) {
189 | /* die; */ /* set error flag: incorrect address format */
190 | return err;
191 | }
192 |
193 | /* stop at first non-digit */
194 | for(trash = slash+1; isdigit(*trash) ; trash++);
195 | len = trash - (slash+1) ;
196 | if( len > 4 ) {
197 | /* die; */ /* ERROR - prefix length part of the string too long. */
198 | return IP_PRTOLO;
199 | }
200 | strncpy(ip, slash+1, len);
201 | ip[len]=0;
202 |
203 | if( ut_dec_2_uns(ip, &prefptr->bits) < 0 ) {
204 |
205 | /* if( sscanf (slash+1, "%d", &(prefptr->bits)) < 1 ) {
206 | die; */ /* handle syntax ERROR invalid characters found */
207 | return IP_INVPRF;
208 | }
209 | }
210 | /* sanitify the prefix - maybe some irrelevant bits are set */
211 | /* never create broken binary prefixes. */
212 |
213 | IP_pref_bit_fix(prefptr);
214 |
215 | return IP_OK;
216 | }
217 |
218 | /***************************************************************************/
219 |
220 | /*+ convert a range string into a binary range struct.
221 | +*/
222 | er_ret_t
223 | IP_rang_t2b(ip_range_t *rangptr, char *rangstr, ip_exp_t expf)
224 | {
225 | char *ips, *dash;
226 | er_ret_t err;
227 |
228 | if( expf != IP_PLAIN && expf != IP_EXPN ) {
229 | return IP_INVARG;
230 | }
231 |
232 | if( (dash=index(rangstr, '-')) == NULL ) {
233 | /* die; */ /* error: missing dash in range */
234 | return IP_INVRAN;
235 | }
236 | else {
237 | /* copy the first IP */
238 | if( (err = wr_calloc( (void*) &ips,1,dash - rangstr + 1)) != UT_OK ) {
239 | return err;
240 | }
241 |
242 | strncpy(ips, rangstr, dash - rangstr);
243 |
244 | /* convert the first IP into a binary struct */
245 | err=IP_addr_t2b( &(rangptr->begin), ips, expf);
246 |
247 | /* check later */ /* set error flag: incorrect address format */
248 |
249 | wr_free(ips);
250 |
251 | if( err != IP_OK ) {
252 | return err;
253 | }
254 |
255 | /* now find the other ip, skip the space */
256 | ips=dash+1;
257 | while( *ips == ' ' ) {
258 | ips++;
259 | }
260 |
261 | /* convert the second IP into a binary struct */
262 | if( (err=IP_addr_t2b( &(rangptr->end), ips, expf)) != IP_OK ) {
263 | /* die; */ /* incorrect address format */
264 | return err;
265 | }
266 |
267 | if( rangptr->begin.space != rangptr->end.space ) {
268 | /* die; */ /* incompatible IP spaces */
269 | return IP_INVRAN;
270 | }
271 |
272 | return IP_OK;
273 | }
274 | }
275 |
276 | /***************************************************************************/
277 | /*+ convert the socket's idea of address into a binary range struct.
278 |
279 | space select the address type (and consequently struct type)
280 | */
281 |
282 | er_ret_t
283 | IP_addr_s2b(ip_addr_t *addrptr,
284 | void *addr_in,
285 | int addr_len)
286 | {
287 | if( addr_len == sizeof(struct sockaddr_in)
288 | && ((struct sockaddr_in *)addr_in)->sin_family == AF_INET ) {
289 | addrptr->space = IP_V4;
290 | addrptr->words[0] =
291 | ntohl( ((struct sockaddr_in*)addr_in)->sin_addr.s_addr);
292 |
293 | addrptr->words[1] = addrptr->words[2] = addrptr->words[3] = 0;
294 | }
295 | else { /* unsupported family or invalid struct */
296 | die;
297 | }
298 | return IP_OK;
299 | }
300 |
301 |
302 | /*+converts the IP binary address (binaddr) to a string (ascaddr)
303 | of at most strmax characters. Independent of the result
304 | (success or failure) it messes up the string.
305 | +*/
306 | er_ret_t
307 | IP_addr_b2a( ip_addr_t *binaddr, char *ascaddr, int strmax )
308 | {
309 |
310 | if(binaddr->space == IP_V4) {
311 | if (snprintf(ascaddr, strmax, "%d.%d.%d.%d",
312 | ((binaddr->words[0]) & ((unsigned)0xff<<24))>>24,
313 | ((binaddr->words[0]) & (0xff<<16))>>16,
314 | ((binaddr->words[0]) & (0xff<<8))>>8,
315 | ((binaddr->words[0]) & (0xff<<0))>>0
316 | ) >= strmax) {
317 | /*die; */ /* string too short */
318 | return IP_TOSHRT;
319 | }
320 |
321 | #if 0
322 | char buf[5];
323 | int mask;
324 |
325 | *ascaddr = '\0';
326 |
327 | /* this is very inefficient - but maybe this is the way to go for IPv6 */
328 |
329 | for(mask=24; mask >= 0; mask -= 8) {
330 |
331 | sprintf(buf, "%d%s", ((binaddr->words[0]) & 0xff<<mask)>>mask,
332 | mask==0 ? "" : ".");
333 | if( (strlen(buf)+strlen(ascaddr)) >= strmax ) {
334 | /* die; */ /* error: insufficient space */
335 | return IP_TOSHRT;
336 | }
337 | else {
338 | strcat(ascaddr, buf);
339 | }
340 | }
341 |
342 | #endif
343 |
344 | }
345 | else {
346 | /* IPv6 */
347 | /* not yet implemented. Sorry. */
348 | /* die; */
349 | return IP_NO6YET;
350 | }
351 | return IP_OK;
352 | }
353 |
354 | /***************************************************************************/
355 |
356 | /*+ convert a binary prefix back into ascii string at most strmax chars long
357 | +*/
358 | er_ret_t
359 | IP_pref_b2a(ip_prefix_t *prefptr, char *ascaddr, int strmax)
360 | {
361 | int strl;
362 | er_ret_t err;
363 |
364 | if( (err=IP_addr_b2a (&(prefptr->ip), ascaddr, strmax)) != IP_OK) {
365 | /*die; */ /* what the hell */
366 | return err;
367 | }
368 | strl = strlen(ascaddr);
369 | strmax -= strl;
370 |
371 | /* now strmax holds the space that is left */
372 |
373 | if( snprintf(ascaddr+strl, strmax, "/%d", prefptr->bits) >= strmax) {
374 | /* die; */ /* error: string too short */
375 | return IP_TOSHRT;
376 | }
377 | return IP_OK;
378 | }
379 |
380 |
381 |
382 | /***************************************************************************/
383 | /*+ convert a binary range back into ascii string at most strmax chars long
384 | +*/
385 | er_ret_t
386 | IP_rang_b2a(ip_range_t *rangptr, char *ascaddr, int strmax)
387 | {
388 | int strl=0, strleft;
389 | er_ret_t err;
390 |
391 | strleft = strmax - strl;
392 | if( (err=IP_addr_b2a (&(rangptr->begin), ascaddr, strleft)) != IP_OK) {
393 | return err;
394 | }
395 | strl = strlen(ascaddr);
396 |
397 | strleft = strmax - strl;
398 | if( strleft < 5 ) {
399 | return IP_TOSHRT;
400 | }
401 | strcat( ascaddr, " - " );
402 | strl += 3;
403 |
404 | strleft = strmax - strl;
405 | if( (err=IP_addr_b2a (&(rangptr->end), ascaddr+strl, strleft)) != IP_OK) {
406 | return err;
407 | }
408 |
409 | return IP_OK;
410 | }
411 |
412 | /***************************************************************************/
413 | /*+ return the bitnum bit of the address,
414 | COUNTING FROM THE TOP !!!!! ,
415 | starting with 0 for the *most significant bit*.
416 | +*/
417 | int
418 | IP_addr_bit_get(ip_addr_t *binaddr, int bitnum) {
419 | register int bitval;
420 |
421 | /* IPv4 is easy... */
422 | bitval = (binaddr->words[0] & (0x80000000 >> (bitnum)));
423 |
424 | return (bitval != 0);
425 |
426 | }
427 |
428 | /***************************************************************************/
429 | /*+ set the bitnum bit of the address to bitval,
430 | COUNTING FROM THE TOP !!!!! ,
431 | starting with 0 for the *most significant bit*.
432 | +*/
433 | void
434 | IP_addr_bit_set(ip_addr_t *binaddr, int bitnum, int bitval) {
435 |
436 | /* IPv4 is easy... */
437 | if ( bitval == 1 )
438 | binaddr->words[0] |= (0x80000000 >> (bitnum));
439 | else
440 | binaddr->words[0] &= ~(0x80000000 >> (bitnum));
441 | }
442 | /***************************************************************************/
443 |
444 | /*+ this fixes a prefix by setting insignificant bits to 0 +*/
445 | void
446 | IP_pref_bit_fix( ip_prefix_t *prefix )
447 | {
448 |
449 | unsigned mask=0xffffffff;
450 |
451 | /* shorthand for ipv4 */
452 |
453 | /* Shifting out by 32 bits does NOT turn all bits into 0... */
454 | if( prefix->bits < 32 ) {
455 | prefix->ip.words[0] &= ~(mask >> prefix->bits);
456 | }
457 |
458 | #if 0
459 | int i;
460 | for(i=prefix->bits; i < IP_sizebits(prefix->ip.space) ; i++) {
461 | IP_addr_bit_set( & prefix->ip, i, 0);
462 | }
463 | #endif
464 |
465 |
466 | }
467 |
468 | /***************************************************************************/
469 |
470 |
471 | /*+
472 | This is a hook function for use with g_list_foreach, to print a list
473 | of prefixes
474 | +*/
475 |
476 | void ip_print_prefix(void *dataptr, void *junk) {
477 | char ascpref[IP_PREFSTR_MAX];
478 | ip_prefix_t *binpref=dataptr;
479 |
480 | IP_pref_b2a( binpref, ascpref, IP_PREFSTR_MAX );
481 | printf ("prefix: %s\n", ascpref);
482 | }
483 |
484 |
485 | /***************************************************************************/
486 |
487 | /*+ compares two IP addresses up to the bit # len,
488 | returns 0 if equal, 1 if ptra greater, -1 if ptrb greater.
489 |
490 | It is the responsility of the caller to ensure that both addresses
491 | are from the same IP space.
492 | +*/
493 |
494 | int
495 | IP_addr_cmp(ip_addr_t *ptra, ip_addr_t *ptrb, int len)
496 | {
497 | int a,b,i;
498 |
499 | for(i=0; i<len; i++) {
500 | a=IP_addr_bit_get(ptra, i);
501 | b=IP_addr_bit_get(ptrb, i);
502 | if( a != b ) {
503 | if( a > b ) return 1;
504 | else return -1;
505 | }
506 | }
507 | return 0;
508 | }
509 |
510 |
511 |
512 |
513 |
514 | /***************************************************************************/
515 |
516 | /*+
517 | this is a shorthand notation to pull out the first word of the address.
518 | it is defined for the scope od the following functions
519 | +*/
520 | #define ad(which) (rangptr->which)
521 |
522 | /***************************************************************************/
523 | /*+ calculate the span of a range == size - 1 +*/
524 |
525 | ip_rangesize_t
526 | /* ottrey 30/12/1999
527 | IP_rang_span( ip_range_t *rangptr )
528 | */
529 | IP_rang_span( ip_range_t rangptr )
530 | {
531 | /* IPv4: */
532 | /* ottrey 30/12/1999
533 | return ad(end).words[0] - ad(begin).words[0];
534 | */
535 | return rangptr.end.words[0] - rangptr.begin.words[0];
536 | }
537 |
538 | /***************************************************************************/
539 |
540 | /*+ Decomposes a binary range into prefixes and appends them to the list.
541 | Allocates prefix structures and list elements, they must be freed after use.
542 |
543 | returns a bitmask of prefix lengths used.
544 | +*/
545 |
546 | unsigned
547 | IP_rang_decomp(ip_range_t *rangptr, GList **preflist)
548 | {
549 | unsigned prefmask=0;
550 | register int slash=0;
551 | register unsigned c_dif, blk, ff;
552 | ip_range_t workrange;
553 | ip_addr_t workbegin;
554 | ip_addr_t workend;
555 | ip_prefix_t *prefptr;
556 |
557 | if( ad(begin).words[0] > ad(end).words[0] ) { /* has gone too far */
558 | return 0;
559 | }
560 |
561 | if( ad(begin).words[0] == ad(end).words[0] ) { /* one IP, i.e. /32 for IPv4 */
562 | prefmask |= 1;
563 | if( wr_calloc( (void **)& prefptr, sizeof(ip_prefix_t), 1) != UT_OK) {
564 | die;
565 | }
566 | prefptr->ip = ad(begin);
567 | prefptr->bits = 32;
568 |
569 | *preflist = g_list_append( *preflist, prefptr );
570 |
571 | return prefmask;
572 | }
573 |
574 | c_dif = ad(end).words[0] - ad(begin).words[0];
575 |
576 | /* initialize work vars */
577 |
578 | workbegin = ad(begin);
579 | workend = ad(end);
580 |
581 | /* now find the biggest block fitting in this range */
582 | /* i.e. the first 2^n number smaller than c_dif */
583 |
584 | /* the loop would not work for /0 (some stupid queries may have that) */
585 | /* so this must be checked for separately */
586 |
587 | if( c_dif == 0xffffffff ) {
588 | /* they are already set to 0.0.0.0 - 255.255.255.255 */
589 | /* leave them alone. */
590 | blk = 0;
591 | slash = 0;
592 | }
593 | else {
594 |
595 | c_dif += 1; /* was not done earlier to protect from overflow */
596 |
597 | for(slash=1;
598 | slash<32 && ((blk=((unsigned)0x80000000>>(slash-1))) & c_dif) == 0;
599 | slash++) {}
600 |
601 | /* clear all digits in a and b under the blk one. */
602 | ff=blk-1;
603 |
604 | workbegin.words[0] = (workbegin.words[0] + ff) & ~ff;
605 |
606 | workend.words[0] = (workend.words[0] + 1) & ~ff;
607 | }
608 |
609 | if( workbegin.words[0] != workend.words[0] ) {
610 | prefmask |= blk;
611 | if( wr_malloc( (void **)& prefptr, sizeof(ip_prefix_t)) != UT_OK) {
612 | die;
613 | }
614 | prefptr->ip = workbegin;
615 | prefptr->bits = slash;
616 |
617 | *preflist = g_list_append( *preflist, prefptr );
618 | }
619 |
620 | if( ad(begin).words[0] != workbegin.words[0] ) {
621 | workrange.begin = ad(begin);
622 |
623 | workbegin.words[0] -= 1;
624 | workrange.end = workbegin;
625 |
626 | prefmask |= IP_rang_decomp( &workrange, preflist );
627 | }
628 |
629 | /* here we must protect from decomposition of */
630 | /* 255.255.255.255 - 255.255.255.255 in case the range */
631 | /* 0.0.0.0 - 255.255.255.255 is considered. Hence the slash>0 condition. */
632 |
633 | if( workend.words[0] <= ad(end).words[0] && slash > 0) {
634 | workrange.begin = workend;
635 | workrange.end = ad(end);
636 |
637 | prefmask |= IP_rang_decomp( &workrange, preflist );
638 | }
639 |
640 | return prefmask;
641 | }
642 |
643 |
644 | /***************************************************************************/
645 |
646 | /*+ Similar name, slightly different code, totally different functionality.
647 |
648 | finds the smallest canonical block encompassing the whole given range,
649 | then MODIFIES the range pointed to by the argument
650 | so that it's equal to this block.
651 |
652 | returns a bitmask of prefix length used.
653 | +*/
654 |
655 | unsigned
656 | IP_rang_encomp(ip_range_t *rangptr)
657 | {
658 | unsigned prefmask=0;
659 | int slash=0;
660 | unsigned c_dif, blk, ff, t_dif;
661 | ip_range_t workrange;
662 | ip_addr_t workbegin;
663 | ip_addr_t workend;
664 |
665 | c_dif = ad(end).words[0] - ad(begin).words[0];
666 |
667 | /* now find the biggest block fitting in this range */
668 | /* i.e. the first 2^n number smaller than c_dif */
669 |
670 | /* the loop would not work for /0 (some stupid queries may have that) */
671 | /* so this must be checked for separately */
672 |
673 | if( c_dif > 0x80000000 ) {
674 | slash = 0;
675 | ff = 0xffffffff;
676 | blk = 0;
677 |
678 | workbegin = workend = ad(begin);
679 | workbegin.words[0] = 0;
680 | workend.words[0] = ff;
681 | }
682 | else {
683 |
684 | do {
685 | c_dif += 1;
686 |
687 | /* find the smallest block ENCOMPASSING c_dif. */
688 | /* this implies a loop from the bottom up */
689 |
690 | for(slash=32;
691 | slash>1 && (blk=((unsigned)0x80000000>>(slash-1))) < c_dif;
692 | slash--) {}
693 |
694 | ff=blk-1;
695 |
696 | /* clear all digits in workbegin under the blk one. */
697 |
698 | workbegin = ad(begin);
699 | workbegin.words[0] = workbegin.words[0] & ~ff;
700 |
701 | /* see if it has not made the difference larger than blk, */
702 | /* retry if so */
703 |
704 | t_dif = c_dif;
705 | c_dif = ad(end).words[0] - workbegin.words[0];
706 |
707 | } while( c_dif >= t_dif );
708 |
709 | /* set the endpoint to workbegin + blocksize - 1 */
710 | /* which amounts to + ff */
711 |
712 | workend = ad(begin);
713 | workend.words[0] = workbegin.words[0] + ff;
714 | }
715 |
716 |
717 | /* set the range to new values */
718 |
719 | rangptr->begin = workbegin;
720 | rangptr->end = workend;
721 | }
722 |
723 | /***************************************************************************/
724 | /*+ sets a range equal to a prefix +*/
725 |
726 | er_ret_t
727 | IP_pref_2_rang( ip_range_t *rangptr, ip_prefix_t *prefptr )
728 | {
729 | ip_rangesize_t span;
730 |
731 | ad(begin) = ad(end) = prefptr->ip;
732 |
733 | if( prefptr->bits > 0 ) {
734 | span = (1 << (32 - prefptr->bits)) - 1 ;
735 | }
736 | else {
737 | span = 0xffffffff;
738 | }
739 |
740 | ad(end).words[0] += span;
741 |
742 | return IP_OK;
743 | }
744 |
745 | #undef ad
746 |
747 | /***************************************************************************/
748 |
749 | /*+
750 | This is to parse a classfull address into a range.
751 |
752 | Takes the address by pointer from addrptr and puts the result
753 | at rangptr.
754 |
755 | Throws error if the address does not fall into any of the
756 | classfull categories
757 |
758 | +*/
759 |
760 | er_ret_t
761 | IP_rang_classful( ip_range_t *rangptr, ip_addr_t *addrptr)
762 | {
763 | int i;
764 | unsigned b[4];
765 |
766 | if( addrptr->space != IP_V4 ) {
767 | /* it's IPv6. There are no classful ranges or anything like that. */
768 | /* we accept only explicit ranges */
769 |
770 | die;
771 | }
772 |
773 | rangptr->begin = *addrptr;
774 | rangptr->end.space = IP_V4;
775 | for(i=0; i<4; i++) {
776 | rangptr->end.words[i] = 0;
777 | }
778 |
779 | /* assume it's at least a valid IP. let's try different classes now */
780 |
781 | /* we could have used a union here, but it would not work on */
782 | /* low endians. So byte by byte copying to and from an array. */
783 |
784 | for(i=0; i<4; i++) {
785 | b[i] = ( rangptr->begin.words[0] & (0xFF << i*8) ) >> i*8;
786 | }
787 |
788 | if( b[3] >= 1 && b[3] < 128
789 | && b[2] == 0 && b[1] == 0 && b[0] == 0 ) {
790 | b[2]=b[1]=b[0]=255;
791 | }
792 | else if( b[3] >= 128 && b[3] < 192
793 | && b[1] == 0 && b[0] == 0 ) {
794 | b[1]=b[0]=255;
795 | }
796 | else if( b[3] >= 192 && b[3] < 224
797 | && b[0] == 0 ) {
798 | b[0]=255;
799 | }
800 | else if( b[3] >= 224 && b[3] < 255 ) {
801 | /* just leave it, make it a /32, i.e. begin == end */
802 | }
803 | else {
804 | /* Leave it and make it a /32 */
805 | /* This is AGAINST the rule! but we have some junk */
806 | /* so we have to compensate for it. */
807 | }
808 |
809 | /* copy the (now - modified) bytes into the end of range */
810 | for(i=0; i<4; i++) {
811 | rangptr->end.words[0] |= (b[i] << i*8);
812 | }
813 |
814 | return IP_OK;
815 | }
816 |
817 |
818 | /***************************************************************************/
819 | /*+
820 | Trying to be smart :-) and convert a query search term into prefix(es),
821 | regardless of whether specified as IP address, prefix or range.
822 |
823 | justcheck - if just checking the syntax (justcheck == 1),
824 | then the prefixes are freed before the function returns,
825 | otherwise it is the responsibility of the caller to free the list.
826 |
827 | +*/
828 |
829 | er_ret_t
830 | IP_smart_conv(char *key,
831 | int justcheck,
832 | int encomp,
833 | GList **preflist,
834 | ip_exp_t expf)
835 | {
836 | int free_it;
837 | er_ret_t call_err, err=IP_OK; /* let's be optimistic :-) */
838 | ip_prefix_t *querypref;
839 |
840 | /* if just checking the syntax (justcheck == 1),
841 | then free_it = 1,
842 | else 0, but may be modified later (in range conversion)
843 | */
844 |
845 | free_it = justcheck;
846 |
847 | if( (call_err = wr_malloc( (void **) &querypref, sizeof(ip_prefix_t)))
848 | != UT_OK) {
849 | return call_err;
850 | }
851 |
852 | if( IP_pref_t2b(querypref, key, expf) == IP_OK ) {
853 | if( justcheck == 0) {
854 | *preflist = g_list_append(*preflist, querypref);
855 | }
856 | }
857 | else {
858 | /* not a prefix. */
859 | /* Maybe an IP ? */
860 | if( IP_addr_t2b( &(querypref->ip), key, expf) == IP_OK ) {
861 |
862 | /*convert to a /32 */
863 | querypref->bits = 32;
864 |
865 | if( justcheck == 0) {
866 | *preflist = g_list_append(*preflist, querypref);
867 | }
868 | }
869 | else {
870 | /* hm, maybe a range then ? */
871 | ip_range_t myrang;
872 |
873 | /* won't use the querypref anymore, mark it for freeing later */
874 | free_it = 1;
875 |
876 | if( IP_rang_t2b(&myrang, key, expf) == IP_OK ) {
877 | /* Wow. Great. */
878 |
879 | /* sometimes (exless match) we look for the first bigger(shorter) */
880 | /* prefix containing this range. */
881 |
882 | if( encomp ) {
883 | IP_rang_encomp(&myrang);
884 | }
885 | /* OK, now we can let the engine happily find that it's just one */
886 | /* range */
887 |
888 | if( justcheck == 0) {
889 | IP_rang_decomp(&myrang, preflist);
890 | }
891 | }
892 | else {
893 | err = IP_INVARG; /* "conversion error" */
894 | }
895 | }
896 | }
897 |
898 | if( free_it ) {
899 | wr_free(querypref);
900 | }
901 |
902 | return err;
903 | }
904 |
905 |
906 | #ifdef MODULE_TEST
907 | #include "ip_test.c"
908 | #endif