1 /*
2  *
3  * Copyright (c) 2009 Wouter de Jong <maddog2k@maddog2k.net>
4  * Copyright (c) 2005-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  * Heavily based on ssp_cisco_nullroute of Frank Knobbe <frank@knobbe.us>
31  *
32  *
33  * ssp_cisco_nullroute2.c
34  *
35  * Purpose:
36  *
37  * This SnortSam plugin telnet's into one or more Cisco routers and issues
38  * a route command to effectively "null-route" the intruding IP address.
39  * SnortSam will remove the added routes when the blocks expire.
40  * This plugin is an improved version, that add's the option to add
41  * a tag to a route, and to use 'auto-enable' mode.
42  *
43  *
44  */
45 
46 
47 #ifndef		__SSP_CISCO_NULLROUTE2_C__
48 #define		__SSP_CISCO_NULLROUTE2_C__
49 
50 
51 #include "snortsam.h"
52 #include "ssp_cisco_nullroute2.h"
53 
54 
55 #include <sys/types.h>
56 #include <stdio.h>
57 #include <string.h>
58 #include <time.h>
59 
60 #ifdef WIN32
61 #include <winsock.h>
62 
63 #ifndef strsep
64 /* Okay, I'm lazy today. Below a copy of strsep which doesn't exist on Windows,
65  * at least my old compiler. Remove/disable this section as necessary.
66 */
67 /* ---8<------8<------8<------8<------8<------8<------8<------8<------8<--- */
68 /*-
69  * Copyright (c) 1990, 1993
70  *	The Regents of the University of California.  All rights reserved.
71  *
72  * Redistribution and use in source and binary forms, with or without
73  * modification, are permitted provided that the following conditions
74  * are met:
75  * 1. Redistributions of source code must retain the above copyright
76  *    notice, this list of conditions and the following disclaimer.
77  * 2. Redistributions in binary form must reproduce the above copyright
78  *    notice, this list of conditions and the following disclaimer in the
79  *    documentation and/or other materials provided with the distribution.
80  * 4. Neither the name of the University nor the names of its contributors
81  *    may be used to endorse or promote products derived from this software
82  *    without specific prior written permission.
83  *
84  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
85  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
86  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
87  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
88  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
89  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
90  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
91  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
92  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
93  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
94  * SUCH DAMAGE.
95  */
96 /*
97  * Get next token from string *stringp, where tokens are possibly-empty
98  * strings separated by characters from delim.
99  *
100  * Writes NULs into the string at *stringp to end tokens.
101  * delim need not remain constant from call to call.
102  * On return, *stringp points past the last NUL written (if there might
103  * be further tokens), or is NULL (if there are definitely no more tokens).
104  *
105  * If *stringp is NULL, strsep returns NULL.
106  */
107 
108 char *strsep(char **, const char *);
109 
strsep(stringp,delim)110 char *strsep(stringp, delim)
111 	char **stringp;
112 	const char *delim;
113 {
114 	char *s;
115 	const char *spanp;
116 	int c, sc;
117 	char *tok;
118 
119 	if ((s = *stringp) == NULL)
120 		return (NULL);
121 	for (tok = s;;) {
122 		c = *s++;
123 		spanp = delim;
124 		do {
125 			if ((sc = *spanp++) == c) {
126 				if (c == 0)
127 					s = NULL;
128 				else
129 					s[-1] = 0;
130 				*stringp = s;
131 				return (tok);
132 			}
133 		} while (sc != 0);
134 	}
135 	/* NOTREACHED */
136 }
137 
138 /* --->8------>8------>8------>8------>8------>8------>8------>8------>8--- */
139 #endif /* strsep */
140 
141 #else
142 #include <netinet/in.h>
143 #include <arpa/inet.h>
144 #endif /* WIN32 */
145 
146 
147 
148 
149 /* This routine parses the cisconullroute2 statements in the config file.
150  * It builds a list of routers)
151 */
CiscoNullRoute2Parse(char * val,char * file,unsigned long line,DATALIST * plugindatalist)152 void CiscoNullRoute2Parse(char *val,char *file,unsigned long line,DATALIST *plugindatalist)
153 {
154 	CISCONULLROUTE2DATA *ciscop;
155 	char *p2,msg[STRBUFSIZE+2],*p3,*p4,*p5;
156 	struct in_addr routerip;
157 
158 #ifdef FWSAMDEBUG
159 	printf("Debug: [cisconullroute2] Plugin Parsing...\n");
160 #endif
161 
162 	if(*val)
163 	{
164 		p2=val;
165 		ciscop=safemalloc(sizeof(CISCONULLROUTE2DATA),"cisconullroute2parse","ciscop");	/* create new router */
166 		plugindatalist->data=ciscop;
167 		ciscop->routersocket=0;
168 		ciscop->loggedin=FALSE;
169 		ciscop->username[0]=ciscop->telnetpw[0]=ciscop->enablepw[0]=ciscop->routetag[0]=ciscop->userlogin=0;
170 		ciscop->autoenable=FALSE;
171 
172 		while ((p3 = strsep(&p2, " ")) != NULL)
173 		{
174 			if (!p3)
175 				continue;
176 
177 			p4	= strsep(&p3, "=");
178 			if(p4 != NULL)
179 			{
180 				p5	= strsep(&p3, "=");
181 
182 				if(p5 == NULL)
183 				{
184 					snprintf(msg,sizeof(msg)-1,"Error: [%s: %lu] Skipping unknown option '%s'",file,line,p4);
185 					logmessage(1,msg,"cisconullroute2",0);
186 					continue;
187 				}
188 
189 				if (!strcmp(p4, "r"))
190 				{
191 					routerip.s_addr=getip(p5);
192 					if(routerip.s_addr)
193 						ciscop->ip.s_addr=routerip.s_addr;	/* save router ip */
194 					continue;
195 				}
196 				if(!strcmp(p4, "u"))
197 				{
198 					safecopy(ciscop->username,p5);			/* save username */
199 					continue;
200 				}
201 				if(!strcmp(p4, "p"))
202 				{
203 					safecopy(ciscop->telnetpw,p5);			/* save telnet password */
204 					continue;
205 				}
206 				if(!strcmp(p4, "e"))
207 				{
208 					safecopy(ciscop->enablepw,p5);			/* save enable password */
209 					continue;
210 				}
211 				if(!strcmp(p4, "t"))
212 				{
213 					safecopy(ciscop->routetag,p5);			/* save route tag */
214 					continue;
215 				}
216 				if(!strcmp(p4, "a"))
217 				{
218 					if(!strcasecmp(p5, "y"))
219 						ciscop->autoenable=TRUE;		/* set autoenable */
220 					continue;
221 				}
222 
223 				snprintf(msg,sizeof(msg)-1,"Error: [%s: %lu] Skipping unknown option '%s' (%s)",file,line,p4,p5);
224 				logmessage(1,msg,"cisconullroute2",0);
225 			}
226 		}
227 
228 		if(!ciscop->ip.s_addr)
229 		{
230 			snprintf(msg,sizeof(msg)-1,"Error: [%s: %lu] No router specified, CiscoNullRoute2 Plugin disabled",file,line);
231 			logmessage(1,msg,"cisconullroute2",0);
232 			free(ciscop);
233 			plugindatalist->data=NULL;
234 			return;
235 		}
236 
237 		if(ciscop->username[0])
238 			ciscop->userlogin=TRUE;
239 
240 		if(!ciscop->telnetpw[0])
241 		{
242 			snprintf(msg,sizeof(msg)-1,"Error: [%s: %lu] No password specified, CiscoNullRoute2 Plugin disabled",file,line);
243 			logmessage(1,msg,"cisconullroute2",0);
244 			free(ciscop);
245 			plugindatalist->data=NULL;
246 			return;
247 		}
248 
249 		if(ciscop->routetag[0] && !((strtoul(ciscop->routetag,NULL,10))>=(unsigned long)RTAGVAL_MIN && (strtoul(ciscop->routetag,NULL,10))<=(unsigned long)RTAGVAL_MAX))
250 		{
251 			snprintf(msg,sizeof(msg)-1,"Error: [%s: %lu] Invalid CiscoNullRoute2 route tag value '%s' (min: %lu, max: %lu), CiscoNullRoute2 Plugin disabled",
252 				file,line,ciscop->routetag,(unsigned long)RTAGVAL_MIN,(unsigned long)RTAGVAL_MAX);
253 			logmessage(1,msg,"cisconullroute2",0);
254 			free(ciscop);
255 			plugindatalist->data=NULL;
256 			return;
257 		}
258 
259 		if(!ciscop->enablepw[0])
260 			safecopy(ciscop->enablepw,ciscop->telnetpw);	/* If no enable password specified, make it the same as telnet password */
261 
262 #ifdef FWSAMDEBUG
263 		printf("Debug: [cisconullroute2] Adding Cisco Router: IP \"%s\", USER \"%s\", PW \"%s\", EN \"%s\", TAG \"%s\", AUTO-ENABLE \"%s\"\n",
264 			inettoa(ciscop->ip.s_addr),ciscop->userlogin?ciscop->username:"(none)",ciscop->telnetpw,ciscop->enablepw,ciscop->routetag[0]?ciscop->routetag:"(none)",ciscop->autoenable?"y":"n");
265 #endif
266 	}
267 	else
268 	{
269 		snprintf(msg,sizeof(msg)-1,"Error: [%s: %lu] Empty CiscoNullRoute2 parameter.",file,line);
270 		logmessage(1,msg,"cisconullroute2",0);
271 	}
272 }
273 
274 
275 /* This routine initiates the block. It walks the list of routers
276  * telnet's in, and issues the route command.
277  */
CiscoNullRoute2Block(BLOCKINFO * bd,void * data,unsigned long qp)278 void CiscoNullRoute2Block(BLOCKINFO *bd,void *data,unsigned long qp)
279 {
280 	CISCONULLROUTE2DATA *ciscop;
281 	struct sockaddr_in thissocketaddr,routersocketaddr;
282 	unsigned long flag;
283 	char cnrmsg[STRBUFSIZE+1],cnrat[STRBUFSIZE+1];
284 #ifdef FWSAMDEBUG
285 #ifdef WIN32
286 	unsigned long threadid=GetCurrentThreadId();
287 #else
288 	pthread_t threadid=pthread_self();
289 #endif
290 #endif
291 
292 	if(!data)
293 		return;
294     ciscop=(CISCONULLROUTE2DATA *)data;
295 
296 #ifdef FWSAMDEBUG
297 	printf("Debug: [cisconullroute2][%lx] Plugin Blocking...\n",(unsigned long)threadid);
298 #endif
299 
300 	snprintf(cnrat,sizeof(cnrat)-1,"router at %s",inettoa(ciscop->ip.s_addr));
301 
302 	if(!ciscop->routersocket)
303 	{
304 		routersocketaddr.sin_port=htons(23); /* telnet */
305 		routersocketaddr.sin_addr.s_addr=ciscop->ip.s_addr;
306 		routersocketaddr.sin_family=AF_INET;
307 
308 		thissocketaddr.sin_port=htons(0); /* get a dynamic port  */
309 		thissocketaddr.sin_addr.s_addr=0;
310 		thissocketaddr.sin_family=AF_INET;
311 
312 		/* create socket */
313 		ciscop->routersocket=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
314 		if(ciscop->routersocket==INVALID_SOCKET)
315 		{
316 			snprintf(cnrmsg,sizeof(cnrmsg)-1,"Error: [cisconullroute2] Couldn't create socket!");
317 			logmessage(1,cnrmsg,"cisconullroute2",ciscop->ip.s_addr);
318 			ciscop->routersocket=0;
319 			return;
320 		}
321 		/* bind it */
322 		if(bind(ciscop->routersocket,(struct sockaddr *)&(thissocketaddr),sizeof(struct sockaddr)))
323 		{
324 			snprintf(cnrmsg,sizeof(cnrmsg)-1,"Error: [cisconullroute2] Couldn't bind socket!");
325 			logmessage(1,cnrmsg,"ciscocnullroute",ciscop->ip.s_addr);
326 			ciscop->routersocket=0;
327 			return;
328 		}
329 		/* and connect to router */
330 		if(connect(ciscop->routersocket,(struct sockaddr *)&routersocketaddr,sizeof(struct sockaddr)))
331 		{
332 			snprintf(cnrmsg,sizeof(cnrmsg)-1,"Error: [cisconullroute2] Could not connect to %s! Will try later.",cnrat);
333 			logmessage(1,cnrmsg,"cisconullroute2",ciscop->ip.s_addr);
334 			closesocket(ciscop->routersocket);
335 			ciscop->routersocket=0;
336 		}
337 	}
338 	if(ciscop->routersocket)
339 	{
340 		do
341 		{
342 #ifdef FWSAMDEBUG
343 			printf("Debug: [cisconullroute2][%lx] Connected to %s.\n",(unsigned long)threadid,cnrat);
344 #endif
345 			flag=-1;
346 			ioctlsocket(ciscop->routersocket,FIONBIO,&flag);	/* set non blocking  */
347 			flag=FALSE;
348 
349 			if(!ciscop->loggedin)
350 			{
351 				if(ciscop->userlogin)
352 				{
353 					if(!sendreceive(ciscop->routersocket,CNRNETWAIT,"cisconullroute2",ciscop->ip,"","username","waiting for user logon prompt from ",cnrat))
354 					{
355 						flag=TRUE;
356 						continue;
357 					}
358 					snprintf(cnrmsg,sizeof(cnrmsg)-1,"%s\r",ciscop->username);	/* Send username */
359 
360 					if(!sendreceive(ciscop->routersocket,CNRNETWAIT,"cisconullroute2",ciscop->ip,cnrmsg,"pass","at password prompt from ",cnrat))
361 					{
362 						flag=TRUE;
363 						continue;
364 					}
365 				}
366 				else
367 				{
368 					if(!sendreceive(ciscop->routersocket,CNRNETWAIT,"cisconullroute2",ciscop->ip,"","pass","waiting for logon prompt from ",cnrat))
369 					{
370 						flag=TRUE;
371 						continue;
372 					}
373 				}
374 
375 				snprintf(cnrmsg,sizeof(cnrmsg)-1,"%s\r",ciscop->telnetpw);	/* Send telnet password */
376 
377 				if(ciscop->autoenable)
378 				{
379 					if(!sendreceive(ciscop->routersocket,CNRNETWAIT,"cisconullroute2",ciscop->ip,cnrmsg,"#","at enable prompt of ",cnrat))
380 					{
381 						flag=TRUE;
382 						continue;
383 					}
384 				}
385 				else
386 				{
387 					if(!sendreceive(ciscop->routersocket,CNRNETWAIT,"cisconullroute2",ciscop->ip,cnrmsg,">","at logon prompt of ",cnrat))
388 					{
389 						flag=TRUE;
390 						continue;
391 					}
392 
393 					/* Send enable */
394 					if(!sendreceive(ciscop->routersocket,CNRNETWAIT,"cisconullroute2",ciscop->ip,"enable\r","pass","at enable command of ",cnrat))
395 					{
396 						flag=TRUE;
397 						continue;
398 					}
399 
400 					/* Send enable password */
401 					snprintf(cnrmsg,sizeof(cnrmsg)-1,"%s\r",ciscop->enablepw);
402 					if(!sendreceive(ciscop->routersocket,CNRNETWAIT,"cisconullroute2",ciscop->ip,cnrmsg,"#","at enable prompt of ",cnrat))
403 					{
404 						flag=TRUE;
405 						continue;
406 					}
407 				}
408 
409 				/* Send config */
410 				if(!sendreceive(ciscop->routersocket,CNRNETWAIT,"cisconullroute2",ciscop->ip,"config t\r","#","at config command of ",cnrat))
411 				{
412 					flag=TRUE;
413 					continue;
414 				}
415 				ciscop->loggedin=TRUE;
416 			}
417 
418 			/* send route command */
419 			snprintf(cnrmsg,sizeof(cnrmsg)-1,"%sip route %s 255.255.255.255 null 0%s%s\r",
420 				bd->block?"":"no ",inettoa(bd->blockip),ciscop->routetag[0]?" tag ":"",ciscop->routetag[0]?ciscop->routetag:"");
421 			if(!sendreceive(ciscop->routersocket,CNRNETWAIT,"cisconullroute2",ciscop->ip,cnrmsg,"#","at route command of ",cnrat))
422 			{
423 				flag=TRUE;
424 				continue;
425 			}
426 
427 			if(!moreinqueue(qp))
428 			{
429 				/* End input */
430 				if(!sendreceive(ciscop->routersocket,CNRNETWAIT,"cisconullroute2",ciscop->ip,"\032","#","at CTRL-Z of ",cnrat))
431 				{
432 					flag=TRUE;
433 					continue;
434 				}
435 
436 				/* Save config */
437 				if(!sendreceive(ciscop->routersocket,CNRNETWAIT,"cisconullroute2",ciscop->ip,"write mem\r","#","at write mem command of ",cnrat))
438 				{
439 					flag=TRUE;
440 					continue;
441 				}
442 
443 				/* and we're outta here... */
444 				sendreceive(ciscop->routersocket,CNRNETWAIT,"cisconullroute2",ciscop->ip,"quit\r","","at quit command of ",cnrat);
445 				flag=TRUE;
446 			}
447 		}while(FALSE);
448 
449 		if(flag)
450 		{
451 			closesocket(ciscop->routersocket);
452 			ciscop->routersocket=0;
453 			ciscop->loggedin=FALSE;
454 		}
455 	}
456 }
457 
458 #endif /* __SSP_CISCO_NULLROUTE2_C__ */
459 
460 
461 
462 
463 
464 
465