From: Josh Date: Thu, 11 Dec 2014 18:17:51 +0000 (-0600) Subject: initial CAPWAP support X-Git-Tag: 3.0.0-233~1089^2~17 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ea9d943a6f6946ce1cd57766df969e5edbda0b77;p=thirdparty%2Fsnort3.git initial CAPWAP support --- diff --git a/src/codecs/codec_api.cc b/src/codecs/codec_api.cc index 06e4fdad8..b81502ce9 100644 --- a/src/codecs/codec_api.cc +++ b/src/codecs/codec_api.cc @@ -39,6 +39,7 @@ extern const BaseApi* cd_tcp; // static because only file that specific functio #ifdef STATIC_CODECS extern const BaseApi* cd_ah; extern const BaseApi* cd_arp; +extern const BaseApi* cd_capwap; extern const BaseApi* cd_dstopts; extern const BaseApi* cd_erspan2; extern const BaseApi* cd_erspan3; @@ -91,6 +92,7 @@ const BaseApi* codecs[] = #ifdef STATIC_CODECS cd_ah, cd_arp, + cd_capwap, cd_dstopts, cd_erspan2, cd_erspan3, diff --git a/src/codecs/codec_module.h b/src/codecs/codec_module.h index 398bab648..c7e20619f 100644 --- a/src/codecs/codec_module.h +++ b/src/codecs/codec_module.h @@ -203,7 +203,8 @@ enum CodecSid DECODE_AUTH_HDR_TRUNC, DECODE_AUTH_HDR_BAD_LEN, DECODE_TOO_MANY_LAYERS, - DECODE_INDEX_MAX // = 468 + DECODE_CAPWAP_TRUNC, + DECODE_INDEX_MAX // = 469 }; diff --git a/src/codecs/ip/cd_icmp4.cc b/src/codecs/ip/cd_icmp4.cc index 9f8fd6cae..c6f962ea3 100644 --- a/src/codecs/ip/cd_icmp4.cc +++ b/src/codecs/ip/cd_icmp4.cc @@ -247,7 +247,7 @@ bool Icmp4Codec::decode(const RawData& raw, CodecData& codec,DecodeData& snort) case icmp::IcmpType::PARAMETERPROB: /* account for extra 4 bytes in header */ len += 4; - codec.next_prot_id = IP_EMBEDDED_IN_ICMP4; + codec.next_prot_id = PROTO_IP_EMBEDDED_IN_ICMP4; break; default: diff --git a/src/codecs/ip/cd_icmp6.cc b/src/codecs/ip/cd_icmp6.cc index 9f23def7f..6d0d4e931 100644 --- a/src/codecs/ip/cd_icmp6.cc +++ b/src/codecs/ip/cd_icmp6.cc @@ -195,7 +195,7 @@ bool Icmp6Codec::decode(const RawData& raw, CodecData& codec, DecodeData& snort) codec_events::decoder_event(codec, DECODE_ICMPV6_TOO_BIG_BAD_MTU); len = icmp::ICMP6_HEADER_NORMAL_LEN; - codec.next_prot_id = IP_EMBEDDED_IN_ICMP6; + codec.next_prot_id = PROTO_IP_EMBEDDED_IN_ICMP6; } else { @@ -218,7 +218,7 @@ bool Icmp6Codec::decode(const RawData& raw, CodecData& codec, DecodeData& snort) codec_events::decoder_event(codec, DECODE_ICMPV6_UNREACHABLE_NON_RFC_4443_CODE); } len = icmp::ICMP6_HEADER_NORMAL_LEN; - codec.next_prot_id = IP_EMBEDDED_IN_ICMP6; + codec.next_prot_id = PROTO_IP_EMBEDDED_IN_ICMP6; } else { diff --git a/src/codecs/ip/cd_udp.cc b/src/codecs/ip/cd_udp.cc index c453ce233..986fa3468 100644 --- a/src/codecs/ip/cd_udp.cc +++ b/src/codecs/ip/cd_udp.cc @@ -77,6 +77,9 @@ static const Parameter udp_params[] = { "gtp_ports", Parameter::PT_BIT_LIST, "65535", "2152 3386", "set GTP ports" }, + { "capwap_ports", Parameter::PT_BIT_LIST, "65535", + "5246 5247", "customize capwap_ports" }, + { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } }; @@ -138,6 +141,10 @@ public: } } } + else if ( v.is("capwap_ports") ) + { + v.get_bits(*(sc->capwap_ports)); + } else { return false; @@ -330,13 +337,18 @@ bool UdpCodec::decode(const RawData& raw, CodecData& codec, DecodeData& snort) (ScIsGTPPort(src_port)||ScIsGTPPort(dst_port))) { if ( !(snort.decode_flags & DECODE_FRAG) ) - codec.next_prot_id = PROTOCOL_GTP; + codec.next_prot_id = PROTO_GTP; } else if (teredo::is_teredo_port(src_port) || teredo::is_teredo_port(dst_port) || ScDeepTeredoInspection()) { - codec.next_prot_id = PROTOCOL_TEREDO; + codec.next_prot_id = PROTO_TEREDO; + } + else if (snort_conf->is_capwap_port(dst_port) || + snort_conf->is_capwap_port(src_port)) + { + codec.next_prot_id = PROTO_CAPWAP; } diff --git a/src/codecs/link/cd_vlan.cc b/src/codecs/link/cd_vlan.cc index 63da35f92..c8b908942 100644 --- a/src/codecs/link/cd_vlan.cc +++ b/src/codecs/link/cd_vlan.cc @@ -100,7 +100,7 @@ bool VlanCodec::decode(const RawData& raw, CodecData& codec, DecodeData&) * http://www.geocities.com/billalexander/ethernet.html */ if(proto <= ETHERNET_MAX_LEN_ENCAP) - codec.next_prot_id = ETHERNET_LLC; + codec.next_prot_id = PROTO_ETHERNET_LLC; else codec.next_prot_id = proto; diff --git a/src/codecs/misc/CMakeLists.txt b/src/codecs/misc/CMakeLists.txt index 6425e338d..b709da2f8 100644 --- a/src/codecs/misc/CMakeLists.txt +++ b/src/codecs/misc/CMakeLists.txt @@ -19,6 +19,7 @@ endif(STATIC_CODECS) add_library( misc_codecs STATIC cd_default.cc + cd_capwap.cc ${PLUGIN_LIST} ) diff --git a/src/codecs/misc/cd_gtp.cc b/src/codecs/misc/cd_gtp.cc index 041d7cb18..7069bb3fc 100644 --- a/src/codecs/misc/cd_gtp.cc +++ b/src/codecs/misc/cd_gtp.cc @@ -96,7 +96,7 @@ static const uint32_t GTP_V1_HEADER_LEN = 12; void GtpCodec::get_protocol_ids(std::vector& v) { - v.push_back(PROTOCOL_GTP); + v.push_back(PROTO_GTP); } /* Function: DecodeGTP(uint8_t *, uint32_t, Packet *) diff --git a/src/codecs/misc/cd_icmp4_ip.cc b/src/codecs/misc/cd_icmp4_ip.cc index 64b804252..576cd7cec 100644 --- a/src/codecs/misc/cd_icmp4_ip.cc +++ b/src/codecs/misc/cd_icmp4_ip.cc @@ -59,7 +59,7 @@ public: void Icmp4IpCodec::get_protocol_ids(std::vector& v) -{ v.push_back(IP_EMBEDDED_IN_ICMP4); } +{ v.push_back(PROTO_IP_EMBEDDED_IN_ICMP4); } bool Icmp4IpCodec::decode(const RawData& raw, CodecData& codec, DecodeData& snort) { diff --git a/src/codecs/misc/cd_icmp6_ip.cc b/src/codecs/misc/cd_icmp6_ip.cc index 08a2e2ed6..fd5b4350e 100644 --- a/src/codecs/misc/cd_icmp6_ip.cc +++ b/src/codecs/misc/cd_icmp6_ip.cc @@ -59,7 +59,7 @@ public: } // namespace void Icmp6IpCodec::get_protocol_ids(std::vector& v) -{ v.push_back(IP_EMBEDDED_IN_ICMP6); } +{ v.push_back(PROTO_IP_EMBEDDED_IN_ICMP6); } bool Icmp6IpCodec::decode(const RawData& raw, CodecData& codec, DecodeData&) { diff --git a/src/codecs/misc/cd_llc.cc b/src/codecs/misc/cd_llc.cc index 11e8a3f9c..7d14e26b9 100644 --- a/src/codecs/misc/cd_llc.cc +++ b/src/codecs/misc/cd_llc.cc @@ -32,10 +32,7 @@ #include "log/text_log.h" #include "protocols/packet_manager.h" -// yes, macros are necessary. The API and class constructor require different strings. -// -// this macros is defined in the module to ensure identical names. However, -// if you don't want a module, define the name here. + #define LLC_NAME "llc" #define LLC_HELP "support for logical link control" @@ -67,7 +64,10 @@ struct EthLlc struct EthLlcOther { uint8_t org_code[3]; - uint16_t proto_id; + uint8_t proto_id[2]; + + uint16_t proto() const + { return ntohs(*((uint16_t*)(&proto_id[0]))); } }; #define ETH_DSAP_SNA 0x08 /* SNA */ @@ -84,9 +84,7 @@ struct EthLlcOther void LlcCodec::get_protocol_ids(std::vector& v) -{ - v.push_back(ETHERNET_LLC); -} +{ v.push_back(PROTO_ETHERNET_LLC); } bool LlcCodec::decode(const RawData& raw, CodecData& codec, DecodeData&) { @@ -117,7 +115,7 @@ bool LlcCodec::decode(const RawData& raw, CodecData& codec, DecodeData&) ehllcother->org_code[2] == 0) { codec.lyr_len = sizeof(EthLlc) + sizeof(EthLlcOther); - codec.next_prot_id = ntohs(ehllcother->proto_id); + codec.next_prot_id = ehllcother->proto(); } } @@ -138,7 +136,7 @@ void LlcCodec::log(TextLog* const text_log, const uint8_t* raw_pkt, { const EthLlcOther *other = reinterpret_cast(raw_pkt + sizeof(EthLlc)); - const uint16_t proto = ntohs(other->proto_id); + const uint16_t proto = other->proto(); TextLog_Print(text_log, " ORG:0x%02X%02X%02X PROTO:0x%04X", other->org_code[0], other->org_code[1], other->org_code[2], diff --git a/src/codecs/misc/cd_teredo.cc b/src/codecs/misc/cd_teredo.cc index a114dd6c9..e7a4a5f01 100644 --- a/src/codecs/misc/cd_teredo.cc +++ b/src/codecs/misc/cd_teredo.cc @@ -26,8 +26,6 @@ #include "config.h" #endif -//#include "prot_ipv6.h" - #include "framework/codec.h" #include "packet_io/active.h" #include "snort_types.h" @@ -58,7 +56,7 @@ public: void TeredoCodec::get_protocol_ids(std::vector& v) { - v.push_back(PROTOCOL_TEREDO); + v.push_back(PROTO_TEREDO); } bool TeredoCodec::decode(const RawData& raw, CodecData& codec, DecodeData& snort) diff --git a/src/codecs/root/cd_eth.cc b/src/codecs/root/cd_eth.cc index 56a11b9f7..72fc0c571 100644 --- a/src/codecs/root/cd_eth.cc +++ b/src/codecs/root/cd_eth.cc @@ -88,7 +88,7 @@ void EthCodec::get_data_link_type(std::vector&v) void EthCodec::get_protocol_ids(std::vector&v) { - v.push_back(ETHERNET_802_3); + v.push_back(PROTO_ETHERNET_802_3); } @@ -126,7 +126,7 @@ bool EthCodec::decode(const RawData& raw, CodecData& codec, DecodeData&) if (next_prot > eth::MIN_ETHERTYPE ) codec.proto_bits |= PROTO_BIT__ETH; else - next_prot = ETHERNET_LLC; + next_prot = PROTO_ETHERNET_LLC; codec.next_prot_id = next_prot; codec.lyr_len = eth::ETH_HEADER_LEN; diff --git a/src/codecs/root/cd_wlan.cc b/src/codecs/root/cd_wlan.cc index abf919f1f..ad78ee972 100644 --- a/src/codecs/root/cd_wlan.cc +++ b/src/codecs/root/cd_wlan.cc @@ -33,6 +33,10 @@ #include "main/snort.h" #include "log/text_log.h" +#ifndef DLT_IEEE802_11 +#define DLT_IEEE802_11 105 +#endif + #define CD_WLAN_NAME "wlan" #define CD_WLAN_HELP_STR "support for wireless local area network protocol" #define CD_WLAN_HELP ADD_DLT(CD_WLAN_HELP_STR, DLT_IEEE802_11) @@ -66,6 +70,7 @@ public: bool decode(const RawData&, CodecData&, DecodeData&) override; void get_data_link_type(std::vector&) override; + void get_protocol_ids(std::vector&v) override; void log(TextLog* const, const uint8_t* /*raw_pkt*/, const Packet* const) override; }; @@ -77,11 +82,10 @@ public: void WlanCodec::get_data_link_type(std::vector&v) -{ -#ifdef DLT_IEEE802_11 - v.push_back(DLT_IEEE802_11); -#endif -} +{ v.push_back(DLT_IEEE802_11); } + +void WlanCodec::get_protocol_ids(std::vector&v) +{ v.push_back(PROTO_ETHERNET_802_11); } bool WlanCodec::decode(const RawData& raw, CodecData& codec, DecodeData&) { @@ -131,7 +135,7 @@ bool WlanCodec::decode(const RawData& raw, CodecData& codec, DecodeData&) case WLAN_TYPE_DATA_DATA: { codec.lyr_len = IEEE802_11_DATA_HDR_LEN; - codec.next_prot_id = ETHERNET_LLC; + codec.next_prot_id = PROTO_ETHERNET_LLC; break; } diff --git a/src/main/snort_config.cc b/src/main/snort_config.cc index fa1f586ef..950a05283 100644 --- a/src/main/snort_config.cc +++ b/src/main/snort_config.cc @@ -44,6 +44,7 @@ #include "filters/detection_filter.h" #include "detection/fpcreate.h" #include "ips_options/ips_pcre.h" +#include "protocols/udp.h" //------------------------------------------------------------------------- // private implementation @@ -181,6 +182,9 @@ SnortConfig * SnortConfNew(void) sc->max_ip6_extensions = 0; sc->max_ip_layers = 0; sc->gtp_ports = nullptr; + sc->capwap_ports = new PortList; + sc->capwap_ports->set(udp::CAPWAP_CONTROL_CHANNEL_PORT); + sc->capwap_ports->set(udp::CAPWAP_DATA_CHANNEL_PORT); /*user_id and group_id should be initialized to -1 by default, because * chown() use this later, -1 means no change to user_id/group_id*/ @@ -356,6 +360,9 @@ void SnortConfFree(SnortConfig *sc) if (sc->gtp_ports) delete sc->gtp_ports; + if (sc->capwap_ports) + delete sc->capwap_ports; + free(sc); } diff --git a/src/main/snort_config.h b/src/main/snort_config.h index f538aea16..2bf22442e 100644 --- a/src/main/snort_config.h +++ b/src/main/snort_config.h @@ -158,6 +158,7 @@ struct SnortConfig uint8_t enable_teredo; uint8_t enable_esp; PortList *gtp_ports; + PortList *capwap_ports; uint8_t num_layers; uint8_t max_ip6_extensions; @@ -312,6 +313,9 @@ struct SnortConfig // curr_ip is the zero based ip layer inline bool hit_ip_maxlayers(uint8_t curr_ip) const { return max_ip_layers && (curr_ip >= max_ip_layers); } + + inline bool is_capwap_port(uint16_t port) const + { return capwap_ports->test(port); } }; SnortConfig* SnortConfNew(void); diff --git a/src/protocols/layer.cc b/src/protocols/layer.cc index 024381749..a96fa1181 100644 --- a/src/protocols/layer.cc +++ b/src/protocols/layer.cc @@ -414,14 +414,14 @@ bool set_api_ip_embed_icmp(const Packet* p, ip::IpApi& api) { const Layer& lyr = p->layers[i]; - if (lyr.prot_id == IP_EMBEDDED_IN_ICMP4) + if (lyr.prot_id == PROTO_IP_EMBEDDED_IN_ICMP4) { const ip::IP4Hdr* ip4h = reinterpret_cast(lyr.start); api.set(ip4h); return true; } - else if (lyr.prot_id == IP_EMBEDDED_IN_ICMP6) + else if (lyr.prot_id == PROTO_IP_EMBEDDED_IN_ICMP6) { const ip::IP6Hdr* ip6h = reinterpret_cast(lyr.start); diff --git a/src/protocols/packet_manager.cc b/src/protocols/packet_manager.cc index 84078edb6..927170b3c 100644 --- a/src/protocols/packet_manager.cc +++ b/src/protocols/packet_manager.cc @@ -282,7 +282,7 @@ void PacketManager::decode( p->ptrs.decode_flags |= DECODE_PKT_TRUST; break; - case PROTOCOL_TEREDO: + case PROTO_TEREDO: // if we just decoded teredo and the next // layer fails, we made a mistake. Therefore, // remove this bit. diff --git a/src/protocols/protocol_ids.h b/src/protocols/protocol_ids.h index 485ecd692..8eb7d8929 100644 --- a/src/protocols/protocol_ids.h +++ b/src/protocols/protocol_ids.h @@ -69,12 +69,14 @@ constexpr uint16_t IPPROTO_ID_RESERVED = 255; // == 0xFF */ constexpr uint16_t FINISHED_DECODE = 0x0100; // Indicates Codecs have succesfully decoded packet -constexpr uint16_t PROTOCOL_TEREDO = 0x0101; -constexpr uint16_t PROTOCOL_GTP = 0x0102; -constexpr uint16_t IP_EMBEDDED_IN_ICMP4 = 0x0103; -constexpr uint16_t IP_EMBEDDED_IN_ICMP6 = 0x0104; -constexpr uint16_t ETHERNET_802_3 = 0x0105; // CAPWAP sends data back to eth layer -constexpr uint16_t ETHERNET_LLC = 0x0106; +constexpr uint16_t PROTO_TEREDO = 0x0101; +constexpr uint16_t PROTO_GTP = 0x0102; +constexpr uint16_t PROTO_IP_EMBEDDED_IN_ICMP4 = 0x0103; +constexpr uint16_t PROTO_IP_EMBEDDED_IN_ICMP6 = 0x0104; +constexpr uint16_t PROTO_ETHERNET_802_3 = 0x0105; +constexpr uint16_t PROTO_ETHERNET_802_11 = 0x0106; +constexpr uint16_t PROTO_ETHERNET_LLC = 0x0107; +constexpr uint16_t PROTO_CAPWAP = 0x0108; diff --git a/src/protocols/udp.h b/src/protocols/udp.h index 116833ed2..1cf5abbfa 100644 --- a/src/protocols/udp.h +++ b/src/protocols/udp.h @@ -31,6 +31,9 @@ namespace udp constexpr uint8_t UDP_HEADER_LEN = 8; +constexpr uint16_t CAPWAP_CONTROL_CHANNEL_PORT = 5246; +constexpr uint16_t CAPWAP_DATA_CHANNEL_PORT = 5247; + struct UDPHdr { uint16_t uh_sport;