From: Josh Date: Tue, 9 Sep 2014 20:16:35 +0000 (-0400) Subject: removing ip options, tcp options, and frag options from packet struct. Adding iterat... X-Git-Tag: 3.0.0-233~1414^2~2^2~4^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9e592a5eb483bd950545f6aa9a710b4858b7653e;p=thirdparty%2Fsnort3.git removing ip options, tcp options, and frag options from packet struct. Adding iterators for tcp and ip options --- diff --git a/src/codecs/ip/cd_frag.cc b/src/codecs/ip/cd_frag.cc index 13c38faaf..fcab7554d 100644 --- a/src/codecs/ip/cd_frag.cc +++ b/src/codecs/ip/cd_frag.cc @@ -90,8 +90,6 @@ bool Ipv6FragCodec::decode(const uint8_t *raw_pkt, const uint32_t& raw_len, /* If this is an IP Fragment, set some data... */ p->ip6_frag_index = p->num_layers; - p->ip_frag_start = raw_pkt + sizeof(ip::IP6Frag); - p->decode_flags &= ~DECODE__DF; if (ntohs(ip6frag_hdr->ip6f_offlg) & ip::IP6F_MF_MASK) @@ -105,7 +103,6 @@ bool Ipv6FragCodec::decode(const uint8_t *raw_pkt, const uint32_t& raw_len, // three least signifigant bits are all flags const uint16_t frag_offset = ntohs(ip6frag_hdr->get_off()) >> 3; - p->frag_offset = frag_offset; if (frag_offset || (p->decode_flags & DECODE__MF)) { p->decode_flags |= DECODE__FRAG; @@ -125,7 +122,6 @@ bool Ipv6FragCodec::decode(const uint8_t *raw_pkt, const uint32_t& raw_len, lyr_len = sizeof(ip::IP6Frag); next_prot_id = ip6frag_hdr->ip6f_nxt; - p->ip_frag_len = (uint16_t)(raw_len - lyr_len); // check header ordering up thru frag header ip_util::CheckIPv6ExtensionOrder(p, IPPROTO_ID_FRAGMENT, next_prot_id); diff --git a/src/codecs/ip/cd_icmp4.cc b/src/codecs/ip/cd_icmp4.cc index a7b4b6dc4..7bfc911f5 100644 --- a/src/codecs/ip/cd_icmp4.cc +++ b/src/codecs/ip/cd_icmp4.cc @@ -30,13 +30,16 @@ #include "protocols/icmp4.h" #include "codecs/codec_events.h" #include "codecs/ip/checksum.h" -#include "protocols/protocol_ids.h" -#include "protocols/packet.h" #include "codecs/decode_module.h" #include "codecs/sf_protocols.h" #include "codecs/ip/ip_util.h" +#include "protocols/protocol_ids.h" +#include "protocols/packet.h" +#include "protocols/ipv4_options.h" #include "packet_io/active.h" #include "log/text_log.h" +#include "main/snort_debug.h" +#include "sfip/sf_ip.h" namespace{ @@ -304,11 +307,14 @@ void Icmp4Codec::ICMP4MiscTests (Packet *p) if (p->icmph->type == icmp::IcmpType::ECHOREPLY) { - int i; - for (i = 0; i < p->ip_option_count; i++) + if (p->ip_api.is_ip4()) { - if (p->ip_options[i].is_opt_rr()) - codec_events::decoder_event(p, DECODE_ICMP_TRACEROUTE_IPOPTS); + ip::IpOptionIterator iter(p->ip_api.get_ip4h(), p); + for (const ip::IpOptions& opt : iter) + { + if (opt.code == ip::IPOptionCodes::RR) + codec_events::decoder_event(p, DECODE_ICMP_TRACEROUTE_IPOPTS); + } } } diff --git a/src/codecs/ip/cd_icmp6.cc b/src/codecs/ip/cd_icmp6.cc index b2a331355..aa6e7a7bf 100644 --- a/src/codecs/ip/cd_icmp6.cc +++ b/src/codecs/ip/cd_icmp6.cc @@ -38,6 +38,7 @@ #include "codecs/ip/ip_util.h" #include "packet_io/active.h" #include "log/text_log.h" +#include "main/snort_debug.h" namespace diff --git a/src/codecs/ip/cd_igmp.cc b/src/codecs/ip/cd_igmp.cc index e15d94fa5..609c944eb 100644 --- a/src/codecs/ip/cd_igmp.cc +++ b/src/codecs/ip/cd_igmp.cc @@ -29,6 +29,7 @@ #include "codecs/decode_module.h" #include "codecs/codec_events.h" #include "protocols/packet.h" +#include "protocols/ipv4_options.h" namespace @@ -80,8 +81,6 @@ public: bool IgmpCodec::decode(const uint8_t *raw_pkt, const uint32_t& raw_len, Packet *p, uint16_t& /*lyr_len*/, uint16_t& /*next_prot_id*/) { - int i, alert = 0; - if (raw_len >= 1 && raw_pkt[0] == 0x11) { const uint8_t* ip_opt_data = p->ip_api.get_ip_opt_data(); @@ -96,20 +95,23 @@ bool IgmpCodec::decode(const uint8_t *raw_pkt, const uint32_t& raw_len, } } - for(i=0; i< (int) p->ip_option_count; i++) { + + ip::IpOptionIterator iter(p->ip_api.get_ip4h(), p); + for (const ip::IpOptions& opt : iter) + { /* All IGMPv2 packets contain IP option code 148 (router alert). This vulnerability only applies to IGMPv3, so return early. */ - if (p->ip_options[i].is_opt_rtralt()) { + if (opt.code == ip::IPOptionCodes::RTRALT) + { return true; /* No alert. */ } - if (p->ip_options[i].len == 1) { - alert++; + if (opt.len == 3) + { + codec_events::decoder_event(p, DECODE_IGMP_OPTIONS_DOS); + return true; } } - - if (alert > 0) - codec_events::decoder_event(p, DECODE_IGMP_OPTIONS_DOS); } return true; } diff --git a/src/codecs/ip/cd_ipv4.cc b/src/codecs/ip/cd_ipv4.cc index a8609f37b..32c5cec91 100644 --- a/src/codecs/ip/cd_ipv4.cc +++ b/src/codecs/ip/cd_ipv4.cc @@ -44,6 +44,7 @@ #include "codecs/decode_module.h" #include "codecs/sf_protocols.h" #include "protocols/ip.h" +#include "protocols/ipv4_options.h" #include "log/text_log.h" #include "log/log_text.h" @@ -129,15 +130,9 @@ static THREAD_LOCAL std::array s_id_pool{{0}}; static inline void IP4AddrTests (const IP4Hdr*, const Packet* p); -static inline void IPMiscTests(Packet *); -static void DecodeIPOptions(const uint8_t *start, uint32_t o_len, Packet *p); +static inline void IPMiscTests(Packet *, const IP4Hdr* const, uint16_t len); +static void DecodeIPOptions(const uint8_t *start, uint8_t& o_len, Packet *p); -static int OptLenValidate(const uint8_t *option_ptr, - const uint8_t *end, - const uint8_t *len_ptr, - int expected_len, - Options *tcpopt, - uint8_t *byte_skip); /******************************************* ************ PRIVATE FUNCTIONS *********** @@ -325,22 +320,10 @@ bool Ipv4Codec::decode(const uint8_t *raw_pkt, const uint32_t& raw_len, } /* test for IP options */ - uint16_t ip_opt_len = (uint16_t)(hlen - ip::IP4_HEADER_LEN); + uint8_t ip_opt_len = (uint8_t)(hlen - ip::IP4_HEADER_LEN); if(ip_opt_len > 0) - { DecodeIPOptions((raw_pkt + ip::IP4_HEADER_LEN), ip_opt_len, p); - } - else - { - /* If delivery header for GRE encapsulated packet is IP and it - * had options, the packet's ip options will be refering to this - * outer IP's options - * Zero these options so they aren't associated with this inner IP - * since p->iph will be pointing to this inner IP - */ - p->ip_option_count = 0; - } /* set the remaining packet length */ const_cast(raw_len) = ip_len; @@ -386,8 +369,6 @@ bool Ipv4Codec::decode(const uint8_t *raw_pkt, const uint32_t& raw_len, { /* set the packet fragment flag */ p->decode_flags |= DECODE__FRAG; - p->ip_frag_start = raw_pkt + hlen; - p->ip_frag_len = (uint16_t)ip_len; } } else @@ -400,24 +381,20 @@ bool Ipv4Codec::decode(const uint8_t *raw_pkt, const uint32_t& raw_len, codec_events::decoder_event(p, DECODE_BAD_FRAGBITS); } - p->frag_offset = frag_off; - /* See if there are any ip_proto only rules that match */ fpEvalIpProtoOnlyRules(snort_conf->ip_proto_only_lists, p, iph->get_proto()); p->proto_bits |= PROTO_BIT__IP; - IPMiscTests(p); + IPMiscTests(p, iph, ip::IP4_HEADER_LEN + ip_opt_len); lyr_len = hlen; + /* if this packet isn't a fragment * or if it is, its a UDP packet and offset is 0 */ if(!(p->decode_flags & DECODE__FRAG) || - ((p->decode_flags & DECODE__FRAG) && (frag_off == 0) && - (iph->get_proto() == IPPROTO_UDP))) + ((frag_off == 0) && + (iph->get_proto() == IPPROTO_UDP))) { - DEBUG_WRAP(DebugMessage(DEBUG_DECODE, "IP header length: %lu\n", - (unsigned long)hlen);); - if (iph->get_proto() >= MIN_UNASSIGNED_IP_PROTO) codec_events::decoder_event(p, DECODE_IP_UNASSIGNED_PROTO); else @@ -486,71 +463,61 @@ static inline void IP4AddrTests(const IP4Hdr* iph, const Packet* p) /* IPv4-layer decoder rules */ -static inline void IPMiscTests(Packet *p) +static inline void IPMiscTests(Packet *p, const IP4Hdr* const ip4h, uint16_t len) { /* Yes, it's an ICMP-related vuln in IP options. */ - uint8_t i, length, pointer; + uint8_t length, pointer; + /* Alert on IP packets with either 0x07 (Record Route) or 0x44 (Timestamp) options that are specially crafted. */ - for (i = 0; i < p->ip_option_count; i++) + ip::IpOptionIterator iter(ip4h, (uint8_t)(len - ip::IP4_HEADER_LEN)); + for (const ip::IpOptions& opt : iter) { - if (p->ip_options[i].data == NULL) - continue; - - if (p->ip_options[i].is_opt_rr()) + if (opt.code == ip::IPOptionCodes::RR) { - length = p->ip_options[i].len; - if (length < 1) + length = opt.len; + if (length < 3) continue; - pointer = p->ip_options[i].data[0]; + pointer = opt.data[0]; /* If the pointer goes past the end of the data, then the data is full. That's okay. */ - if (pointer >= length + 2) + if (pointer >= length) continue; /* If the remaining space in the option isn't a multiple of 4 bytes, alert. */ - if (((length + 3) - pointer) % 4) + if (((length + 1) - pointer) % 4) codec_events::decoder_event(p, DECODE_ICMP_DOS_ATTEMPT); } - else if (p->ip_options[i].is_opt_ts()) + else if (opt.code == ip::IPOptionCodes::TS) { - length = p->ip_options[i].len; + length = opt.get_len(); if (length < 2) continue; - pointer = p->ip_options[i].data[0]; + pointer = opt.data[0]; /* If the pointer goes past the end of the data, then the data is full. That's okay. */ - if (pointer >= length + 2) + if (pointer >= length) continue; /* If the remaining space in the option isn't a multiple of 4 bytes, alert. */ - if (((length + 3) - pointer) % 4) + if (((length + 1) - pointer) % 4) codec_events::decoder_event(p, DECODE_ICMP_DOS_ATTEMPT); /* If there is a timestamp + address, we need a multiple of 8 bytes instead. */ - if ((p->ip_options[i].data[1] & 0x01) && /* address flag */ - (((length + 3) - pointer) % 8)) + if ((opt.data[1] & 0x01) && /* address flag */ + (((length + 1) - pointer) % 8)) codec_events::decoder_event(p, DECODE_ICMP_DOS_ATTEMPT); } } } - -// TODO :: delete. IN TCP -int OptLenValidate(const uint8_t *option_ptr, - const uint8_t *end, - const uint8_t *len_ptr, - int expected_len, - Options *tcpopt, - uint8_t *byte_skip); - /* * Function: DecodeIPOptions(uint8_t *, uint32_t, Packet *) * @@ -562,128 +529,70 @@ int OptLenValidate(const uint8_t *option_ptr, * * Returns: void function */ -static void DecodeIPOptions(const uint8_t *start, uint32_t o_len, Packet *p) +static void DecodeIPOptions(const uint8_t *start, uint8_t& o_len, Packet *p) { - const uint8_t *option_ptr = start; - u_char done = 0; /* have we reached IP_OPTEOL yet? */ - const uint8_t *end_ptr = start + o_len; - uint8_t opt_count = 0; /* what option are we processing right now */ - uint8_t byte_skip; - const uint8_t *len_ptr; + uint32_t tot_len = 0; int code = 0; /* negative error codes are returned from bad options */ DEBUG_WRAP(DebugMessage(DEBUG_DECODE, "Decoding %d bytes of IP options\n", o_len);); + const ip::IpOptions* option = reinterpret_cast(start); - while((option_ptr < end_ptr) && (opt_count < IP_OPTMAX) && (code >= 0)) - { - p->ip_options[opt_count].code = *option_ptr; - if((option_ptr + 1) < end_ptr) - { - len_ptr = option_ptr + 1; - } - else - { - len_ptr = NULL; - } - - switch(static_cast(*option_ptr)) + while(tot_len < o_len) + { + switch(option->code) { - case ip::IPOptionCodes::EOL: - done = 1; - // fall through - - case ip::IPOptionCodes::NOP: - /* if we hit an EOL, we're done */ - - p->ip_options[opt_count].len = 0; - p->ip_options[opt_count].data = NULL; - byte_skip = 1; - break; - default: - /* FIXIT-L - J ip option validation should be updated. 3 of these fields are useless */ - code = OptLenValidate(option_ptr, end_ptr, len_ptr, -1, - reinterpret_cast(&p->ip_options[opt_count]), &byte_skip); - } + case ip::IPOptionCodes::EOL: + /* if we hit an EOL, we're done */ + tot_len++; + p->byte_skip = o_len - tot_len; + o_len = tot_len; + return; + // fall through - if(code < 0) - { - /* Yes, we use TCP_OPT_* for the IP option decoder. - */ - if(code == tcp::OPT_BADLEN) - { - codec_events::decoder_event(p, DECODE_IPV4OPT_BADLEN); - } - else if(code == tcp::OPT_TRUNC) - { - codec_events::decoder_event(p, DECODE_IPV4OPT_TRUNCATED); - } - return; - } + case ip::IPOptionCodes::NOP: + tot_len++; + break; - if(!done) - opt_count++; + default: - option_ptr += byte_skip; - } + if((tot_len + 1) >= o_len) + code = tcp::OPT_TRUNC; - p->ip_option_count = opt_count; + /* RFC sez that we MUST have atleast this much data */ + else if (option->get_len() < 2) + code = tcp::OPT_BADLEN; - return; -} + else if (tot_len + option->get_len() > o_len) + /* not enough data to read in a perfect world */ + code = tcp::OPT_TRUNC; -static int OptLenValidate(const uint8_t *option_ptr, - const uint8_t *end, - const uint8_t *len_ptr, - int expected_len, - Options *tcpopt, - uint8_t *byte_skip) -{ - *byte_skip = 0; - if(len_ptr == NULL) - return tcp::OPT_TRUNC; + if(code < 0) + { + /* Yes, we use TCP_OPT_* for the IP option decoder. */ + if(code == tcp::OPT_BADLEN) + codec_events::decoder_event(p, DECODE_IPV4OPT_BADLEN); + else if(code == tcp::OPT_TRUNC) + codec_events::decoder_event(p, DECODE_IPV4OPT_TRUNCATED); + p->byte_skip = o_len - tot_len; + o_len = tot_len; + return; + } - if(*len_ptr == 0 || expected_len == 0 || expected_len == 1) - { - return tcp::OPT_BADLEN; - } - else if(expected_len > 1) - { - /* not enough data to read in a perfect world */ - if((option_ptr + expected_len) > end) - return tcp::OPT_TRUNC; + tot_len += option->len; + } - if(*len_ptr != expected_len) - return tcp::OPT_BADLEN; - } - else /* expected_len < 0 (i.e. variable length) */ - { - /* RFC sez that we MUST have atleast this much data */ - if(*len_ptr < 2) - return tcp::OPT_BADLEN; - /* not enough data to read in a perfect world */ - if((option_ptr + *len_ptr) > end) - return tcp::OPT_TRUNC; + option = &(option->next()); } - - tcpopt->len = *len_ptr - 2; - - if(*len_ptr == 2) - tcpopt->data = NULL; - else - tcpopt->data = option_ptr + 2; - - *byte_skip = *len_ptr; - - return 0; } + /****************************************************************** ********************* L O G G E R ****************************** *******************************************************************/ @@ -745,11 +654,11 @@ void Ipv4Codec::log(TextLog* const text_log, const uint8_t* raw_pkt, TextLog_Puts(text_log, " MF"); /* print IP options */ - if(p->ip_option_count > 0) + if (ip4h->has_options()) { TextLog_Putc(text_log, '\t'); TextLog_NewLine(text_log); - LogIpOptions(text_log, p); + LogIpOptions(text_log, ip4h, p); } @@ -871,6 +780,12 @@ void Ipv4Codec::format(EncodeFlags f, const Packet* p, Packet* c, Layer* lyr) } if ( f & ENC_FLAG_DEF ) { + lyr->length = ip::IP4_HEADER_LEN; + ch->set_ip_len(htons(ip::IP4_HEADER_LEN)); + ch->set_hlen(ip::IP4_HEADER_LEN >> 2); + +#if 0 + // FIXIT-L - J why did Snort check for this? int i = lyr - c->layers; if ( i + 1 == p->num_layers ) { @@ -878,6 +793,7 @@ void Ipv4Codec::format(EncodeFlags f, const Packet* p, Packet* c, Layer* lyr) ch->set_ip_len(htons(ip::IP4_HEADER_LEN)); ch->set_hlen(ip::IP4_HEADER_LEN >> 2); } +#endif } c->ip_api.set(ch); diff --git a/src/codecs/ip/cd_ipv6.cc b/src/codecs/ip/cd_ipv6.cc index 46c5f0006..6f6d926dc 100644 --- a/src/codecs/ip/cd_ipv6.cc +++ b/src/codecs/ip/cd_ipv6.cc @@ -25,6 +25,7 @@ #include "config.h" #endif +#include #include "detection/fpdetect.h" #include "protocols/ipv6.h" @@ -40,6 +41,7 @@ #include "protocols/protocol_ids.h" #include "protocols/packet_manager.h" #include "log/text_log.h" +#include "sfip/sf_ip.h" namespace { @@ -241,10 +243,6 @@ bool Ipv6Codec::decode(const uint8_t *raw_pkt, const uint32_t& raw_len, } - - /* Remove outer IP options */ - p->ip_option_count = 0; - /* set the real IP length for logging */ p->proto_bits |= PROTO_BIT__IP; // extra ipv6 header will be removed in PacketManager @@ -255,6 +253,8 @@ bool Ipv6Codec::decode(const uint8_t *raw_pkt, const uint32_t& raw_len, p->ip_api.set(ip6h); p->curr_ip6_extension_order = 0; + p->ip6_extension_count = 0; + p->ip6_frag_index = std::numeric_limits::max(); p->decode_flags &= ~DECODE__ROUTING_SEEN; IPV6MiscTests(p); diff --git a/src/codecs/ip/cd_tcp.cc b/src/codecs/ip/cd_tcp.cc index 6407c4027..bad73f4bc 100644 --- a/src/codecs/ip/cd_tcp.cc +++ b/src/codecs/ip/cd_tcp.cc @@ -25,12 +25,12 @@ #include "config.h" #endif - #include "framework/codec.h" #include "codecs/decode_module.h" #include "codecs/ip/checksum.h" #include "codecs/sf_protocols.h" #include "protocols/tcp.h" +#include "protocols/tcp_options.h" #include "protocols/ipv6.h" #include "protocols/packet.h" #include "packet_io/active.h" @@ -44,6 +44,8 @@ #include "protocols/packet_manager.h" +using namespace tcp; + namespace { @@ -115,12 +117,9 @@ static sfip_var_t *SynToMulticastDstIp = NULL; -static int OptLenValidate(const uint8_t *option_ptr, - const uint8_t *end, - const uint8_t *len_ptr, - int expected_len, - Options *tcpopt, - uint8_t *byte_skip); +static int OptLenValidate(const tcp::TcpOption* const opt, + const uint8_t* const end, + const int expected_len); static void DecodeTCPOptions(const uint8_t *, uint32_t, Packet *); @@ -165,13 +164,13 @@ bool TcpCodec::decode(const uint8_t *raw_pkt, const uint32_t& raw_len, lyr_len = tcph->hdr_len(); DEBUG_WRAP(DebugMessage(DEBUG_DECODE, "TCP th_off is %d, passed len is %lu\n", - TCP_OFFSET(p->tcph), (unsigned long)raw_len);); + tcph->off(), (unsigned long)raw_len);); if(lyr_len < tcp::TCP_HEADER_LEN) { DEBUG_WRAP(DebugMessage(DEBUG_DECODE, "TCP Data Offset (%d) < lyr_len (%d) \n", - TCP_OFFSET(p->tcph), lyr_len);); + tcph->off(), lyr_len);); codec_events::decoder_event(p, DECODE_TCP_INVALID_OFFSET); @@ -183,7 +182,7 @@ bool TcpCodec::decode(const uint8_t *raw_pkt, const uint32_t& raw_len, { DEBUG_WRAP(DebugMessage(DEBUG_DECODE, "TCP Data Offset(%d) < longer than payload(%d)!\n", - TCP_OFFSET(p->tcph) << 2, raw_len);); + tcph->off() << 2, raw_len);); codec_events::decoder_event(p, DECODE_TCP_LARGE_OFFSET); @@ -210,7 +209,7 @@ bool TcpCodec::decode(const uint8_t *raw_pkt, const uint32_t& raw_len, /* if we're being "stateless" we probably don't care about the TCP * checksum, but it's not bad to keep around for shits and giggles */ /* calculate the checksum */ - csum = checksum::tcp_cksum((uint16_t *)(p->tcph), raw_len, &ph); + csum = checksum::tcp_cksum((uint16_t *)(tcph), raw_len, &ph); } /* IPv6 traffic */ @@ -224,7 +223,7 @@ bool TcpCodec::decode(const uint8_t *raw_pkt, const uint32_t& raw_len, ph6.len = htons((uint16_t)raw_len); - csum = checksum::tcp_cksum((uint16_t *)(p->tcph), raw_len, &ph6); + csum = checksum::tcp_cksum((uint16_t *)(tcph), raw_len, &ph6); } if(csum) @@ -241,7 +240,7 @@ bool TcpCodec::decode(const uint8_t *raw_pkt, const uint32_t& raw_len, p->error_flags |= PKT_ERR_CKSUM_TCP; DEBUG_WRAP(DebugMessage(DEBUG_DECODE, "Bad TCP checksum\n", "0x%x versus 0x%x\n", csum, - ntohs(p->tcph->th_sum));); + ntohs(tcph->th_sum));); if( ScInlineMode() && ScTcpChecksumDrops() ) @@ -257,9 +256,9 @@ bool TcpCodec::decode(const uint8_t *raw_pkt, const uint32_t& raw_len, } } - if(TCP_ISFLAGSET(p->tcph, (TH_FIN|TH_PUSH|TH_URG))) + if(TCP_ISFLAGSET(tcph, (TH_FIN|TH_PUSH|TH_URG))) { - if(TCP_ISFLAGSET(p->tcph, (TH_SYN|TH_ACK|TH_RST))) + if(TCP_ISFLAGSET(tcph, (TH_SYN|TH_ACK|TH_RST))) { codec_events::decoder_event(p, DECODE_TCP_XMAS); } @@ -273,12 +272,12 @@ bool TcpCodec::decode(const uint8_t *raw_pkt, const uint32_t& raw_len, return;*/ } - if(TCP_ISFLAGSET(p->tcph, (TH_SYN))) + if(TCP_ISFLAGSET(tcph, (TH_SYN))) { /* check if only SYN is set */ - if( p->tcph->th_flags == TH_SYN ) + if( tcph->th_flags == TH_SYN ) { - if( p->tcph->th_seq == 6060842 ) + if( tcph->th_seq == 6060842 ) { if( p->ip_api.id(p) == 413 ) { @@ -291,61 +290,45 @@ bool TcpCodec::decode(const uint8_t *raw_pkt, const uint32_t& raw_len, { codec_events::decoder_event(p, DECODE_SYN_TO_MULTICAST); } - if ( (p->tcph->th_flags & TH_RST) ) + if ( (tcph->th_flags & TH_RST) ) codec_events::decoder_event(p, DECODE_TCP_SYN_RST); - if ( (p->tcph->th_flags & TH_FIN) ) + if ( (tcph->th_flags & TH_FIN) ) codec_events::decoder_event(p, DECODE_TCP_SYN_FIN); } else { // we already know there is no SYN - if ( !(p->tcph->th_flags & (TH_ACK|TH_RST)) ) + if ( !(tcph->th_flags & (TH_ACK|TH_RST)) ) codec_events::decoder_event(p, DECODE_TCP_NO_SYN_ACK_RST); } - if ( (p->tcph->th_flags & (TH_FIN|TH_PUSH|TH_URG)) && - !(p->tcph->th_flags & TH_ACK) ) + if ( (tcph->th_flags & (TH_FIN|TH_PUSH|TH_URG)) && + !(tcph->th_flags & TH_ACK) ) codec_events::decoder_event(p, DECODE_TCP_MUST_ACK); /* stuff more data into the printout data struct */ - p->sp = ntohs(p->tcph->th_sport); - p->dp = ntohs(p->tcph->th_dport); + p->sp = ntohs(tcph->th_sport); + p->dp = ntohs(tcph->th_dport); /* if options are present, decode them */ uint16_t tcp_opt_len = (uint16_t)(tcph->hdr_len() - tcp::TCP_HEADER_LEN); if(tcp_opt_len > 0) - { - DEBUG_WRAP(DebugMessage(DEBUG_DECODE, "%lu bytes of tcp options....\n", - (unsigned long)(tcp_opt_len));); - DecodeTCPOptions((uint8_t *) (raw_pkt + tcp::TCP_HEADER_LEN), tcp_opt_len, p); - } - else - { - p->tcp_option_count = 0; - } - /* set the data pointer and size */ - p->data = (uint8_t *) (raw_pkt + lyr_len); - if(lyr_len < raw_len) - { - p->dsize = (uint16_t)(raw_len - lyr_len); - } - else - { - p->dsize = 0; - } + int dsize = raw_len - tcph->hdr_len(); + if (dsize < 0) + dsize = 0; - if ( (p->tcph->th_flags & TH_URG) && - (!p->dsize || ntohs(p->tcph->th_urp) > p->dsize) ) + if ( (tcph->th_flags & TH_URG) && + ((dsize == 0) || ntohs(tcph->th_urp) > dsize) ) codec_events::decoder_event(p, DECODE_TCP_BAD_URP); p->proto_bits |= PROTO_BIT__TCP; TCPMiscTests(p); - + return true; } @@ -401,17 +384,15 @@ bool TcpCodec::decode(const uint8_t *raw_pkt, const uint32_t& raw_len, */ void DecodeTCPOptions(const uint8_t *start, uint32_t o_len, Packet *p) { - const uint8_t *option_ptr = start; - const uint8_t *end_ptr = start + o_len; /* points to byte after last option */ - const uint8_t *len_ptr; - uint8_t opt_count = 0; - u_char done = 0; /* have we reached TCPOPT_EOL yet?*/ - u_char experimental_option_found = 0; /* are all options RFC compliant? */ - u_char obsolete_option_found = 0; - u_char ttcp_found = 0; - + const uint8_t* const end_ptr = start + o_len; /* points to byte after last option */ + const tcp::TcpOption* opt = reinterpret_cast(start); int code = 2; - uint8_t byte_skip; + uint16_t tot_len = 0; + bool done = false; /* have we reached TCPOPT_EOL yet?*/ + bool experimental_option_found = false; /* are all options RFC compliant? */ + bool obsolete_option_found = false; + + /* Here's what we're doing so that when we find out what these * other buggers of TCP option codes are, we can do something @@ -419,7 +400,6 @@ void DecodeTCPOptions(const uint8_t *start, uint32_t o_len, Packet *p) * * 1) get option code * 2) check for enough space for current option code - * 3) set option data ptr * 4) increment option code ptr * * TCP_OPTLENMAX = 40 because of @@ -427,126 +407,99 @@ void DecodeTCPOptions(const uint8_t *start, uint32_t o_len, Packet *p) * */ - if(o_len > TCP_OPTLENMAX) + while((tot_len < o_len) && !done) { - /* This shouldn't ever alert if we are doing our job properly - * in the caller */ - p->tcph = NULL; /* let's just alert */ - DEBUG_WRAP(DebugMessage(DEBUG_DECODE, - "o_len(%u) > TCP_OPTLENMAX(%u)\n", - o_len, TCP_OPTLENMAX)); - return; - } - - while((option_ptr < end_ptr) && (opt_count < TCP_OPTLENMAX) && !done) - { - p->tcp_options[opt_count].code = *option_ptr; - - if((option_ptr + 1) < end_ptr) + switch(opt->code) { - len_ptr = option_ptr + 1; - } - else - { - len_ptr = NULL; - } - - switch(*option_ptr) - { - case tcp::TcpOpt::EOL: - done = 1; /* fall through to the NOP case */ - case tcp::TcpOpt::NOP: - p->tcp_options[opt_count].len = 0; - p->tcp_options[opt_count].data = NULL; - byte_skip = 1; + case tcp::TcpOptCode::EOL: + done = true; /* fall through to the NOP case */ + p->byte_skip = o_len - tot_len; + case tcp::TcpOptCode::NOP: code = 0; break; - case tcp::TcpOpt::MAXSEG: - code = OptLenValidate(option_ptr, end_ptr, len_ptr, TCPOLEN_MAXSEG, - &p->tcp_options[opt_count], &byte_skip); + + case tcp::TcpOptCode::MAXSEG: + code = OptLenValidate(opt, end_ptr, TCPOLEN_MAXSEG); break; - case tcp::TcpOpt::SACKOK: - code = OptLenValidate(option_ptr, end_ptr, len_ptr, TCPOLEN_SACKOK, - &p->tcp_options[opt_count], &byte_skip); + + case tcp::TcpOptCode::SACKOK: + code = OptLenValidate(opt, end_ptr, TCPOLEN_SACKOK); break; - case tcp::TcpOpt::WSCALE: - code = OptLenValidate(option_ptr, end_ptr, len_ptr, TCPOLEN_WSCALE, - &p->tcp_options[opt_count], &byte_skip); + + case tcp::TcpOptCode::WSCALE: + code = OptLenValidate(opt, end_ptr, TCPOLEN_WSCALE); if (code == 0) { - if ( - ((uint16_t) p->tcp_options[opt_count].data[0] > 14)) + if (((uint16_t) opt->data[0] > 14)) { /* LOG INVALID WINDOWSCALE alert */ codec_events::decoder_event(p, DECODE_TCPOPT_WSCALE_INVALID); } } break; - case tcp::TcpOpt::ECHO: /* both use the same lengths */ - case tcp::TcpOpt::ECHOREPLY: - obsolete_option_found = 1; - code = OptLenValidate(option_ptr, end_ptr, len_ptr, TCPOLEN_ECHO, - &p->tcp_options[opt_count], &byte_skip); + + case tcp::TcpOptCode::ECHO: /* both use the same lengths */ + case tcp::TcpOptCode::ECHOREPLY: + obsolete_option_found = true; + code = OptLenValidate(opt, end_ptr, TCPOLEN_ECHO); break; - case tcp::TcpOpt::MD5SIG: + + case tcp::TcpOptCode::MD5SIG: /* RFC 5925 obsoletes this option (see below) */ obsolete_option_found = 1; - code = OptLenValidate(option_ptr, end_ptr, len_ptr, TCPOLEN_MD5SIG, - &p->tcp_options[opt_count], &byte_skip); + code = OptLenValidate(opt, end_ptr, TCPOLEN_MD5SIG); break; - case tcp::TcpOpt::AUTH: + + case tcp::TcpOptCode::AUTH: + code = OptLenValidate(opt, end_ptr, -1); + /* Has to have at least 4 bytes - see RFC 5925, Section 2.2 */ - if ((len_ptr != NULL) && (*len_ptr < 4)) + if (code >= 0 && opt->len < 4) code = tcp::OPT_BADLEN; - else - code = OptLenValidate(option_ptr, end_ptr, len_ptr, -1, - &p->tcp_options[opt_count], &byte_skip); break; - case tcp::TcpOpt::SACK: - code = OptLenValidate(option_ptr, end_ptr, len_ptr, -1, - &p->tcp_options[opt_count], &byte_skip); - if((code == 0) && (p->tcp_options[opt_count].data == NULL)) - code = tcp::OPT_BADLEN; + case tcp::TcpOptCode::SACK: + code = OptLenValidate(opt, end_ptr, -1); + + if((code >= 0) && (opt->len < 2)) + code = tcp::OPT_BADLEN; break; - case tcp::TcpOpt::CC_ECHO: - ttcp_found = 1; + + case tcp::TcpOptCode::CC_ECHO: + codec_events::decoder_event(p, DECODE_TCPOPT_TTCP); /* fall through */ - case tcp::TcpOpt::CC: /* all 3 use the same lengths / T/TCP */ - case tcp::TcpOpt::CC_NEW: - code = OptLenValidate(option_ptr, end_ptr, len_ptr, TCPOLEN_CC, - &p->tcp_options[opt_count], &byte_skip); + case tcp::TcpOptCode::CC: /* all 3 use the same lengths / T/TCP */ + case tcp::TcpOptCode::CC_NEW: + code = OptLenValidate(opt, end_ptr, TCPOLEN_CC); break; - case tcp::TcpOpt::TRAILER_CSUM: - experimental_option_found = 1; - code = OptLenValidate(option_ptr, end_ptr, len_ptr, TCPOLEN_TRAILER_CSUM, - &p->tcp_options[opt_count], &byte_skip); + + case tcp::TcpOptCode::TRAILER_CSUM: + experimental_option_found = true; + code = OptLenValidate(opt, end_ptr, TCPOLEN_TRAILER_CSUM); break; - case tcp::TcpOpt::TIMESTAMP: - code = OptLenValidate(option_ptr, end_ptr, len_ptr, TCPOLEN_TIMESTAMP, - &p->tcp_options[opt_count], &byte_skip); + case tcp::TcpOptCode::TIMESTAMP: + code = OptLenValidate(opt, end_ptr, TCPOLEN_TIMESTAMP); break; - case tcp::TcpOpt::SKEETER: - case tcp::TcpOpt::BUBBA: - case tcp::TcpOpt::UNASSIGNED: - obsolete_option_found = 1; - code = OptLenValidate(option_ptr, end_ptr, len_ptr, -1, - &p->tcp_options[opt_count], &byte_skip); + case tcp::TcpOptCode::SKEETER: + case tcp::TcpOptCode::BUBBA: + case tcp::TcpOptCode::UNASSIGNED: + obsolete_option_found = true; + code = OptLenValidate(opt, end_ptr, -1); break; + + case tcp::TcpOptCode::SCPS: + case tcp::TcpOptCode::SELNEGACK: + case tcp::TcpOptCode::RECORDBOUND: + case tcp::TcpOptCode::CORRUPTION: + case tcp::TcpOptCode::PARTIAL_PERM: + case tcp::TcpOptCode::PARTIAL_SVC: + case tcp::TcpOptCode::ALTCSUM: + case tcp::TcpOptCode::SNAP: default: - case tcp::TcpOpt::SCPS: - case tcp::TcpOpt::SELNEGACK: - case tcp::TcpOpt::RECORDBOUND: - case tcp::TcpOpt::CORRUPTION: - case tcp::TcpOpt::PARTIAL_PERM: - case tcp::TcpOpt::PARTIAL_SVC: - case tcp::TcpOpt::ALTCSUM: - case tcp::TcpOpt::SNAP: - experimental_option_found = 1; - code = OptLenValidate(option_ptr, end_ptr, len_ptr, -1, - &p->tcp_options[opt_count], &byte_skip); + experimental_option_found = true; + code = OptLenValidate(opt, end_ptr, -1); break; } @@ -565,18 +518,15 @@ void DecodeTCPOptions(const uint8_t *start, uint32_t o_len, Packet *p) * options found before this bad one * some implementations (BSD and Linux) ignore * the bad ones, but accept the good ones */ - p->tcp_option_count = opt_count; + p->byte_skip = o_len - tot_len; return; } - opt_count++; - - option_ptr += byte_skip; + tot_len += ((uint8_t)opt->code <= 1) ? 1 : opt->len; + opt = &(opt->next()); } - p->tcp_option_count = opt_count; - if (experimental_option_found) { codec_events::decoder_event(p, DECODE_TCPOPT_EXPERIMENTAL); @@ -585,15 +535,42 @@ void DecodeTCPOptions(const uint8_t *start, uint32_t o_len, Packet *p) { codec_events::decoder_event(p, DECODE_TCPOPT_OBSOLETE); } - else if (ttcp_found) - { - codec_events::decoder_event(p, DECODE_TCPOPT_TTCP); - } return; } +static int OptLenValidate(const tcp::TcpOption* const opt, + const uint8_t* const end, + const int expected_len) +{ + // case for pointer arithmetic + const uint8_t* const opt_ptr = reinterpret_cast(opt); + + + if(expected_len > 1) + { + /* not enough data to read in a perfect world */ + if((opt_ptr + expected_len) > end) + return tcp::OPT_TRUNC; + + if(opt->len != expected_len) + return tcp::OPT_BADLEN; + } + else /* expected_len < 0 (i.e. variable length) */ + { + /* RFC sez that we MUST have atleast this much data */ + if(opt->len < 2) + return tcp::OPT_BADLEN; + + /* not enough data to read in a perfect world */ + if((opt_ptr + opt->len) > end) + return tcp::OPT_TRUNC; + } + + return 0; +} + /* TCP-layer decoder alerts */ static inline void TCPMiscTests(Packet *p) @@ -604,6 +581,7 @@ static inline void TCPMiscTests(Packet *p) if (p->sp == 0 || p->dp == 0) codec_events::decoder_event(p, DECODE_TCP_PORT_ZERO); + } /****************************************************************** @@ -616,7 +594,7 @@ void TcpCodec::log(TextLog* const text_log, const uint8_t* raw_pkt, { char tcpFlags[9]; - const tcp::TCPHdr* tcph = reinterpret_cast(raw_pkt); + const tcp::TCPHdr* const tcph = reinterpret_cast(raw_pkt); /* print TCP flags */ CreateTCPFlagString(tcph, tcpFlags); @@ -627,14 +605,14 @@ void TcpCodec::log(TextLog* const text_log, const uint8_t* raw_pkt, "Win: 0x%X TcpLen: %d",ntohs(tcph->th_sport), ntohs(tcph->th_dport), (u_long) ntohl(tcph->th_seq), (u_long) ntohl(tcph->th_ack), - ntohs(tcph->th_win), TCP_OFFSET(tcph) << 2); + ntohs(tcph->th_win), tcph->off() << 2); if((tcph->th_flags & TH_URG) != 0) TextLog_Print(text_log, "UrgPtr: 0x%X", (uint16_t) ntohs(tcph->th_urp)); /* dump the TCP options */ - if(p->tcp_option_count > 0) + if(tcph->has_options()) { TextLog_Puts(text_log, "\n\t"); LogTcpOptions(text_log, p); @@ -674,7 +652,7 @@ bool TcpCodec::encode (EncState* enc, Buffer* out, const uint8_t* raw_in) memcpy(out->base, enc->payLoad, enc->payLen); } - if (!update_buffer(out, tcp::get_tcp_hdr_len(hi))) + if (!update_buffer(out, hi->hdr_len())) return false; tcp::TCPHdr* ho = reinterpret_cast(out->base); @@ -710,7 +688,7 @@ bool TcpCodec::encode (EncState* enc, Buffer* out, const uint8_t* raw_in) } ho->th_offx2 = 0; - tcp::set_tcp_offset(ho, (tcp::TCP_HEADER_LEN >> 2)); + ho->set_offset(tcp::TCP_HEADER_LEN >> 2); ho->th_win = ho->th_urp = 0; if ( attach_payload ) @@ -820,261 +798,6 @@ void TcpCodec::format(EncodeFlags f, const Packet* p, Packet* c, Layer* lyr) } -static int OptLenValidate(const uint8_t *option_ptr, - const uint8_t *end, - const uint8_t *len_ptr, - int expected_len, - Options *tcpopt, - uint8_t *byte_skip) -{ - *byte_skip = 0; - - if(len_ptr == NULL) - return tcp::OPT_TRUNC; - - - if(*len_ptr == 0 || expected_len == 0 || expected_len == 1) - { - return tcp::OPT_BADLEN; - } - else if(expected_len > 1) - { - /* not enough data to read in a perfect world */ - if((option_ptr + expected_len) > end) - return tcp::OPT_TRUNC; - - if(*len_ptr != expected_len) - return tcp::OPT_BADLEN; - } - else /* expected_len < 0 (i.e. variable length) */ - { - /* RFC sez that we MUST have atleast this much data */ - if(*len_ptr < 2) - return tcp::OPT_BADLEN; - - /* not enough data to read in a perfect world */ - if((option_ptr + *len_ptr) > end) - return tcp::OPT_TRUNC; - } - - tcpopt->len = *len_ptr - 2; - - if(*len_ptr == 2) - tcpopt->data = NULL; - else - tcpopt->data = option_ptr + 2; - - *byte_skip = *len_ptr; - - return 0; -} - - -// KEEPING FOR TESTING AND PROFILING -#if 0 - - -/* - * Checksum Functions - */ - -/* -* checksum tcp -* -* h - pseudo header - 12 bytes -* d - tcp hdr + payload -* dlen - length of tcp hdr + payload in bytes -* -*/ -static inline unsigned short in_chksum_tcp(pseudoheader *ph, - unsigned short * d, int dlen ) -{ - uint16_t *h = (uint16_t *)ph; - unsigned int cksum; - unsigned short answer=0; - - /* PseudoHeader must have 12 bytes */ - cksum = h[0]; - cksum += h[1]; - cksum += h[2]; - cksum += h[3]; - cksum += h[4]; - cksum += h[5]; - - /* TCP hdr must have 20 hdr bytes */ - cksum += d[0]; - cksum += d[1]; - cksum += d[2]; - cksum += d[3]; - cksum += d[4]; - cksum += d[5]; - cksum += d[6]; - cksum += d[7]; - cksum += d[8]; - cksum += d[9]; - - dlen -= 20; /* bytes */ - d += 10; /* short's */ - - while(dlen >=32) - { - cksum += d[0]; - cksum += d[1]; - cksum += d[2]; - cksum += d[3]; - cksum += d[4]; - cksum += d[5]; - cksum += d[6]; - cksum += d[7]; - cksum += d[8]; - cksum += d[9]; - cksum += d[10]; - cksum += d[11]; - cksum += d[12]; - cksum += d[13]; - cksum += d[14]; - cksum += d[15]; - d += 16; - dlen -= 32; - } - - while(dlen >=8) - { - cksum += d[0]; - cksum += d[1]; - cksum += d[2]; - cksum += d[3]; - d += 4; - dlen -= 8; - } - - while(dlen > 1) - { - cksum += *d++; - dlen -= 2; - } - - if( dlen == 1 ) - { - /* printf("new checksum odd byte-packet\n"); */ - *(unsigned char*)(&answer) = (*(unsigned char*)d); - - /* cksum += (uint16_t) (*(uint8_t*)d); */ - - cksum += answer; - } - - cksum = (cksum >> 16) + (cksum & 0x0000ffff); - cksum += (cksum >> 16); - - return (unsigned short)(~cksum); -} -/* -* checksum tcp for IPv6. -* -* h - pseudo header - 12 bytes -* d - tcp hdr + payload -* dlen - length of tcp hdr + payload in bytes -* -*/ -static inline unsigned short in_chksum_tcp6(pseudoheader6 *ph, - unsigned short * d, int dlen ) -{ - uint16_t *h = (uint16_t *)ph; - unsigned int cksum; - unsigned short answer=0; - - /* PseudoHeader must have 36 bytes */ - cksum = h[0]; - cksum += h[1]; - cksum += h[2]; - cksum += h[3]; - cksum += h[4]; - cksum += h[5]; - cksum += h[6]; - cksum += h[7]; - cksum += h[8]; - cksum += h[9]; - cksum += h[10]; - cksum += h[11]; - cksum += h[12]; - cksum += h[13]; - cksum += h[14]; - cksum += h[15]; - cksum += h[16]; - cksum += h[17]; - - /* TCP hdr must have 20 hdr bytes */ - cksum += d[0]; - cksum += d[1]; - cksum += d[2]; - cksum += d[3]; - cksum += d[4]; - cksum += d[5]; - cksum += d[6]; - cksum += d[7]; - cksum += d[8]; - cksum += d[9]; - - dlen -= 20; /* bytes */ - d += 10; /* short's */ - - while(dlen >=32) - { - cksum += d[0]; - cksum += d[1]; - cksum += d[2]; - cksum += d[3]; - cksum += d[4]; - cksum += d[5]; - cksum += d[6]; - cksum += d[7]; - cksum += d[8]; - cksum += d[9]; - cksum += d[10]; - cksum += d[11]; - cksum += d[12]; - cksum += d[13]; - cksum += d[14]; - cksum += d[15]; - d += 16; - dlen -= 32; - } - - while(dlen >=8) - { - cksum += d[0]; - cksum += d[1]; - cksum += d[2]; - cksum += d[3]; - d += 4; - dlen -= 8; - } - - while(dlen > 1) - { - cksum += *d++; - dlen -= 2; - } - - if( dlen == 1 ) - { - /* printf("new checksum odd byte-packet\n"); */ - *(unsigned char*)(&answer) = (*(unsigned char*)d); - - /* cksum += (uint16_t) (*(uint8_t*)d); */ - - cksum += answer; - } - - cksum = (cksum >> 16) + (cksum & 0x0000ffff); - cksum += (cksum >> 16); - - return (unsigned short)(~cksum); -} - -#endif - //------------------------------------------------------------------------- // api //------------------------------------------------------------------------- diff --git a/src/codecs/ip/cd_udp.cc b/src/codecs/ip/cd_udp.cc index fb6b93c96..deafc055f 100644 --- a/src/codecs/ip/cd_udp.cc +++ b/src/codecs/ip/cd_udp.cc @@ -43,6 +43,7 @@ #include "snort_config.h" #include "parser/config_file.h" #include "codecs/ip/ip_util.h" +#include "main/snort_debug.h" namespace @@ -158,11 +159,7 @@ bool UdpCodec::decode(const uint8_t *raw_pkt, const uint32_t& raw_len, if(raw_len < sizeof(udp::UDPHdr)) { - DEBUG_WRAP(DebugMessage(DEBUG_DECODE, - "Truncated UDP header (%d bytes)\n", raw_len);); - codec_events::decoder_event(p, DECODE_UDP_DGRAM_LT_UDPHDR); - PopUdp(p); return false; } @@ -349,6 +346,7 @@ static inline void UDPMiscTests(Packet *p) */ static inline void PopUdp (Packet* p) { + //FIXIT-J-H // required for detect.c to short-circuit preprocessing if ( !p->dsize ) @@ -382,7 +380,7 @@ typedef struct { -bool UdpCodec::encode (EncState* enc, Buffer* out, const uint8_t* raw_in) +bool UdpCodec::encode(EncState* enc, Buffer* out, const uint8_t* raw_in) { const ip::IpApi* const ip_api = &enc->p->ip_api; diff --git a/src/codecs/link/cd_ppp_encap.cc b/src/codecs/link/cd_ppp_encap.cc index 0e9495095..fa23a11d7 100644 --- a/src/codecs/link/cd_ppp_encap.cc +++ b/src/codecs/link/cd_ppp_encap.cc @@ -28,6 +28,7 @@ #include "protocols/protocol_ids.h" #include "snort.h" #include "codecs/sf_protocols.h" +#include "main/snort_debug.h" namespace { @@ -101,14 +102,7 @@ bool PppEncap::decode(const uint8_t *raw_pkt, const uint32_t& raw_len, * */ if(raw_len < 2) - { - if (ScLogVerbose()) - { - ErrorMessage("Length not big enough for even a single " - "header or a one byte payload\n"); - } return false; - } if(raw_pkt[0] & 0x01) @@ -175,14 +169,10 @@ bool PppEncap::decode(const uint8_t *raw_pkt, const uint32_t& raw_len, //------------------------------------------------------------------------- static Codec* ctor(Module*) -{ - return new PppEncap(); -} +{ return new PppEncap(); } static void dtor(Codec *cd) -{ - delete cd; -} +{ delete cd; } static const CodecApi pppencap_api = { diff --git a/src/codecs/link/cd_pppoe.cc b/src/codecs/link/cd_pppoe.cc index 8e59c6e24..1282e9712 100644 --- a/src/codecs/link/cd_pppoe.cc +++ b/src/codecs/link/cd_pppoe.cc @@ -27,6 +27,7 @@ #include "protocols/packet.h" #include "codecs/sf_protocols.h" #include "protocols/layer.h" +#include "main/snort_debug.h" namespace { @@ -437,9 +438,7 @@ bool PPPoESessCodec::decode(const uint8_t *raw_pkt, const uint32_t& raw_len, bool PPPoESessCodec::encode(EncState *enc, Buffer* out, const uint8_t* raw_in) -{ - return pppoepkt_encode(enc, out, raw_in); -} +{ return pppoepkt_encode(enc, out, raw_in); } //------------------------------------------------------------------------- @@ -448,14 +447,10 @@ bool PPPoESessCodec::encode(EncState *enc, Buffer* out, const uint8_t* raw_in) static Codec* sess_ctor(Module*) -{ - return new PPPoESessCodec(); -} +{ return new PPPoESessCodec(); } static void sess_dtor(Codec *cd) -{ - delete cd; -} +{ delete cd; } static const CodecApi pppoepkt_sess_api = diff --git a/src/codecs/misc/Makefile.am b/src/codecs/misc/Makefile.am index b61583e9d..a3fe55a7c 100644 --- a/src/codecs/misc/Makefile.am +++ b/src/codecs/misc/Makefile.am @@ -32,7 +32,7 @@ libcd_icmp6_ip_la_SOURCES = cd_icmp6_ip.cc ehlib_LTLIBRARIES += libcd_llc.la libcd_llc_la_CXXFLAGS = $(AM_CXXFLAGS) -DBUILDING_SO libcd_llc_la_LDFLAGS = -export-dynamic -shared -libcd_llc_la_SOURCES = libcd_llc.cc +libcd_llc_la_SOURCES = cd_llc.cc ehlib_LTLIBRARIES += libcd_gtp.la libcd_gtp_la_CXXFLAGS = $(AM_CXXFLAGS) -DBUILDING_SO diff --git a/src/codecs/misc/cd_icmp4_ip.cc b/src/codecs/misc/cd_icmp4_ip.cc index e769b4bd9..49da9f925 100644 --- a/src/codecs/misc/cd_icmp4_ip.cc +++ b/src/codecs/misc/cd_icmp4_ip.cc @@ -256,7 +256,7 @@ void Icmp4IpCodec::log(TextLog* const text_log, const uint8_t* raw_pkt, "Ack: 0x%lX Win: 0x%X TcpLen: %d",ntohs(tcph->th_sport), ntohs(tcph->th_dport), (u_long) ntohl(tcph->th_seq), (u_long) ntohl(tcph->th_ack), - ntohs(tcph->th_win), TCP_OFFSET(tcph) << 2); + ntohs(tcph->th_win), tcph->off() << 2); break; } diff --git a/src/codecs/root/cd_null.cc b/src/codecs/root/cd_null.cc index 7853585bd..fce984252 100644 --- a/src/codecs/root/cd_null.cc +++ b/src/codecs/root/cd_null.cc @@ -70,18 +70,9 @@ static const uint16_t NULL_HDRLEN = 4; bool NullCodec::decode(const uint8_t* /*raw_pkt*/, const uint32_t& raw_len, Packet* /*p*/, uint16_t &lyr_len, uint16_t &next_prot_id) { - DEBUG_WRAP(DebugMessage(DEBUG_DECODE, "NULL Packet!\n"); ); - /* do a little validation */ if(raw_len < NULL_HDRLEN) - { - if (ScLogVerbose()) - { - ErrorMessage("NULL header length < captured len! (%d bytes)\n", - raw_len); - } return false; - } lyr_len = NULL_HDRLEN; next_prot_id = ETHERTYPE_IPV4; @@ -98,14 +89,10 @@ void NullCodec::get_data_link_type(std::vector&v) //------------------------------------------------------------------------- static Codec* ctor(Module*) -{ - return new NullCodec(); -} +{ return new NullCodec(); } static void dtor(Codec *cd) -{ - delete cd; -} +{ delete cd; } static const CodecApi null_api = { diff --git a/src/codecs/root/cd_wlan.cc b/src/codecs/root/cd_wlan.cc index eed16656d..7fb9d4232 100644 --- a/src/codecs/root/cd_wlan.cc +++ b/src/codecs/root/cd_wlan.cc @@ -31,12 +31,9 @@ #include "codecs/codec_events.h" #include "protocols/protocol_ids.h" #include "main/snort.h" +#include "log/text_log.h" -#ifdef DEBUG_MSGS -#include "log/log.h" -#endif - namespace { @@ -67,22 +64,9 @@ public: virtual bool decode(const uint8_t *raw_pkt, const uint32_t& raw_len, Packet *, uint16_t &lyr_len, uint16_t &next_prot_id); - virtual void get_data_link_type(std::vector&); - -}; - -struct EthLlc -{ - uint8_t dsap; - uint8_t ssap; -} ; - -struct EthLlcOther -{ - uint8_t ctrl; - uint8_t org_code[3]; - uint16_t proto_id; + virtual void log(TextLog* const, const uint8_t* /*raw_pkt*/, + const Packet* const); }; #define MINIMAL_IEEE80211_HEADER_LEN 10 /* Ack frames and others */ @@ -101,27 +85,13 @@ void WlanCodec::get_data_link_type(std::vector&v) bool WlanCodec::decode(const uint8_t *raw_pkt, const uint32_t &raw_len, Packet*, uint16_t &lyr_len, uint16_t &next_prot_id) { - uint32_t cap_len = raw_len; - // reinterpret the raw data into this codec's data format - - /* do a little validation */ - if(cap_len < MINIMAL_IEEE80211_HEADER_LEN) - { - if (ScLogVerbose()) - { - ErrorMessage("Captured data length < IEEE 802.11 header length! " - "(%d bytes)\n", cap_len); - } - + if(raw_len < MINIMAL_IEEE80211_HEADER_LEN) return false; - } /* lay the wireless structure over the packet data */ const wlan::WifiHdr *wifih = reinterpret_cast(raw_pkt); - DEBUG_WRAP(DebugMessage(DEBUG_DECODE, "%X %X\n", *wifih->addr1, - *wifih->addr2);); /* determine frame type */ switch(wifih->frame_control & 0x00ff) @@ -162,61 +132,7 @@ bool WlanCodec::decode(const uint8_t *raw_pkt, const uint32_t &raw_len, { lyr_len = IEEE802_11_DATA_HDR_LEN; next_prot_id = ETHERNET_LLC; -#if 0 - if(cap_len < IEEE802_11_DATA_HDR_LEN + sizeof(EthLlc)) - { - codec_events::decoder_event(p, DECODE_BAD_80211_ETHLLC); - return false; - } - - const EthLlc *ehllc = reinterpret_cast(raw_pkt + IEEE802_11_DATA_HDR_LEN); - -#ifdef DEBUG_MSGS - LogNetData((uint8_t*) ehllc, sizeof(EthLlc), NULL); - - printf("LLC Header:\n"); - printf(" DSAP: 0x%X\n", ehllc->dsap); - printf(" SSAP: 0x%X\n", ehllc->ssap); -#endif - if(ehllc->dsap == ETH_DSAP_IP && ehllc->ssap == ETH_SSAP_IP) - { - if(cap_len < IEEE802_11_DATA_HDR_LEN + - sizeof(EthLlc) + sizeof(EthLlcOther)) - { - codec_events::decoder_event(p, DECODE_BAD_80211_OTHER); - return false; - } - - const EthLlcOther *ehllcother = reinterpret_cast(raw_pkt + IEEE802_11_DATA_HDR_LEN + sizeof(EthLlc)); -#ifdef DEBUG_MSGS - LogNetData((uint8_t*)ehllcother, sizeof(EthLlcOther), NULL); - - printf("LLC Other Header:\n"); - printf(" CTRL: 0x%X\n", ehllcother->ctrl); - printf(" ORG: 0x%02X%02X%02X\n", ehllcother->org_code[0], - ehllcother->org_code[1], ehllcother->org_code[2]); - printf(" PROTO: 0x%04X\n", ntohs(ehllcother->proto_id)); -#endif - next_prot_id = ntohs(ehllcother->proto_id); - - switch(ntohs(ehllcother->proto_id)) - { - case ETHERTYPE_IPV4: - case ETHERTYPE_ARP: - case ETHERTYPE_REVARP: - case ETHERTYPE_EAPOL: - lyr_len = IEEE802_11_DATA_HDR_LEN + sizeof(EthLlc) + sizeof(EthLlcOther); - - - case ETHERTYPE_8021Q: - case ETHERTYPE_IPV6: - lyr_len = IEEE802_11_DATA_HDR_LEN; - default: - return false; - } - } -#endif break; } default: @@ -226,6 +142,27 @@ bool WlanCodec::decode(const uint8_t *raw_pkt, const uint32_t &raw_len, return true; } +void WlanCodec::log(TextLog* const text_log, const uint8_t* raw_pkt, + const Packet* const) +{ + const wlan::WifiHdr *wifih = reinterpret_cast(raw_pkt); + + /* src addr */ + TextLog_Print(text_log, "addr1(%02X:%02X:%02X:%02X:%02X:%02X) -> ", + wifih->addr1[0], wifih->addr1[1], wifih->addr1[2], + wifih->addr1[3], wifih->addr1[4], wifih->addr1[5]); + + /* dest addr */ + TextLog_Print(text_log, "%02X:%02X:%02X:%02X:%02X:%02X)", + wifih->addr2[0], wifih->addr2[1], wifih->addr2[2], + wifih->addr2[3], wifih->addr2[4], wifih->addr2[5]); + + TextLog_NewLine(text_log); + TextLog_Putc(text_log, '\t'); + TextLog_Print(text_log, "frame_control:%02x duration_id:%02x " + "seq_control:%02x", ntohs(wifih->frame_control), + ntohs(wifih->duration_id), ntohs(wifih->seq_control)); +} //------------------------------------------------------------------------- diff --git a/src/detection/fpdetect.cc b/src/detection/fpdetect.cc index da3a4c82d..354ed6ce2 100644 --- a/src/detection/fpdetect.cc +++ b/src/detection/fpdetect.cc @@ -73,6 +73,7 @@ #include "actions/actions.h" #include "protocols/packet_manager.h" #include "managers/action_manager.h" +#include "sfip/sf_ip.h" /* ** Static function prototypes diff --git a/src/detection/tag.cc b/src/detection/tag.cc index 2e9804d18..50756d837 100644 --- a/src/detection/tag.cc +++ b/src/detection/tag.cc @@ -39,6 +39,7 @@ #include "sfxhash.h" #include "sfip/sfip_t.h" +#include "sfip/sf_ip.h" /* D E F I N E S **************************************************/ #define MAX_TAG_NODES 256 diff --git a/src/file_api/file_resume_block.cc b/src/file_api/file_resume_block.cc index 1b76857af..959cef9a6 100644 --- a/src/file_api/file_resume_block.cc +++ b/src/file_api/file_resume_block.cc @@ -36,6 +36,7 @@ #include "packet_io/active.h" #include "libs/file_sha256.h" #include "managers/action_manager.h" +#include "sfip/sf_ip.h" /* The hash table of expected files */ static THREAD_LOCAL_TBD SFXHASH *fileHash = NULL; diff --git a/src/file_api/libs/file_config.cc b/src/file_api/libs/file_config.cc index 670daa865..1c892b973 100644 --- a/src/file_api/libs/file_config.cc +++ b/src/file_api/libs/file_config.cc @@ -35,10 +35,11 @@ #include #include -#include "snort_types.h" +#include "main/snort_types.h" +#include "main/snort_debug.h" #include "util.h" #include "mstring.h" -#include "parser.h" +#include "parser/parser.h" #include "file_lib.h" #include "file_identifier.h" diff --git a/src/filters/rate_filter.cc b/src/filters/rate_filter.cc index 34e9d5f3b..d3beb2630 100644 --- a/src/filters/rate_filter.cc +++ b/src/filters/rate_filter.cc @@ -46,6 +46,7 @@ #include "sfrf.h" #include "snort.h" #include "sfthd.h" +#include "sfip/sf_ip.h" //static int _printThresholdContext(RateFilterConfig*); diff --git a/src/flow/expect_cache.cc b/src/flow/expect_cache.cc index 7e83bba10..082858a9d 100644 --- a/src/flow/expect_cache.cc +++ b/src/flow/expect_cache.cc @@ -25,6 +25,7 @@ #include "time/packet_time.h" #include "stream/stream_api.h" // FIXIT-M bad dependency #include "zhash.h" +#include "sfip/sf_ip.h" /* Reasonably small, and prime */ // FIXIT-L size based on max_tcp + max_udp? diff --git a/src/flow/flow.cc b/src/flow/flow.cc index 627479077..d2e8db926 100644 --- a/src/flow/flow.cc +++ b/src/flow/flow.cc @@ -31,6 +31,7 @@ #include "utils/bitop_funcs.h" #include "utils/util.h" #include "protocols/packet.h" +#include "sfip/sf_ip.h" unsigned FlowData:: flow_id = 0; diff --git a/src/flow/flow_key.cc b/src/flow/flow_key.cc index 40ba95b07..b3897f8da 100644 --- a/src/flow/flow_key.cc +++ b/src/flow/flow_key.cc @@ -28,6 +28,7 @@ #include "protocols/packet.h" #include "snort.h" #include "utils/util.h" +#include "sfip/sf_ip.h" //------------------------------------------------------------------------- // init foo diff --git a/src/framework/codec.h b/src/framework/codec.h index 21a96e94e..c6c78b313 100644 --- a/src/framework/codec.h +++ b/src/framework/codec.h @@ -31,6 +31,24 @@ struct TextLog; struct Packet; struct Layer; +namespace ip +{ + class IpApi; +} +namespace tcp +{ + struct TCPHdr; +} +namespace udp +{ + struct UDPHdr; +} +namespace icmp +{ + struct ICMPHdr; +} + + enum EncodeType{ ENC_TCP_FIN, ENC_TCP_RST, @@ -100,6 +118,28 @@ static inline bool update_buffer(Buffer* buf, size_t n) } +struct CodecData +{ + /* Convenience Pointers. These will be passed to the rest of Snort++ */ + const tcp::TCPHdr* tcph; + const udp::UDPHdr* udph; + const icmp::ICMPHdr* icmph; + uint16_t sp; /* source port (TCP/UDP) */ + uint16_t dp; /* dest port (TCP/UDP) */ + + /* Flags which will be sent to the rest of Snort++ */ + uint32_t packet_flags; /* TODO: delete */ + uint16_t proto_bits; /* protocols contained within this packet */ + uint8_t error_flags; /* flags indicate checksum errors, bad TTLs, etc. */ + + + uint8_t ip6_frag_index; + uint8_t curr_ip6_extension_order; + uint8_t ip6_extension_count; + uint8_t byte_skip; /* when decoding, there are bytes between the end of the layer and the start of the next layer */ + ip::IpApi* ip_api; +}; + /* Codec Class */ class SO_PUBLIC Codec diff --git a/src/ips_options/ips_fragbits.cc b/src/ips_options/ips_fragbits.cc index 66a4148fa..78e7b91f8 100644 --- a/src/ips_options/ips_fragbits.cc +++ b/src/ips_options/ips_fragbits.cc @@ -156,17 +156,18 @@ int FragBitsOption::eval(Cursor&, Packet *p) return rval; } + const uint16_t frag_offset = ntohs(p->ip_api.off(p)); MODULE_PROFILE_START(fragBitsPerfStats); DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, " CheckFragBits: "); DebugMessage(DEBUG_PLUGIN, "[rule: 0x%X:%d pkt: 0x%X] ", - fb->frag_bits, fb->mode, (p->ip_api.off(p)&bitmask));); + fb->frag_bits, fb->mode, frag_offset & bitmask);); switch(fb->mode) { case FB_NORMAL: /* check if the rule bits match the bits in the packet */ - if(fb->frag_bits == (p->ip_api.off(p)&bitmask)) + if(fb->frag_bits == (frag_offset & bitmask)) { DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"Got Normal bits match\n");); rval = DETECTION_OPTION_MATCH; @@ -179,7 +180,7 @@ int FragBitsOption::eval(Cursor&, Packet *p) case FB_NOT: /* check if the rule bits don't match the bits in the packet */ - if((fb->frag_bits & (p->ip_api.off(p)&bitmask)) == 0) + if((fb->frag_bits & (frag_offset & bitmask)) == 0) { DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"Got NOT bits match\n");); rval = DETECTION_OPTION_MATCH; @@ -192,7 +193,7 @@ int FragBitsOption::eval(Cursor&, Packet *p) case FB_ALL: /* check if the rule bits are present in the packet */ - if((fb->frag_bits & (p->ip_api.off(p)&bitmask)) == fb->frag_bits) + if((fb->frag_bits & (frag_offset & bitmask)) == fb->frag_bits) { DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"Got ALL bits match\n");); rval = DETECTION_OPTION_MATCH; @@ -205,7 +206,7 @@ int FragBitsOption::eval(Cursor&, Packet *p) case FB_ANY: /* check if any of the rule bits match the bits in the packet */ - if((fb->frag_bits & (p->ip_api.off(p)&bitmask)) != 0) + if((fb->frag_bits & (frag_offset & bitmask)) != 0) { DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"Got ANY bits match\n");); rval = DETECTION_OPTION_MATCH; diff --git a/src/ips_options/ips_fragoffset.cc b/src/ips_options/ips_fragoffset.cc index 6b8fc0b13..4077a7a2e 100644 --- a/src/ips_options/ips_fragoffset.cc +++ b/src/ips_options/ips_fragoffset.cc @@ -90,7 +90,7 @@ bool FragOffsetOption::operator==(const IpsOption& ips) const int FragOffsetOption::eval(Cursor&, Packet *p) { - int p_offset = p->frag_offset * 8; + int p_offset = ntohs(p->ip_api.off(p)) * 8; int rval = DETECTION_OPTION_NO_MATCH; PROFILE_VARS; diff --git a/src/ips_options/ips_ipopts.cc b/src/ips_options/ips_ipopts.cc index 95551e96c..006156417 100644 --- a/src/ips_options/ips_ipopts.cc +++ b/src/ips_options/ips_ipopts.cc @@ -31,6 +31,8 @@ #include "snort_types.h" #include "treenodes.h" #include "protocols/packet.h" +#include "protocols/ipv4.h" +#include "protocols/ipv4_options.h" #include "parser.h" #include "snort_debug.h" #include "util.h" @@ -49,7 +51,7 @@ static THREAD_LOCAL ProfileStats ipOptionPerfStats; struct IpOptionData { - u_char ip_option; + ip::IPOptionCodes ip_option; u_char any_flag; }; @@ -82,7 +84,7 @@ uint32_t IpOptOption::hash() const uint32_t a,b,c; const IpOptionData *data = &config; - a = data->ip_option; + a = (uint32_t)data->ip_option; b = data->any_flag; c = 0; @@ -114,17 +116,19 @@ int IpOptOption::eval(Cursor&, Packet *p) { IpOptionData *ipOptionData = &config; int rval = DETECTION_OPTION_NO_MATCH; - int i; PROFILE_VARS; DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "CheckIpOptions:");); - if(!p->ip_api.is_valid()) + if(!p->ip_api.is_ip4()) return rval; /* if error occured while ip header - * was processed, return 0 automagically. */ + * was processed, return 0 automatically. */ MODULE_PROFILE_START(ipOptionPerfStats); - if((ipOptionData->any_flag == 1) && (p->ip_option_count > 0)) + const ip::IP4Hdr* const ip4h = p->ip_api.get_ip4h(); + const uint8_t option_len = ip4h->get_opt_len(); + + if((ipOptionData->any_flag == 1) && (option_len > 0)) { DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Matched any ip options!\n");); rval = DETECTION_OPTION_MATCH; @@ -132,13 +136,14 @@ int IpOptOption::eval(Cursor&, Packet *p) return rval; } - for(i=0; i< (int) p->ip_option_count; i++) + ip::IpOptionIterator iter(ip4h, p); + for( ip::IpOptions opt : iter) { DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "testing pkt(%d):rule(%d)\n", ipOptionData->ip_option, - p->ip_options[i].code); ); + static_cast(opt.code)); ); - if(ipOptionData->ip_option == p->ip_options[i].code) + if(ipOptionData->ip_option == opt.code) { rval = DETECTION_OPTION_MATCH; MODULE_PROFILE_END(ipOptionPerfStats); @@ -159,47 +164,47 @@ static void ipopts_parse(const char* data, IpOptionData* ds_ptr) { if(strcasecmp(data, "rr") == 0) { - ds_ptr->ip_option = IPOPT_RR; + ds_ptr->ip_option = ip::IPOptionCodes::RR; } else if(strcasecmp(data, "eol") == 0) { - ds_ptr->ip_option = IPOPT_EOL; + ds_ptr->ip_option = ip::IPOptionCodes::EOL; } else if(strcasecmp(data, "nop") == 0) { - ds_ptr->ip_option = IPOPT_NOP; + ds_ptr->ip_option = ip::IPOptionCodes::NOP; } else if(strcasecmp(data, "ts") == 0) { - ds_ptr->ip_option = IPOPT_TS; + ds_ptr->ip_option = ip::IPOptionCodes::TS; } else if(strcasecmp(data, "esec") == 0) { - ds_ptr->ip_option = IPOPT_ESEC; + ds_ptr->ip_option = ip::IPOptionCodes::ESEC; } else if(strcasecmp(data, "sec") == 0) { - ds_ptr->ip_option = IPOPT_SECURITY; + ds_ptr->ip_option = ip::IPOptionCodes::SECURITY; } else if(strcasecmp(data, "lsrr") == 0) { - ds_ptr->ip_option = IPOPT_LSRR; + ds_ptr->ip_option = ip::IPOptionCodes::LSRR; } else if(strcasecmp(data, "lsrre") == 0) { - ds_ptr->ip_option = IPOPT_LSRR_E; + ds_ptr->ip_option = ip::IPOptionCodes::LSRR_E; } else if(strcasecmp(data, "satid") == 0) { - ds_ptr->ip_option = IPOPT_SATID; + ds_ptr->ip_option = ip::IPOptionCodes::SATID; } else if(strcasecmp(data, "ssrr") == 0) { - ds_ptr->ip_option = IPOPT_SSRR; + ds_ptr->ip_option = ip::IPOptionCodes::SSRR; } else if(strcasecmp(data, "any") == 0) { - ds_ptr->ip_option = 0; + ds_ptr->ip_option = static_cast(0); ds_ptr->any_flag = 1; } } diff --git a/src/ips_options/ips_session.cc b/src/ips_options/ips_session.cc index 453bde0a1..023bb95a3 100644 --- a/src/ips_options/ips_session.cc +++ b/src/ips_options/ips_session.cc @@ -69,6 +69,7 @@ #include "framework/ips_option.h" #include "framework/parameter.h" #include "framework/module.h" +#include "sfip/sf_ip.h" static const char* s_name = "session"; diff --git a/src/log/log.cc b/src/log/log.cc index 0c5430b14..6bbddccdf 100644 --- a/src/log/log.cc +++ b/src/log/log.cc @@ -39,6 +39,7 @@ using namespace std; #include "main/analyzer.h" #include "snort.h" #include "protocols/tcp.h" +#include "main/snort_debug.h" #define DEFAULT_DAEMON_ALERT_FILE "alert" diff --git a/src/log/log_text.cc b/src/log/log_text.cc index 3e04c1589..f0bbd7df1 100644 --- a/src/log/log_text.cc +++ b/src/log/log_text.cc @@ -65,6 +65,8 @@ #include "protocols/wlan.h" #include "protocols/linux_sll.h" #include "protocols/eapol.h" +#include "protocols/ipv4_options.h" +#include "protocols/tcp_options.h" /*-------------------------------------------------------------------- * utility functions @@ -436,17 +438,18 @@ void Log2ndHeader(TextLog* log, Packet* p) *------------------------------------------------------------------- */ -void LogIpOptions(TextLog* log, const Packet* const p) +void LogIpOptions(TextLog* log, const IP4Hdr* ip4h, const Packet* const p) { - uint8_t i, j; u_long init_offset; u_long print_offset; - const uint8_t option_count = p->ip_option_count; + init_offset = TextLog_Tell(log); - TextLog_Print(log, "IP Options (%d) => ", option_count); + TextLog_Puts(log, "IP Options => "); + + ip::IpOptionIterator options(ip4h, p); - for(i = 0; i < option_count; i++) + for (auto op : options) { print_offset = TextLog_Tell(log); @@ -456,84 +459,67 @@ void LogIpOptions(TextLog* log, const Packet* const p) init_offset = TextLog_Tell(log); } - switch(p->ip_options[i].code) + switch(op.code) { - case IPOPT_RR: + case ip::IPOptionCodes::RR: TextLog_Puts(log, "RR "); break; - case IPOPT_EOL: + case ip::IPOptionCodes::EOL: TextLog_Puts(log, "EOL "); break; - case IPOPT_NOP: + case ip::IPOptionCodes::NOP: TextLog_Puts(log, "NOP "); break; - case IPOPT_TS: + case ip::IPOptionCodes::TS: TextLog_Puts(log, "TS "); break; - case IPOPT_ESEC: + case ip::IPOptionCodes::ESEC: TextLog_Puts(log, "ESEC "); break; - case IPOPT_SECURITY: + case ip::IPOptionCodes::SECURITY: TextLog_Puts(log, "SEC "); break; - case IPOPT_LSRR: - case IPOPT_LSRR_E: + case ip::IPOptionCodes::LSRR: + case ip::IPOptionCodes::LSRR_E: TextLog_Puts(log, "LSRR "); break; - case IPOPT_SATID: + case ip::IPOptionCodes::SATID: TextLog_Puts(log, "SID "); break; - case IPOPT_SSRR: + case ip::IPOptionCodes::SSRR: TextLog_Puts(log, "SSRR "); break; - case IPOPT_RTRALT: + case ip::IPOptionCodes::RTRALT: TextLog_Puts(log, "RTRALT "); break; default: - TextLog_Print(log, "Opt %d: ", p->ip_options[i].code); + TextLog_Print(log, "Opt %d: ", (int)op.code); - const ip::IpOptions* const ip_opt = &(p->ip_options[i]); - const uint8_t opt_len = ip_opt->len; + // the only cases where len is invalid were handled aboved + const uint8_t opt_len = op.len; + int j; - if(opt_len) + for(j = 0; (j + 1) < opt_len; j += 2) { - if (ip_opt->data) - { - for(j = 0; (j + 1) < opt_len; j += 2) - { - TextLog_Print(log, "%02X%02X ",ip_opt->data[j], - ip_opt->data[j+1]); - } - - // since we're skipping by two, if (j+1) == opt_len, - // we will not have printed j - if (j < opt_len) - TextLog_Print(log, "%02X",ip_opt->data[j]); - } - else - { - for(j = 0; (j + 1) < opt_len; j += 2) - { - TextLog_Print(log, "%02X%02X ", 0, 0); - } - - // since we're skipping by two, if (j+1) == opt_len, - // we will not have printed j - if (j < opt_len) - TextLog_Print(log, "%02X",0); - } + TextLog_Print(log, "%02X%02X ",op.data[j], + op.data[j+1]); } - break; + + // since we're skipping by two, if (j+1) == opt_len, + // we will not have printed j + if (j < opt_len) + TextLog_Print(log, "%02X", op.data[j]); + break; } } TextLog_NewLine(log); @@ -631,42 +617,45 @@ void LogIPHeader(TextLog* log, Packet * p) p->ip_api.hlen() << 2, p->ip_api.dgram_len()); + const uint16_t frag_off = ntohs(p->ip_api.off(p)); + /* print the reserved bit if it's set */ - if((uint8_t)((ntohs(p->ip_api.off(p)) & 0x8000) >> 15) == 1) + if(frag_off & 0x8000) TextLog_Puts(log, " RB"); /* printf more frags/don't frag bits */ - if((uint8_t)((ntohs(p->ip_api.off(p)) & 0x4000) >> 14) == 1) + if(frag_off & 0x4000) TextLog_Puts(log, " DF"); - if((uint8_t)((ntohs(p->ip_api.off(p)) & 0x2000) >> 13) == 1) + if(frag_off & 0x2000) TextLog_Puts(log, " MF"); TextLog_NewLine(log); /* print IP options */ - if(p->ip_option_count != 0) + if(p->ip_api.is_ip4()) { - LogIpOptions(log, p); + const ip::IP4Hdr* const ip4h = p->ip_api.get_ip4h(); + + if (ip4h->has_options()) + LogIpOptions(log, ip4h, p); } /* print fragment info if necessary */ if(p->decode_flags & DECODE__FRAG) { TextLog_Print(log, "Frag Offset: 0x%04X Frag Size: 0x%04X\n", - (p->frag_offset & 0x1FFF), + (frag_off & 0x1FFF), p->ip_api.pay_len()); } } static void LogOuterIPHeader(TextLog *log, Packet *p) { - uint8_t save_ip_option_count = p->ip_option_count; uint8_t save_frag_flag = (p->decode_flags & DECODE__FRAG); uint16_t save_sp, save_dp; ip::IpApi save_ip_api = p->ip_api; - p->ip_option_count = 0; p->decode_flags &= ~DECODE__FRAG; if (p->proto_bits & PROTO_BIT__TEREDO) @@ -687,7 +676,6 @@ static void LogOuterIPHeader(TextLog *log, Packet *p) LogIPHeader(log, p); p->ip_api = save_ip_api; - p->ip_option_count = save_ip_option_count; p->decode_flags |= save_frag_flag; } @@ -703,14 +691,12 @@ inline uint32_t extract_32_bits(const uint8_t* const buf) void LogTcpOptions(TextLog* log, const Packet* const p) { - uint8_t i; - int j; - const uint8_t option_count = p->tcp_option_count; - const Options* const opts = p->tcp_options; + tcp::TcpOptIterator opt_iter(p->tcph, p); + - TextLog_Print(log, "TCP Options (%d) => ", option_count); + TextLog_Print(log, "TCP Options =>"); - for(i = 0; i < option_count; i++) + for (const tcp::TcpOption& opt : opt_iter) { #if 0 print_offset = TextLog_Tell(log); @@ -721,53 +707,37 @@ void LogTcpOptions(TextLog* log, const Packet* const p) init_offset = TextLog_Tell(log); } #endif - switch(opts[i].code) + switch(opt.code) { - case TCPOPT_MAXSEG: - { - uint16_t val; - TextLog_Puts(log, "MSS: "); - - if (opts[i].data) - val = extract_16_bits(opts[i].data); - else - val = 0; - - TextLog_Print(log, "%u ", val); - break; - } - case TCPOPT_EOL: - TextLog_Puts(log, "EOL "); + case tcp::TcpOptCode::MAXSEG: + TextLog_Print(log, " MSS: %u", extract_16_bits(opt.data)); break; - case TCPOPT_NOP: - TextLog_Puts(log, "NOP "); + case tcp::TcpOptCode::EOL: + TextLog_Puts(log, " EOL"); break; - case TCPOPT_WSCALE: - { - uint8_t val; - - if (opts[i].data) - val = opts[i].data[0]; - else - val = 0; + case tcp::TcpOptCode::NOP: + TextLog_Puts(log, " NOP"); + break; - TextLog_Print(log, "WS: %u ", val); + case tcp::TcpOptCode::WSCALE: + TextLog_Print(log, " WS: %u", opt.data[0]); break; - } - case TCPOPT_SACK: + + case tcp::TcpOptCode::SACK: { + /* This length was not check during tcp decode */ uint16_t val1, val2; - if (opts[i].data && (opts[i].len >= 4)) + if (opt.len >= 4) { - val1 = extract_16_bits(opts[i].data); - val2 = extract_16_bits(opts[i].data + 2); + val1 = extract_16_bits(opt.data); + val2 = extract_16_bits(opt.data + 2); } - else if (opts[i].data && (opts[i].len >= 2)) + else if (opt.len >= 2) { - val1 = extract_16_bits(opts[i].data); + val1 = extract_16_bits(opt.data); val2 = 0; } else @@ -776,126 +746,59 @@ void LogTcpOptions(TextLog* log, const Packet* const p) val2 = 0; } - TextLog_Print(log, "Sack: %u@%u", val1, val2); + TextLog_Print(log, " Sack: %u@%u", val1, val2); break; } - case TCPOPT_SACKOK: + case tcp::TcpOptCode::SACKOK: TextLog_Puts(log, "SackOK "); break; - case TCPOPT_ECHO: - { - uint32_t val; - - if (opts[i].data) - val = extract_32_bits(opts[i].data); - else - val = 0; - - TextLog_Print(log, "Echo: %u ", val); + case tcp::TcpOptCode::ECHO: + TextLog_Print(log, "Echo: %u", extract_32_bits(opt.data)); break; - } - case TCPOPT_ECHOREPLY: - { - uint32_t val; - - if (opts[i].data) - val = extract_32_bits(opts[i].data); - else - val = 0; - TextLog_Print(log, "Echo Rep: %u ", val); + case tcp::TcpOptCode::ECHOREPLY: + TextLog_Print(log, "Echo Rep: %u", extract_32_bits(opt.data)); break; - } - case TCPOPT_TIMESTAMP: - { - uint32_t val1, val2; - if (opts[i].data) - { - val1 = extract_32_bits(opts[i].data); - val2 = extract_32_bits(opts[i].data + 4); - } - else - { - val1 = 0; - val2 = 0; - } - TextLog_Print(log, "TS: %u %u ", val1, val2); + case tcp::TcpOptCode::TIMESTAMP: + TextLog_Print(log, "TS: %u %u", extract_32_bits(opt.data), opt.data + 4); break; - } - case TCPOPT_CC: - { - uint32_t val; - if (opts[i].data) - val = extract_32_bits(opts[i].data); - else - val = 0; - - TextLog_Print(log, "CC %u ", val); + case tcp::TcpOptCode::CC: + TextLog_Print(log, "CC %u", extract_32_bits(opt.data)); break; - } - case TCPOPT_CC_NEW: - { - uint32_t val; - if (opts[i].data) - val = extract_32_bits(opts[i].data); - else - val = 0; - - TextLog_Print(log, "CCNEW: %u ", val); + case tcp::TcpOptCode::CC_NEW: + TextLog_Print(log, "CCNEW: %u", extract_32_bits(opt.data)); break; - } - case TCPOPT_CC_ECHO: - { - uint32_t val; - if (opts[i].data) - val = extract_32_bits(opts[i].data); - else - val = 0; - - TextLog_Print(log, "CCECHO: %u ", val); + case tcp::TcpOptCode::CC_ECHO: + TextLog_Print(log, "CCECHO: %u", extract_32_bits(opt.data)); break; - } + default: { - const uint8_t opts_len = opts[i].len; + const int opt_len = opt.len - 2; - if(opts_len) + if(opt_len > 0) { - TextLog_Print(log, "Opt %d (%d): ", opts[i].code, - (int) opts_len); + TextLog_Print(log, " Opt %d (%d):", opt.code, + (int) opt_len); - if (opts[i].data) + for (int i = 0; (i + 1) < opt_len; i += 2) { - for(j = 0; (j +1) < opts_len; j += 2) - { - TextLog_Print(log, "%02X%02X ", opts[i].data[j], - opts[i].data[j+1]); - } - - if (j < opts_len) - TextLog_Print(log, "%02x", opts[i].data[j]); - } - else - { - for(j = 0; (j +1) < opts_len; j += 2) - { - TextLog_Print(log, "%02X%02X ", 0, 0); - } - - if (j < opts_len) - TextLog_Print(log, "%02x", 0); + TextLog_Print(log, " %02X%02X", opt.data[i], + opt.data[i+1]); } - TextLog_Putc(log, ' '); + // if there is an odd number of bytes + if (opt_len & 1) + TextLog_Print(log, " %02x", opt.data[opt_len - 1]); } else { - TextLog_Print(log, "Opt %d ", p->tcp_options[i].code); + TextLog_Print(log, " Opt %d", opt.code); } break; } @@ -918,25 +821,26 @@ void LogTcpOptions(TextLog* log, const Packet* const p) void LogTCPHeader(TextLog* log, Packet * p) { char tcpFlags[9]; + const tcp::TCPHdr* tcph = p->tcph; - if(p->tcph == NULL) + if(tcph == NULL) { TextLog_Print(log, "TCP header truncated\n"); return; } /* print TCP flags */ - CreateTCPFlagString(p->tcph, tcpFlags); + CreateTCPFlagString(tcph, tcpFlags); TextLog_Puts(log, tcpFlags); /* We don't care about the NULL */ /* print other TCP info */ TextLog_Print(log, " Seq: 0x%lX Ack: 0x%lX Win: 0x%X TcpLen: %d", - (u_long) ntohl(p->tcph->th_seq), - (u_long) ntohl(p->tcph->th_ack), - ntohs(p->tcph->th_win), TCP_OFFSET(p->tcph) << 2); + (u_long) ntohl(tcph->th_seq), + (u_long) ntohl(tcph->th_ack), + ntohs(tcph->th_win), tcph->off() << 2); - if((p->tcph->th_flags & TH_URG) != 0) + if((tcph->th_flags & TH_URG) != 0) { - TextLog_Print(log, " UrgPtr: 0x%X\n", (uint16_t) ntohs(p->tcph->th_urp)); + TextLog_Print(log, " UrgPtr: 0x%X\n", (uint16_t) ntohs(tcph->th_urp)); } else { @@ -944,7 +848,7 @@ void LogTCPHeader(TextLog* log, Packet * p) } /* dump the TCP options */ - if(p->tcp_option_count != 0) + if(tcph->has_options()) { LogTcpOptions(log, p); } diff --git a/src/log/log_text.h b/src/log/log_text.h index 71ae30557..91eac5ea5 100644 --- a/src/log/log_text.h +++ b/src/log/log_text.h @@ -44,6 +44,12 @@ struct Packet; struct Event; +namespace ip +{ +struct IP4Hdr; +} +typedef ip::IP4Hdr IP4Hdr; + void LogPriorityData(TextLog*, const Event*, bool doNewLine); void LogXrefs(TextLog*, const Event*, bool doNewLine); @@ -54,7 +60,7 @@ void LogTimeStamp(TextLog*, Packet*); void LogTrHeader(TextLog*, Packet*); void Log2ndHeader(TextLog*, Packet*); void LogIpAddrs(TextLog*, Packet*); -SO_PUBLIC void LogIpOptions(TextLog*, const Packet* const); +void SO_PUBLIC LogIpOptions(TextLog*, const IP4Hdr*, const Packet* const); void LogIPHeader(TextLog*, Packet*); void LogTCPHeader(TextLog*, Packet*); SO_PUBLIC void LogTcpOptions(TextLog*, const Packet* const); diff --git a/src/log/messages.cc b/src/log/messages.cc index bf5a1c2a0..33a5ffaff 100644 --- a/src/log/messages.cc +++ b/src/log/messages.cc @@ -48,6 +48,8 @@ #include "main/snort_config.h" #include "packet_io/sfdaq.h" #include "time/packet_time.h" +#include "main/snort_debug.h" +#include "sfip/sf_ip.h" static int already_fatal = 0; diff --git a/src/loggers/Makefile.am b/src/loggers/Makefile.am index d3ac06cf7..b3b1d1bb5 100644 --- a/src/loggers/Makefile.am +++ b/src/loggers/Makefile.am @@ -3,6 +3,7 @@ AUTOMAKE_OPTIONS=foreign no-dependencies noinst_LIBRARIES = libloggers.a libloggers_a_SOURCES = \ alert_luajit.cc \ +log_codecs.cc \ loggers.cc \ loggers.h diff --git a/src/loggers/alert_csv.cc b/src/loggers/alert_csv.cc index 74b2fa3b9..e4983caf9 100644 --- a/src/loggers/alert_csv.cc +++ b/src/loggers/alert_csv.cc @@ -372,7 +372,7 @@ void CsvLogger::alert(Packet *p, const char *msg, Event *event) else if (!strcasecmp("tcp_len", type)) { if (p->tcph != NULL) - TextLog_Print(csv_log, "%d", TCP_OFFSET(p->tcph) << 2); + TextLog_Print(csv_log, "%d", (p->tcph->off()) << 2); } else if (!strcasecmp("tcp_win", type)) { diff --git a/src/loggers/log_codecs.cc b/src/loggers/log_codecs.cc index 650f97f10..6fdb167b7 100644 --- a/src/loggers/log_codecs.cc +++ b/src/loggers/log_codecs.cc @@ -199,4 +199,4 @@ static const LogApi log_codecs_api = }; -const BaseApi* eh_codecs = &log_codecs_api.base; +const BaseApi* log_codecs = &log_codecs_api.base; diff --git a/src/loggers/loggers.cc b/src/loggers/loggers.cc index ad0c37283..dda8a989a 100644 --- a/src/loggers/loggers.cc +++ b/src/loggers/loggers.cc @@ -27,7 +27,7 @@ #include "framework/logger.h" // to ensure PacketManager::log_protocols() is built into Snort++ -extern const BaseApi* eh_codecs; +extern const BaseApi* log_codecs; extern const BaseApi* log_luajit; #ifdef LINUX @@ -68,8 +68,8 @@ const BaseApi* loggers[] = eh_unified2, #endif // loggers + log_codecs, log_luajit, // both - eh_codecs, nullptr }; diff --git a/src/main/modules.cc b/src/main/modules.cc index 4b1f7e829..dd7f403c1 100644 --- a/src/main/modules.cc +++ b/src/main/modules.cc @@ -54,6 +54,7 @@ using namespace std; #include "detection/fpcreate.h" #include "filters/detection_filter.h" #include "filters/sfthreshold.h" +#include "sfip/sf_ip.h" #if defined(DEBUG_MSGS) || defined (REG_TEST) #include "file_api/file_api.h" diff --git a/src/network_inspectors/arp_spoof/arp_spoof.cc b/src/network_inspectors/arp_spoof/arp_spoof.cc index ef38581d8..9b3e8b982 100644 --- a/src/network_inspectors/arp_spoof/arp_spoof.cc +++ b/src/network_inspectors/arp_spoof/arp_spoof.cc @@ -93,6 +93,7 @@ #include "framework/inspector.h" #include "protocols/layer.h" #include "protocols/arp.h" +#include "sfip/sf_ip.h" static const uint8_t bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; diff --git a/src/network_inspectors/normalize/norm.cc b/src/network_inspectors/normalize/norm.cc index c6b1d1a0e..4b95f2f54 100644 --- a/src/network_inspectors/normalize/norm.cc +++ b/src/network_inspectors/normalize/norm.cc @@ -32,7 +32,9 @@ #include "perf_monitor/perf.h" #include "packet_io/sfdaq.h" #include "protocols/ipv4.h" +#include "protocols/ipv4_options.h" #include "protocols/tcp.h" +#include "protocols/tcp_options.h" #include "stream/stream.h" typedef enum { @@ -226,7 +228,7 @@ static int Norm_IP4 ( uint8_t* opts = const_cast(p->layers[layer].start) + ip::IP4_HEADER_LEN; uint8_t len = p->layers[layer].length - ip::IP4_HEADER_LEN; // expect len > 0 because IHL yields a multiple of 4 - memset(opts, IPOPT_NOP, len); + memset(opts, static_cast(ip::IPOptionCodes::NOP), len); normStats[PC_IP4_OPTS]++; sfBase.iPegs[PERF_COUNT_IP4_OPTS]++; changes++; @@ -337,7 +339,7 @@ static int Norm_UDP (Packet * p, uint8_t layer, int changes) static inline void NopDaOpt (uint8_t* opt, uint8_t len) { - memset(opt, TCPOPT_NOP, len); + memset(opt, (uint8_t)tcp::TcpOptCode::NOP , len); } #define TS_ECR_OFFSET 6 @@ -345,13 +347,13 @@ static inline void NopDaOpt (uint8_t* opt, uint8_t len) static inline int Norm_TCPOptions ( NormalizerConfig* config, - uint8_t* opts, size_t len, const tcp::TCPHdr* h, uint8_t numOpts, int changes) + uint8_t* opts, size_t len, const tcp::TCPHdr* h, uint8_t validated_len, int changes) { size_t i = 0; - uint8_t c = 0; - while ( (i < len) && (opts[i] != TCPOPT_EOL) && - (c++ < numOpts) ) + while ( (i < len) && + (opts[i] != (uint8_t)tcp::TcpOptCode::EOL) && + (i < validated_len) ) { uint8_t olen = ( opts[i] <= 1 ) ? 1 : opts[i+1]; @@ -361,13 +363,13 @@ static inline int Norm_TCPOptions ( if ( i + olen > len) break; - switch ( opts[i] ) + switch ( static_cast(opts[i]) ) { - case TCPOPT_NOP: + case tcp::TcpOptCode::NOP: break; - case TCPOPT_MAXSEG: - case TCPOPT_WSCALE: + case tcp::TcpOptCode::MAXSEG: + case tcp::TcpOptCode::WSCALE: if ( !(h->th_flags & TH_SYN) ) { NopDaOpt(opts+i, olen); @@ -377,7 +379,7 @@ static inline int Norm_TCPOptions ( } break; - case TCPOPT_TIMESTAMP: + case tcp::TcpOptCode::TIMESTAMP: if ( !(h->th_flags & TH_ACK) && // use memcmp because opts have arbitrary alignment memcmp(opts+i+TS_ECR_OFFSET, MAX_EOL_PAD, TS_ECR_LENGTH) ) @@ -412,12 +414,13 @@ static inline int Norm_TCPOptions ( } static inline int Norm_TCPPadding ( - uint8_t* opts, size_t len, uint8_t numOpts, int changes) + uint8_t* opts, size_t len, uint8_t validated_len, int changes) { size_t i = 0; - uint8_t c = 0; - while ( (i < len) && (opts[i] != TCPOPT_EOL) && (c++ < numOpts) ) + while ( (i < len) && + (opts[i] != (uint8_t)tcp::TcpOptCode::EOL) && + (i < validated_len) ) { i += ( opts[i] <= 1 ) ? 1 : opts[i+1]; } @@ -496,20 +499,24 @@ static int Norm_TCP ( changes++; } - uint8_t tcp_options_len = p->tcph->options_len(); + uint8_t tcp_options_len = h->options_len(); + if ( tcp_options_len > 0 ) { - uint8_t* opts = const_cast(p->layers[layer].start) + tcp::TCP_HEADER_LEN; + const Layer& lyr = p->layers[layer]; + uint8_t* opts = const_cast(lyr.start) + tcp::TCP_HEADER_LEN; + // lyr.length only includes valid tcp options + uint8_t valid_opts_len = lyr.length - tcp::TCP_HEADER_LEN; if ( Norm_IsEnabled(c, NORM_TCP_OPT) ) { changes = Norm_TCPOptions(c, opts, tcp_options_len, - h, p->tcp_option_count, changes); + h, valid_opts_len, changes); } else { changes = Norm_TCPPadding(opts, tcp_options_len, - p->tcp_option_count, changes); + valid_opts_len, changes); } } return changes; diff --git a/src/network_inspectors/perf_monitor/perf_flow.cc b/src/network_inspectors/perf_monitor/perf_flow.cc index 12718b300..9fdd26969 100644 --- a/src/network_inspectors/perf_monitor/perf_flow.cc +++ b/src/network_inspectors/perf_monitor/perf_flow.cc @@ -57,6 +57,7 @@ #include "util.h" #include "snort_types.h" #include "perf.h" +#include "sfip/sf_ip.h" static void DisplayFlowStats(SFFLOW_STATS *sfFlowStats); static void WriteFlowStats(SFFLOW_STATS *, FILE *); diff --git a/src/network_inspectors/port_scan/ps_detect.cc b/src/network_inspectors/port_scan/ps_detect.cc index 695b0cdab..00242c301 100644 --- a/src/network_inspectors/port_scan/ps_detect.cc +++ b/src/network_inspectors/port_scan/ps_detect.cc @@ -115,6 +115,7 @@ #include "sfxhash.h" #include "ipobj.h" #include "stream/stream_api.h" +#include "sfip/sf_ip.h" typedef struct s_PS_HASH_KEY { diff --git a/src/packet_io/intf.cc b/src/packet_io/intf.cc index 2898463c0..415aea9b5 100644 --- a/src/packet_io/intf.cc +++ b/src/packet_io/intf.cc @@ -27,6 +27,7 @@ #include "snort_debug.h" #include "snort.h" #include "utils/util.h" +#include "sfip/sf_ip.h" //------------------------------------------------------------------------------ // interface stuff diff --git a/src/parser/config_file.cc b/src/parser/config_file.cc index 2939bed45..93f40dd11 100644 --- a/src/parser/config_file.cc +++ b/src/parser/config_file.cc @@ -55,6 +55,7 @@ #include "target_based/sftarget_reader.h" #include "managers/event_manager.h" #include "detection/detect.h" +#include "sfip/sf_ip.h" #define LOG_NONE "none" #define LOG_TEXT "text" diff --git a/src/parser/parse_byte_code.cc b/src/parser/parse_byte_code.cc index 535f445e5..3ac9f0e48 100644 --- a/src/parser/parse_byte_code.cc +++ b/src/parser/parse_byte_code.cc @@ -46,8 +46,8 @@ bool parse_byte_code(const char* in, bool& negate, std::string& out) unsigned idx = 0, len = strlen(in); negate = false; - uint8_t hex; - unsigned nx; + uint8_t hex = 0; + unsigned nx = 0; bool ok = true; while ( ok && (idx < len) ) diff --git a/src/protocols/CMakeLists.txt b/src/protocols/CMakeLists.txt index f01b188b0..766fa998d 100644 --- a/src/protocols/CMakeLists.txt +++ b/src/protocols/CMakeLists.txt @@ -7,6 +7,7 @@ set (PROTOCOL_HEADERS icmp6.h ip.h ipv4.h + ipv4_options.h ipv6.h gre.h layer.h @@ -16,6 +17,7 @@ set (PROTOCOL_HEADERS packet_manager.h protocol_ids.h tcp.h + tcp_options.h teredo.h token_ring.h udp.h @@ -27,6 +29,8 @@ add_library (protocols STATIC ${PROTOCOL_HEADERS} layer.cc ip.cc + ipv4_options.cc + tcp_options.cc packet_manager.cc ) diff --git a/src/protocols/Makefile.am b/src/protocols/Makefile.am index 5cb15db0b..4baa722c5 100644 --- a/src/protocols/Makefile.am +++ b/src/protocols/Makefile.am @@ -12,6 +12,7 @@ icmp4.h \ icmp6.h \ ip.h \ ipv4.h \ +ipv4_options.h \ ipv6.h \ gre.h \ layer.h \ @@ -20,6 +21,7 @@ packet.h \ packet_manager.h \ protocol_ids.h \ tcp.h \ +tcp_options.h \ teredo.h \ token_ring.h \ udp.h \ @@ -29,7 +31,9 @@ wlan.h libprotocols_a_SOURCES = \ layer.cc \ packet_manager.cc \ -ip.cc +ip.cc \ +ipv4_options.cc \ +tcp_options.cc AM_CXXFLAGS = @AM_CXXFLAGS@ diff --git a/src/protocols/ip.cc b/src/protocols/ip.cc index 61dbffb05..581e1bf0d 100644 --- a/src/protocols/ip.cc +++ b/src/protocols/ip.cc @@ -20,6 +20,7 @@ // ip.cc author Josh Rosenbaum #include +#include #include "protocols/ip.h" #include "protocols/packet.h" @@ -38,16 +39,34 @@ void IpApi::set(const IP4Hdr* h4) { ip4h = h4; ip6h = nullptr; - src_p = nullptr; - dst_p = nullptr; + + src.family = AF_INET; + src.bits = 32; + src.ip32[0] = *(uint32_t*)(&ip4h->ip_src); + std::memset(&(src.ip32[1]), 0, 12); + src_p = &src; + + dst.family = AF_INET; + dst.bits = 32; + dst.ip32[0] = *(uint32_t*)(&ip4h->ip_dst); + std::memset(&(dst.ip32[1]), 0, 12); + dst_p = &dst; } void IpApi::set(const ip::IP6Hdr* h6) { ip6h = h6; ip4h = nullptr; - src_p = nullptr; - dst_p = nullptr; + + src.family = AF_INET6; + src.bits = 128; + std::memcpy(&(src.ip8), &(ip6h->ip6_src), 16); + src_p = &src; + + dst.family = AF_INET6; + dst.bits = 128; + std::memcpy(&(dst.ip8), &(ip6h->ip6_dst), 16); + dst_p = &dst; } bool IpApi::set(const uint8_t* raw_ip_data) @@ -59,77 +78,15 @@ bool IpApi::set(const uint8_t* raw_ip_data) return true; } - const ip::IP6Hdr* h6 = - reinterpret_cast(raw_ip_data); - - if (h6->get_ver() != 6) - return false; - - set(h6); - return true; -} - -const sfip_t *IpApi::get_src() -{ - if (src_p) - return src_p; - - if(ip4h) - { - src.family = AF_INET; - src.bits = 32; - - // TODO: Make this a pointer rather than copying - // will likely need to change Snort++ - src.ip32[0] = *(uint32_t*)(&ip4h->ip_src); - std::memset(&(src.ip32[1]), 0, 12); - } - else if (ip6h) - { - src.family = AF_INET6; - src.bits = 128; - - std::memcpy(&(src.ip8), &(ip6h->ip6_src), 16); - } - else - { - return nullptr; - } + const IP6Hdr* h6 = reinterpret_cast(raw_ip_data); - src_p = &src; - return src_p; -} - - -const sfip_t *IpApi::get_dst() -{ - if (dst_p) - return dst_p; - - if(ip4h) - { - dst.family = AF_INET; - dst.bits = 32; - - // TODO: Make this a pointer rather than copying - // will likely need to change Snort++ - dst.ip32[0] = *(uint32_t*)(&ip4h->ip_dst); - std::memset(&(dst.ip32[1]), 0, 12); - } - else if (ip6h) - { - dst.family = AF_INET6; - dst.bits = 128; - std::memcpy(&(dst.ip8), &(ip6h->ip6_dst), 16); - } - else + if (h6->get_ver() == 6) { - return nullptr; + set(h6); + return true; } - dst_p = &dst; - return dst_p; - + return false; } uint32_t IpApi::id(const Packet* const p) const @@ -138,7 +95,7 @@ uint32_t IpApi::id(const Packet* const p) const return ip4h->get_id(); // ensure we have an ipv6 frag - if (p->ip6_extension_count == 0 || p->ip_frag_start == 0 || !ip6h ) + if (!ip6h || p->ip6_frag_index == std::numeric_limits::max()) return 0; const IP6Frag* const frag_hdr = reinterpret_cast( @@ -150,10 +107,10 @@ uint32_t IpApi::id(const Packet* const p) const uint16_t IpApi::off(const Packet* const p) const { if (ip4h) - return (uint32_t)ip4h->get_id(); + return (uint32_t)ip4h->get_off(); // ensure we have an ipv6 frag - if (p->ip6_extension_count == 0 || p->ip_frag_start == 0 || !ip6h) + if (!ip6h || p->ip6_frag_index == std::numeric_limits::max()) return 0; const IP6Frag* const frag_hdr = reinterpret_cast( diff --git a/src/protocols/ip.h b/src/protocols/ip.h index 832b7ef0a..ad0f19747 100644 --- a/src/protocols/ip.h +++ b/src/protocols/ip.h @@ -60,8 +60,6 @@ public: void set(const IP6Hdr* h6); bool set(const uint8_t* raw_ip_data); void reset(); - const sfip_t *get_src(); - const sfip_t *get_dst(); uint32_t id(const Packet* const p) const; uint16_t off(const Packet* const p) const; // returns a pointer to this ip layer's data @@ -97,6 +95,12 @@ public: inline const IP6Hdr* get_ip6h() const { return ip6h; } + inline const sfip_t *get_src() const + { return src_p; } + + inline const sfip_t *get_dst() const + { return dst_p; } + inline uint16_t tos() const { return ip4h ? ip4h->get_tos() : ip6h ? ip6h->get_tos() : 0; } diff --git a/src/protocols/ipv4.h b/src/protocols/ipv4.h index 3fa7a08f7..7691be562 100644 --- a/src/protocols/ipv4.h +++ b/src/protocols/ipv4.h @@ -39,8 +39,6 @@ #include "protocols/protocol_ids.h" // include ipv4 protocol numbers - - #define ETHERNET_TYPE_IP 0x0800 #ifndef IP_MAXPACKET @@ -59,38 +57,6 @@ constexpr uint8_t IP4_RESERVED = 0x0F; // ms nibble constexpr uint8_t IP4_LOOPBACK = 0x7F; // msb -enum class IPOptionCodes : std::uint8_t { - EOL = 0x00, - NOP = 0x01, - RR = 0x07, - TS = 0x44, - SECURITY = 0x82, - LSRR = 0x83, - LSRR_E = 0x84, - ESEC = 0x85, - SATID = 0x88, - SSRR = 0x89, - RTRALT = 0x94, - ANY = 0xff, -}; - - -struct IpOptions -{ - uint8_t code; - uint8_t len; /* length of the data section */ - const uint8_t *data; - - inline bool is_opt_rtralt() const - { return code == static_cast(IPOptionCodes::RTRALT); } - - inline bool is_opt_ts() const - { return code == static_cast(IPOptionCodes::TS); } - - inline bool is_opt_rr() const - { return code == static_cast(IPOptionCodes::RR); } -}; - // This must be a standard layour struct! struct IP4Hdr @@ -150,6 +116,9 @@ struct IP4Hdr inline bool is_dst_broadcast() const { return ip_dst == IP4_BROADCAST; } + inline bool has_options() const + { return get_hlen() > 5; } + /* setters */ inline void set_hlen(uint8_t value) { ip_verhl = (ip_verhl & 0xf0) | (value & 0x0f); } @@ -162,6 +131,7 @@ struct IP4Hdr } ; + static inline bool isPrivateIP(uint32_t addr) { switch (addr & 0xff) @@ -184,27 +154,15 @@ static inline bool isPrivateIP(uint32_t addr) } /* namespace ip */ + + /* tcpdump shows us the way to cross platform compatibility */ /* we need to change them as well as get them */ // TYPEDEF WHICH NEED TO BE DELETED - typedef ip::IP4Hdr IP4Hdr; -constexpr uint8_t IPOPT_EOL = 0x00; -constexpr uint8_t IPOPT_NOP = 0x01; -constexpr uint8_t IPOPT_RR = 0x07; -constexpr uint8_t IPOPT_TS = 0x44; -constexpr uint8_t IPOPT_SECURITY = 0x82; -constexpr uint8_t IPOPT_LSRR = 0x83; -constexpr uint8_t IPOPT_LSRR_E = 0x84; -constexpr uint8_t IPOPT_ESEC = 0x85; -constexpr uint8_t IPOPT_SATID = 0x88; -constexpr uint8_t IPOPT_SSRR = 0x89; -constexpr uint8_t IPOPT_RTRALT = 0x94; -constexpr uint8_t IPOPT_ANY = 0xff; - /* #define IP_HEADER_LEN ip::ip4_hdr_len() */ diff --git a/src/protocols/ipv4_options.cc b/src/protocols/ipv4_options.cc new file mode 100644 index 000000000..b57b2263c --- /dev/null +++ b/src/protocols/ipv4_options.cc @@ -0,0 +1,80 @@ +/* +** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. +** Copyright (C) 2007-2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +// ipv4_options.cc author Josh Rosenbaum + +#include "protocols/ipv4_options.h" +#include "protocols/ipv4.h" +#include "protocols/layer.h" +#include "protocols/packet.h" + +namespace ip +{ + + +IpOptionIteratorIter::IpOptionIteratorIter(const IpOptions* first_opt) : opt(first_opt) +{ } + +const IpOptions& IpOptionIteratorIter::operator* () const +{ return *opt; } + + +IpOptionIterator::IpOptionIterator(const IP4Hdr* const ip4_header, const Packet* const p) +{ + const uint8_t* const hdr = (const uint8_t* const)ip4_header; + start_ptr = hdr + IP4_HEADER_LEN; + end_ptr = start_ptr; + + for (int i = p->num_layers-1; i >= 0; --i) + { + if (p->layers[i].start == (const uint8_t*)ip4_header) + { + // the Options do not necessarily include + // the entire header + end_ptr = (hdr + p->layers[i].length); + return; + } + } +} + + + +IpOptionIterator::IpOptionIterator(const IP4Hdr* const ip4_header, const uint8_t valid_hdr_len) +{ + const uint8_t* const hdr = (const uint8_t* const)ip4_header; + start_ptr = hdr + IP4_HEADER_LEN; + + if (valid_hdr_len < IP4_HEADER_LEN) + end_ptr = start_ptr; + else + end_ptr = hdr + valid_hdr_len; +} + +IpOptionIteratorIter IpOptionIterator::begin() const +{ + return IpOptionIteratorIter(reinterpret_cast(start_ptr)); +} + +IpOptionIteratorIter IpOptionIterator::end() const +{ + return IpOptionIteratorIter(reinterpret_cast(end_ptr)); +} + + +} // namespace ip diff --git a/src/protocols/ipv4_options.h b/src/protocols/ipv4_options.h new file mode 100644 index 000000000..3ddd4c2cd --- /dev/null +++ b/src/protocols/ipv4_options.h @@ -0,0 +1,147 @@ +/* +** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. +** Copyright (C) 2007-2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +// ipv4_options.H author Josh Rosenbaum + +#ifndef PROTOCOLS_IP_OPTIONS_H +#define PROTOCOLS_IP_OPTIONS_H + +#include + +struct Packet; + + +namespace ip +{ + +struct IP4Hdr; + +enum class IPOptionCodes : std::uint8_t { + EOL = 0x00, + NOP = 0x01, + RR = 0x07, + TS = 0x44, + SECURITY = 0x82, + LSRR = 0x83, + LSRR_E = 0x84, + ESEC = 0x85, + SATID = 0x88, + SSRR = 0x89, + RTRALT = 0x94, + ANY = 0xff, +}; + + +struct IpOptions +{ + IPOptionCodes code; + uint8_t len; + uint8_t data[6]; // arbitrary number. choosing six to align with 64 bits + + inline uint8_t get_len() const + { return ((uint8_t)code <= 1) ? 1 : len; } + + inline const uint8_t* get_data() const + { return (((uint8_t)code <= 1) || (len < 2)) ? nullptr : &data[0]; } + + inline const IpOptions& next() const + { + + // because gcc requires strict aliasing. +# if defined(__GNUC__) + const uint8_t tmp_len = ((uint8_t) code <= 1) ? 1 : len; + const uint8_t* const tmp = reinterpret_cast(this); + const IpOptions* opt = reinterpret_cast(&tmp[tmp_len]); + return *opt; + + // ... and the legible code +# else + if ( (uint8_t)code <= 1 ) + return reinterpret_cast(len); + else + return reinterpret_cast(data[len -2]); +# endif + } +}; + +/* + * relly creative name ... right + * Use IpOptionIter ... this is the placehold + */ +class IpOptionIteratorIter +{ +public: + IpOptionIteratorIter(const IpOptions*); + + bool operator== (const IpOptionIteratorIter& rhs) + { return opt == rhs.opt; } + + bool operator!= (const IpOptionIteratorIter& rhs) + { return opt != rhs.opt; } + + // I'd suggest just using IpOptionIterator and completley ignoring this + // horror of a ++ operation. + IpOptionIteratorIter& operator++() + { + opt = &opt->next(); + return *this; + } + + const IpOptions& operator* () const; + +private: + const IpOptions* opt; +}; + +/* + * relly creative name ... right + * Use IP ranged for loop rather than calling this directly. + * i.e., + * IpOptionIter iter(ip4h, p) + * for (auto i : iter) + * { + * do_something + * } + */ +class IpOptionIterator +{ +public: + /* CONSTRUCTOR VALID AFTER DECODE() + * Some options in the provided header may not be valid. + * Provide the packet struct ensures only valid options + * will be returned + */ + IpOptionIterator(const IP4Hdr* const, const Packet* const); + /* If you already know the validated option length (for instance, + * if you are in a decode() method), then call this constructor. + * You MUST validate the a;; ip_options within len before + * using this constuctor*/ + IpOptionIterator(const IP4Hdr* const, const uint8_t valid_hdr_len); + IpOptionIteratorIter begin() const; + IpOptionIteratorIter end() const; + +private: + const uint8_t* end_ptr; + const uint8_t* start_ptr; +}; + +} // namespace ip + + +#endif /* PROTOCOLS_IP_OPTIONS_H */ diff --git a/src/protocols/layer.cc b/src/protocols/layer.cc index 589306a13..6f42a14cf 100644 --- a/src/protocols/layer.cc +++ b/src/protocols/layer.cc @@ -158,7 +158,6 @@ const uint8_t* get_root_layer(const Packet* const p) return nullptr; } - uint8_t get_outer_ip_next_pro(const Packet* const p) { const Layer* layers = p->layers; @@ -170,7 +169,7 @@ uint8_t get_outer_ip_next_pro(const Packet* const p) { case ETHERTYPE_IPV4: case IPPROTO_ID_IPIP: - return reinterpret_cast(layers[i].start)->get_proto(); + return reinterpret_cast(layers[i].start)->get_proto(); case ETHERTYPE_IPV6: case IPPROTO_ID_IPV6: return reinterpret_cast(layers[i].start)->get_next(); @@ -181,7 +180,7 @@ uint8_t get_outer_ip_next_pro(const Packet* const p) return -1; } -int get_inner_ip_lyr(const Packet* const p) +int get_inner_ip_lyr_index(const Packet* const p) { const Layer* layers = p->layers; diff --git a/src/protocols/layer.h b/src/protocols/layer.h index 5cb5071b4..f8f125bd8 100644 --- a/src/protocols/layer.h +++ b/src/protocols/layer.h @@ -28,10 +28,22 @@ struct Layer { + const uint8_t* start; uint16_t prot_id; - PROTO_ID proto; uint16_t length; - const uint8_t* start; +// uint16_t invalid_bytes; -- Commented out since nothing uses this + /* + * Data which should not be considered part of + * this layer's valid data, but must be skipped + * before the next layer. For instance, an invalid + * ip option. It should not be part of length but + * must be skipped before the next layer. + * + * Generally calculated by + * (layers_entire_length) - length; + * (ip::IP4Hdr*) ip4h->get_hlen() * 4 - length; + */ + PROTO_ID proto; }; @@ -102,6 +114,9 @@ SO_PUBLIC const eth::EtherHdr* get_eth_layer(const Packet*); SO_PUBLIC const uint8_t* get_root_layer(const Packet* const); /* return a pointer to the outermost UDP layer */ SO_PUBLIC const udp::UDPHdr* get_outer_udp_lyr(const Packet* const); +// return the inner ip layer's index in the p->layers array +SO_PUBLIC int get_inner_ip_lyr_index(const Packet* const p); + // ICMP with Embedded IP layer @@ -113,7 +128,6 @@ SO_PUBLIC const udp::UDPHdr* get_outer_udp_lyr(const Packet* const); // true - ip layer found and api set // false - ip layer NOT found, api reset SO_PUBLIC bool set_api_ip_embed_icmp(const Packet*, ip::IpApi& api); - // a helper function when the api to be set is inside the packet SO_PUBLIC bool set_api_ip_embed_icmp(const Packet* p); @@ -126,11 +140,6 @@ SO_PUBLIC bool set_api_ip_embed_icmp(const Packet* p); SO_PUBLIC const tcp::TCPHdr* get_tcp_embed_icmp(const ip::IpApi&); SO_PUBLIC const udp::UDPHdr* get_udp_embed_icmp(const ip::IpApi&); SO_PUBLIC const icmp::ICMPHdr* get_icmp_embed_icmp(const ip::IpApi&); - - - -SO_PUBLIC int get_inner_ip_lyr(const Packet* const p); - /* * Starting from layer 'curr_layer', continuing looking at increasingly * outermost layer for another IP protocol. If an IP protocol is found, diff --git a/src/protocols/packet.h b/src/protocols/packet.h index 281366b02..44a6c1923 100644 --- a/src/protocols/packet.h +++ b/src/protocols/packet.h @@ -47,7 +47,6 @@ extern "C" { } #include "main/snort_types.h" -#include "sfip/sf_ip.h" #include "protocols/tcp.h" @@ -162,15 +161,6 @@ constexpr uint8_t LAYER_MAX = 32; class Flow; -struct Options -{ - uint8_t code; - uint8_t len; /* length of the data section */ - const uint8_t *data; -} ; - - - struct Packet { @@ -194,17 +184,6 @@ struct Packet uint16_t sp; /* source port (TCP/UDP) */ uint16_t dp; /* dest port (TCP/UDP) */ - - uint16_t frag_offset; /* fragment offset number */ - uint16_t ip_frag_len; - - - - uint8_t ip_option_count; /* number of options in this packet */ - uint8_t tcp_option_count; - uint8_t ip6_extension_count; - uint8_t ip6_frag_index; - uint8_t error_flags; /* flags indicate checksum errors, bad TTLs, etc. */ uint8_t num_layers; /* index into layers for next encap */ uint8_t decode_flags; /* flags used while decoding */ @@ -218,12 +197,11 @@ struct Packet const uint8_t* data; /* packet payload pointer */ uint16_t dsize; /* packet payload size */ - ip::IpOptions ip_options[IP_OPTMAX]; /* ip options decode structure */ - Options tcp_options[TCP_OPTLENMAX]; /* tcp options decode struct */ + uint8_t ip6_frag_index; uint8_t curr_ip6_extension_order; - - const uint8_t *ip_frag_start; + uint8_t ip6_extension_count; + uint8_t byte_skip; /* when decoding, there are bytes between the end of the layer and the start of the next layer */ Layer layers[LAYER_MAX]; /* decoded encapsulations */ @@ -239,7 +217,6 @@ struct Packet uint16_t user_policy_id; uint32_t iplist_id; - unsigned char iprep_layer; uint8_t ps_proto; // Used for portscan and unified2 logging diff --git a/src/protocols/packet_manager.cc b/src/protocols/packet_manager.cc index 7e2f2ea6a..33fcaca63 100644 --- a/src/protocols/packet_manager.cc +++ b/src/protocols/packet_manager.cc @@ -41,6 +41,7 @@ #include "codecs/decode_module.h" #include "utils/stats.h" #include "log/text_log.h" +#include "main/snort_debug.h" #ifdef PERF_PROFILING @@ -86,20 +87,14 @@ static inline void push_layer(Packet *p, uint32_t len, Codec *const cd) { - if ( p->num_layers < LAYER_MAX ) - { - Layer& lyr = p->layers[p->num_layers++]; - lyr.proto = cd->get_proto_id(); - lyr.prot_id = prot_id; - lyr.start = hdr_start; - lyr.length = (uint16_t)len; - } - else - { - //FIXIT-M Alert when max layers maxed out. - LogMessage("(packet_manager) WARNING: decoder has too many layers;" - " next proto is something.\n"); - } + + // We check to ensure num_layer < MAX_LAYERS before this function call + Layer& lyr = p->layers[p->num_layers++]; + lyr.proto = cd->get_proto_id(); + lyr.prot_id = prot_id; + lyr.start = hdr_start; + lyr.length = (uint16_t)len; +// lyr.invalid_bits = p->byte_skip; -- currently unused } //------------------------------------------------------------------------- @@ -181,11 +176,14 @@ void PacketManager::decode( mapped_prot = CodecManager::s_proto_map[prot_id]; prev_prot_id = prot_id; + lyr_len += p->byte_skip; + // set for next call prot_id = FINISHED_DECODE; len -= lyr_len; pkt += lyr_len; lyr_len = 0; + p->byte_skip = 0; } DEBUG_WRAP(DebugMessage(DEBUG_DECODE, "Codec %s (protocol_id: %hu: ip header" @@ -360,7 +358,7 @@ int PacketManager::encode_format_with_daq_info ( if ( f & ENC_FLAG_NET ) { - num_layers = layer::get_inner_ip_lyr(p) + 1; + num_layers = layer::get_inner_ip_lyr_index(p) + 1; // TBD: is this an extraneous check? if (num_layers == 0) diff --git a/src/protocols/packet_manager.h b/src/protocols/packet_manager.h index 1abb34483..98096b3f6 100644 --- a/src/protocols/packet_manager.h +++ b/src/protocols/packet_manager.h @@ -16,10 +16,10 @@ ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -// codec_manager.h author Josh Rosenbaum +// packet_manager.h author Josh Rosenbaum -#ifndef MANAGERS_PACKET_MANAGER_H -#define MANAGERS_PACKET_MANAGER_H +#ifndef PROTOCOLS_PACKET_MANAGER_H +#define PROTOCOLS_PACKET_MANAGER_H #include #include @@ -50,6 +50,13 @@ public: static Packet* encode_new(void); // release the allocated Packet static void encode_delete(Packet*); + + // when encoding, rather than copy the destination MAC address from the + // inbound packet, manually set the MAC address. + static void encode_set_dst_mac(uint8_t* ); + // get the MAC address which has been set using encode_set_dst_mac(). + // Useful for root decoders setting the MAC address + static uint8_t *encode_get_dst_mac(); // update the packet's checksums and length variables. Call this function // after Snort has changed any data in this packet static void encode_update(Packet*); @@ -64,12 +71,6 @@ public: static const uint8_t* encode_response( EncodeType, EncodeFlags, const Packet* orig, uint32_t* len, const uint8_t* payLoad, uint32_t payLen); - // when encoding, rather than copy the destination MAC address from the - // inbound packet, manually set the MAC address. - static void encode_set_dst_mac(uint8_t* ); - // get the MAC address which has been set using encode_set_dst_mac(). - // Useful for root decoders setting the MAC address - static uint8_t *encode_get_dst_mac(); // wrapper for encode response. Ensure no payload is encoded. static inline const uint8_t* encode_reject( EncodeType type, diff --git a/src/protocols/protocol_ids.h b/src/protocols/protocol_ids.h index 23aba2bc0..83150d646 100644 --- a/src/protocols/protocol_ids.h +++ b/src/protocols/protocol_ids.h @@ -76,7 +76,6 @@ constexpr uint16_t ETHERNET_LLC = 0x0106; - /* * Below is a partial list of ethertypes. * Defined at: diff --git a/src/protocols/tcp.h b/src/protocols/tcp.h index c8d314d6f..b4fb86678 100644 --- a/src/protocols/tcp.h +++ b/src/protocols/tcp.h @@ -24,7 +24,6 @@ #include - // these are bits in th_flags: #define TH_FIN 0x01 #define TH_SYN 0x02 @@ -67,13 +66,6 @@ #define SOL_TCP 6 /* TCP level */ -/* tcp option codes */ -#define TOPT_EOL 0x00 -#define TOPT_NOP 0x01 -#define TOPT_MSS 0x02 -#define TOPT_WS 0x03 -#define TOPT_TS 0x08 - namespace tcp { @@ -102,97 +94,20 @@ struct TCPHdr inline uint8_t options_len() const { return hdr_len() - TCP_HEADER_LEN; } -}; - - -#if 0 -inline uint8_t hdr_len() -{ - return detail::TCP_HEADER_LEN; -} -#endif - -inline uint8_t get_tcp_hdr_len(const TCPHdr *h) -{ - return ((h->th_offx2 & 0xf0) >> 2); -} - -/* http://www.iana.org/assignments/tcp-parameters - * - * tcp options stuff. used to be in but it breaks - * things on AIX - */ -// enum class TcpOpt{ -enum TcpOpt{ - EOL = 0, /* End of Option List [RFC793] */ - NOP = 1, /* No-Option [RFC793] */ - MAXSEG = 2, /* Maximum Segment Size [RFC793] */ - WSCALE = 3, /* Window scaling option [RFC1323] */ - SACKOK = 4, /* Experimental [RFC2018]*/ - SACK = 5, /* Experimental [RFC2018] variable length */ - ECHO = 6, /* Echo (obsoleted by option 8) [RFC1072] */ - ECHOREPLY = 7, /* Echo Reply (obsoleted by option 8)[RFC1072] */ - TIMESTAMP = 8, /* Timestamp [RFC1323], 10 bytes */ - PARTIAL_PERM = 9, /* Partial Order Permitted/ Experimental [RFC1693] */ - PARTIAL_SVC = 10, /* Partial Order Profile [RFC1693] */ - CC = 11, /* T/TCP Connection count [RFC1644] */ - CC_NEW = 12, /* CC.NEW [RFC1644] */ - CC_ECHO = 13, /* CC.ECHO [RFC1644] */ + inline bool has_options() const + { return (th_offx2 & 0xf0) == 0x50; } - ALTCSUM = 15, /* TCP Alternate Checksum Data [RFC1146], variable length */ - SKEETER = 16, /* Skeeter [Knowles] */ - BUBBA = 17, /* Bubba [Knowles] */ - TRAILER_CSUM = 18, /* Trailer Checksum Option [Subbu & Monroe] */ - MD5SIG = 19, /* MD5 Signature Option [RFC2385] */ + inline bool are_flags_set(uint8_t flags) const + { return (th_flags & flags) == flags; } - - /* Space Communications Protocol Standardization */ - SCPS = 20, /* Capabilities [Scott] */ - SELNEGACK = 21, /* Selective Negative Acknowledgements [Scott] */ - RECORDBOUND = 22, /* Record Boundaries [Scott] */ - CORRUPTION = 23, /* Corruption experienced [Scott] */ - SNAP = 24, /* SNAP [Sukonnik] -- anyone have info?*/ - UNASSIGNED = 25, /* Unassigned (released 12/18/00) */ - COMPRESSION = 26, /* TCP Compression Filter [Bellovin] */ - /* http://www.research.att.com/~smb/papers/draft-bellovin-tcpcomp-00.txt*/ - - AUTH = 29, /* [RFC5925] - The TCP Authentication Option - Intended to replace MD5 Signature Option [RFC2385] */ + // setters + inline void set_offset(uint8_t val) + { th_offx2 = (uint8_t)((th_offx2 & 0x0f) | (val << 4)); } }; -inline void set_tcp_offset(TCPHdr *tcph, uint8_t value) -{ - tcph->th_offx2 = (uint8_t)((tcph->th_offx2 & 0x0f) | (value << 4)); -} - -inline void set_tcp_x2(TCPHdr* tcph, uint8_t value) -{ - tcph->th_offx2 = (tcph->th_offx2 & 0xf0) | (value & 0x0f); -} - -#define TCPOLEN_EOL 1 /* Always one byte */ -#define TCPOLEN_NOP 1 /* Always one byte */ -#define TCPOLEN_MAXSEG 4 /* Always 4 bytes */ -#define TCPOLEN_WSCALE 3 /* 1 byte with logarithmic values */ -#define TCPOLEN_SACKOK 2 -#define TCPOLEN_ECHO 6 /* 6 bytes */ -#define TCPOLEN_ECHOREPLY 6 /* 6 bytes */ -#define TCPOLEN_TIMESTAMP 10 -#define TCPOLEN_PARTIAL_PERM 2 /* Partial Order Permitted/ Experimental [RFC1693] */ -#define TCPOLEN_PARTIAL_SVC 3 /* 3 bytes long -- Experimental */ - -/* atleast decode T/TCP options... */ -#define TCPOLEN_CC 6 /* page 17 of rfc1644 */ -#define TCPOLEN_CC_NEW 6 /* page 17 of rfc1644 */ -#define TCPOLEN_CC_ECHO 6 /* page 17 of rfc1644 */ -#define TCPOLEN_TRAILER_CSUM 3 -#define TCPOLEN_MD5SIG 18 /* more macros for TCP offset */ -#define TCP_OFFSET(tcph) (((tcph)->th_offx2 & 0xf0) >> 4) -#define TCP_X2(tcph) ((tcph)->th_offx2 & 0x0f) - #define TCP_ISFLAGSET(tcph, flags) (((tcph)->th_flags & (flags)) == (flags)) @@ -200,70 +115,4 @@ inline void set_tcp_x2(TCPHdr* tcph, uint8_t value) -/* delete everything from here to the end of the file (excluding the #endif of course) */ - -#define TCPOPT_EOL 0 /* End of Option List [RFC793] */ -#define TCPOLEN_EOL 1 /* Always one byte */ - -#define TCPOPT_NOP 1 /* No-Option [RFC793] */ -#define TCPOLEN_NOP 1 /* Always one byte */ - -#define TCPOPT_MAXSEG 2 /* Maximum Segment Size [RFC793] */ -#define TCPOLEN_MAXSEG 4 /* Always 4 bytes */ - -#define TCPOPT_WSCALE 3 /* Window scaling option [RFC1323] */ -#define TCPOLEN_WSCALE 3 /* 1 byte with logarithmic values */ - -#define TCPOPT_SACKOK 4 /* Experimental [RFC2018]*/ -#define TCPOLEN_SACKOK 2 - -#define TCPOPT_SACK 5 /* Experimental [RFC2018] variable length */ - -#define TCPOPT_ECHO 6 /* Echo (obsoleted by option 8) [RFC1072] */ -#define TCPOLEN_ECHO 6 /* 6 bytes */ - -#define TCPOPT_ECHOREPLY 7 /* Echo Reply (obsoleted by option 8)[RFC1072] */ -#define TCPOLEN_ECHOREPLY 6 /* 6 bytes */ - -#define TCPOPT_TIMESTAMP 8 /* Timestamp [RFC1323], 10 bytes */ -#define TCPOLEN_TIMESTAMP 10 - -#define TCPOPT_PARTIAL_PERM 9 /* Partial Order Permitted/ Experimental [RFC1693] */ -#define TCPOLEN_PARTIAL_PERM 2 /* Partial Order Permitted/ Experimental [RFC1693] */ - -#define TCPOPT_PARTIAL_SVC 10 /* Partial Order Profile [RFC1693] */ -#define TCPOLEN_PARTIAL_SVC 3 /* 3 bytes long -- Experimental */ - -/* atleast decode T/TCP options... */ -#define TCPOPT_CC 11 /* T/TCP Connection count [RFC1644] */ -#define TCPOPT_CC_NEW 12 /* CC.NEW [RFC1644] */ -#define TCPOPT_CC_ECHO 13 /* CC.ECHO [RFC1644] */ -#define TCPOLEN_CC 6 /* page 17 of rfc1644 */ -#define TCPOLEN_CC_NEW 6 /* page 17 of rfc1644 */ -#define TCPOLEN_CC_ECHO 6 /* page 17 of rfc1644 */ - -#define TCPOPT_ALTCSUM 15 /* TCP Alternate Checksum Data [RFC1146], variable length */ -#define TCPOPT_SKEETER 16 /* Skeeter [Knowles] */ -#define TCPOPT_BUBBA 17 /* Bubba [Knowles] */ - -#define TCPOPT_TRAILER_CSUM 18 /* Trailer Checksum Option [Subbu & Monroe] */ -#define TCPOLEN_TRAILER_CSUM 3 - -#define TCPOPT_MD5SIG 19 /* MD5 Signature Option [RFC2385] */ -#define TCPOLEN_MD5SIG 18 - -/* Space Communications Protocol Standardization */ -#define TCPOPT_SCPS 20 /* Capabilities [Scott] */ -#define TCPOPT_SELNEGACK 21 /* Selective Negative Acknowledgements [Scott] */ -#define TCPOPT_RECORDBOUND 22 /* Record Boundaries [Scott] */ -#define TCPOPT_CORRUPTION 23 /* Corruption experienced [Scott] */ - -#define TCPOPT_SNAP 24 /* SNAP [Sukonnik] -- anyone have info?*/ -#define TCPOPT_UNASSIGNED 25 /* Unassigned (released 12/18/00) */ -#define TCPOPT_COMPRESSION 26 /* TCP Compression Filter [Bellovin] */ -/* http://www.research.att.com/~smb/papers/draft-bellovin-tcpcomp-00.txt*/ - -#define TCPOPT_AUTH 29 /* [RFC5925] - The TCP Authentication Option - Intended to replace MD5 Signature Option [RFC2385] */ - #endif /* TCP_H */ diff --git a/src/protocols/tcp_options.cc b/src/protocols/tcp_options.cc new file mode 100644 index 000000000..38bb324f8 --- /dev/null +++ b/src/protocols/tcp_options.cc @@ -0,0 +1,82 @@ +/* +** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. +** Copyright (C) 2007-2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +// tcp_options.cc author Josh Rosenbaum + +#include "protocols/tcp_options.h" +#include "protocols/tcp.h" +#include "protocols/layer.h" +#include "protocols/packet.h" + +namespace tcp +{ + + +TcpOptIteratorIter::TcpOptIteratorIter(const TcpOption* first_opt) : opt(first_opt) +{ +} + +const TcpOption& TcpOptIteratorIter::operator* () const +{ return *opt; } + + +TcpOptIterator::TcpOptIterator(const TCPHdr* const tcp_header, const Packet* const p) +{ + const uint8_t* const hdr = (const uint8_t* const)tcp_header; + start_ptr = hdr + TCP_HEADER_LEN; + end_ptr = start_ptr; // == begin() + + for (int i = p->num_layers-1; i >= 0; --i) + { + if (p->layers[i].start == (const uint8_t*)tcp_header) + { + // the Options do not necessarily include + // the entire header. However, length has + // been validated during decode + end_ptr = (hdr + p->layers[i].length); + return; + } + } +} + + +TcpOptIterator::TcpOptIterator(const TCPHdr* const tcp_header, const uint32_t valid_hdr_len) +{ + const uint8_t* const hdr = (const uint8_t* const)tcp_header; + start_ptr = hdr + TCP_HEADER_LEN; + + if (valid_hdr_len < TCP_HEADER_LEN) + end_ptr = start_ptr; + else + end_ptr = hdr + valid_hdr_len; +} + + +TcpOptIteratorIter TcpOptIterator::begin() const +{ + return TcpOptIteratorIter(reinterpret_cast(start_ptr)); +} + +TcpOptIteratorIter TcpOptIterator::end() const +{ + return TcpOptIteratorIter(reinterpret_cast(end_ptr)); +} + + +} // namespace ip diff --git a/src/protocols/tcp_options.h b/src/protocols/tcp_options.h new file mode 100644 index 000000000..b24428922 --- /dev/null +++ b/src/protocols/tcp_options.h @@ -0,0 +1,190 @@ +/* +** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. +** Copyright (C) 2007-2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +// tcp_options.h author Josh Rosenbaum + +#ifndef PROTOCOLS_TCP_OPTIONS_H +#define PROTOCOLS_TCP_OPTIONS_H + +#include + +struct Packet; + + +namespace tcp +{ + +struct TCPHdr; + +/* http://www.iana.org/assignments/tcp-parameters + * + * tcp options stuff. used to be in but it breaks + * things on AIX + */ + +enum class TcpOptCode : std::uint8_t { + EOL = 0, /* End of Option List [RFC793] */ + NOP = 1, /* No-Option [RFC793] */ + MAXSEG = 2, /* Maximum Segment Size [RFC793] */ + WSCALE = 3, /* Window scaling option [RFC1323] */ + SACKOK = 4, /* Experimental [RFC2018]*/ + SACK = 5, /* Experimental [RFC2018] variable length */ + ECHO = 6, /* Echo (obsoleted by option 8) [RFC1072] */ + ECHOREPLY = 7, /* Echo Reply (obsoleted by option 8)[RFC1072] */ + TIMESTAMP = 8, /* Timestamp [RFC1323], 10 bytes */ + PARTIAL_PERM = 9, /* Partial Order Permitted/ Experimental [RFC1693] */ + PARTIAL_SVC = 10, /* Partial Order Profile [RFC1693] */ + CC = 11, /* T/TCP Connection count [RFC1644] */ + CC_NEW = 12, /* CC.NEW [RFC1644] */ + CC_ECHO = 13, /* CC.ECHO [RFC1644] */ + + ALTCSUM = 15, /* TCP Alternate Checksum Data [RFC1146], variable length */ + SKEETER = 16, /* Skeeter [Knowles] */ + BUBBA = 17, /* Bubba [Knowles] */ + TRAILER_CSUM = 18, /* Trailer Checksum Option [Subbu & Monroe] */ + MD5SIG = 19, /* MD5 Signature Option [RFC2385] */ + + + /* Space Communications Protocol Standardization */ + SCPS = 20, /* Capabilities [Scott] */ + SELNEGACK = 21, /* Selective Negative Acknowledgements [Scott] */ + RECORDBOUND = 22, /* Record Boundaries [Scott] */ + CORRUPTION = 23, /* Corruption experienced [Scott] */ + SNAP = 24, /* SNAP [Sukonnik] -- anyone have info?*/ + UNASSIGNED = 25, /* Unassigned (released 12/18/00) */ + COMPRESSION = 26, /* TCP Compression Filter [Bellovin] */ + /* http://www.research.att.com/~smb/papers/draft-bellovin-tcpcomp-00.txt*/ + + AUTH = 29, /* [RFC5925] - The TCP Authentication Option + Intended to replace MD5 Signature Option [RFC2385] */ +}; + +/* Associated lengths */ +const uint8_t TCPOLEN_EOL = 1; /* Always one byte - [RFC793]*/ +const uint8_t TCPOLEN_NOP = 1; /* Always one byte - [RFC793]*/ +const uint8_t TCPOLEN_MAXSEG = 4; /* Always 4 bytes - [RFC793] */ +const uint8_t TCPOLEN_WSCALE = 3; /* 1 byte with logarithmic values - [RFC1323]*/ +const uint8_t TCPOLEN_SACKOK = 2; /* Experimental [RFC2018]*/ +const uint8_t TCPOLEN_ECHO = 6; /* 6 bytes - Echo (obsoleted by option 8) [RFC1072] */ +const uint8_t TCPOLEN_ECHOREPLY = 6; /* 6 bytes - Echo Reply (obsoleted by option 8)[RFC1072]*/ +const uint8_t TCPOLEN_TIMESTAMP = 10; /* Timestamp [RFC1323], 10 bytes */ +const uint8_t TCPOLEN_PARTIAL_PERM = 2; /* Partial Order Permitted/ Experimental [RFC1693] */ +const uint8_t TCPOLEN_PARTIAL_SVC = 3; /* 3 bytes long -- Experimental - [RFC1693] */ + +/* atleast decode T/TCP options... */ +const uint8_t TCPOLEN_CC = 6; /* page 17 of rfc1644 */ +const uint8_t TCPOLEN_CC_NEW = 6; /* page 17 of rfc1644 */ +const uint8_t TCPOLEN_CC_ECHO = 6; /* page 17 of rfc1644 */ + +const uint8_t TCPOLEN_TRAILER_CSUM = 3; +const uint8_t TCPOLEN_MD5SIG = 18; + + +struct TcpOption +{ + TcpOptCode code; + uint8_t len; + uint8_t data[13]; // arbitrary number. choosing 13 to align with 128 bits + + inline uint8_t get_len() const + { return ((uint8_t)code <= 1) ? 1 : len; } + + inline const uint8_t* get_data() const + { return ((uint8_t)code <= 1 || len < 2) ? nullptr : &data[0]; } + + inline const TcpOption& next() const + { +# if defined(__GNUC__) + const uint8_t tmp_len = ((uint8_t) code <= 1) ? 1 : len; + const uint8_t* const tmp = reinterpret_cast(this); + const TcpOption* opt = reinterpret_cast(&tmp[tmp_len]); + return *opt; + + // ... and the legible code +# else + if ( (uint8_t)code <= 1 ) + return reinterpret_cast(len); + else + return reinterpret_cast(data[len -2]); +# endif + } +}; + + +/* + * Use TcpOptIterator ... this should NOT be called directly + * unless you want to an actual iterator or some buggy code. + */ +class TcpOptIteratorIter +{ +public: + TcpOptIteratorIter(const TcpOption*); + + bool operator== (const TcpOptIteratorIter& rhs) + { return opt == rhs.opt; } + + bool operator!= (const TcpOptIteratorIter& rhs) + { return opt != rhs.opt; } + + TcpOptIteratorIter& operator++() + { + opt = &opt->next(); + return *this; + } + + const TcpOption& operator* () const; + +private: + const TcpOption* opt; +}; + +/* + * Use IP ranged for loop rather than calling this directly. + * i.e., + * IpOptionIter iter(tcph, p) + * for (const TcpOption& opt : iter) + * { + * do_something + * } + */ +class TcpOptIterator +{ +public: + /* CONSTRUCTOR VALID AFTER DECODE() + * Some options in the provided header may not be valid. + * Provide the packet struct ensures only valid options + * will be returned + */ + TcpOptIterator(const TCPHdr* const, const Packet* const); + /* If you already know the validated option length (for instance, + * if you are in a decode() method), then call this constructor.*/ + TcpOptIterator(const TCPHdr* const, const uint32_t valid_hdr_len); + TcpOptIteratorIter begin() const; + TcpOptIteratorIter end() const; + +private: + const uint8_t* start_ptr; + const uint8_t* end_ptr; +}; + + +} // namespace tcp + + +#endif /* PROTOCOLS_TCP_OPTIONS_H */ diff --git a/src/stream/icmp/icmp_session.cc b/src/stream/icmp/icmp_session.cc index 8ec6db96e..f47346ad2 100644 --- a/src/stream/icmp/icmp_session.cc +++ b/src/stream/icmp/icmp_session.cc @@ -44,6 +44,7 @@ #include "protocols/vlan.h" #include "protocols/ip.h" #include "protocols/icmp4.h" +#include "sfip/sf_ip.h" THREAD_LOCAL SessionStats icmpStats; THREAD_LOCAL ProfileStats icmp_perf_stats; diff --git a/src/stream/ip/ip_defrag.cc b/src/stream/ip/ip_defrag.cc index 80e294a42..19d808451 100644 --- a/src/stream/ip/ip_defrag.cc +++ b/src/stream/ip/ip_defrag.cc @@ -64,7 +64,6 @@ */ /* I N C L U D E S ************************************************/ -#include "ip_defrag.h" #ifdef HAVE_CONFIG_H #include "config.h" @@ -77,32 +76,26 @@ #include #include -#include "ip_session.h" -#include "ip_module.h" -#include "stream_ip.h" -#include "stream/stream.h" -#include "main/analyzer.h" -#include "snort_bounds.h" -#include "log_text.h" -#include "detect.h" -#include "protocols/packet.h" -#include "protocols/packet_manager.h" -#include "event.h" -#include "util.h" -#include "snort_debug.h" -#include "parser.h" -#include "mstring.h" -#include "perf_monitor/perf.h" -#include "timersub.h" -#include "fpcreate.h" -#include "utils/sflsq.h" -#include "snort.h" -#include "profiler.h" + +#include "framework/codec.h" +#include "framework/counts.h" +#include "flow/flow_control.h" +#include "ip_defrag.h" +#include "stream/ip/ip_session.h" +#include "stream/ip/ip_module.h" +#include "stream/ip/stream_ip.h" #include "packet_io/active.h" #include "packet_io/sfdaq.h" -#include "framework/inspector.h" -#include "flow/flow_control.h" -#include "framework/codec.h" +#include "protocols/layer.h" +#include "protocols/ipv4_options.h" +#include "protocols/packet_manager.h" +#include "main/snort_debug.h" +#include "main/snort.h" +#include "time/profiler.h" +#include "time/timersub.h" +#include "network_inspectors/perf_monitor/perf.h" +#include "utils/stats.h" +#include "utils/snort_bounds.h" /* D E F I N E S **************************************************/ @@ -257,7 +250,7 @@ THREAD_LOCAL ProfileStats fragRebuildPerfStats; /* P R O T O T Y P E S ********************************************/ static void FragRebuild(FragTracker *, Packet *); static inline int FragIsComplete(FragTracker *); -static int FragHandleIPOptions(FragTracker *, Packet *); +static int FragHandleIPOptions(FragTracker *, const Packet* const); /* deletion funcs */ static THREAD_LOCAL struct timeval *pkttime; /* packet timestamp */ @@ -525,27 +518,30 @@ static inline int CheckTimeout(struct timeval *current_time, * * @return none */ -static inline int FragCheckFirstLast(Packet *p, FragTracker *ft) +static inline int FragCheckFirstLast(const Packet* const p, + FragTracker *ft, + const uint16_t frag_offset) { uint16_t fragLength; int retVal = FRAG_FIRSTLAST_OK; uint16_t endOfThisFrag; /* set the frag flag if this is the first fragment */ - if((p->decode_flags & DECODE__MF) && p->frag_offset == 0) + if((p->decode_flags & DECODE__MF) && frag_offset == 0) { ft->frag_flags |= FRAG_GOT_FIRST; DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "Got first frag\n");); } - else if((!(p->decode_flags & DECODE__MF)) && (p->frag_offset > 0)) /* set for last frag too */ + else if((!(p->decode_flags & DECODE__MF)) && (frag_offset > 0)) /* set for last frag too */ { - /* Use the actual length here, because packet may have been - * truncated. Don't want to try to copy more than we actually - * captured. */ - //fragLength = p->actual_ip_len - GET_IPH_HLEN(p) * 4; - fragLength = p->ip_frag_len; - endOfThisFrag = (p->frag_offset << 3) + fragLength; + /* Use the actual length here because packet may have been + * truncated. Don't want to try to copy more than we actually + * captured. Use dsize as the frag length since it is distance + * between the last sucesfully decoded layer (which is ip6_frag + * or ipv4) and the end of packet, */ + fragLength = p->dsize; + endOfThisFrag = (frag_offset << 3) + fragLength; if (ft->frag_flags & FRAG_GOT_LAST) { @@ -621,7 +617,7 @@ static inline int FragCheckFirstLast(Packet *p, FragTracker *ft) } } - if (p->frag_offset != 0) + if (frag_offset != 0) { ft->frag_flags |= FRAG_NO_BSD_VULN; } @@ -644,23 +640,25 @@ static inline int FragCheckFirstLast(Packet *p, FragTracker *ft) * @retval 1 on success */ static int FragHandleIPOptions(FragTracker *ft, - Packet *p) + const Packet* const p) { - unsigned int i = 0; /* counter */ - if(p->frag_offset == 0) + // FIXIT-J pass in frag_offset as a parameter + const uint16_t frag_offset = ntohs(p->ip_api.off(p)); + const uint16_t ip_options_len = p->ip_api.get_ip_opt_len(); + + if(frag_offset == 0) { /* * This is the first packet. If it has IP options, * save them off, so we can set them on the reassembled packet. */ - uint16_t ip_options_len = p->ip_api.get_ip_opt_len(); if (ip_options_len) { if (ft->ip_options_data) { /* Already seen 0 offset packet and copied some IP options */ if ((ft->frag_flags & FRAG_GOT_FIRST) - && (ft->ip_option_count != p->ip_option_count)) + && (ft->ip_options_len != ip_options_len)) { EventAnomIpOpts(ft->engine); } @@ -671,7 +669,6 @@ static int FragHandleIPOptions(FragTracker *ft, ft->ip_options_data = (uint8_t*)SnortAlloc(ip_options_len); memcpy(ft->ip_options_data, p->ip_api.get_ip_opt_data(), ip_options_len); ft->ip_options_len = ip_options_len; - ft->ip_option_count = p->ip_option_count; } } } @@ -681,23 +678,26 @@ static int FragHandleIPOptions(FragTracker *ft, /* XXX: could check each individual option here, but that * would be performance ugly. So, we'll just check that the - * option counts match. Alert if invalid, but still include in + * option sizes match. Alert if invalid, but still include in * reassembly. */ - if (ft->copied_ip_option_count) + if (ft->copied_ip_options_len) { - if (ft->copied_ip_option_count != p->ip_option_count) + if (ft->copied_ip_options_len != ip_options_len) { EventAnomIpOpts(ft->engine); } } else { - ft->copied_ip_option_count = p->ip_option_count; - for (i = 0;i< p->ip_option_count && i < IP_OPTMAX; i++) + ft->copied_ip_options_len = ip_options_len; + + ip::IpOptionIterator iter(p->ip_api.get_ip4h(), p); + + for (ip::IpOptions opt : iter) { /* Is the high bit set? If not, weird anomaly. */ - if (!(p->ip_options[i].code & 0x80)) + if (!(static_cast(opt.code) & 0x80)) EventAnomIpOpts(ft->engine); } } @@ -749,7 +749,7 @@ int FragGetPolicy(Packet *p, FragEngine *engine) */ static inline int checkTinyFragments( FragEngine *engine, - Packet *p, + const Packet* const p, unsigned int trimmedLength ) { @@ -760,11 +760,11 @@ static inline int checkTinyFragments( ///detect tiny fragments before processing overlaps. if (engine->min_fragment_length) { - if (p->ip_frag_len <= engine->min_fragment_length) + if (p->dsize <= engine->min_fragment_length) { DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "Frag3: Received fragment size(%d) is not more than configured min_fragment_length (%d)\n", - p->ip_frag_len, engine->min_fragment_length);); + p->dsize, engine->min_fragment_length);); EventTinyFragments(engine); return 1; } @@ -1333,6 +1333,8 @@ void Defrag::process(Packet* p, FragTracker* ft) assert(p->ip_api.is_valid() && !(p->error_flags & PKT_ERR_CKSUM_IP)); assert(p->decode_flags & DECODE__FRAG); + const uint16_t frag_offset = ntohs(p->ip_api.off(p)); + /* * First case: if frag offset is 0 & UDP, let that packet go * through the rest of the system. Ugly HACK to detect DNS @@ -1351,7 +1353,7 @@ void Defrag::process(Packet* p, FragTracker* ft) * Disable Inspection since we'll look at the payload in * a rebuilt packet later. So don't process it further. */ - if ((p->frag_offset != 0) || + if ((frag_offset != 0) || ((p->ip_api.proto() != IPPROTO_UDP) && (p->decode_flags & DECODE__MF))) { DisableDetect(p); @@ -1367,7 +1369,7 @@ void Defrag::process(Packet* p, FragTracker* ft) "[0x%X->0x%X], TTL: %d " "Offset: %d Length: %d\n", ntohl(p->ip_api.get_ip4h()->get_src()), ntohl(p->ip_api.get_ip4h()->get_dst()), - p->ip_api.ttl(), p->frag_offset, + p->ip_api.ttl(), frag_offset, p->dsize);); EventAnomScMinTTL(fe); @@ -1429,7 +1431,7 @@ void Defrag::process(Packet* p, FragTracker* ft) case FRAG_INSERT_FAILED: #ifdef DEBUG LogMessage("WARNING: Insert into Fraglist failed, " - "(offset: %u).\n", p->frag_offset); + "(offset: %u).\n", frag_offset); #endif MODULE_PROFILE_END(fragPerfStats); return; @@ -1440,7 +1442,7 @@ void Defrag::process(Packet* p, FragTracker* ft) "Offset: %d Length: %d\n", ntohl(p->ip_api.get_ip4h()->get_src()), ntohl(p->ip_api.get_ip4h()->get_dst()), - p->ip_api.ttl(), ft->ttl, p->frag_offset, + p->ip_api.ttl(), ft->ttl, frag_offset, p->dsize);); t_stats.discards++; MODULE_PROFILE_END(fragPerfStats); @@ -1453,7 +1455,7 @@ void Defrag::process(Packet* p, FragTracker* ft) case FRAG_INSERT_TIMEOUT: #ifdef DEBUG LogMessage("WARNING: Insert into Fraglist failed due to timeout, " - "(offset: %u).\n", p->frag_offset); + "(offset: %u).\n", frag_offset); #endif MODULE_PROFILE_END(fragPerfStats); return; @@ -1462,7 +1464,7 @@ void Defrag::process(Packet* p, FragTracker* ft) LogMessage("WARNING: Excessive IP fragment overlap, " "(More: %u, offset: %u, offsetSize: %u).\n", (p->decode_flags & DECODE__MF), - (p->frag_offset<<3), p->ip_frag_len); + (frag_offset << 3), p->dsize); #endif t_stats.discards++; MODULE_PROFILE_END(fragPerfStats); @@ -1488,7 +1490,7 @@ void Defrag::process(Packet* p, FragTracker* ft) { FragRebuild(ft, p); - if (p->frag_offset != 0 || + if (frag_offset != 0 || (p->ip_api.proto() != IPPROTO_UDP && ft->frag_flags & FRAG_REBUILT)) { /* Need to reset some things here because the @@ -1550,12 +1552,13 @@ int Defrag::insert(Packet *p, FragTracker *ft, FragEngine *fe) const uint8_t *fragStart; int16_t fragLength; PROFILE_VARS; + const uint16_t net_frag_offset = ntohs(p->ip_api.off(p)); sfBase.iFragInserts++; MODULE_PROFILE_START(fragInsertPerfStats); - if (p->ip_api.is_ip6() && (p->frag_offset == 0)) + if (p->ip_api.is_ip6() && (net_frag_offset == 0)) { ip::IP6Frag *fragHdr = (ip::IP6Frag *)p->layers[p->ip6_frag_index].start; if (ft->protocol != fragHdr->ip6f_nxt) @@ -1568,15 +1571,19 @@ int Defrag::insert(Packet *p, FragTracker *ft, FragEngine *fe) * Check to see if this fragment is the first or last one and * set the appropriate flags and values in the FragTracker */ - firstLastOk = FragCheckFirstLast(p, ft); + firstLastOk = FragCheckFirstLast(p, ft, net_frag_offset); + + // if we're here, then the last layer was a fragment. + const Layer& lyr = p->layers[p->num_layers-1]; + fragStart = lyr.start + lyr.length; - fragStart = p->ip_frag_start; - //fragStart = (uint8_t *)p->iph + GET_IPH_HLEN(p) * 4; - /* Use the actual length here, because packet may have been + /* Use the actual length here because packet may have been * truncated. Don't want to try to copy more than we actually - * captured. */ - //len = fragLength = p->actual_ip_len - GET_IPH_HLEN(p) * 4; - len = fragLength = p->ip_frag_len; + * captured. Use dsize as the frag length since it is distance + * between the last sucesfully decoded layer (which is ip6_frag + * or ipv4) and the end of packet, */ + len = fragLength = p->dsize; + #ifdef DEBUG_MSGS if (p->ip_api.actual_ip_len() != ntohs(p->ip_api.len())) { @@ -1590,7 +1597,7 @@ int Defrag::insert(Packet *p, FragTracker *ft, FragEngine *fe) /* * setup local variables for tracking this frag */ - orig_offset = frag_offset = p->frag_offset << 3; + orig_offset = frag_offset = net_frag_offset << 3; /* Reset the offset to handle the weird Solaris case */ if (firstLastOk == FRAG_LAST_OFFSET_ADJUST) frag_offset = (uint16_t)ft->calculated_size; @@ -1908,7 +1915,7 @@ left_overlap_last: DEBUG_WRAP(DebugMessage(DEBUG_FRAG, "Overly large fragment %d 0x%x 0x%x %d\n", fragLength, ntohs(p->ip_api.len()), p->ip_api.off(p), - p->frag_offset << 3);); + net_frag_offset << 3);); MODULE_PROFILE_END(fragInsertPerfStats); return FRAG_INSERT_FAILED; } @@ -2273,22 +2280,26 @@ int Defrag::new_tracker(Packet *p, FragTracker* ft) const uint8_t *fragStart; uint16_t fragLength; uint16_t frag_end; + uint16_t frag_off; + + // if we're here, then the last layer was a fragment. + const Layer& lyr = p->layers[p->num_layers-1]; + fragStart = lyr.start + lyr.length; - fragStart = p->ip_frag_start; - //fragStart = (uint8_t *)p->iph + GET_IPH_HLEN(p) * 4; - /* Use the actual length here, because packet may have been + /* Use the actual length here because packet may have been * truncated. Don't want to try to copy more than we actually - * captured. */ - //fragLength = p->actual_ip_len - GET_IPH_HLEN(p) * 4; - fragLength = p->ip_frag_len; + * captured. Use dsize as the frag length since it is distance + * between the last sucesfully decoded layer (which is ip6_frag + * or ipv4) and the end of packet, */ + fragLength = p->dsize; /* Just to double check */ if (fragLength > pkt_snaplen) { DEBUG_WRAP(DebugMessage(DEBUG_FRAG, - "Overly large fragment %d 0x%x 0x%x %d\n", - fragLength, ntohs(p->ip_api.len()), p->ip_api.off(p), - p->frag_offset << 3);); + "Overly large fragment length:%d(0x%x) off:0x%x(%d)\n", + fragLength, ntohs(p->ip_api.len()), ntohs(p->ip_api.off(p)) << 3, + ntohs(p->ip_api.off(p)) << 3);); /* Ah, crap. Return that tracker. */ return 0; @@ -2299,15 +2310,19 @@ int Defrag::new_tracker(Packet *p, FragTracker* ft) if (p->ip_api.is_ip4()) { ft->protocol = p->ip_api.proto(); + + const ip::IP4Hdr *ip4h = reinterpret_cast(lyr.start); + frag_off = ntohs(ip4h->get_off()); } else /* IPv6 */ { - if (p->frag_offset == 0) - { - ip::IP6Frag *fragHdr = (ip::IP6Frag *)p->layers[p->ip6_frag_index].start; + const ip::IP6Frag *fragHdr = reinterpret_cast(lyr.start); + frag_off = ntohs(fragHdr->get_off()); + + if (frag_off == 0) ft->protocol = fragHdr->ip6f_nxt; - } } + ft->ttl = p->ip_api.ttl(); /* store the first ttl we got */ ft->calculated_size = 0; ft->alerted = 0; @@ -2317,10 +2332,8 @@ int Defrag::new_tracker(Packet *p, FragTracker* ft) ft->frag_time.tv_sec = p->pkth->ts.tv_sec; ft->frag_time.tv_usec = p->pkth->ts.tv_usec; ft->ip_options_len = 0; - ft->ip_option_count = 0; ft->ip_options_data = NULL; ft->copied_ip_options_len = 0; - ft->copied_ip_option_count = 0; ft->ordinal = 0; ft->frag_policy = FragGetPolicy(p, &engine); ft->engine = &engine; @@ -2358,7 +2371,7 @@ int Defrag::new_tracker(Packet *p, FragTracker* ft) memcpy(f->fptr, fragStart, fragLength); f->size = f->flen = fragLength; - f->offset = p->frag_offset << 3; + f->offset = frag_off << 3; frag_end = f->offset + fragLength; f->ord = ft->ordinal++; f->data = f->fptr; /* ptr to adjusted start position */ @@ -2400,7 +2413,7 @@ int Defrag::new_tracker(Packet *p, FragTracker* ft) /* * mark the FragTracker if this is the first/last frag */ - FragCheckFirstLast(p, ft); + FragCheckFirstLast(p, ft, frag_off); ft->frag_bytes += fragLength; diff --git a/src/stream/ip/ip_session.cc b/src/stream/ip/ip_session.cc index 006a51882..17c3bf1fe 100644 --- a/src/stream/ip/ip_session.cc +++ b/src/stream/ip/ip_session.cc @@ -32,6 +32,7 @@ #include "stream/stream.h" #include "perf_monitor/perf.h" #include "flow/flow_control.h" +#include "sfip/sf_ip.h" THREAD_LOCAL SessionStats ipStats; THREAD_LOCAL ProfileStats ip_perf_stats; diff --git a/src/stream/ip/ip_session.h b/src/stream/ip/ip_session.h index 1fd570582..57ed05552 100644 --- a/src/stream/ip/ip_session.h +++ b/src/stream/ip/ip_session.h @@ -55,11 +55,9 @@ struct FragTracker int fraglist_count; /* handy dandy counter */ uint32_t ip_options_len; /* length of ip options for this set of frags */ - uint32_t ip_option_count; /* number of ip options for this set of frags */ uint8_t *ip_options_data; /* ip options from offset 0 packet */ uint32_t copied_ip_options_len; /* length of 'copied' ip options */ - uint32_t copied_ip_option_count; /* number of 'copied' ip options */ FragEngine *engine; diff --git a/src/stream/tcp/ips_stream_size.cc b/src/stream/tcp/ips_stream_size.cc index 891c8e016..94edfb778 100644 --- a/src/stream/tcp/ips_stream_size.cc +++ b/src/stream/tcp/ips_stream_size.cc @@ -32,6 +32,7 @@ #include "detection/detection_defines.h" #include "hash/sfhashfcn.h" #include "time/profiler.h" +#include "sfip/sf_ip.h" enum SsodOp { diff --git a/src/stream/tcp/tcp_session.cc b/src/stream/tcp/tcp_session.cc index ef436a189..bda1df6c9 100644 --- a/src/stream/tcp/tcp_session.cc +++ b/src/stream/tcp/tcp_session.cc @@ -69,6 +69,7 @@ #include "time/packet_time.h" #include "protocols/packet.h" #include "protocols/packet_manager.h" +#include "protocols/tcp_options.h" #include "log_text.h" #include "packet_io/active.h" #include "normalize/normalize.h" @@ -81,6 +82,7 @@ #include "file_api/file_api.h" #include "tcp_module.h" #include "stream/stream_splitter.h" +#include "sfip/sf_ip.h" using namespace tcp; @@ -1024,26 +1026,11 @@ static inline int NormalDropPacketIf (Packet* p, NormFlags f) return 0; } -static inline void NormalStripTimeStamp (Packet* p, int i) +static inline void NormalStripTimeStamp (Packet* p, const TcpOption* opt) { - uint8_t* opt; + // set raw option bytes to nops + memset((uint8_t*)(opt), (uint8_t)tcp::TcpOptCode::NOP, TCPOLEN_TIMESTAMP); - if ( i < 0 ) - { - for ( i = 0; i < p->tcp_option_count; i++ ) - { - if ( p->tcp_options[i].code == TCPOPT_TIMESTAMP ) - break; - } - if ( i == p->tcp_option_count ) - return; - } - // first set raw option bytes to nops - opt = (uint8_t*)p->tcp_options[i].data - 2; - memset(opt, TCPOPT_NOP, TCPOLEN_TIMESTAMP); - - // then nop decoded option code only - p->tcp_options[i].code = TCPOPT_NOP; p->packet_flags |= PKT_MODIFIED; normStats[PC_TCP_TS_NOP]++; @@ -2759,28 +2746,29 @@ static inline void S5TraceTCP ( static uint32_t Stream5GetTcpTimestamp(Packet *p, uint32_t *ts, int strip) { - unsigned int i = 0; - STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Getting timestamp...\n");); - while(i < p->tcp_option_count && i < TCP_OPTLENMAX) + + TcpOptIterator iter(p->tcph, p); + + // using const because non-const is not supported + for (const TcpOption& opt : iter) { - if(p->tcp_options[i].code == TCPOPT_TIMESTAMP) + if(opt.code == TcpOptCode::TIMESTAMP) { if ( strip && Normalize_IsEnabled(p, NORM_TCP_OPT) ) { - NormalStripTimeStamp(p, i); + NormalStripTimeStamp(p, &opt); } else { - *ts = EXTRACT_32BITS(p->tcp_options[i].data); + *ts = EXTRACT_32BITS(opt.data); STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Found timestamp %lu\n", *ts);); return TF_TSTAMP; } } - i++; } *ts = 0; @@ -2792,21 +2780,19 @@ static uint32_t Stream5GetTcpTimestamp(Packet *p, uint32_t *ts, int strip) static uint32_t Stream5GetMss(Packet *p, uint16_t *value) { - unsigned int i = 0; - STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Getting MSS...\n");); - while(i < p->tcp_option_count && i < TCP_OPTLENMAX) + + TcpOptIterator iter(p->tcph, p); + for (const TcpOption& opt : iter) { - if(p->tcp_options[i].code == TCPOPT_MAXSEG) + if(opt.code == TcpOptCode::MAXSEG) { - *value = EXTRACT_16BITS(p->tcp_options[i].data); + *value = EXTRACT_16BITS(opt.data); STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Found MSS %u\n", *value);); return TF_MSS; } - - i++; } *value = 0; @@ -2818,15 +2804,18 @@ static uint32_t Stream5GetMss(Packet *p, uint16_t *value) static uint32_t Stream5GetWscale(Packet *p, uint16_t *value) { - unsigned int i = 0; - STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Getting wscale...\n");); - while(i < p->tcp_option_count && i < TCP_OPTLENMAX) + + + TcpOptIterator iter(p->tcph, p); + + // using const because non-const is not supported + for (const TcpOption& opt : iter) { - if(p->tcp_options[i].code == TCPOPT_WSCALE) + if(opt.code == TcpOptCode::WSCALE) { - *value = (uint16_t) p->tcp_options[i].data[0]; + *value = (uint16_t) opt.data[0]; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Found wscale %d\n", *value);); @@ -2843,8 +2832,6 @@ static uint32_t Stream5GetWscale(Packet *p, uint16_t *value) return TF_WSCALE; } - - i++; } *value = 0; diff --git a/src/stream/udp/udp_session.cc b/src/stream/udp/udp_session.cc index 4213d17ee..f56d5226c 100644 --- a/src/stream/udp/udp_session.cc +++ b/src/stream/udp/udp_session.cc @@ -44,6 +44,7 @@ #include "packet_io/active.h" #include "perf_monitor/perf.h" #include "profiler.h" +#include "sfip/sf_ip.h" /* sender/responder ip/port dereference */ #define udp_sender_ip flow->client_ip diff --git a/src/target_based/sftarget_reader.cc b/src/target_based/sftarget_reader.cc index 53259836d..699dad2b6 100644 --- a/src/target_based/sftarget_reader.cc +++ b/src/target_based/sftarget_reader.cc @@ -50,6 +50,7 @@ #include "snort.h" #include "snort_debug.h" #include "utils/stats.h" +#include "sfip/sf_ip.h" #define ATTRIBUTE_MAP_MAX_ROWS 1024 diff --git a/src/time/ppm.cc b/src/time/ppm.cc index 1d28b3cbd..ed5786c6c 100644 --- a/src/time/ppm.cc +++ b/src/time/ppm.cc @@ -75,6 +75,7 @@ #include "actions/actions.h" #include "protocols/packet.h" #include "utils/stats.h" +#include "sfip/sf_ip.h" #ifdef PPM_MGR diff --git a/src/utils/dnet_header.h b/src/utils/dnet_header.h index 04e4b066e..eac129932 100644 --- a/src/utils/dnet_header.h +++ b/src/utils/dnet_header.h @@ -30,12 +30,17 @@ #endif -#if __clang__ +#if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wc99-extensions" #pragma clang diagnostic ignored "-Wflexible-array-extensions" #endif +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" +#endif + // Encoder FOO #ifdef HAVE_DUMBNET_H #include @@ -44,9 +49,13 @@ #endif -#if __clang__ +#if defined(__clang__) #pragma clang diagnostic pop #endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + #endif