1 /* $Id: ssp_ipchains.c,v 2.8 2008/04/26 19:53:21 fknobbe Exp $
2  *
3  * Copyright (c) 2002-2008 Hector Paterno <apaterno@dsnsecurity.com>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  *
28  * ssp_ipchains.c
29  *
30  * Purpose:
31  *
32  * This SnortSam plugin is meant for dynamic (un)blocking on ipchains (Linux) firewall,
33  * SnortSam will expire the blocks itself since ipchains does not have
34  * automatic time-out functionality.
35  *
36  * Todo:
37  *
38  * This is a basic plugin, I'v a lot of ideas to implement on ipchains.
39  *
40  */
41 
42 
43 #ifdef Linux
44 
45 #ifndef		__SSP_IPCHAINS_C__
46 #define		__SSP_IPCHAINS_C__
47 
48 
49 #include <stdio.h>
50 #include <string.h>
51 #include <sys/types.h>
52 #include <sys/socket.h>
53 #include <net/if.h>
54 #include <errno.h>
55 #include "snortsam.h"
56 #include "ssp_ipchains.h"
57 
58 
59 static int sockfd = -1;
60 
61 
ipfwc_init()62 static int ipfwc_init()
63 {
64    return ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) != -1);
65 }
66 
do_setsockopt(int cmd,const void * data,int length)67 static int do_setsockopt(int cmd, const void *data, int length)
68 {
69    return setsockopt(sockfd, IPPROTO_IP, cmd, (char *)data, length) != -1;
70 }
71 
72 /*
73  * This routine parses the ipchains statements in the config file.
74  */
75 void
IPCHParse(char * val,char * file,unsigned long line,DATALIST * plugindatalist)76 IPCHParse(char *val, char *file, unsigned long line, DATALIST * plugindatalist)
77 {
78 	IPCHDATA         *ipchp = NULL;
79 	char           *p2, msg[STRBUFSIZE + 2];
80 
81 #ifdef FWSAMDEBUG
82 	printf("Debug: [ipchains] Plugin Parsing...\n");
83 #endif
84 
85 	if (*val)
86         {
87 		p2 = val;
88 		while (*p2 && !myisspace(*p2))
89 			p2++;
90 		if (*p2)
91 			*p2++ = 0;
92 		ipchp = safemalloc(sizeof(IPCHDATA), "IPCHParse", "ipchp");
93 		plugindatalist->data = ipchp;
94 		ipchp->logopt = 0;
95 		safecopy(ipchp->iface, val);	/* save interface */
96 
97 		if (*p2) 	/* if we have a log option defined */
98 		{	while (*p2 && myisspace(*p2)) p2++;
99 			if (strcmp(p2, "log") == 0)
100 			{	ipchp->logopt = 1;
101 			}
102 		}
103 
104 #ifdef FWSAMDEBUG
105 		printf("Debug: [ipchains] Adding IPCH: interface \"%s\", log \"%d\"\n", ipchp->iface, ipchp->logopt);
106 #endif
107 
108 	} else
109 	{	snprintf(msg, sizeof(msg) - 1, "Error: [%s: %lu] ipchains defined without parameters!", file, line);
110 		logmessage(1, msg, "ipchains", 0);
111 	}
112 
113 }
114 
115 
116 /*
117  * This routine initiates the block.
118  */
IPCHBlock(BLOCKINFO * bd,void * data,unsigned long qp)119 void IPCHBlock(BLOCKINFO *bd, void *data,unsigned long qp)
120 {
121 
122    IPCHDATA * ipchp;
123    struct ip_fwchange newfw;
124    char            msg[STRBUFSIZE + 2];
125    int             who;
126 #ifdef FWSAMDEBUG
127     pthread_t       threadid = pthread_self();
128 #endif
129 
130    if (!data)
131      return;
132    ipchp=(IPCHDATA *)data;
133 
134 #ifdef FWSAMDEBUG
135 	printf("Debug: [ipchains][%lx] Plugin Blocking...\n", threadid);
136 #endif
137 
138 
139    bzero(&newfw, sizeof(struct ip_fwchange));
140 
141    if(ipfwc_init()==-1)
142      {
143 	snprintf(msg, sizeof(msg) - 1, "Error: Can't open RAW socket, %s", strerror(errno));
144 	logmessage(1, msg, "ipchains", 0);
145 	return;
146      }
147 
148       newfw.fwc_rule.ipfw.fw_smsk.s_addr = 0xffffffff;
149       memcpy(newfw.fwc_rule.label, IP_FW_LABEL_BLOCK, sizeof(newfw.fwc_rule.label));
150       memcpy(newfw.fwc_rule.ipfw.fw_vianame, ipchp->iface, IFNAMSIZ-1);
151       newfw.fwc_rule.ipfw.fw_tosand = 255;
152       newfw.fwc_rule.ipfw.fw_spts[0] = 0; /* Default all */
153       newfw.fwc_rule.ipfw.fw_spts[1] = 65535;
154       newfw.fwc_rule.ipfw.fw_dpts[0] = 0;
155       newfw.fwc_rule.ipfw.fw_dpts[1] = 65535;
156 
157       if(ipchp->logopt)
158         newfw.fwc_rule.ipfw.fw_flg = 0x0001;
159 
160       /* Future Improvments via config file
161        newfw.fwc_rule.ipfw.fw_mark =
162        newfw.fwc_rule.ipfw.fw_flg =
163        newfw.fwc_rule.ipfw.fw_invflg =
164        newfw.fwc_rule.ipfw.fw_redirpt =
165        newfw.fwc_rule.ipfw.fw_outputsize =
166        newfw.fwc_rule.ipfw.fw_tosxor =  */
167 
168    if (bd->block) { // Will block
169       snprintf(msg, sizeof(msg) - 1, "Info: Blocking ip %s", inettoa(bd->blockip));
170       logmessage(1, msg, "ipchains", 0);
171 
172       switch (bd->mode & FWSAM_HOW) {
173        case FWSAM_HOW_THIS:
174 	 memcpy(newfw.fwc_label, IP_FW_LABEL_INPUT, sizeof(newfw.fwc_label));
175 	 newfw.fwc_rule.ipfw.fw_src.s_addr = (u_int32_t) bd->blockip;
176 	 newfw.fwc_rule.ipfw.fw_dst.s_addr = (u_int32_t) bd->peerip;
177          newfw.fwc_rule.ipfw.fw_dmsk.s_addr = 0xffffffff;
178 	 newfw.fwc_rule.ipfw.fw_proto = bd->proto;
179 
180 	 if(bd->port)
181 	   {
182 	      newfw.fwc_rule.ipfw.fw_dpts[0] = bd->port;
183 	      newfw.fwc_rule.ipfw.fw_dpts[1] = bd->port;
184 	   }
185 
186        break;
187 
188        default: ; /* IN Rule */
189        case FWSAM_HOW_IN:	/* Incoming FROM host ( src ) */
190 	 memcpy(newfw.fwc_label, IP_FW_LABEL_INPUT, sizeof(newfw.fwc_label));
191 	 newfw.fwc_rule.ipfw.fw_src.s_addr = (u_int32_t) bd->blockip;
192 
193        break;
194 
195        case FWSAM_HOW_OUT:	/* Outgoing TO host ( dst ) */
196          memcpy(newfw.fwc_label, IP_FW_LABEL_OUTPUT, sizeof(newfw.fwc_label));
197 	 newfw.fwc_rule.ipfw.fw_dst.s_addr = (u_int32_t) bd->blockip;
198 	 newfw.fwc_rule.ipfw.fw_smsk.s_addr = 0x0;
199          newfw.fwc_rule.ipfw.fw_dmsk.s_addr = 0xffffffff;
200 
201        break;
202 
203        case FWSAM_HOW_INOUT:	/* Need 2 rules 1 for IN, 1 for OUT */
204 
205 			/* Incoming FROM */
206 	 memcpy(newfw.fwc_label, IP_FW_LABEL_INPUT, sizeof(newfw.fwc_label));
207 	 newfw.fwc_rule.ipfw.fw_src.s_addr = (u_int32_t) bd->blockip;
208 
209 	 if(do_setsockopt(IP_FW_APPEND, &newfw, sizeof(newfw))==-1)
210 	   {
211 	      snprintf(msg, sizeof(msg) - 1, "Error: Can't Block ip %s, %s", inettoa(bd->blockip), strerror(errno));
212 	      logmessage(1, msg, "ipchains", 0);
213 	      return;
214 	   }
215 
216 			/* Outgoing TO */
217 	 memcpy(newfw.fwc_label, IP_FW_LABEL_OUTPUT, sizeof(newfw.fwc_label));
218 	 newfw.fwc_rule.ipfw.fw_dst.s_addr = (u_int32_t) bd->blockip;
219 	 newfw.fwc_rule.ipfw.fw_dmsk.s_addr = 0xffffffff;
220          newfw.fwc_rule.ipfw.fw_smsk.s_addr = 0x0;
221 
222       break;
223 
224       }
225 
226 	 if(do_setsockopt(IP_FW_APPEND, &newfw, sizeof(newfw))==-1)
227 	   {
228 	      snprintf(msg, sizeof(msg) - 1, "Error: Can't Block ip %s, %s", inettoa(bd->blockip), strerror(errno));
229 	      logmessage(1, msg, "ipchains", 0);
230 	      return;
231 	   }
232 
233 
234    }else{ /* Will unblock */
235       snprintf(msg, sizeof(msg) - 1, "Info: UnBlocking ip %s", inettoa(bd->blockip));
236       logmessage(1, msg, "ipchains", 0);
237 
238       switch (bd->mode & FWSAM_HOW) {
239        case FWSAM_HOW_THIS:
240 	 memcpy(newfw.fwc_label, IP_FW_LABEL_INPUT, sizeof(newfw.fwc_label));
241 	 newfw.fwc_rule.ipfw.fw_src.s_addr = (u_int32_t) bd->blockip;
242 	 newfw.fwc_rule.ipfw.fw_dst.s_addr = (u_int32_t) bd->peerip;
243          newfw.fwc_rule.ipfw.fw_dmsk.s_addr = 0xffffffff;
244 
245 	 if(bd->port)
246 	   {
247 	      newfw.fwc_rule.ipfw.fw_dpts[0] = bd->port;
248 	      newfw.fwc_rule.ipfw.fw_dpts[1] = bd->port;
249 	   }
250 
251        break;
252 
253        default: ; /* IN Rule */
254        case FWSAM_HOW_IN:	/* Incoming FROM host ( src ) */
255 	 memcpy(newfw.fwc_label, IP_FW_LABEL_INPUT, sizeof(newfw.fwc_label));
256 	 newfw.fwc_rule.ipfw.fw_src.s_addr = (u_int32_t) bd->blockip;
257 
258        break;
259 
260        case FWSAM_HOW_OUT:	/* Outgoing TO host ( dst ) */
261          memcpy(newfw.fwc_label, IP_FW_LABEL_OUTPUT, sizeof(newfw.fwc_label));
262 	 newfw.fwc_rule.ipfw.fw_dst.s_addr = (u_int32_t) bd->blockip;
263 	 newfw.fwc_rule.ipfw.fw_smsk.s_addr = 0x0;
264          newfw.fwc_rule.ipfw.fw_dmsk.s_addr = 0xffffffff;
265 
266        break;
267 
268        case FWSAM_HOW_INOUT:	/* Need 2 rules 1 for IN, 1 for OUT */
269 
270 			/* Incoming FROM */
271 	 memcpy(newfw.fwc_label, IP_FW_LABEL_INPUT, sizeof(newfw.fwc_label));
272 	 newfw.fwc_rule.ipfw.fw_src.s_addr = (u_int32_t) bd->blockip;
273 
274 	 if(do_setsockopt(IP_FW_DELETE, &newfw, sizeof(newfw))==-1)
275 	   {
276 	      snprintf(msg, sizeof(msg) - 1, "Error: Can't UnBlock ip %s, %s", inettoa(bd->blockip), strerror(errno));
277 	      logmessage(1, msg, "ipchains", 0);
278 	      return;
279 	   }
280 
281 			/* Outgoing TO */
282 	 memcpy(newfw.fwc_label, IP_FW_LABEL_OUTPUT, sizeof(newfw.fwc_label));
283 	 newfw.fwc_rule.ipfw.fw_dst.s_addr = (u_int32_t) bd->blockip;
284 	 newfw.fwc_rule.ipfw.fw_dmsk.s_addr = 0xffffffff;
285          newfw.fwc_rule.ipfw.fw_smsk.s_addr = 0x0;
286 
287       break;
288 
289       }
290 
291 
292 	 if(do_setsockopt(IP_FW_DELETE, &newfw, sizeof(newfw))==-1)
293 	   {
294 	      snprintf(msg, sizeof(msg) - 1, "Error: Can't UnBlock ip %s, %s", inettoa(bd->blockip), strerror(errno));
295 	      logmessage(1, msg, "ipchains", 0);
296 	      return;
297 	   }
298 
299 
300      }
301 
302 	close(sockfd);
303 
304 	return;
305 }
306 
307 #endif				/* __SSP_IPCHAINS_C__ */
308 #endif /* LINUX */
309