?? spp_dns.c
字號:
/* $Id *//*** Copyright (C) 2006 Sourcefire Inc.****** This program is free software; you can redistribute it and/or modify** it under the terms of the GNU General Public License Version 2 as** published by the Free Software Foundation. You may not use, modify or** distribute this program under any other version of the GNU General** Public License.**** This program is distributed in the hope that it will be useful,** but WITHOUT ANY WARRANTY; without even the implied warranty of** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the** GNU General Public License for more details.**** You should have received a copy of the GNU General Public License** along with this program; if not, write to the Free Software** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*//* * DNS preprocessor * Author: Steven Sturges * * * Alert for DNS client rdata buffer overflow. * Alert for Obsolete or Experimental RData types (per RFC 1035) * */#ifdef HAVE_CONFIG_H#include "config.h"#endif /* HAVE_CONFIG_H */#include "sf_snort_packet.h"#include "sf_dynamic_preprocessor.h"#include "sf_snort_plugin_api.h"#include "preprocids.h"#include "debug.h"#include "spp_dns.h"#include <stdio.h>#include <syslog.h>#include <string.h>#ifndef WIN32#include <sys/time.h>#endif#include <stdlib.h>#include <ctype.h>#include "profiler.h"#ifdef PERF_PROFILINGPreprocStats dnsPerfStats;#endif/* * Generator id. Define here the same as the official registry * in generators.h */#define GENERATOR_SPP_DNS 131/* * Function prototype(s) */DNSSessionData* GetDNSSessionData( SFSnortPacket* );static void DNSInit( char* );static void PrintDNSConfig();static void FreeDNSSessionData( void* );static void ParseDNSArgs( u_char* );static void ProcessDNS( void*, void* );static void DNSConfigCheck( void );static inline int CheckDNSPort( u_int16_t );/* Ultimately calls SnortEventqAdd *//* Arguments are: gid, sid, rev, classification, priority, message, rule_info */#define DNS_ALERT(x,y) { _dpd.alertAdd(GENERATOR_SPP_DNS, x, 1, 0, 3, y, 0 ); }/* Convert port value into an index for the dns_config.ports array */#define PORT_INDEX(port) port/8/* Convert port value into a value for bitwise operations */#define CONV_PORT(port) 1<<(port%8)#define DNS_RR_PTR 0xC0/* * DNS preprocessor global configuration structure. */static DNSConfig dns_config ={#if 0 0, /* Autodetection */#endif DNS_ALERT_NONE, /* Enabled alerts */};extern DynamicPreprocessorData _dpd;/* Called at preprocessor setup time. Links preprocessor keyword * to corresponding preprocessor initialization function. * * PARAMETERS: None. * * RETURNS: Nothing. * */void SetupDNS(){ /* Link preprocessor keyword to initialization function * in the preprocessor list. */ _dpd.registerPreproc( "dns", DNSInit ); memset(dns_config.ports, 0, sizeof(char) * (MAX_PORTS/8));}/* Initializes the DNS preprocessor module and registers * it in the preprocessor list. * * PARAMETERS: * * argp: Pointer to argument string to process for config * data. * * RETURNS: Nothing. */static void DNSInit( char* argp ){#ifdef SUP_IP6 DynamicPreprocessorFatalMessage("DNS is not currently supported when IPv6 support is enabled.\n");#endif _dpd.addPreproc( ProcessDNS, PRIORITY_APPLICATION, PP_DNS ); _dpd.addPreprocConfCheck( DNSConfigCheck ); ParseDNSArgs( (u_char *)argp ); #ifdef PERF_PROFILING _dpd.addPreprocProfileFunc("dns", (void *)&dnsPerfStats, 0, _dpd.totalPerfStats);#endif}/* Verify configuration and that Stream API is available. * * PARAMETERS: None * * RETURNS: Nothing. */static void DNSConfigCheck( void ){ if ((!_dpd.streamAPI) || (_dpd.streamAPI->version < STREAM_API_VERSION4)) { DynamicPreprocessorFatalMessage("DNSConfigCheck() Streaming & reassembly must be enabled\n"); }}/* Parses and processes the configuration arguments * supplied in the DNS preprocessor rule. * * PARAMETERS: * * argp: Pointer to string containing the config arguments. * * RETURNS: Nothing. */static void ParseDNSArgs( u_char* argp ){ char* cur_tokenp = NULL; char* argcpyp = NULL; int port; /* Set up default port to listen on */ dns_config.ports[ PORT_INDEX( DNS_PORT ) ] |= CONV_PORT(DNS_PORT); /* Sanity check(s) */ if ( !argp ) { PrintDNSConfig(); return; } argcpyp = strdup( (char*) argp ); if ( !argcpyp ) { DynamicPreprocessorFatalMessage("Could not allocate memory to parse DNS options.\n"); return; } cur_tokenp = strtok( argcpyp, " "); while ( cur_tokenp ) { if ( !strcmp( cur_tokenp, DNS_PORTS_KEYWORD )) { /* If the user specified ports, remove 'DNS_PORT' for now since * it now needs to be set explicitely. */ dns_config.ports[ PORT_INDEX( DNS_PORT ) ] = 0; /* Eat the open brace. */ cur_tokenp = strtok( NULL, " "); if (( !cur_tokenp ) || ( strcmp(cur_tokenp, "{" ))) { DynamicPreprocessorFatalMessage("%s(%d) Bad value specified for %s. Must start " "with '{' and be space seperated.\n", *(_dpd.config_file), *(_dpd.config_line), DNS_PORTS_KEYWORD); //free(argcpyp); //return; } cur_tokenp = strtok( NULL, " "); while (( cur_tokenp ) && strcmp(cur_tokenp, "}" )) { if ( !isdigit( (int)cur_tokenp[0] )) { DynamicPreprocessorFatalMessage("%s(%d) Bad port %s.\n", *(_dpd.config_file), *(_dpd.config_line), cur_tokenp ); //free(argcpyp); //return; } else { port = atoi( cur_tokenp ); if( port < 0 || port > MAX_PORTS ) { DynamicPreprocessorFatalMessage("%s(%d) Port value illegitimate: %s\n", *(_dpd.config_file), *(_dpd.config_line), cur_tokenp ); //free(argcpyp); //return; } dns_config.ports[ PORT_INDEX( port ) ] |= CONV_PORT(port); } cur_tokenp = strtok( NULL, " "); } } else if ( !strcmp( cur_tokenp, DNS_ENABLE_RDATA_OVERFLOW_KEYWORD )) { dns_config.enabled_alerts |= DNS_ALERT_RDATA_OVERFLOW; } else if ( !strcmp( cur_tokenp, DNS_ENABLE_OBSOLETE_TYPES_KEYWORD )) { dns_config.enabled_alerts |= DNS_ALERT_OBSOLETE_TYPES; } else if ( !strcmp( cur_tokenp, DNS_ENABLE_EXPERIMENTAL_TYPES_KEYWORD )) { dns_config.enabled_alerts |= DNS_ALERT_EXPERIMENTAL_TYPES; }#if 0 else if ( !strcmp( cur_tokenp, DNS_AUTODETECT_KEYWORD )) { dns_config.autodetect++; }#endif else { DynamicPreprocessorFatalMessage("Invalid argument: %s\n", cur_tokenp); return; } cur_tokenp = strtok( NULL, " " ); } PrintDNSConfig(); free(argcpyp);}/* Display the configuration for the DNS preprocessor. * * PARAMETERS: None. * * RETURNS: Nothing. */static void PrintDNSConfig(){ int index; _dpd.logMsg("DNS config: \n");#if 0 _dpd.logMsg(" Autodetection: %s\n", dns_config.autodetect ? "ENABLED":"DISABLED");#endif _dpd.logMsg(" DNS Client rdata txt Overflow Alert: %s\n", dns_config.enabled_alerts & DNS_ALERT_RDATA_OVERFLOW ? "ACTIVE" : "INACTIVE" ); _dpd.logMsg(" Obsolete DNS RR Types Alert: %s\n", dns_config.enabled_alerts & DNS_ALERT_OBSOLETE_TYPES ? "ACTIVE" : "INACTIVE" ); _dpd.logMsg(" Experimental DNS RR Types Alert: %s\n", dns_config.enabled_alerts & DNS_ALERT_EXPERIMENTAL_TYPES ? "ACTIVE" : "INACTIVE" ); /* Printing ports */ _dpd.logMsg(" Ports:"); for(index = 0; index < MAX_PORTS; index++) { if( dns_config.ports[ PORT_INDEX(index) ] & CONV_PORT(index) ) { _dpd.logMsg(" %d", index); } } _dpd.logMsg("\n");}/* Retrieves the DNS data block registered with the stream * session associated w/ the current packet. If none exists, * allocates it and registers it with the stream API. * * PARAMETERS: * * p: Pointer to the packet from which/in which to * retrieve/store the DNS data block. * * RETURNS: Pointer to an DNS data block, upon success. * NULL, upon failure. */static DNSSessionData udpSessionData;#define MIN_UDP_PAYLOAD 0x1FFFDNSSessionData* GetDNSSessionData( SFSnortPacket* p ){ DNSSessionData* dnsSessionData = NULL; /* This is done in the calling function, don't need to * do it again here. * * Sanity check if (!p) { return NULL; } */ if (p->udp_header) { if (!(dns_config.enabled_alerts & DNS_ALERT_OBSOLETE_TYPES) && !(dns_config.enabled_alerts & DNS_ALERT_EXPERIMENTAL_TYPES)) { if (dns_config.enabled_alerts & DNS_ALERT_RDATA_OVERFLOW) { /* Checking RData Overflow... */ if (p->payload_size < (sizeof(DNSHdr) + sizeof(DNSRR) + MIN_UDP_PAYLOAD)) { /* But we don't have sufficient data. Go away. */ return NULL; } } else { /* Not checking for experimental or obsolete types. Go away. */ return NULL; } } /* Its a UDP packet, use the "stateless" one */ dnsSessionData = &udpSessionData; memset(dnsSessionData, 0, sizeof(DNSSessionData)); return dnsSessionData; } /* More Sanity check(s) */ if ( !p->stream_session_ptr ) { return NULL; } /* Attempt to get a previously allocated DNS block. If none exists, * allocate and register one with the stream layer. */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -