1 | /***************************************
2 | $Revision: 1.9 $
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[4];
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 | IP_rang_span( ip_range_t *rangptr )
527 | {
528 | /* IPv4: */
529 | return ad(end).words[0] - ad(begin).words[0];
530 | }
531 |
532 | /***************************************************************************/
533 |
534 | /*+ Decomposes a binary range into prefixes and appends them to the list.
535 | Allocates prefix structures and list elements, they must be freed after use.
536 |
537 | returns a bitmask of prefix lengths used.
538 | +*/
539 |
540 | unsigned
541 | IP_rang_decomp(ip_range_t *rangptr, GList **preflist)
542 | {
543 | unsigned prefmask=0;
544 | register int slash=0;
545 | register unsigned c_dif, blk, ff;
546 | ip_range_t workrange;
547 | ip_addr_t workbegin;
548 | ip_addr_t workend;
549 | ip_prefix_t *prefptr;
550 |
551 | if( ad(begin).words[0] > ad(end).words[0] ) { /* has gone too far */
552 | return 0;
553 | }
554 |
555 | if( ad(begin).words[0] == ad(end).words[0] ) { /* one IP, i.e. /32 for IPv4 */
556 | prefmask |= 1;
557 | if( wr_calloc( (void **)& prefptr, sizeof(ip_prefix_t), 1) != UT_OK) {
558 | die;
559 | }
560 | prefptr->ip = ad(begin);
561 | prefptr->bits = 32;
562 |
563 | *preflist = g_list_append( *preflist, prefptr );
564 |
565 | return prefmask;
566 | }
567 |
568 | c_dif = ad(end).words[0] - ad(begin).words[0];
569 |
570 | /* initialize work vars */
571 |
572 | workbegin = ad(begin);
573 | workend = ad(end);
574 |
575 | /* now find the biggest block fitting in this range */
576 | /* i.e. the first 2^n number smaller than c_dif */
577 |
578 | /* the loop would not work for /0 (some stupid queries may have that) */
579 | /* so this must be checked for separately */
580 |
581 | if( c_dif == 0xffffffff ) {
582 | /* they are already set to 0.0.0.0 - 255.255.255.255 */
583 | /* leave them alone. */
584 | blk = 0;
585 | slash = 0;
586 | }
587 | else {
588 |
589 | c_dif += 1; /* was not done earlier to protect from overflow */
590 |
591 | for(slash=1;
592 | slash<32 && ((blk=((unsigned)0x80000000>>(slash-1))) & c_dif) == 0;
593 | slash++) {}
594 |
595 | /* clear all digits in a and b under the blk one. */
596 | ff=blk-1;
597 |
598 | workbegin.words[0] = (workbegin.words[0] + ff) & ~ff;
599 |
600 | workend.words[0] = (workend.words[0] + 1) & ~ff;
601 | }
602 |
603 | if( workbegin.words[0] != workend.words[0] ) {
604 | prefmask |= blk;
605 | if( wr_malloc( (void **)& prefptr, sizeof(ip_prefix_t)) != UT_OK) {
606 | die;
607 | }
608 | prefptr->ip = workbegin;
609 | prefptr->bits = slash;
610 |
611 | *preflist = g_list_append( *preflist, prefptr );
612 | }
613 |
614 | if( ad(begin).words[0] != workbegin.words[0] ) {
615 | workrange.begin = ad(begin);
616 |
617 | workbegin.words[0] -= 1;
618 | workrange.end = workbegin;
619 |
620 | prefmask |= IP_rang_decomp( &workrange, preflist );
621 | }
622 |
623 | /* here we must protect from decomposition of */
624 | /* 255.255.255.255 - 255.255.255.255 in case the range */
625 | /* 0.0.0.0 - 255.255.255.255 is considered. Hence the slash>0 condition. */
626 |
627 | if( workend.words[0] <= ad(end).words[0] && slash > 0) {
628 | workrange.begin = workend;
629 | workrange.end = ad(end);
630 |
631 | prefmask |= IP_rang_decomp( &workrange, preflist );
632 | }
633 |
634 | return prefmask;
635 | }
636 |
637 |
638 | /***************************************************************************/
639 |
640 | /*+ Similar name, slightly different code, totally different functionality.
641 |
642 | finds the smallest canonical block encompassing the whole given range,
643 | then MODIFIES the range pointed to by the argument
644 | so that it's equal to this block.
645 |
646 | returns a bitmask of prefix length used.
647 | +*/
648 |
649 | unsigned
650 | IP_rang_encomp(ip_range_t *rangptr)
651 | {
652 | unsigned prefmask=0;
653 | int slash=0;
654 | unsigned c_dif, blk, ff, t_dif;
655 | ip_range_t workrange;
656 | ip_addr_t workbegin;
657 | ip_addr_t workend;
658 |
659 | c_dif = ad(end).words[0] - ad(begin).words[0];
660 |
661 | /* now find the biggest block fitting in this range */
662 | /* i.e. the first 2^n number smaller than c_dif */
663 |
664 | /* the loop would not work for /0 (some stupid queries may have that) */
665 | /* so this must be checked for separately */
666 |
667 | if( c_dif > 0x80000000 ) {
668 | slash = 0;
669 | ff = 0xffffffff;
670 | blk = 0;
671 |
672 | workbegin = workend = ad(begin);
673 | workbegin.words[0] = 0;
674 | workend.words[0] = ff;
675 | }
676 | else {
677 |
678 | do {
679 | c_dif += 1;
680 |
681 | /* find the smallest block ENCOMPASSING c_dif. */
682 | /* this implies a loop from the bottom up */
683 |
684 | for(slash=32;
685 | slash>1 && (blk=((unsigned)0x80000000>>(slash-1))) < c_dif;
686 | slash--) {}
687 |
688 | ff=blk-1;
689 |
690 | /* clear all digits in workbegin under the blk one. */
691 |
692 | workbegin = ad(begin);
693 | workbegin.words[0] = workbegin.words[0] & ~ff;
694 |
695 | /* see if it has not made the difference larger than blk, */
696 | /* retry if so */
697 |
698 | t_dif = c_dif;
699 | c_dif = ad(end).words[0] - workbegin.words[0];
700 |
701 | } while( c_dif >= t_dif );
702 |
703 | /* set the endpoint to workbegin + blocksize - 1 */
704 | /* which amounts to + ff */
705 |
706 | workend = ad(begin);
707 | workend.words[0] = workbegin.words[0] + ff;
708 | }
709 |
710 |
711 | /* set the range to new values */
712 |
713 | rangptr->begin = workbegin;
714 | rangptr->end = workend;
715 | }
716 |
717 | /***************************************************************************/
718 | /*+ sets a range equal to a prefix +*/
719 |
720 | er_ret_t
721 | IP_pref_2_rang( ip_range_t *rangptr, ip_prefix_t *prefptr )
722 | {
723 | ip_rangesize_t span;
724 |
725 | ad(begin) = ad(end) = prefptr->ip;
726 |
727 | if( prefptr->bits > 0 ) {
728 | span = (1 << (32 - prefptr->bits)) - 1 ;
729 | }
730 | else {
731 | span = 0xffffffff;
732 | }
733 |
734 | ad(end).words[0] += span;
735 |
736 | return IP_OK;
737 | }
738 |
739 | #undef ad
740 |
741 | /***************************************************************************/
742 |
743 | /*+
744 | This is to parse a classfull address into a range.
745 |
746 | Takes the address by pointer from addrptr and puts the result
747 | at rangptr.
748 |
749 | Throws error if the address does not fall into any of the
750 | classfull categories
751 |
752 | +*/
753 |
754 | er_ret_t
755 | IP_rang_classful( ip_range_t *rangptr, ip_addr_t *addrptr)
756 | {
757 | int i;
758 | unsigned b[4];
759 |
760 | if( addrptr->space != IP_V4 ) {
761 | /* it's IPv6. There are no classful ranges or anything like that. */
762 | /* we accept only explicit ranges */
763 |
764 | die;
765 | }
766 |
767 | rangptr->begin = *addrptr;
768 | rangptr->end.space = IP_V4;
769 | for(i=0; i<4; i++) {
770 | rangptr->end.words[i] = 0;
771 | }
772 |
773 | /* assume it's at least a valid IP. let's try different classes now */
774 |
775 | /* we could have used a union here, but it would not work on */
776 | /* low endians. So byte by byte copying to and from an array. */
777 |
778 | for(i=0; i<4; i++) {
779 | b[i] = ( rangptr->begin.words[0] & (0xFF << i*8) ) >> i*8;
780 | }
781 |
782 | if( b[3] >= 1 && b[3] < 128
783 | && b[2] == 0 && b[1] == 0 && b[0] == 0 ) {
784 | b[2]=b[1]=b[0]=255;
785 | }
786 | else if( b[3] >= 128 && b[3] < 192
787 | && b[1] == 0 && b[0] == 0 ) {
788 | b[1]=b[0]=255;
789 | }
790 | else if( b[3] >= 192 && b[3] < 224
791 | && b[0] == 0 ) {
792 | b[0]=255;
793 | }
794 | else if( b[3] >= 224 && b[3] < 255 ) {
795 | /* just leave it, make it a /32, i.e. begin == end */
796 | }
797 | else {
798 | /* Leave it and make it a /32 */
799 | /* This is AGAINST the rule! but we have some junk */
800 | /* so we have to compensate for it. */
801 | }
802 |
803 | /* copy the (now - modified) bytes into the end of range */
804 | for(i=0; i<4; i++) {
805 | rangptr->end.words[0] |= (b[i] << i*8);
806 | }
807 |
808 | return IP_OK;
809 | }
810 |
811 |
812 | /***************************************************************************/
813 | /*+
814 | Trying to be smart :-) and convert a query search term into prefix(es),
815 | regardless of whether specified as IP address, prefix or range.
816 |
817 | justcheck - if just checking the syntax (justcheck == 1),
818 | then the prefixes are freed before the function returns,
819 | otherwise it is the responsibility of the caller to free the list.
820 |
821 | +*/
822 |
823 | er_ret_t
824 | IP_smart_conv(char *key,
825 | int justcheck,
826 | int encomp,
827 | GList **preflist,
828 | ip_exp_t expf)
829 | {
830 | int free_it;
831 | er_ret_t call_err, err=IP_OK; /* let's be optimistic :-) */
832 | ip_prefix_t *querypref;
833 |
834 | /* if just checking the syntax (justcheck == 1),
835 | then free_it = 1,
836 | else 0, but may be modified later (in range conversion)
837 | */
838 |
839 | free_it = justcheck;
840 |
841 | if( (call_err = wr_malloc( (void **) &querypref, sizeof(ip_prefix_t)))
842 | != UT_OK) {
843 | return call_err;
844 | }
845 |
846 | if( IP_pref_t2b(querypref, key, expf) == IP_OK ) {
847 | if( justcheck == 0) {
848 | *preflist = g_list_append(*preflist, querypref);
849 | }
850 | }
851 | else {
852 | /* not a prefix. */
853 | /* Maybe an IP ? */
854 | if( IP_addr_t2b( &(querypref->ip), key, expf) == IP_OK ) {
855 |
856 | /*convert to a /32 */
857 | querypref->bits = 32;
858 |
859 | if( justcheck == 0) {
860 | *preflist = g_list_append(*preflist, querypref);
861 | }
862 | }
863 | else {
864 | /* hm, maybe a range then ? */
865 | ip_range_t myrang;
866 |
867 | /* won't use the querypref anymore, mark it for freeing later */
868 | free_it = 1;
869 |
870 | if( IP_rang_t2b(&myrang, key, expf) == IP_OK ) {
871 | /* Wow. Great. */
872 |
873 | /* sometimes (exless match) we look for the first bigger(shorter) */
874 | /* prefix containing this range. */
875 |
876 | if( encomp ) {
877 | IP_rang_encomp(&myrang);
878 | }
879 | /* OK, now we can let the engine happily find that it's just one */
880 | /* range */
881 |
882 | if( justcheck == 0) {
883 | IP_rang_decomp(&myrang, preflist);
884 | }
885 | }
886 | else {
887 | err = IP_INVARG; /* "conversion error" */
888 | }
889 | }
890 | }
891 |
892 | if( free_it ) {
893 | wr_free(querypref);
894 | }
895 |
896 | return err;
897 | }
898 |
899 |
900 | #ifdef MODULE_TEST
901 | #include "ip_test.c"
902 | #endif