1 /* $Id: ssp_netscreen.c,v 2.10 2009/11/27 01:39:40 fknobbe Exp $
2  *
3  *
4  * Copyright (c) 2002-2008 Frank Knobbe <frank@knobbe.us>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * Acknowledgements:
29  *
30  * Thanks to Christopher Lyon for his assistance in the concept, support,
31  * and providing a test environment.
32  *
33  *
34  *
35  * ssp_netscreen.c
36  *
37  * Purpose:
38  *
39  * This SnortSam plugin telnet's into one or more Netscreen firewalls,
40  * setups up a global group for blocked addresses, and then adds
41  * blocked IP address to this group. SnortSam will also expire the blocks
42  * itself since the Netscreen does not have automatic time-out functionality.
43  *
44  * Comments:
45  *
46  * Since only whole IP's can be placed into the address group for blocking,
47  * only complete addresses are blocked. That means that service pairs
48  * (src-dst:port) can not be individually be blocked. Any such request
49  * will result in the whole IP being blocked.
50  *
51  * It is theoratically possible to block service pairs, but that would require
52  * rewriting the existing rulebase completely to insert the service pairs on
53  * top of the rule base. Because this is very invasive and time consuming,
54  * the only practical way of blocking is by adding addresses to the Blocked group.
55  *
56  */
57 
58 
59 #ifndef		__SSP_NETSCREEN_C__
60 #define		__SSP_NETSCREEN_C__
61 
62 
63 #include "snortsam.h"
64 #include "ssp_netscreen.h"
65 
66 
67 #include <sys/types.h>
68 #include <stdio.h>
69 #include <string.h>
70 #include <time.h>
71 #ifdef WIN32
72 #include <winsock.h>
73 #else
74 #include <netinet/in.h>
75 #include <arpa/inet.h>
76 #endif
77 
78 
79 
80 
81 /* This routine checks the version of the given NetScreen box. It is called as part of parse,
82  * but also as part of Block if it didn't run before.
83  * It issues the GET SYSTEM command and note the software version.
84 */
85 
NetScrnCheckVersion(SOCKET nssocket,NETSCRNDATA * nsp,char * nsat)86 int NetScrnCheckVersion(SOCKET nssocket,NETSCRNDATA *nsp,char *nsat)
87 {	char *p,*p2,msg[STRBUFSIZE+1];
88 
89 	if(!sendreceive(nssocket,NETSCRN_NETWAIT,"netscrn",nsp->ip,"get system\r","software version: ","at get system command ",nsat))
90 		return FALSE;
91 	recv(nssocket,msg,40,0);
92 	msg[40]=0;
93 	p2=msg;
94 	while(*p2 && !myisdigit(*p2))
95 		p2++;
96 	p=p2;
97 	while(*p2 && myisdigit(*p2))
98 		p2++;
99 	*p2=0;
100 	nsp->software_version=(unsigned char)atoi(p);
101 
102 	if(!*(nsp->zone))
103 	{	switch(nsp->software_version)
104 		{	case 4:		safecopy(nsp->zone,"V1-Untrust");
105 					break;
106 			case 3:
107 			default:	safecopy(nsp->zone,"untrust");
108 					break;
109 		}
110 	}
111 	return TRUE;
112 }
113 
114 /* This routine parses the netscreen statements in the config file.
115  * It builds a list of firewalls)
116 */
NetScrnParse(char * val,char * file,unsigned long line,DATALIST * plugindatalist)117 void NetScrnParse(char *val,char *file,unsigned long line,DATALIST *plugindatalist)
118 {	NETSCRNDATA *nsp;
119 	char *p2,msg[STRBUFSIZE+1],nsat[STRBUFSIZE+1];
120 	struct in_addr nsip;
121 	struct sockaddr_in thissocketaddr,nssocketaddr;
122 	SOCKET nssocket;
123 	unsigned long flag;
124 
125 #ifdef FWSAMDEBUG
126 	printf("Debug: [netscrn] Plugin Parsing...\n");
127 #endif
128 
129 	if(*val)
130 	{	p2=val;
131 		while(*p2 && !myisspace(*p2))
132 			p2++;
133 		if(*p2)
134 			*p2++ =0;
135 		nsip.s_addr=getip(val);
136 		if(nsip.s_addr)			/* If we have a valid IP address */
137 		{	nsp=safemalloc(sizeof(NETSCRNDATA),"NetScrnParse","nsp");	/* create new netscreen */
138 			plugindatalist->data=nsp;
139 			nsp->ip.s_addr=nsip.s_addr;
140 			nsp->software_version=0;			/* no version discovered yet */
141 			nsp->loginid[0]=nsp->loginpw[0]=0;
142 			safecopy(nsp->denygroup,"SnortSam");  /* set default group */
143 			nsp->zone[0]=0;
144 
145 			if(*p2)
146 			{	val=p2;
147 				while(*val && myisspace(*val))		/* skip spaces */
148 					val++;
149 				if(val)
150 				{	p2=val;
151 					while(*p2 && !myisspace(*p2))	/* parse id */
152 						p2++;
153 					if(*p2)
154 						*p2++ =0;
155 					safecopy(nsp->loginid,val);	/* save user id */
156 
157 					if(*p2)									/* if we have a password */
158 					{	val=p2;
159 						while(*val && myisspace(*val))		/* skip spaces */
160 							val++;
161 						if(val)
162 						{	p2=val;
163 							while(*p2 && !myisspace(*p2))	/* parse it */
164 								p2++;
165 							if(*p2)
166 								*p2++ =0;
167 							safecopy(nsp->loginpw,val);	/* save password */
168 
169 							if(*p2)									/* if we have a group name */
170 							{	val=p2;
171 								while(*val && myisspace(*val))		/* skip spaces */
172 									val++;
173 								if(val)
174 								{	p2=val;
175 									while(*p2 && !myisspace(*p2))	/* parse it */
176 										p2++;
177 									if(*p2)
178 										*p2++ =0;
179 									safecopy(nsp->denygroup,val);	/* save group name */
180 								}
181 
182 								if(*p2)									/* if we have a zone name */
183 								{	val=p2;
184 									while(*val && myisspace(*val))		/* skip spaces */
185 										val++;
186 									if(val)
187 									{	p2=val;
188 										while(*p2 && !myisspace(*p2))	/* parse it */
189 											p2++;
190 										if(*p2)
191 											*p2++ =0;
192 										safecopy(nsp->zone,val);		/* save optional zone name */
193 									}
194 								}
195 							}
196 						}
197 					}
198 				}
199 			}
200 			if(!nsp->loginid[0])
201 			{	snprintf(msg,sizeof(msg)-1,"Error: [%s: %lu] Netscreen defined without login ID!",file,line);
202 				logmessage(1,msg,"netscrn",0);
203 				free(nsp);
204 				plugindatalist->data=NULL;
205 			}
206 			else if(!nsp->loginpw[0])
207 			{	snprintf(msg,sizeof(msg)-1,"Error: [%s: %lu] Netscreen defined without login password!",file,line);
208 				logmessage(1,msg,"netscrn",0);
209 				free(nsp);
210 				plugindatalist->data=NULL;
211 			}
212 			else
213 			{
214 				snprintf(nsat,sizeof(nsat)-1,"NetScreen at %s",inettoa(nsp->ip.s_addr));
215 
216 				nssocketaddr.sin_port=htons(23); /* telnet */
217 				nssocketaddr.sin_addr.s_addr=nsp->ip.s_addr;
218 				nssocketaddr.sin_family=AF_INET;
219 
220 				thissocketaddr.sin_port=htons(0); /* get a dynamic port  */
221 				thissocketaddr.sin_addr.s_addr=0;
222 				thissocketaddr.sin_family=AF_INET;
223 
224 				/* create socket */
225 				nssocket=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
226 				if(nssocket==INVALID_SOCKET)
227 				{	snprintf(msg,sizeof(msg)-1,"Error: [netscrn] Couldn't create socket!");
228 					logmessage(1,msg,"netscrn",nsp->ip.s_addr);
229 					return;
230 				}
231 				/* bind it */
232 				if(bind(nssocket,(struct sockaddr *)&(thissocketaddr),sizeof(struct sockaddr)))
233 				{	snprintf(msg,sizeof(msg)-1,"Error: [netsrcn] Couldn't bind socket!");
234 					logmessage(1,msg,"netscrn",nsp->ip.s_addr);
235 					return;
236 				}
237 				/* and connect to netscreen */
238 				if(connect(nssocket,(struct sockaddr *)&nssocketaddr,sizeof(struct sockaddr)))
239 				{	snprintf(msg,sizeof(msg)-1,"Error: [netscrn] Could not connect to %s! Will try later.",nsat);
240 					logmessage(1,msg,"netscrn",nsp->ip.s_addr);
241 				}
242 				else
243 				{	do
244 					{
245 						flag=-1;
246 						ioctlsocket(nssocket,FIONBIO,&flag);	/* set non blocking  */
247 
248 						if(!sendreceive(nssocket,NETSCRN_NETWAIT,"netscrn",nsp->ip,"","login","waiting for logon prompt from ",nsat))
249 							continue;
250 
251 						snprintf(msg,sizeof(msg)-1,"%s\r",nsp->loginid);	/* send login id */
252 						if(!sendreceive(nssocket,NETSCRN_NETWAIT,"netscrn",nsp->ip,msg,"password","at logon prompt of ",nsat))
253 							continue;
254 
255 						snprintf(msg,sizeof(msg)-1,"%s\r",nsp->loginpw);	/* send login password */
256 						if(!sendreceive(nssocket,NETSCRN_NETWAIT,"netscrn",nsp->ip,msg,"->","at password prompt of ",nsat))
257 							continue;
258 
259 						/* Check for the version of the NetScreen box */
260 						if(!NetScrnCheckVersion(nssocket,nsp,nsat))
261 							continue;
262 
263 						sendreceive(nssocket,NETSCRN_NETWAIT,"netscrn",nsp->ip,"exit\r","","at exit ",nsat); /* exit */
264 					}while(FALSE);
265 				}
266 #ifdef FWSAMDEBUG
267 				printf("Debug: [netscrn] Adding Netscreen: IP \"%s\", ID \"%s\", PW \"%s\", Group \"%s\", Version \"%u\"\n",inettoa(nsp->ip.s_addr),nsp->loginid,nsp->loginpw,nsp->denygroup,(unsigned int)nsp->software_version);
268 #endif
269 				}
270 			}
271 		else
272 		{	snprintf(msg,sizeof(msg)-1,"Error: [%s: %lu] Invalid NetSscreen parameter '%s' ignored.",file,line,val);
273 			logmessage(1,msg,"netscrn",0);
274 		}
275 	}
276 	else
277 	{	snprintf(msg,sizeof(msg)-1,"Error: [%s: %lu] Empty NetScreen parameter.",file,line);
278 		logmessage(1,msg,"netscrn",0);
279 	}
280 }
281 
282 
283 /* This routine initiates the block. It walks the list of Netscreen
284  * firewalls, telnet's in, and adds IP address to the deny group.
285  */
NetScrnBlock(BLOCKINFO * bd,void * data,unsigned long qp)286 void NetScrnBlock(BLOCKINFO *bd,void *data,unsigned long qp)
287 {   NETSCRNDATA *nsp;
288 	struct sockaddr_in thissocketaddr,nssocketaddr;
289 	SOCKET nssocket;
290 	unsigned long flag;
291 	char msg[STRBUFSIZE+1],nsat[STRBUFSIZE+1];
292 #ifdef FWSAMDEBUG
293 #ifdef WIN32
294 	unsigned long threadid=GetCurrentThreadId();
295 #else
296 	pthread_t threadid=pthread_self();
297 #endif
298 #endif
299 
300 	if(!data)
301 		return;
302 	nsp=(NETSCRNDATA *)data;
303 
304 #ifdef FWSAMDEBUG
305 	printf("Debug: [netsrcn][%lx] Plugin Blocking...\n",(unsigned long)threadid);
306 #endif
307 
308 	snprintf(nsat,sizeof(nsat)-1,"NetScreen at %s",inettoa(nsp->ip.s_addr));
309 
310 	nssocketaddr.sin_port=htons(23); /* telnet */
311 	nssocketaddr.sin_addr.s_addr=nsp->ip.s_addr;
312 	nssocketaddr.sin_family=AF_INET;
313 
314 	thissocketaddr.sin_port=htons(0); /* get a dynamic port  */
315 	thissocketaddr.sin_addr.s_addr=0;
316 	thissocketaddr.sin_family=AF_INET;
317 
318 	/* create socket */
319 	nssocket=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
320 	if(nssocket==INVALID_SOCKET)
321 	{	snprintf(msg,sizeof(msg)-1,"Error: [netscrn] Couldn't create socket!");
322 		logmessage(1,msg,"netscrn",nsp->ip.s_addr);
323 		return;
324 	}
325 	/* bind it */
326 	if(bind(nssocket,(struct sockaddr *)&(thissocketaddr),sizeof(struct sockaddr)))
327 	{	snprintf(msg,sizeof(msg)-1,"Error: [netsrcn] Couldn't bind socket!");
328 		logmessage(1,msg,"netscrn",nsp->ip.s_addr);
329 		return;
330 	}
331 	/* and connect to netscreen */
332 	if(connect(nssocket,(struct sockaddr *)&nssocketaddr,sizeof(struct sockaddr)))
333 	{	snprintf(msg,sizeof(msg)-1,"Error: [netscrn] Could not connect to %s! Will try later.",nsat);
334 		logmessage(1,msg,"netscrn",nsp->ip.s_addr);
335 	}
336 	else
337 	{	do
338 		{
339 #ifdef FWSAMDEBUG
340 			printf("Debug: [netscrn][%lx] Connected to %s.\n",(unsigned long)threadid,nsat);
341 #endif
342 			flag=-1;
343 			ioctlsocket(nssocket,FIONBIO,&flag);	/* set non blocking  */
344 
345 			if(!sendreceive(nssocket,NETSCRN_NETWAIT,"netscrn",nsp->ip,"","login","waiting for logon prompt from ",nsat))
346 				continue;
347 
348 			snprintf(msg,sizeof(msg)-1,"%s\r",nsp->loginid);	/* send login id */
349 			if(!sendreceive(nssocket,NETSCRN_NETWAIT,"netscrn",nsp->ip,msg,"password","at logon prompt of ",nsat))
350 				continue;
351 
352 			snprintf(msg,sizeof(msg)-1,"%s\r",nsp->loginpw);	/* send login password */
353 			if(!sendreceive(nssocket,NETSCRN_NETWAIT,"netscrn",nsp->ip,msg,"->","at password prompt of ",nsat))
354 				continue;
355 
356 			/* If we weren't able to get the version of the Netscreen box at startup, we'll try now. */
357 			if(!nsp->software_version)
358 			{	if(!NetScrnCheckVersion(nssocket,nsp,nsat))	/* If we still can't get a version, we'll assume version 3. */
359 				{	safecopy(nsp->zone,"untrusted");
360 					nsp->software_version=3;
361 				}
362 			}
363 
364 /* The deny group is set up at every block. This could be done just once, but if the group were to become erase on the firewall, */
365 /* Snortsam would have to be restarted to recreate the group. This seems safer... */
366 
367 						if(bd->block)
368 						{	snprintf(msg,sizeof(msg)-1,"set group address %s \"%s\" comment \"SnortSam Block Rule\"\r",nsp->zone,nsp->denygroup);	/* setup deny group */
369 							if(!sendreceive(nssocket,NETSCRN_NETWAIT,"netscrn",nsp->ip,msg,"->","at group setup ",nsat))
370 								continue;
371 
372 							snprintf(msg,sizeof(msg)-1,"set address %s \"Blocked_%s\" %s 255.255.255.255\r",nsp->zone,inettoa(bd->blockip),inettoa(bd->blockip)); /* create host object */
373 							if(!sendreceive(nssocket,NETSCRN_NETWAIT,"netscrn",nsp->ip,msg,"->","at set address ",nsat))
374 								continue;
375 
376 							snprintf(msg,sizeof(msg)-1,"set group address %s \"%s\" add \"Blocked_%s\"\r",nsp->zone,nsp->denygroup,inettoa(bd->blockip)); /* add host to group */
377 							if(!sendreceive(nssocket,NETSCRN_NETWAIT,"netscrn",nsp->ip,msg,"->","at set group add ",nsat))
378 								continue;
379 						}
380 						else
381 						{	snprintf(msg,sizeof(msg)-1,"unset group address %s \"%s\" remove \"Blocked_%s\"\r",nsp->zone,nsp->denygroup,inettoa(bd->blockip)); /* remove host from group */
382 							if(!sendreceive(nssocket,NETSCRN_NETWAIT,"netscrn",nsp->ip,msg,"->","at unset group remove ",nsat))
383 								continue;
384 
385 							snprintf(msg,sizeof(msg)-1,"unset address %s \"Blocked_%s\"\r",nsp->zone,inettoa(bd->blockip)); /* remove host object */
386 							if(!sendreceive(nssocket,NETSCRN_NETWAIT,"netscrn",nsp->ip,msg,"->","at set group add ",nsat))
387 								continue;
388 						}
389 						break;
390 
391 			if(!sendreceive(nssocket,NETSCRN_NETWAIT,"netscrn",nsp->ip,"save\r","->","at save ",nsat)) /* save config */
392 				continue;
393 
394 			sendreceive(nssocket,NETSCRN_NETWAIT,"netscrn",nsp->ip,"exit\r","","at exit ",nsat); /* exit */
395 
396 		}while(FALSE);
397 	}
398 	closesocket(nssocket);
399 }
400 
401 #endif /* __SSP_NETSCREEN_C__ */
402 
403 
404 
405 
406 
407 
408