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