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, &not_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, &not_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