1 /****************************************************************************
2 *
3 * Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
4 * Copyright (C) 2003-2013 Sourcefire, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License Version 2 as
8 * published by the Free Software Foundation. You may not use, modify or
9 * distribute this program under any other version of the GNU General
10 * Public License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 ****************************************************************************/
22
23 /*
24
25 ipobj.c
26
27 IP address encapsulation interface
28
29 This module provides encapsulation of single IP ADDRESSes as
30 objects, and collections of IP ADDRESSes as objects
31
32
33 */
34
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
38
39 #include <stdlib.h>
40 #include <stdio.h>
41 #include <string.h>
42
43 #ifndef WIN32
44 #include <sys/types.h>
45 #include <sys/socket.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
48 #endif
49
50 #include <ctype.h>
51
52 #include "ipobj.h"
53 #include "util.h"
54 #include "snort_bounds.h"
55
56
57
58 /*
59
60
61 IP COLLECTION INTERFACE
62
63
64 Snort Accepts:
65
66 IP-Address 192.168.1.1
67 IP-Address/MaskBits 192.168.1.0/24
68 IP-Address/Mask 192.168.1.0/255.255.255.0
69
70
71 These can all be handled via the CIDR block notation : IP/MaskBits
72
73 We use collections (lists) of cidr blocks to represent address blocks
74 and indivdual addresses.
75
76 For a single IPAddress the implied Mask is 32 bits,or 255.255.255.255, or 0xffffffff, or -1.
77
78 */
ipset_new(void)79 IPSET * ipset_new(void)
80 {
81 IPSET * p = (IPSET *)SnortAlloc( sizeof(IPSET));
82 sflist_init(&p->ip_list);
83
84 return p;
85 }
86
ipset_copy(IPSET * ipsp)87 IPSET * ipset_copy( IPSET *ipsp )
88 {
89 IPSET * newset = ipset_new();
90 IP_PORT *ip_port;
91
92 for(ip_port =(IP_PORT*)sflist_first( &ipsp->ip_list );
93 ip_port !=NULL;
94 ip_port =(IP_PORT*)sflist_next( &ipsp->ip_list ) )
95 {
96 ipset_add(newset, &ip_port->ip, &ip_port->portset, ip_port->notflag);
97 }
98 return newset;
99 }
100
ipset_free(IPSET * ipc)101 void ipset_free( IPSET * ipc )
102 {
103 if (ipc)
104 {
105
106 IP_PORT *p = (IP_PORT *) sflist_first(&ipc->ip_list);
107 while ( p )
108 {
109 sflist_static_free_all(&p->portset.port_list, free);
110 p = (IP_PORT *) sflist_next(&ipc->ip_list);
111 }
112 sflist_static_free_all(&ipc->ip_list, free);
113 free( ipc );
114 }
115 }
116
ipset_add(IPSET * ipset,sfcidr_t * ip,void * vport,int notflag)117 int ipset_add ( IPSET * ipset, sfcidr_t *ip, void * vport, int notflag)
118 {
119 if( !ipset ) return -1;
120
121 {
122 PORTSET * portset = (PORTSET *) vport;
123 IP_PORT *p = (IP_PORT*)calloc( 1,sizeof(IP_PORT) );
124 if(!p) return -1;
125
126 sfip_set_ip(&p->ip, ip);
127 p->portset = *portset;
128 p->notflag = (char)notflag;
129
130 if( notflag )sflist_add_head( &ipset->ip_list, p ); // test NOT items 1st
131 else sflist_add_tail( &ipset->ip_list, p );
132 }
133
134 return 0;
135 }
136
ipset_contains(IPSET * ipc,sfaddr_t * ip,void * port)137 int ipset_contains( IPSET * ipc, sfaddr_t * ip, void *port)
138 {
139 PORTRANGE *pr;
140 unsigned short portu;
141 IP_PORT * p;
142
143 if( !ipc ) return 0;
144
145 if ( port )
146 portu = *((unsigned short *)port);
147 else
148 portu = 0;
149
150
151 for(p =(IP_PORT*)sflist_first( &ipc->ip_list );
152 p!=0;
153 p =(IP_PORT*)sflist_next( &ipc->ip_list ) )
154 {
155 if( sfip_contains(&p->ip, ip) == SFIP_CONTAINS)
156 {
157 for( pr=(PORTRANGE*)sflist_first(&p->portset.port_list);
158 pr != 0;
159 pr=(PORTRANGE*)sflist_next(&p->portset.port_list) )
160 {
161 /*
162 * If the matching IP has a wildcard port (pr->port_hi == 0 )
163 * or if the ports actually match.
164 */
165 if ( (pr->port_hi == 0) ||
166 (portu >= pr->port_lo && portu <= pr->port_hi) )
167 {
168 if( p->notflag )
169 return 0;
170 return 1;
171 }
172 }
173 }
174 }
175 return 0;
176 }
177
ipset_print(IPSET * ipc)178 int ipset_print( IPSET * ipc )
179 {
180 char ip_str[80];
181 PORTRANGE * pr;
182
183 if( !ipc ) return 0;
184
185 {
186 IP_PORT * p;
187
188 printf("IPSET\n");
189
190 for( p =(IP_PORT*)sflist_first( &ipc->ip_list );
191 p!=0;
192 p =(IP_PORT*)sflist_next( &ipc->ip_list ) )
193 {
194 SnortSnprintf(ip_str, 80, "%s", sfip_to_str(&p->ip.addr));
195
196 printf("CIDR BLOCK: %c%s", p->notflag ? '!' : ' ', ip_str);
197
198 for( pr=(PORTRANGE*)sflist_first(&p->portset.port_list);
199 pr != 0;
200 pr=(PORTRANGE*)sflist_next(&p->portset.port_list) )
201 {
202 printf(" %d", pr->port_lo);
203 if ( pr->port_hi != pr->port_lo )
204 printf("-%d", pr->port_hi);
205 }
206 printf("\n");
207 }
208 }
209 return 0;
210 }
211
212
portset_init(PORTSET * portset)213 static void portset_init( PORTSET * portset )
214 {
215 sflist_init(&portset->port_list);
216 }
217
portset_add(PORTSET * portset,unsigned port_lo,unsigned port_hi)218 static int portset_add(PORTSET * portset, unsigned port_lo, unsigned port_hi)
219 {
220 PORTRANGE *p;
221
222 if( !portset ) return -1;
223
224 p = (PORTRANGE *) calloc( 1,sizeof(PORTRANGE) );
225 if(!p) return -1;
226
227 p->port_lo = port_lo;
228 p->port_hi = port_hi;
229
230 sflist_add_tail(&portset->port_list, p );
231
232 return 0;
233 }
234
port_parse(char * portstr,PORTSET * portset)235 static int port_parse(char *portstr, PORTSET *portset)
236 {
237 unsigned port_lo = 0, port_hi = 0;
238 char *port1;
239 char *port_begin;
240 char *port_end;
241 char *port2 = NULL;
242
243 port_begin = SnortStrdup(portstr);
244
245 port1 = port_begin;
246 port2 = strstr(port_begin, "-");
247
248 {
249 if (*port1 == '\0')
250 {
251 free(port_begin);
252 return -1;
253 }
254
255 if (port2)
256 {
257 *port2 = '\0';
258 port2++;
259 }
260
261 port_lo = strtoul(port1, &port_end, 10);
262 if (port_end == port1)
263 {
264 free(port_begin);
265 return -2;
266 }
267
268 if (port2)
269 {
270 port_hi = strtoul(port2, &port_end, 10);
271 if (port_end == port2)
272 {
273 free(port_begin);
274 return -3;
275 }
276 }
277 else
278 {
279 port_hi = port_lo;
280 }
281
282 /* check to see if port is out of range */
283 if ( port_hi > MAXPORTS-1 || port_lo > MAXPORTS-1)
284 {
285 free(port_begin);
286 return -4;
287 }
288
289 /* swap ports if necessary */
290 if (port_hi < port_lo)
291 {
292 unsigned tmp;
293
294 tmp = port_hi;
295 port_hi = port_lo;
296 port_lo = tmp;
297 }
298
299 portset_add(portset, port_lo, port_hi);
300 }
301
302 free(port_begin);
303
304 return 0;
305 }
306
ip_parse(char * ipstr,sfcidr_t * ip,char * not_flag,PORTSET * portset,char ** endIP)307 static int ip_parse(char *ipstr, sfcidr_t *ip, char *not_flag, PORTSET *portset, char **endIP)
308 {
309 char *port_str;
310 char *comma;
311 char *end_bracket;
312
313 if (*ipstr == '!')
314 {
315 ipstr++;
316 *not_flag = 1;
317 }
318 else
319 {
320 *not_flag = 0;
321 }
322
323 comma = strchr(ipstr, ',');
324 end_bracket = strrchr(ipstr, ']');
325
326 if (comma)
327 {
328 *comma = '\0';
329 }
330 else if (end_bracket)
331 {
332 *end_bracket = '\0';
333 }
334
335 if (sfip_pton(ipstr, ip) != SFIP_SUCCESS)
336 return -1;
337
338 /* Just to get the IP string out of the way */
339 port_str = strtok(ipstr, " \t");
340 /* Is either the port after the 1st space, or NULL */
341 port_str = strtok(NULL, " \t");
342
343 while (port_str)
344 {
345 if (!comma)
346 {
347 comma = strchr(port_str, ',');
348 if (comma)
349 *comma = '\0';
350 }
351
352 if (!end_bracket)
353 {
354 end_bracket = strrchr(port_str, ']');
355 if (end_bracket)
356 *end_bracket = '\0';
357 }
358
359 port_parse(port_str, portset);
360 port_str = strtok(NULL, " \t");
361 }
362
363 if (portset->port_list.count == 0)
364 {
365 /* Make sure we have at least one port range in list, but
366 * an invalid port range to convey all is good. */
367 portset_add(portset, 0, 0);
368 }
369
370 if (comma)
371 {
372 *endIP = comma;
373 *comma = ',';
374 }
375 else if (end_bracket)
376 {
377 *end_bracket = ']';
378 *endIP = end_bracket;
379 }
380 else
381 {
382 /* Didn't see the comma or end bracket, so set endIP now */
383 *endIP = port_str;
384 }
385
386 return 0;
387 }
388
ipset_parse(IPSET * ipset,char * ipstr)389 int ipset_parse(IPSET *ipset, char *ipstr)
390 {
391 char *copy, *startIP, *endIP;
392 int parse_count = 0;
393 char set_not_flag = 0;
394 char item_not_flag;
395 char open_bracket = 0;
396 sfcidr_t ip;
397 PORTSET portset;
398
399 copy = strdup(ipstr);
400
401 if(!copy)
402 return -2;
403
404 startIP = copy;
405
406 if (*startIP == '!')
407 {
408 set_not_flag = 1;
409 startIP++;
410 }
411
412 while (startIP)
413 {
414 if (*startIP == '[')
415 {
416 open_bracket++;
417 startIP++;
418 if (!*startIP)
419 break;
420 }
421
422 if ((*startIP == ']') || (*startIP == '\0'))
423 {
424 open_bracket--;
425 break;
426 }
427
428 portset_init(&portset);
429
430 if(ip_parse(startIP, &ip, &item_not_flag, &portset, &endIP) != 0)
431 {
432 free(copy);
433 return -5;
434 }
435
436 if(ipset_add(ipset, &ip, &portset, (item_not_flag ^ set_not_flag)) != 0)
437 {
438 free(copy);
439 return -6;
440 }
441
442 parse_count++;
443
444 if (endIP && (*endIP != ']'))
445 {
446 endIP++;
447 }
448
449 startIP = endIP;
450 }
451
452 free(copy);
453
454 if (!parse_count)
455 return -7;
456
457 if (open_bracket)
458 return -8;
459
460 return 0;
461 }
462
463 #ifdef MAIN_IP
464
465 #include <time.h>
466
467 #ifndef WIN32
468 #define rand random
469 #define srand srandom
470 #endif
471
472 #define MAXIP 100
473
474 #include "sflsq.c"
475
test_ip4_parsing(void)476 void test_ip4_parsing(void)
477 {
478 unsigned host, mask, not_flag;
479 PORTSET portset;
480 char **curip;
481 int ret;
482 IPADDRESS *adp;
483 char *ips[] = {
484 "138.26.1.24:25",
485 "1.1.1.1/255.255.255.0:444",
486 "1.1.1.1/16:25-28",
487 "1.1.1.1/255.255.255.255:25 27-29",
488 "z/24",
489 "0/0",
490 "0.0.0.0/0.0.0.0:25-26 28-29 31",
491 "0.0.0.0/0.0.2.0",
492 NULL };
493
494 for(curip = ips; curip[0] != NULL; curip++)
495 {
496
497 portset_init(&portset);
498
499 /* network byte order stuff */
500 if((ret = ip4_parse(curip[0], 1, ¬_flag, &host, &mask, &portset)) != 0)
501 {
502 fprintf(stderr, "Unable to parse %s with ret %d\n", curip[0], ret);
503 }
504 else
505 {
506 printf("%c", not_flag ? '!' : ' ');
507 printf("%s/", inet_ntoa(*(struct in_addr *) &host));
508 printf("%s", inet_ntoa(*(struct in_addr *) &mask));
509 printf(" parsed successfully!\n");
510 }
511
512 /* host byte order stuff */
513 if((ret = ip4_parse(curip[0], 0, ¬_flag, &host, &mask, &portset)) != 0)
514 {
515 fprintf(stderr, "Unable to parse %s with ret %d\n", curip[0], ret);
516 }
517 else
518 {
519 adp = ip_new(IPV4_FAMILY);
520 ip_set(adp, &host, IPV4_FAMILY);
521 ip_fprint(stdout, adp);
522 fprintf(stdout, "*****************\n");
523 ip_free(adp);
524 }
525 }
526
527 return;
528 }
529
530
test_ip4set_parsing(void)531 void test_ip4set_parsing(void)
532 {
533 char **curip;
534 int ret;
535 char *ips[] = {
536 "12.24.24.1/32,!24.24.24.1",
537 "[0.0.0.0/0.0.2.0,241.242.241.22]",
538 "138.26.1.24",
539 "1.1.1.1",
540 "1.1.1.1/16",
541 "1.1.1.1/255.255.255.255",
542 "z/24",
543 "0/0",
544 "0.0.0.0/0.0.0.0",
545 "0.0.0.0/0.0.2.0",
546 NULL };
547
548 for(curip = ips; curip[0] != NULL; curip++)
549 {
550 IPSET *ipset = ipset_new(IPV4_FAMILY);
551
552 /* network byte order stuff */
553 if((ret = ip4_setparse(ipset, curip[0])) != 0)
554 {
555 ipset_free(ipset);
556 fprintf(stderr, "Unable to parse %s with ret %d\n", curip[0], ret);
557 }
558 else
559 {
560 printf("-[%s]\n ", curip[0]);
561 ipset_print(ipset);
562 printf("---------------------\n ");
563 }
564 }
565
566 return;
567 }
568
569 // -----------------------------
test_ip(void)570 void test_ip(void)
571 {
572 int i,k;
573 IPADDRESS * ipa[MAXIP];
574 unsigned ipaddress,ipx;
575 unsigned short ipaddress6[8], ipx6[8];
576
577 printf("IPADDRESS testing\n");
578
579 srand( time(0) );
580
581 for(i=0;i<MAXIP;i++)
582 {
583 if( i % 2 )
584 {
585 ipa[i]= ip_new(IPV4_FAMILY);
586 ipaddress = rand() * rand();
587 ip_set( ipa[i], &ipaddress, IPV4_FAMILY );
588
589 if( !ip_equal(ipa[i],&ipaddress, IPV4_FAMILY ) )
590 printf("error with ip_equal\n");
591
592 ip_get( ipa[i], &ipx, IPV4_FAMILY );
593 if( ipx != ipaddress )
594 printf("error with ip_get\n");
595
596 }
597 else
598 {
599 ipa[i]= ip_new(IPV6_FAMILY);
600
601 for(k=0;k<8;k++) ipaddress6[k] = (char) (rand() % (1<<16));
602
603 ip_set( ipa[i], ipaddress6, IPV6_FAMILY );
604
605 if( !ip_equal(ipa[i],&ipaddress6, IPV6_FAMILY ) )
606 printf("error with ip6_equal\n");
607
608 ip_get( ipa[i], ipx6, IPV6_FAMILY );
609
610 for(k=0;k<8;k++)
611 if( ipx6[k] != ipaddress6[k] )
612 printf("error with ip6_get\n");
613
614 }
615
616 printf("[%d] ",i);
617 ip_fprint(stdout,ipa[i]);
618 printf("\n");
619 }
620
621 printf("IP testing completed\n");
622 }
623
624
625
626 // -----------------------------
test_ipset(void)627 void test_ipset(void)
628 {
629 int i,k;
630 IPSET * ipset, * ipset6;
631 IPSET * ipset_copyp, * ipset6_copyp;
632
633 unsigned ipaddress, mask;
634 unsigned short mask6[8];
635 unsigned short ipaddress6[8];
636 unsigned port_lo, port_hi;
637 PORTSET portset;
638
639 printf("IPSET testing\n");
640
641 ipset = ipset_new(IPV4_FAMILY);
642 ipset6 = ipset_new(IPV6_FAMILY);
643
644 srand( time(0) );
645
646 for(i=0;i<MAXIP;i++)
647 {
648 if( i % 2 )
649 {
650 ipaddress = rand() * rand();
651 mask = 0xffffff00;
652 port_lo = rand();
653 port_hi = rand() % 5 + port_lo;
654 portset_init(&portset);
655 portset_add(&portset, port_lo, port_hi);
656
657 ipset_add( ipset, &ipaddress, &mask, &portset, 0, IPV4_FAMILY ); //class C cidr blocks
658
659 if( !ipset_contains( ipset, &ipaddress, &port_lo, IPV4_FAMILY ) )
660 printf("error with ipset_contains\n");
661 }
662 else
663 {
664 for(k=0;k<8;k++) ipaddress6[k] = (char) (rand() % (1<<16));
665
666 for(k=0;k<8;k++) mask6[k] = 0xffff;
667
668 port_lo = rand();
669 port_hi = rand() % 5 + port_lo;
670 portset_init(&portset);
671 portset_add(&portset, port_lo, port_hi);
672
673 ipset_add( ipset6, ipaddress6, mask6, &portset, 0, IPV6_FAMILY );
674
675 if( !ipset_contains( ipset6, &ipaddress6, &port_lo, IPV6_FAMILY ) )
676 printf("error with ipset6_contains\n");
677 }
678
679 }
680
681 ipset_copyp = ipset_copy( ipset );
682 ipset6_copyp = ipset_copy( ipset6 );
683
684
685 printf("-----IP SET-----\n");
686 ipset_print( ipset );
687 printf("\n");
688
689 printf("-----IP SET6-----\n");
690 ipset_print( ipset6 );
691 printf("\n");
692
693 printf("-----IP SET COPY -----\n");
694 ipset_print( ipset_copyp );
695 printf("\n");
696
697 printf("-----IP SET6 COPY -----\n");
698 ipset_print( ipset6_copyp );
699 printf("\n");
700
701 printf("IP set testing completed\n");
702 }
703
704
705 // -----------------------------
main(int argc,char ** argv)706 int main( int argc, char ** argv )
707 {
708 printf("ipobj \n");
709
710 test_ip();
711
712 test_ipset();
713
714 test_ip4_parsing();
715
716 test_ip4set_parsing();
717
718 printf("normal pgm completion\n");
719
720 return 0;
721 }
722
723 #endif
724
725