1 /*
2 ** Copyright (C) 1998-2009 Sourcefire, Inc.
3 ** Adam Keeton
4 ** Kevin Liu <kliu@sourcefire.com>
5 **
6 ** $Id$
7 ** This program is free software; you can redistribute it and/or modify
8 ** it under the terms of the GNU General Public License Version 2 as
9 ** published by the Free Software Foundation.  You may not use, modify or
10 ** distribute this program under any other version of the GNU General
11 ** Public License.
12 **
13 ** This program is distributed in the hope that it will be useful,
14 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 ** GNU General Public License for more details.
17 **
18 ** You should have received a copy of the GNU General Public License
19 ** along with this program; if not, write to the Free Software
20 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 */
22 
23 /*
24  * Adam Keeton
25  * sf_ip.c
26  * 11/17/06
27  *
28  * Library for managing IP addresses of either v6 or v4 families.
29 */
30 
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34 
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <ctype.h>
39 #include <math.h> /* For ceil */
40 #include "sf_ip.h"
41 
42 /* For inet_pton */
43 #ifndef WIN32
44 #include <sys/types.h>
45 #include <sys/socket.h>
46 #include <arpa/inet.h>
47 #endif  /* WIN32 */
48 
49 #if 0
50 /* Support function .. but could see some external uses */
51 static INLINE int sfip_length(sfip_t *ip) {
52     ARG_CHECK1(ip, 0);
53 
54     if(sfip_family(ip) == AF_INET) return 4;
55     return 16;
56 }
57 #endif
58 
59 /* Support function */
60 // note that an ip6 address may have a trailing dotted quad form
61 // but that it always has at least 2 ':'s; furthermore there is
62 // no valid ip4 format (including mask) with 2 ':'s
63 // we don't have to figure out if the format is entirely legal
64 // we just have to be able to tell correct formats apart
sfip_str_to_fam(const char * str)65 static INLINE int sfip_str_to_fam(const char *str) {
66     const char* s;
67     ARG_CHECK1(str, 0);
68     s = strchr(str, (int)':');
69     if ( s && strchr(s+1, (int)':') ) return AF_INET6;
70     if ( strchr(str, (int)'.') ) return AF_INET;
71     return AF_UNSPEC;
72 }
73 
74 /* Place-holder allocation incase we want to do something more indepth later */
_sfip_alloc()75 static INLINE sfip_t *_sfip_alloc() {
76     /* Note: using calloc here instead of SnortAlloc since the dynamic libs
77      * can't presently resolve SnortAlloc */
78     return (sfip_t*)calloc(sizeof(sfip_t), 1);
79 }
80 
81 /* Masks off 'val' bits from the IP contained within 'ip' */
sfip_cidr_mask(sfip_t * ip,int val)82 static INLINE int sfip_cidr_mask(sfip_t *ip, int val) {
83     int i;
84     unsigned int mask = 0;
85     unsigned int *p;
86     int index = (int)ceil(val / 32.0) - 1;
87 
88     ARG_CHECK1(ip, SFIP_ARG_ERR);
89 
90     p = ip->ip32;
91 
92     if( val < 0 ||
93         ((sfip_family(ip) == AF_INET6) && val > 128) ||
94         ((sfip_family(ip) == AF_INET) && val > 32) ) {
95         return SFIP_ARG_ERR;
96     }
97 
98     /* Build the netmask by converting "val" into
99      * the corresponding number of bits that are set */
100     for(i = 0; i < 32- (val - (index * 32)); i++)
101         mask = (mask<<1) + 1;
102 
103     p[index] = htonl((ntohl(p[index]) & ~mask));
104 
105     index++;
106 
107     /* 0 off the rest of the IP */
108     for( ; index<4; index++) p[index] = 0;
109 
110     return SFIP_SUCCESS;
111 }
112 
113 /* Allocate IP address from a character array describing the IP */
sfip_alloc(const char * ip,SFIP_RET * status)114 sfip_t *sfip_alloc(const char *ip, SFIP_RET *status) {
115     int tmp;
116     sfip_t *ret;
117 
118     if(!ip) {
119         if(status)
120             *status = SFIP_ARG_ERR;
121         return NULL;
122     }
123 
124     if((ret = _sfip_alloc()) == NULL) {
125         if(status)
126             *status = SFIP_ALLOC_ERR;
127         return NULL;
128     }
129 
130     if( (tmp = sfip_pton(ip, ret)) != SFIP_SUCCESS) {
131         if(status)
132             *status = tmp;
133 
134         sfip_free(ret);
135         return NULL;
136     }
137 
138     if(status)
139         *status = SFIP_SUCCESS;
140 
141     return ret;
142 }
143 
144 /* Allocate IP address from an array of 8 byte integers */
sfip_alloc_raw(void * ip,int family,SFIP_RET * status)145 sfip_t *sfip_alloc_raw(void *ip, int family, SFIP_RET *status) {
146     sfip_t *ret;
147 
148     if(!ip) {
149         if(status)
150             *status = SFIP_ARG_ERR;
151         return NULL;
152     }
153 
154     if((ret = _sfip_alloc()) == NULL) {
155         if(status)
156             *status = SFIP_ALLOC_ERR;
157         return NULL;
158     }
159 
160     ret->bits = (family==AF_INET?32:128);
161     ret->family = family;
162     /* XXX Replace with appropriate "high speed" copy */
163     memcpy(ret->ip8, ip, ret->bits/8);
164 
165     if(status)
166         *status = SFIP_SUCCESS;
167 
168     return ret;
169 }
170 
171 /* Support function for _netmask_str_to_bit_count */
_count_bits(unsigned int val)172 static INLINE int _count_bits(unsigned int val) {
173     unsigned int count;
174 
175     for (count = 0; val; count++) {
176         val &= val - 1;
177     }
178 
179     return count;
180 }
181 
182 /* Support function for sfip_pton.  Used for converting a netmask string
183  * into a number of bits to mask off */
_netmask_str_to_bit_count(char * mask,int family)184 static INLINE int _netmask_str_to_bit_count(char *mask, int family) {
185     u_int32_t buf[4];
186     int bits, i, nBits, nBytes;
187     u_int8_t* bytes = (u_int8_t*)buf;
188 
189     /* XXX
190      * Mask not validated.
191      * Only sfip_pton should be using this function, and using it safely.
192      * XXX */
193 
194     if(inet_pton(family, mask, buf) < 1)
195         return -1;
196 
197     bits =  _count_bits(buf[0]);
198 
199     if(family == AF_INET6) {
200         bits += _count_bits(buf[1]);
201         bits += _count_bits(buf[2]);
202         bits += _count_bits(buf[3]);
203         nBytes = 16;
204     } else {
205         nBytes = 4;
206     }
207 
208     // now make sure that only the most significant bits are set
209     nBits = bits;
210     for ( i = 0; i < nBytes; i++ ) {
211         if ( nBits >= 8 ) {
212             if ( bytes[i] != 0xff ) return -1;
213             nBits -= 8;
214 
215         } else if ( nBits == 0 ) {
216             if ( bytes[i] != 0x00 ) return -1;
217 
218         } else {
219             if ( bytes[i] != ((0xff00 >> nBits) & 0xff) ) return -1;
220             nBits = 0;
221         }
222     }
223     return bits;
224 }
225 
226 /* Parses "src" and stores results in "dst" */
sfip_pton(const char * src,sfip_t * dst)227 SFIP_RET sfip_pton(const char *src, sfip_t *dst) {
228     char *mask;
229     char *sfip_buf;
230     char *ip;
231     int bits;
232 
233     if(!dst || !src)
234         return SFIP_ARG_ERR;
235 
236     if((sfip_buf = strdup(src)) == NULL)
237         return SFIP_ALLOC_ERR;
238 
239     ip = sfip_buf;
240     dst->family = sfip_str_to_fam(src);
241 
242     /* skip whitespace or opening bracket */
243     while(isspace((int)*ip) || (*ip == '[')) ip++;
244 
245     /* check for and extract a mask in CIDR form */
246     if( (mask = strchr(ip, (int)'/')) != NULL ) {
247         /* NULL out this character so inet_pton will see the
248          * correct ending to the IP string */
249         char* end = mask++;
250         while ( (end > ip) && isspace((int)end[-1]) ) end--;
251         *end = 0;
252 
253         while(isspace((int)*mask)) mask++;
254 
255         /* verify a leading digit */
256         if(((dst->family == AF_INET6) && !isxdigit((int)*mask)) ||
257            ((dst->family == AF_INET) && !isdigit((int)*mask))) {
258             free(sfip_buf);
259             return SFIP_CIDR_ERR;
260         }
261 
262         /* Check if there's a netmask here instead of the number of bits */
263         if(strchr(mask, (int)'.') || strchr(mask, (int)':'))
264             bits = _netmask_str_to_bit_count(mask, sfip_str_to_fam(mask));
265         else
266             bits = atoi(mask);
267     }
268     else if(
269             /* If this is IPv4, ia ':' may used specified to indicate a netmask */
270             ((dst->family == AF_INET) && (mask = strchr(ip, (int)':')) != NULL) ||
271 
272             /* We've already skipped the leading whitespace, if there is more
273              * whitespace, then there's probably a netmask specified after it. */
274              (mask = strchr(ip, (int)' ')) != NULL
275     ) {
276         char* end = mask++;
277         while ( (end > ip) && isspace((int)end[-1]) ) end--;
278         *end = 0;  /* Now the IP will end at this point */
279 
280         /* skip whitespace */
281         while(isspace((int)*mask)) mask++;
282 
283         /* Make sure we're either looking at a valid digit, or a leading
284          * colon, such as can be the case with IPv6 */
285         if(((dst->family == AF_INET) && isdigit((int)*mask)) ||
286            ((dst->family == AF_INET6) && (isxdigit((int)*mask) || *mask == ':'))) {
287             bits = _netmask_str_to_bit_count(mask, sfip_str_to_fam(mask));
288         }
289         /* No netmask */
290         else {
291             if(dst->family == AF_INET) bits = 32;
292             else bits = 128;
293         }
294     }
295     /* No netmask */
296     else {
297         if(dst->family == AF_INET) bits = 32;
298         else bits = 128;
299     }
300 
301     if(inet_pton(dst->family, ip, dst->ip8) < 1) {
302         free(sfip_buf);
303         return SFIP_INET_PARSE_ERR;
304     }
305 
306     /* Store mask */
307     dst->bits = bits;
308 
309     /* Apply mask */
310     if(sfip_cidr_mask(dst, bits) != SFIP_SUCCESS) {
311         free(sfip_buf);
312         return SFIP_INVALID_MASK;
313     }
314 
315     free(sfip_buf);
316     return SFIP_SUCCESS;
317 }
318 
319 /* Sets existing IP, "dst", to be source IP, "src" */
sfip_set_raw(sfip_t * dst,void * src,int family)320 SFIP_RET sfip_set_raw(sfip_t *dst, void *src, int family) {
321 
322     ARG_CHECK3(dst, src, dst->ip32, SFIP_ARG_ERR);
323 
324     dst->family = family;
325 
326     if(family == AF_INET) {
327         dst->ip32[0] = *(u_int32_t*)src;
328         memset(&dst->ip32[1], 0, 12);
329         dst->bits = 32;
330     } else if(family == AF_INET6) {
331         memcpy(dst->ip8, src, 16);
332         dst->bits = 128;
333     } else {
334         return SFIP_ARG_ERR;
335     }
336 
337     return SFIP_SUCCESS;
338 }
339 
340 /* Sets existing IP, "dst", to be source IP, "src" */
sfip_set_ip(sfip_t * dst,sfip_t * src)341 SFIP_RET sfip_set_ip(sfip_t *dst, sfip_t *src) {
342     ARG_CHECK2(dst, src, SFIP_ARG_ERR);
343 
344     dst->family = src->family;
345     dst->bits = src->bits;
346     dst->ip32[0] = src->ip32[0];
347     dst->ip32[1] = src->ip32[1];
348     dst->ip32[2] = src->ip32[2];
349     dst->ip32[3] = src->ip32[3];
350 
351     return SFIP_SUCCESS;
352 }
353 
354 /* Obfuscates an IP
355  * Makes 'ip': ob | (ip & mask) */
sfip_obfuscate(sfip_t * ob,sfip_t * ip)356 void sfip_obfuscate(sfip_t *ob, sfip_t *ip) {
357     unsigned int *ob_p, *ip_p;
358     int index, i;
359     unsigned int mask = 0;
360 
361     if(!ob || !ip)
362         return;
363 
364     ob_p = ob->ip32;
365     ip_p = ip->ip32;
366 
367     /* Build the netmask by converting "val" into
368      * the corresponding number of bits that are set */
369     index = (int)ceil(ob->bits / 32.0) - 1;
370 
371     for(i = 0; i < 32- (ob->bits - (index * 32)); i++)
372         mask = (mask<<1) + 1;
373 
374     /* Note: The old-Snort obfuscation code uses !mask for masking.
375      * hence, this code uses the same algorithm as sfip_cidr_mask
376      * except the mask below is not negated. */
377     ip_p[index] = htonl((ntohl(ip_p[index]) & mask));
378 
379     /* 0 off the start of the IP */
380     while ( index > 0 ) ip_p[--index] = 0;
381 
382     /* OR remaining pieces */
383     ip_p[0] |= ob_p[0];
384     ip_p[1] |= ob_p[1];
385     ip_p[2] |= ob_p[2];
386     ip_p[3] |= ob_p[3];
387 }
388 
389 
390 /* Check if ip is contained within the network specified by net */
391 /* Returns SFIP_EQUAL if so.
392  * XXX sfip_contains assumes that "ip" is
393  *      not less-specific than "net" XXX
394 */
sfip_contains(sfip_t * net,sfip_t * ip)395 SFIP_RET sfip_contains(sfip_t *net, sfip_t *ip) {
396     unsigned int bits, mask, temp, i;
397     int net_fam, ip_fam;
398     unsigned int *p1, *p2;
399 
400     /* SFIP_CONTAINS is returned here due to how IpAddrSetContains
401      * handles zero'ed IPs" */
402     ARG_CHECK2(net, ip, SFIP_CONTAINS);
403 
404     bits = sfip_bits(net);
405     net_fam = sfip_family(net);
406     ip_fam = sfip_family(ip);
407 
408     /* If the families are mismatched, check if we're really comparing
409      * an IPv4 with a mapped IPv4 (in IPv6) address. */
410     if(net_fam != ip_fam) {
411         if((net_fam != AF_INET) || !sfip_ismapped(ip))
412             return SFIP_ARG_ERR;
413 
414         /* Both are really IPv4.  Only compare last 4 bytes of 'ip'*/
415         p1 = net->ip32;
416         p2 = &ip->ip32[3];
417 
418         /* Mask off bits */
419         bits = 32 - bits;
420         temp = (ntohl(*p2) >> bits) << bits;
421 
422         if(ntohl(*p1) == temp) return SFIP_CONTAINS;
423 
424         return SFIP_NOT_CONTAINS;
425     }
426 
427     p1 = net->ip32;
428     p2 = ip->ip32;
429 
430     /* Iterate over each 32 bit segment */
431     for(i=0; i < bits/32 && i < 3; i++, p1++, p2++) {
432         if(*p1 != *p2)
433             return SFIP_NOT_CONTAINS;
434     }
435 
436     mask = 32 - (bits - 32*i);
437     if ( mask == 32 ) return SFIP_CONTAINS;
438 
439     /* At this point, there are some number of remaining bits to check.
440      * Mask the bits we don't care about off of "ip" so we can compare
441      * the ints directly */
442     temp = ntohl(*p2);
443     temp = (temp >> mask) << mask;
444 
445     /* If p1 was setup correctly through this library, there is no need to
446      * mask off any bits of its own. */
447     if(ntohl(*p1) == temp)
448         return SFIP_CONTAINS;
449 
450     return SFIP_NOT_CONTAINS;
451 
452 }
453 
sfip_raw_ntop(int family,const void * ip_raw,char * buf,int bufsize)454 void sfip_raw_ntop(int family, const void *ip_raw, char *buf, int bufsize) {
455     int i;
456 
457     if(!ip_raw || !buf || !bufsize ||
458        (family != AF_INET && family != AF_INET6) ||
459        /* Make sure if it's IPv6 that the buf is large enough. */
460        /* Need atleast a max of 8 fields of 4 bytes plus 7 for colons in
461         * between.  Need 1 more byte for null. */
462        (family == AF_INET6 && bufsize < 8*4 + 7 + 1) ||
463        /* Make sure if it's IPv4 that the buf is large enough. */
464        /* 4 fields of 3 numbers, plus 3 dots and a null byte */
465        (family == AF_INET && bufsize < 3*4 + 4) )
466     {
467         if(buf && bufsize > 0) buf[0] = 0;
468         return;
469     }
470 
471     /* 4 fields of at most 3 characters each */
472     if(family == AF_INET) {
473         u_int8_t *p = (u_int8_t*)ip_raw;
474 
475         for(i=0; p < ((u_int8_t*)ip_raw) + 4; p++) {
476             i += sprintf(&buf[i], "%d", *p);
477 
478             /* If this is the last iteration, this could technically cause one
479              *  extra byte to be written past the end. */
480             if(i < bufsize && ((p + 1) < ((u_int8_t*)ip_raw+4)))
481                 buf[i] = '.';
482 
483             i++;
484         }
485 
486     /* Check if this is really just an IPv4 address represented as 6,
487      * in compatible format */
488 #if 0
489     }
490     else if(!field[0] && !field[1] && !field[2]) {
491         unsigned char *p = (unsigned char *)(&ip->ip[12]);
492 
493         for(i=0; p < &ip->ip[16]; p++)
494              i += sprintf(&buf[i], "%d.", *p);
495 #endif
496     }
497     else {
498         u_int16_t *p = (u_int16_t*)ip_raw;
499 
500         for(i=0; p < ((u_int16_t*)ip_raw) + 8; p++) {
501             i += sprintf(&buf[i], "%04x", ntohs(*p));
502 
503             /* If this is the last iteration, this could technically cause one
504              *  extra byte to be written past the end. */
505             if(i < bufsize && ((p + 1) < ((u_int16_t*)ip_raw) + 8))
506                 buf[i] = ':';
507 
508             i++;
509         }
510     }
511 }
512 
513 /* Uses a static buffer to return a string representation of the IP */
sfip_to_str(const sfip_t * ip)514 char *sfip_to_str(const sfip_t *ip) {
515     /* IPv6 addresses will be at most 8 fields, of 4 characters each,
516      * with 7 colons inbetween, one NULL, and one fudge byte for sloppy use
517      * in sfip_to_strbuf */
518     static char buf[8*4 + 7 + 1 + 1];
519 
520     if(!ip)
521          return NULL;
522 
523     sfip_raw_ntop(sfip_family(ip), ip->ip32, buf, sizeof(buf));
524 
525     return buf;
526 }
527 
sfip_free(sfip_t * ip)528 void sfip_free(sfip_t *ip) {
529     if(ip) free(ip);
530 }
531 
532 /* Returns 1 if the IP is non-zero. 0 otherwise */
sfip_is_loopback(sfip_t * ip)533 int sfip_is_loopback(sfip_t *ip) {
534     unsigned int *p;
535 
536     ARG_CHECK1(ip, 0);
537 
538     if(sfip_family(ip) == AF_INET) {
539         // 127.0.0.0/8 is IPv4 loopback
540         return (ip->ip8[0] == 0x7f);
541     }
542 
543     p = ip->ip32;
544 
545     /* Check the first 64 bits in an IPv6 address, and */
546     /* verify they're zero.  If not, it's not a loopback */
547     if(p[0] || p[1]) return 0;
548 
549     /* Check if the 3rd 32-bit int is zero */
550     if ( p[2] == 0 ) {
551         /* ::7f00:0/104 is ipv4 compatible ipv6 */
552         /* ::1 is the IPv6 loopback */
553         return ( (ip->ip8[12] == 0x7f) || (ntohl(p[3]) == 0x1) );
554     }
555     /* Check the 3rd 32-bit int for a mapped IPv4 address */
556     if ( ntohl(p[2]) == 0xffff ) {
557         /* ::ffff:127.0.0.0/104 is IPv4 loopback mapped over IPv6 */
558         return ( ip->ip8[12] == 0x7f );
559     }
560     return 0;
561 }
562 
sfip_ismapped(sfip_t * ip)563 int sfip_ismapped(sfip_t *ip) {
564     unsigned int *p;
565 
566     ARG_CHECK1(ip, 0);
567 
568     if(sfip_family(ip) == AF_INET)
569         return 0;
570 
571     p = ip->ip32;
572 
573     if(p[0] || p[1] || (ntohl(p[2]) != 0xffff && p[2] != 0)) return 0;
574 
575     return 1;
576 }
577 
578