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

sp_respond.c

Go to the documentation of this file.
00001 /* $Id$ */
00002 /*
00003 ** Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
00004 ** Copyright (C) 1999,2000,2001 Christian Lademann <cal@zls.de>
00005 **
00006 ** This program is free software; you can redistribute it and/or modify
00007 ** it under the terms of the GNU General Public License as published by
00008 ** the Free Software Foundation; either version 2 of the License, or
00009 ** (at your option) any later version.
00010 **
00011 ** This program is distributed in the hope that it will be useful,
00012 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 ** GNU General Public License for more details.
00015 **
00016 ** You should have received a copy of the GNU General Public License
00017 ** along with this program; if not, write to the Free Software
00018 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00019 */
00020 
00021 /* $Id$ */
00022 
00023 /*
00024  * CREDITS:
00025  *
00026  * The functionality presented here was inspired by
00027  * the program "couic" by Michel Arboi <arboi@bigfoot.com>
00028  *
00029 */
00030 
00031 #ifdef HAVE_CONFIG_H
00032 #include "config.h"
00033 #endif
00034 
00035 
00036 #ifdef ENABLE_RESPONSE
00037 #include <libnet.h>
00038 
00039 #include "decode.h"
00040 #include "rules.h"
00041 #include "plugbase.h"
00042 #include "parser.h"
00043 #include "debug.h"
00044 #include "util.h"
00045 #include "log.h"
00046 #include "plugin_enum.h"
00047 #include "snort.h"
00048 
00049 typedef struct _RespondData
00050 {
00051     u_int response_flag;
00052 } RespondData;
00053 
00054 void RespondInit(char *, OptTreeNode *, int ); 
00055 void RespondRestartFunction(int, void *);
00056 int ParseResponse(char *);
00057 int SendICMP_UNREACH(int, u_long, u_long, Packet *);
00058 int SendTCPRST(u_long, u_long, u_short, u_short, u_long, u_long);
00059 int Respond(Packet *, RspFpList *);
00060 
00061 
00062 
00063 
00064 int nd; /* raw socket descriptor */
00065 u_int8_t ttl;   /* placeholder for randomly generated TTL */
00066 
00067 char *tcp_pkt;
00068 char *icmp_pkt;
00069 
00070 void PrecacheTcp(void);
00071 void PrecacheIcmp(void);
00072 
00073 /**************************************************************************
00074  *
00075  * Function: SetupRespond();
00076  *
00077  * Purpose: Initialize repsond plugin
00078  *
00079  * Arguments: None.
00080  *
00081  * Returns: void
00082  **************************************************************************/
00083 
00084 void SetupRespond(void)
00085 {
00086     RegisterPlugin("resp", RespondInit);
00087     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"Plugin: Respond Setup\n"););
00088     nd = -1;
00089 }
00090 
00091 void RespondRestartFunction(int signal, void *foo)
00092 {
00093     if (nd != -1)
00094     {
00095         libnet_close_raw_sock(nd);
00096         nd = -1;
00097     }
00098     if (tcp_pkt != NULL)
00099         libnet_destroy_packet((u_char **)&tcp_pkt);
00100     if (icmp_pkt != NULL)
00101         libnet_destroy_packet((u_char **)&icmp_pkt);
00102 
00103     return;
00104 }
00105 
00106 void RespondInit(char *data, OptTreeNode *otn, int protocol) 
00107 {
00108     RespondData *rd;
00109 
00110     if(protocol != IPPROTO_TCP && protocol != IPPROTO_UDP &&
00111        protocol != IPPROTO_ICMP)
00112     {
00113         FatalError("%s(%d): Can't respond to IP protocol rules\n", 
00114                    file_name, file_line);
00115     }
00116     if(nd == -1) /* need to open it only once */
00117     {
00118         if((nd = libnet_open_raw_sock(IPPROTO_RAW)) < 0)
00119         {
00120             FatalError("cannot open raw socket for libnet, exiting...\n");
00121         }
00122     }
00123 
00124     ttl = (u_int8_t)libnet_get_prand(PR8);
00125 
00126     if(ttl < 64)
00127     {
00128         ttl += 64;
00129     } 
00130 
00131     if(( rd = (RespondData *)calloc(sizeof(RespondData), sizeof(char))) == NULL)
00132     {
00133         FatalError("sp_respnd RespondInit() calloc failed!\n");
00134     }
00135     
00136     rd->response_flag = ParseResponse(data);
00137     
00138     AddRspFuncToList(Respond, otn, (void *)rd );
00139     AddFuncToRestartList(RespondRestartFunction, NULL);
00140 
00141     return;
00142 }
00143 
00144 /****************************************************************************
00145  *
00146  * Function: ParseResponse(char *)
00147  *
00148  * Purpose: Figure out how to handle hostile connection attempts
00149  *
00150  * Arguments: type => string of comma-sepatared modifiers
00151  *
00152  * Returns: void function
00153  *
00154  ***************************************************************************/
00155 int ParseResponse(char *type)
00156 {
00157     char *p;
00158     int response_flag;
00159     int make_tcp = 0;
00160     int make_icmp = 0;
00161 
00162     while(isspace((int) *type))
00163         type++;
00164 
00165     if(!type || !(*type))
00166         return 0;
00167 
00168     response_flag = 0;
00169 
00170     p = strtok(type, ",");
00171     while(p)
00172     {
00173         if(!strncasecmp(p, "rst_snd", 7))
00174         {
00175             response_flag |= RESP_RST_SND;
00176             make_tcp = 1;
00177         }
00178         else if(!strncasecmp(p, "rst_rcv", 7))
00179         {
00180             response_flag |= RESP_RST_RCV;
00181             make_tcp = 1;
00182         }
00183         else if(!strncasecmp(p, "rst_all", 7))
00184         {
00185             response_flag |= (RESP_RST_SND | RESP_RST_RCV);
00186             make_tcp = 1;
00187         }
00188         else if(!strncasecmp(p, "icmp_net", 8))
00189         {
00190             response_flag |= RESP_BAD_NET;
00191             make_icmp = 1;
00192         }
00193         else if(!strncasecmp(p, "icmp_host", 9))
00194         {
00195             response_flag |= RESP_BAD_HOST;
00196             make_icmp = 1;
00197         }
00198         else if(!strncasecmp(p, "icmp_port", 9))
00199         {
00200             response_flag |= RESP_BAD_PORT;
00201             make_icmp = 1;
00202         }
00203         else if(!strncasecmp(p, "icmp_all", 9))
00204         {
00205             response_flag |= (RESP_BAD_NET | RESP_BAD_HOST | RESP_BAD_PORT);
00206             make_icmp = 1;
00207         }
00208         else
00209         {
00210             FatalError("%s(%d): invalid response modifier: %s\n", file_name, 
00211                     file_line, p);
00212         }
00213 
00214         p = strtok(NULL, ",");
00215     }
00216 
00217     if(make_tcp)
00218     {
00219         PrecacheTcp();
00220     }
00221 
00222     if(make_icmp)
00223     {
00224         /* someday came sooner than expected. -Jeff */
00225         PrecacheIcmp();
00226     }
00227 
00228     return response_flag;
00229 }
00230 
00231 
00232 void PrecacheTcp(void)
00233 {
00234     int sz = IP_H + TCP_H;
00235 
00236     if((tcp_pkt = calloc(sz, sizeof(char))) == NULL)
00237     {
00238         FatalError("PrecacheTCP() calloc failed!\n");
00239     }
00240 
00241     libnet_build_ip( TCP_H                             /* Length of packet data */
00242                    , 0                                 /* IP tos */
00243                    , (u_short) libnet_get_prand(PRu16) /* IP ID */
00244                    , 0                                 /* Fragmentation flags and offset */
00245                    , ttl                               /* TTL */
00246                    , IPPROTO_TCP                       /* Protocol */
00247                    , 0                                 /* Source IP Address */
00248                    , 0                                 /* Destination IP Address */
00249                    , NULL                              /* Pointer to packet data (or NULL) */
00250                    , 0                                 /* Packet payload size */
00251                    , tcp_pkt                           /* Pointer to packet header memory */
00252                    );
00253 
00254     libnet_build_tcp( 0              /* Source port */
00255                     , 0              /* Destination port */
00256                     , 0              /* Sequence Number */
00257                     , 0              /* Acknowledgement Number */
00258                     , TH_RST|TH_ACK  /* Control bits */
00259                     , 0              /* Advertised Window Size */
00260                     , 0              /* Urgent Pointer */
00261                     , NULL           /* Pointer to packet data (or NULL) */
00262                     , 0              /* Packet payload size */
00263                     , tcp_pkt + IP_H /* Pointer to packet header memory */
00264                     );
00265 
00266     return;
00267 }
00268 
00269 void PrecacheIcmp(void)
00270 {
00271     int sz = IP_H + ICMP_UNREACH_H + 68;    /* plan for IP options */
00272 
00273     if((icmp_pkt = calloc(sz, sizeof(char))) == NULL)
00274     {
00275         FatalError("PrecacheIcmp() calloc failed!\n");
00276     }
00277 
00278     libnet_build_ip( ICMP_UNREACH_H                    /* Length of packet data */
00279                    , 0                                 /* IP tos */
00280                    , (u_short) libnet_get_prand(PRu16) /* IP ID */
00281                    , 0                                 /* Fragmentation flags and offset */
00282                    , ttl                               /* TTL */
00283                    , IPPROTO_ICMP                      /* Protocol */
00284                    , 0                                 /* Source IP Address */
00285                    , 0                                 /* Destination IP Address */
00286                    , NULL                              /* Pointer to packet data (or NULL) */
00287                    , 0                                 /* Packet payload size */
00288                    , icmp_pkt                          /* Pointer to packet header memory */
00289                    );
00290 
00291     libnet_build_icmp_unreach( 3                /* icmp type */
00292                              , 0                /* icmp code */
00293                              , 0                /* Original Length of packet data */
00294                              , 0                /* Original IP tos */
00295                              , 0                /* Original IP ID */
00296                              , 0                /* Original Fragmentation flags and offset */
00297                              , 0                /* Original TTL */
00298                              , 0                /* Original Protocol */
00299                              , 0                /* Original Source IP Address */
00300                              , 0                /* Original Destination IP Address */
00301                              , NULL             /* Pointer to original packet data (or NULL) */
00302                              , 0                /* Packet payload size (or 0) */
00303                              , icmp_pkt + IP_H  /* Pointer to packet header memory */
00304                              );
00305 
00306     return;
00307 }
00308 
00309 
00310 /****************************************************************************
00311 
00312  *
00313  * Function: Respond(Packet *p, RspFpList)
00314  *
00315  * Purpose: Respond to hostile connection attempts
00316  *
00317  * Arguments:
00318  *
00319  * Returns: void function
00320  *
00321  ***************************************************************************/
00322 
00323 int Respond(Packet *p, RspFpList *fp_list)
00324 {
00325     RespondData *rd = (RespondData *)fp_list->params;
00326 
00327     if(!p->iph)
00328     {
00329         return 0;
00330     }
00331     
00332     if(rd->response_flag)
00333     {
00334         if(rd->response_flag & (RESP_RST_SND | RESP_RST_RCV))
00335         {
00336             if(p->iph->ip_proto == IPPROTO_TCP && p->tcph != NULL)
00337             {
00338                 /*
00339                 **  This ensures that we don't reset packets that we just
00340                 **  spoofed ourselves, thus inflicting a self-induced DOS
00341                 **  attack.
00342                 **
00343                 **  We still reset packets that may have the SYN set, though.
00344                 */
00345                 if((p->tcph->th_flags & (TH_SYN | TH_RST)) != TH_RST)
00346                 {
00347                     if(rd->response_flag & RESP_RST_SND)
00348                     {
00349                         SendTCPRST(p->iph->ip_dst.s_addr, 
00350                                    p->iph->ip_src.s_addr,
00351                                    p->tcph->th_dport, p->tcph->th_sport,
00352                                    p->tcph->th_ack, 
00353                                    htonl(ntohl(p->tcph->th_seq) + p->dsize));
00354                     }
00355 
00356                     if(rd->response_flag & RESP_RST_RCV)
00357                     {
00358                         SendTCPRST(p->iph->ip_src.s_addr, 
00359                                    p->iph->ip_dst.s_addr,
00360                                    p->tcph->th_sport, p->tcph->th_dport, 
00361                                    p->tcph->th_seq, 
00362                                    htonl(ntohl(p->tcph->th_ack) + p->dsize));
00363                     }
00364                 }
00365             }
00366         }
00367 
00368         /*
00369         **  We check that we only reset packets with an ICMP packet if it is
00370         **  valid.  This means that we don't reset ICMP error types and will
00371         **  only reset ICMP query request.
00372         */
00373         if((p->icmph == NULL) || 
00374            (p->icmph->type == ICMP_ECHO) ||
00375            (p->icmph->type == ICMP_TIMESTAMP) || 
00376            (p->icmph->type == ICMP_INFO_REQUEST) ||
00377            (p->icmph->type == ICMP_ADDRESS))
00378         {
00379             if(rd->response_flag & RESP_BAD_NET)
00380                 SendICMP_UNREACH(ICMP_UNREACH_NET, p->iph->ip_dst.s_addr,
00381                                  p->iph->ip_src.s_addr, p);
00382 
00383             if(rd->response_flag & RESP_BAD_HOST)
00384                 SendICMP_UNREACH(ICMP_UNREACH_HOST, p->iph->ip_dst.s_addr,
00385                                  p->iph->ip_src.s_addr, p);
00386 
00387             if(rd->response_flag & RESP_BAD_PORT)
00388                 SendICMP_UNREACH(ICMP_UNREACH_PORT, p->iph->ip_dst.s_addr,
00389                                  p->iph->ip_src.s_addr, p);
00390         }
00391     }
00392     return 1; /* always success */
00393 }
00394 
00395 
00396 int SendICMP_UNREACH(int code, u_long saddr, u_long daddr, Packet * p)
00397 {
00398     int payload_len, sz;
00399     IPHdr *iph;
00400     ICMPHdr *icmph;
00401 
00402     if(p == NULL)
00403         return -1;
00404 
00405     /* don't send ICMP port unreachable errors in response to ICMP messages */
00406     if (p->iph->ip_proto == 1 && code == ICMP_UNREACH_PORT)
00407     {
00408         if (pv.verbose_flag)
00409         {
00410             ErrorMessage("ignoring icmp_port set on ICMP packet.\n");
00411         }
00412         
00413         return 0;
00414     }
00415 
00416     iph = (IPHdr *) icmp_pkt;
00417     icmph = (ICMPHdr *) (icmp_pkt + IP_H);
00418 
00419     iph->ip_src.s_addr = saddr;
00420     iph->ip_dst.s_addr = daddr;
00421 
00422     icmph->code = code;
00423 
00424     if ((payload_len = ntohs(p->iph->ip_len) - (IP_HLEN(p->iph) << 2)) > 8)
00425         payload_len = 8;
00426 
00427     memcpy((char *)icmph + ICMP_UNREACH_H, p->iph, (IP_HLEN(p->iph) << 2)
00428             + payload_len);
00429 
00430     sz = IP_H + ICMP_UNREACH_H + (IP_HLEN(p->iph) << 2) + payload_len;
00431     iph->ip_len = htons( (u_short) sz);
00432 
00433     libnet_do_checksum(icmp_pkt, IPPROTO_ICMP, sz - IP_H);
00434 
00435 #ifdef DEBUG
00436     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "firing ICMP response packet\n"););
00437     PrintNetData(stdout, icmp_pkt, sz);
00438     ClearDumpBuf();
00439 #endif
00440     if(libnet_write_ip(nd, icmp_pkt, sz) < sz)
00441     {
00442         libnet_error(LIBNET_ERR_CRITICAL, "SendICMP_UNREACH: libnet_write_ip");
00443         return -1;
00444     }
00445     return 0;
00446 }
00447 
00448 
00449 int SendTCPRST(u_long saddr, u_long daddr, u_short sport, u_short dport, 
00450         u_long seq, u_long ack)
00451 {
00452     int sz = IP_H + TCP_H;
00453     IPHdr *iph;
00454     TCPHdr *tcph;
00455 
00456     iph = (IPHdr *) tcp_pkt;
00457     tcph = (TCPHdr *) (tcp_pkt + IP_H);
00458 
00459     iph->ip_src.s_addr = saddr;
00460     iph->ip_dst.s_addr = daddr;
00461 
00462     tcph->th_sport = sport;
00463     tcph->th_dport = dport;
00464     tcph->th_seq = seq;
00465     tcph->th_ack = ack;
00466 
00467     libnet_do_checksum(tcp_pkt, IPPROTO_TCP, sz - IP_H);
00468     
00469     DEBUG_WRAP(
00470                PrintNetData(stdout, tcp_pkt, sz);
00471                ClearDumpBuf();
00472                DebugMessage(DEBUG_PLUGIN, "firing response packet\n");
00473                DebugMessage(DEBUG_PLUGIN,
00474                    "0x%lX:%u -> 0x%lX:%d (seq: 0x%lX  ack: 0x%lX)\n",
00475                                 saddr, sport, daddr, dport, seq, ack););
00476     
00477     if(libnet_write_ip(nd, tcp_pkt, sz) < sz)
00478     {
00479         libnet_error(LIBNET_ERR_CRITICAL, "SendTCPRST: libnet_write_ip");
00480         return -1;
00481     }
00482 
00483     return 0;
00484 }
00485 
00486 #endif

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