Main Page | Modules | Class List | Directories | File List | Class Members | File Members | Related Pages

sp_react.c

Go to the documentation of this file.
00001 /* $Id$ */
00002 
00003 /*
00004 ** Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
00005 ** Copyright (C) 2000,2001 Maciej Szarpak
00006 **
00007 ** This program is free software; you can redistribute it and/or modify
00008 ** it under the terms of the GNU General Public License as published by
00009 ** the Free Software Foundation; either version 2 of the License, or
00010 ** (at your option) any later version.
00011 **
00012 ** This program is distributed in the hope that it will be useful,
00013 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 ** GNU General Public License for more details.
00016 **
00017 ** You should have received a copy of the GNU General Public License
00018 ** along with this program; if not, write to the Free Software
00019 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00020 */
00021 
00022 /* Snort React Plugin by Maciej Szarpak, Warsaw University of Technology */
00023 
00024 /* sp_react.c 
00025  * 
00026  * Purpose:
00027  *
00028  * React! Deny the access to some unsuitable web-sites (like porn sites) or
00029  * close the offending connections.
00030  *
00031  * Arguments:
00032  *   
00033  * This plugin can take two basic arguments:
00034  *    block => closes the connection and sends a suitable HTML page to the
00035  *             browser (if got tcp 80 port packet)
00036  *    warn  => sends a HTML/JavaScript warning to the browser
00037  *
00038  * The following additional arguments are valid for this option:
00039  *    msg             => puts the msg option comment into the HTML page
00040  *    proxy <port_nr> => sends the respond code to the proxy port_nr
00041  *
00042  * Effect:
00043  *
00044  * Closes the connections by sending TCP RST packets (similar to resp option).
00045  * If the connection uses http or proxy server ports a visible information
00046  * to a browser user is send (HTML code).
00047  *
00048  */
00049 
00050 #ifdef HAVE_CONFIG_H
00051 #include "config.h"
00052 #endif
00053 
00054 #ifdef ENABLE_RESPONSE
00055 
00056 #include <sys/types.h>
00057 #include <stdlib.h>
00058 #include <string.h>
00059 #include <ctype.h>
00060 #include <libnet.h>
00061 
00062 #include "rules.h"
00063 #include "decode.h"
00064 #include "plugbase.h"
00065 #include "parser.h"
00066 #include "debug.h"
00067 #include "util.h"
00068 #include "plugin_enum.h"
00069 
00070 #define TCP_DATA_BUF    1024
00071 
00072 #define REACT_BLOCK 0x01
00073 #define REACT_WARN  0x02
00074 
00075 typedef struct _ReactData
00076 {
00077     int reaction_flag;  /* flexible reaction on alert */
00078     int proxy_port_nr;      /* proxy TCP port */
00079     u_int html_resp_size;       /* size of app html response */
00080     u_char *html_resp_buf;      /* html response to send */
00081 
00082 } ReactData;
00083 
00084 void ReactInit(char *, OptTreeNode *, int);
00085 void ParseReact(char *, OptTreeNode *, ReactData *);
00086 int React(Packet *, RspFpList *);
00087 int SendTCP(u_long, u_long, u_short, u_short, int, int, u_char, const u_char *,
00088                     int);
00089 
00090 
00091 
00092 extern int nd; /* raw socket */
00093 
00094 
00095 /****************************************************************************
00096  * 
00097  * Function: SetupReact()
00098  *
00099  * Purpose: Flexible response plugin. Registers the configuration function 
00100  *          and links it to a rule keyword.
00101  *
00102  * Arguments: None.
00103  *
00104  * Returns: void function
00105  *
00106  ****************************************************************************/
00107 void SetupReact(void)
00108 {
00109 
00110 /* we need an empty plug otherwise. To avoid #ifdef in plugbase */
00111 
00112     RegisterPlugin("react", ReactInit);
00113     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Plugin: React Initialized!\n"););
00114 }
00115 
00116 
00117 /****************************************************************************
00118  * 
00119  * Function: ReactInit(char *, OptTreeNode *, int protocol)
00120  *
00121  * Purpose: React rule configuration function.  Handles parsing the rule 
00122  *          information and attaching the associated structures to the OTN.
00123  *
00124  * Arguments: data => rule arguments/data
00125  *            otn => pointer to the current rule option list node
00126  *            protocol => current rule protocol
00127  *
00128  * Returns: void function
00129  *
00130  ****************************************************************************/
00131 void ReactInit(char *data, OptTreeNode *otn, int protocol)
00132 {
00133     ReactData *idx;
00134 
00135     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"In ReactInit()\n"););
00136 
00137     if(protocol != IPPROTO_TCP)
00138     {
00139         FatalError("Line %s(%d): TCP Options on non-TCP rule\n", file_name, file_line);
00140     }
00141 
00142     /* need to check raw sock here too if it's not been opened already */
00143     if(nd == -1) /* need to open it only once */
00144     {
00145         if((nd = libnet_open_raw_sock(IPPROTO_RAW)) < 0)
00146         {
00147             FatalError("cannot open raw socket for libnet, exiting...\n");
00148         }
00149     }
00150 
00151     if((idx = (ReactData *) calloc(sizeof(ReactData), sizeof(char))) == NULL)
00152     {
00153         FatalError("sp_react ReactInit() calloc failed!\n");
00154     }
00155 
00156     /* parse the react keywords */
00157     ParseReact(data, otn, idx);
00158 
00159     /* finally, attach the option's detection function to the rule's 
00160        detect function pointer list */
00161     AddRspFuncToList(React, otn, (void *)idx);
00162 
00163     return;
00164 }
00165 
00166 
00167 
00168 /****************************************************************************
00169  * 
00170  * Function: ParseReact(char *, OptTreeNode *)
00171  *
00172  * Purpose: React rule configuration function. Handles parsing the rule 
00173  *          information.
00174  *
00175  * Arguments: data => rule arguments/data
00176  *            otn => pointer to the current rule option list node
00177  *
00178  * Returns: void function
00179  *
00180  ****************************************************************************/
00181 void ParseReact(char *data, OptTreeNode *otn, ReactData *rd)
00182 {
00183     ReactData *idx;
00184     char *tok;      /* token buffer */
00185     u_int buf_size; 
00186 
00187     char tmp_buf1[] = "<HTML><HEAD><TITLE>Snort</TITLE></HEAD><BODY BGCOLOR=\"#FFFFFF\"><CENTER><BR><H1>Snort!</H1>Version ";
00188     char tmp_buf2[] = "<H1><BR><BR><FONT COLOR=\"#FF0000\">You are not authorized to open this site!</FONT><BR><BR></H1><H2>";
00189     char tmp_buf3[] = "<BR></H2><BR><A HREF=\"mailto:mszarpak@elka.pw.edu.pl\">Any questions?</A></CENTER></BODY></HTML>";    
00190     char tmp_buf4[]="<HTML><HEAD><SCRIPT LANGUAGE=\"JavaScript\"><!-- Hiding function pop() { alert(\"Snort, ver. ";
00191     char tmp_buf5[] = "\\n\\nThis page contents ...!\\n\\n";
00192     char tmp_buf6[] = "\"); } // --></SCRIPT></HEAD><BODY ONLOAD=\"pop()\"></BODY></HTML>";
00193 
00194     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "In ParseReact()\n"););
00195 
00196     idx = rd;
00197 
00198     /* set the standard proxy port */
00199     idx->proxy_port_nr = 8080;
00200 
00201     /* parse the react option keywords */
00202     while(isspace((int)*data)) data++;
00203 
00204     tok = strtok(data, ",");
00205     while(tok)
00206     {
00207         if(!strcasecmp(tok, "block"))
00208             idx->reaction_flag = REACT_BLOCK;
00209         else if(!strcasecmp(tok, "warn"))
00210 /*          idx->reaction_flag = REACT_WARN*/;
00211         else if(!strcasecmp(tok, "msg"))
00212             if(otn->sigInfo.message == NULL)
00213                 FatalError( "%s(%d) => msg option missed or react "
00214                             "keyword placed before msg!\n", file_name, file_line);
00215             else
00216                 idx->html_resp_size = 1;
00217         else if(!strcasecmp(tok, "proxy"))
00218         {
00219             if(strlen(tok) > strlen("proxy"))
00220             {
00221                 char *endp;
00222 
00223                 tok = tok + 5;
00224                 
00225                 while(isspace(*tok))
00226                     tok++;
00227 
00228                 idx->proxy_port_nr = strtoul(tok,&endp,10);
00229                 if(endp ==  tok)
00230                 {
00231                     FatalError("Can't parse the dang proxy option\n");
00232                 }
00233             }
00234             else
00235             {
00236                 FatalError("Can't parse the dang proxy option\n");
00237             }
00238 
00239             /* make sure it's in bounds */
00240             if((idx->proxy_port_nr < 0) || (idx->proxy_port_nr >= 65536))
00241             {
00242                 FatalError("%s(%d): bad proxy port number: %d\n", file_name, file_line, idx->proxy_port_nr);
00243             }
00244         }
00245         else
00246         {
00247             FatalError("%s(%d): invalid react modifier: %s\n", file_name, file_line, tok);
00248         }
00249         tok = strtok(NULL, ","); 
00250 
00251         /* get rid of spaces */
00252         if(tok != NULL)
00253             while(isspace((int)*tok)) tok++;
00254     }
00255 
00256     /* test the basic modifier */
00257     if(idx->reaction_flag == 0)
00258         FatalError("%s(%d): missing react basic modifier\n", file_name, file_line);
00259     else
00260     {
00261         /* prepare the html response data */
00262         buf_size = 0;
00263         if(idx->reaction_flag == REACT_BLOCK)
00264         {
00265             /* count the respond buf size (max TCP_DATA_BUF) */
00266             buf_size = strlen(tmp_buf1) + strlen(tmp_buf2) + strlen(tmp_buf3)
00267                        + strlen(VERSION);
00268 
00269             if(buf_size > TCP_DATA_BUF)
00270             {
00271                 FatalError("%s(%d): invalid html response buffer size: %d\n", file_name, file_line, buf_size);
00272             }
00273             else
00274             {
00275                 /* msg included */
00276                 if((idx->html_resp_size == 1) && (buf_size + 
00277                             strlen(otn->sigInfo.message) < TCP_DATA_BUF))
00278                 {
00279                     buf_size += strlen(otn->sigInfo.message);
00280                 }
00281 
00282                 /* create html response buffer */
00283                 if((idx->html_resp_buf=(char *)malloc(sizeof(char)*buf_size))==NULL)
00284                 {
00285                     FatalError("ParseReact() html_resp_buf malloc filed!\n");
00286                 }
00287                 bzero((char *)idx->html_resp_buf, buf_size);
00288                 tok = strcat(idx->html_resp_buf, tmp_buf1);
00289                 tok = strcat(idx->html_resp_buf, VERSION);
00290                 tok = strcat(idx->html_resp_buf, tmp_buf2);      
00291                 if(idx->html_resp_size == 1)
00292                 {
00293                     tok = strcat(idx->html_resp_buf, otn->sigInfo.message);     
00294                 }
00295                 tok = strcat(idx->html_resp_buf, tmp_buf3);      
00296             }
00297         }
00298         else if(idx->reaction_flag == REACT_WARN)
00299         {
00300             /* count the respond buf size (max TCP_DATA_BUF) */
00301             buf_size = strlen(tmp_buf4) + strlen(tmp_buf5) + strlen(tmp_buf6)
00302                        + strlen(VERSION);
00303 
00304             if(buf_size > TCP_DATA_BUF)
00305             {
00306                 FatalError("%s(%d): invalid html response buffer size: %d\n",
00307                            file_name, file_line, buf_size);
00308             }
00309             else
00310             {
00311                 /* msg included */
00312                 if((idx->html_resp_size == 1) && (buf_size + 
00313                             strlen(otn->sigInfo.message) < TCP_DATA_BUF))
00314                 {
00315                     buf_size += strlen(otn->sigInfo.message);
00316                 }
00317 
00318                 /* create html response buffer */
00319                 if((idx->html_resp_buf=(char *)malloc(sizeof(char)*buf_size))==NULL)
00320                 {
00321                     FatalError("ParseReact() html_resp_buf malloc filed!\n");
00322                 }
00323                 bzero((char *)idx->html_resp_buf, buf_size);
00324                 tok = strcat(idx->html_resp_buf, tmp_buf4);
00325                 tok = strcat(idx->html_resp_buf, VERSION);
00326                 tok = strcat(idx->html_resp_buf, tmp_buf5);      
00327                 if(idx->html_resp_size == 1)
00328                 {
00329                     tok = strcat(idx->html_resp_buf, otn->sigInfo.message);     
00330                 }
00331                 tok = strcat(idx->html_resp_buf, tmp_buf6);      
00332             }
00333         }
00334 
00335         /* set the html response buffer size */
00336         idx->html_resp_size = buf_size;
00337     }
00338 
00339     return;
00340 }
00341 
00342 
00343 
00344 /****************************************************************************
00345  *
00346  * Function: React(Packet *p, OptTreeNode *otn_tmp)
00347  *
00348  * Purpose: React to hostile connection attempts according to reaction_flag
00349  *
00350  * Arguments: p => pointer to the current packet
00351  *            otn => pointer to the current rule option list node
00352  *
00353  * Returns: Always calls the next function (this one doesn't test the data,
00354  *          it just closes the connection...)
00355  *
00356  ***************************************************************************/
00357 int React(Packet *p,  RspFpList *fp_list)
00358 {
00359     ReactData *idx;
00360     int i;
00361 
00362     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"In React()\n"););
00363 
00364     idx = (ReactData *)fp_list->params;
00365 
00366     if(idx == NULL)
00367     {
00368         DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"Nothing to do ... leaving"););
00369         return 1;
00370     }
00371 
00372     /* check the reaction flag */
00373     if(idx->reaction_flag == REACT_BLOCK)
00374     {
00375         /* send HTML page buffer to a rude browser user and close the connection */
00376         /* incoming */
00377         if((ntohs(p->tcph->th_sport)) == 80 || (ntohs(p->tcph->th_sport)) == idx->proxy_port_nr)
00378         {
00379             for(i = 0; i < 5; i++)
00380             {
00381                 SendTCP(p->iph->ip_src.s_addr, p->iph->ip_dst.s_addr,
00382                         p->tcph->th_sport, p->tcph->th_dport,
00383                         p->tcph->th_seq, htonl(ntohl(p->tcph->th_ack) + i),
00384                         TH_FIN, idx->html_resp_buf, idx->html_resp_size);
00385             }
00386             for(i = 0; i < 5; i++)
00387             {
00388                 SendTCP(p->iph->ip_dst.s_addr, p->iph->ip_src.s_addr,
00389                         p->tcph->th_dport, p->tcph->th_sport,
00390                         p->tcph->th_ack, htonl(ntohl(p->tcph->th_seq) + i),
00391                         TH_RST, idx->html_resp_buf, 0);
00392             }
00393         }
00394         /* outgoing */
00395         else if(ntohs(p->tcph->th_dport) == 80 || (ntohs(p->tcph->th_dport)) == idx->proxy_port_nr)
00396         {
00397             for(i = 0; i < 5; i++)
00398             {
00399                 SendTCP(p->iph->ip_dst.s_addr, p->iph->ip_src.s_addr,
00400                         p->tcph->th_dport, p->tcph->th_sport,
00401                         p->tcph->th_ack, htonl(ntohl(p->tcph->th_seq) + i),
00402                         TH_FIN, idx->html_resp_buf, idx->html_resp_size);
00403                 SendTCP(p->iph->ip_src.s_addr, p->iph->ip_dst.s_addr,
00404                         p->tcph->th_sport, p->tcph->th_dport,
00405                         p->tcph->th_seq, htonl(ntohl(p->tcph->th_ack) + i),
00406                         TH_RST, idx->html_resp_buf, 0);
00407             }
00408         }
00409         else
00410         /* reset the connection */
00411         {
00412             for(i = 0; i < 5; i++)
00413             {
00414                 SendTCP(p->iph->ip_dst.s_addr, p->iph->ip_src.s_addr,
00415                         p->tcph->th_dport, p->tcph->th_sport,
00416                         p->tcph->th_ack, htonl(ntohl(p->tcph->th_seq) + i),
00417                         TH_RST, idx->html_resp_buf, 0);
00418                 SendTCP(p->iph->ip_src.s_addr, p->iph->ip_dst.s_addr,
00419                         p->tcph->th_sport, p->tcph->th_dport,
00420                         p->tcph->th_seq, htonl(ntohl(p->tcph->th_ack) + i),
00421                         TH_RST, idx->html_resp_buf, 0);
00422             }
00423         }
00424     }
00425     else if(idx->reaction_flag == REACT_WARN)
00426     { 
00427         /* send HTML warning page buffer to a rude browser user */
00428         /* incoming */
00429         if((ntohs(p->tcph->th_sport)) == 80 || (ntohs(p->tcph->th_sport)) == idx->proxy_port_nr)
00430         {
00431             for(i = 0; i < 5; i++)
00432             {
00433                 SendTCP(p->iph->ip_src.s_addr, p->iph->ip_dst.s_addr,
00434                         p->tcph->th_sport, p->tcph->th_dport,
00435                         p->tcph->th_seq, p->tcph->th_ack + i,
00436                         TH_URG, idx->html_resp_buf, idx->html_resp_size);
00437             }
00438         }
00439         /* outgoing */
00440         else if(ntohs(p->tcph->th_dport) == 80 || (ntohs(p->tcph->th_dport)) == idx->proxy_port_nr)
00441         {
00442             for(i = 0; i < 5; i++)
00443             {
00444                 SendTCP(p->iph->ip_dst.s_addr, p->iph->ip_src.s_addr,
00445                         p->tcph->th_dport, p->tcph->th_sport,
00446                         p->tcph->th_ack, p->tcph->th_seq + i,
00447                         TH_URG, idx->html_resp_buf, idx->html_resp_size);
00448             }
00449         }
00450     }
00451     return 1;
00452 }    
00453 
00454 
00455 
00456 
00457 int SendTCP(u_long saddr, u_long daddr, u_short sport, u_short dport, int seq,
00458             int ack, u_char bits, const u_char *data_buf, int data_size)
00459 {
00460     u_char *buf;
00461     int sz = data_size + IP_H + TCP_H;
00462 
00463     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"In SendTCP()\n"););
00464 
00465     if((buf = malloc(sz)) == NULL)
00466     {
00467         perror("SendTCPRST: malloc");
00468         return -1;
00469     }
00470 
00471     memset(buf, 0, sz);
00472 
00473     libnet_build_ip( TCP_H                             /* Length of packet data */
00474                    , 0xF4                              /* IP tos */
00475                    , (u_short) libnet_get_prand(PRu16) /* IP ID */
00476                    , 0                                 /* Fragmentation flags and offset */
00477                    , 64                                /* TTL */
00478                    , IPPROTO_TCP                       /* Protocol */
00479                    , saddr                             /* Source IP Address */
00480                    , daddr                             /* Destination IP Address */
00481                    , NULL                              /* Pointer to packet data (or NULL) */
00482                    , 0                                 /* Packet payload size */
00483                    , buf                               /* Pointer to packet header memory */
00484                    );
00485 
00486     
00487     libnet_build_tcp( ntohs(sport)  /* Source port */
00488                     , ntohs(dport)  /* Destination port */
00489                     , ntohl(seq)    /* Sequence Number */
00490                     , ntohl(ack)    /* Acknowledgement Number */
00491                     , bits          /* Control bits */
00492                     , 1024          /* Advertised Window Size */
00493                     , 0             /* Urgent Pointer */
00494                     , data_buf      /* Pointer to packet data (or NULL) */
00495                     , data_size     /* Packet payload size */
00496                     , buf + IP_H    /* Pointer to packet header memory */
00497                     );
00498     
00499     libnet_do_checksum(buf, IPPROTO_TCP, sz - IP_H);
00500     
00501     if(libnet_write_ip(nd, buf, sz) < sz)
00502     {
00503         libnet_error(LIBNET_ERR_CRITICAL, "SendTCP: libnet_write_ip\n");
00504         return -1;
00505     }
00506 
00507     libnet_destroy_packet(&buf);
00508 
00509     return 0;
00510 
00511 }
00512 
00513 #endif

Generated on Sun May 14 14:51:13 2006 by  doxygen 1.4.2