00001 //--------------------------------------------------------------------------
00002 // Copyright (C) 2014-2017 Cisco and/or its affiliates. All rights reserved.
00003 // Copyright (C) 2002-2013 Sourcefire, Inc.
00004 //
00005 // This program is free software; you can redistribute it and/or modify it
00006 // under the terms of the GNU General Public License Version 2 as published
00007 // by the Free Software Foundation. You may not use, modify or distribute
00008 // this program under any other version of the GNU General Public License.
00009 //
00010 // This program is distributed in the hope that it will be useful, but
00011 // WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00013 // General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License along
00016 // with this program; if not, write to the Free Software Foundation, Inc.,
00017 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00018 //--------------------------------------------------------------------------
00019 // cd_eth.cc author Josh Rosenbaum <jrosenba@cisco.com>
00020
00021 #ifdef HAVE_CONFIG_H
00022 #include "config.h"
00023 #endif
00024
00025 #include <sfbpf_dlt.h>
00026
00027 #include "codecs/codec_module.h"
00028 #include "framework/codec.h"
00029 #include "log/text_log.h"
00030 #include "main/snort_config.h"
00031 #include "protocols/eth.h"
00032 #include "protocols/packet_manager.h"
00033
00034 #define CD_ETH_NAME "eth"
00035 #define CD_ETH_HELP_STR "support for ethernet protocol"
00036 #define CD_ETH_HELP ADD_DLT(ADD_DLT(CD_ETH_HELP_STR, DLT_EN10MB), DLT_PPP_ETHER)
00037
00038 namespace
00039 {
00040 static const RuleMap eth_rules[] =
00041 {
00042 { DECODE_ETH_HDR_TRUNC, "truncated ethernet header" },
00043 { 0, nullptr }
00044 };
00045
00046 class EthModule : public CodecModule
00047 {
00048 public:
00049 EthModule() : CodecModule(CD_ETH_NAME, CD_ETH_HELP) { }
00050
00051 const RuleMap* get_rules() const override
00052 { return eth_rules; }
00053 };
00054
00055 class EthCodec : public Codec
00056 {
00057 public:
00058 EthCodec() : Codec(CD_ETH_NAME) { }
00059
00060 void get_protocol_ids(std::vector<ProtocolId>&) override;
00061 void get_data_link_type(std::vector<int>&) override;
00062 void log(TextLog* const, const uint8_t* pkt, const uint16_t len) override;
00063 bool decode(const RawData&, CodecData&, DecodeData&) override;
00064 bool encode(const uint8_t* const raw_in, const uint16_t raw_len,
00065 EncState&, Buffer&, Flow*) override;
00066 void format(bool reverse, uint8_t* raw_pkt, DecodeData& snort) override;
00067 void update(const ip::IpApi&, const EncodeFlags, uint8_t* raw_pkt,
00068 uint16_t lyr_len, uint32_t& updated_len) override;
00069 };
00070 } // namespace
00071
00072 void EthCodec::get_data_link_type(std::vector<int>& v)
00073 {
00074 v.push_back(DLT_PPP_ETHER);
00075 v.push_back(DLT_EN10MB);
00076 }
00077
00078 void EthCodec::get_protocol_ids(std::vector<ProtocolId>& v)
00079 {
00080 v.push_back(ProtocolId::ETHERNET_802_3);
00081 }
00082
00083 bool EthCodec::decode(const RawData& raw, CodecData& codec, DecodeData&)
00084 {
00085 if (raw.len < eth::ETH_HEADER_LEN)
00086 {
00087 codec_event(codec, DECODE_ETH_HDR_TRUNC);
00088 return false;
00089 }
00090
00091 /* lay the ethernet structure over the packet data */
00092 const eth::EtherHdr* eh = reinterpret_cast<const eth::EtherHdr*>(raw.data);
00093
00094 ProtocolId next_prot = eh->ethertype();
00095 if ( to_utype(next_prot) <= to_utype(ProtocolId::ETHERTYPE_MINIMUM) )
00096 {
00097 codec.next_prot_id = ProtocolId::ETHERNET_LLC;
00098 codec.lyr_len = eth::ETH_HEADER_LEN;
00099 codec.proto_bits |= PROTO_BIT__ETH;
00100 }
00101 else if ( next_prot == ProtocolId::ETHERTYPE_FPATH )
00102 {
00103 /* If this is FabricPath, the first 16 bytes are FabricPath data
00104 * rather than Ethernet data. So, set the length to zero and
00105 * and decode this FabricPath data. Then, FabricPath will send the decoder
00106 * right back to this Ethernet function.
00107 */
00108 codec.next_prot_id = next_prot;
00109 codec.lyr_len = 0;
00110 }
00111 else
00112 {
00113 codec.proto_bits |= PROTO_BIT__ETH;
00114 codec.lyr_len = eth::ETH_HEADER_LEN;
00115 codec.next_prot_id = next_prot;
00116 }
00117
00118 return true;
00119 }
00120
00121 void EthCodec::log(TextLog* const text_log, const uint8_t* raw_pkt,
00122 const uint16_t /*len*/)
00123 {
00124 const eth::EtherHdr* eh = reinterpret_cast<const eth::EtherHdr*>(raw_pkt);
00125
00126 /* src addr */
00127 TextLog_Print(text_log, "%02X:%02X:%02X:%02X:%02X:%02X -> ", eh->ether_src[0],
00128 eh->ether_src[1], eh->ether_src[2], eh->ether_src[3],
00129 eh->ether_src[4], eh->ether_src[5]);
00130
00131 /* dest addr */
00132 TextLog_Print(text_log, "%02X:%02X:%02X:%02X:%02X:%02X", eh->ether_dst[0],
00133 eh->ether_dst[1], eh->ether_dst[2], eh->ether_dst[3],
00134 eh->ether_dst[4], eh->ether_dst[5]);
00135
00136 const ProtocolId prot_id = eh->ethertype();
00137
00138 if (to_utype(prot_id) <= to_utype(ProtocolId::ETHERTYPE_MINIMUM))
00139 TextLog_Print(text_log, " len:0x%04X", prot_id);
00140 else
00141 TextLog_Print(text_log, " type:0x%04X", prot_id);
00142 }
00143
00144 //-------------------------------------------------------------------------
00145 // ethernet
00146 //-------------------------------------------------------------------------
00147
00148 bool EthCodec::encode(const uint8_t* const raw_in, const uint16_t /*raw_len*/,
00149 EncState& enc, Buffer& buf, Flow*)
00150 {
00151 const eth::EtherHdr* hi = reinterpret_cast<const eth::EtherHdr*>(raw_in);
00152
00153 if (hi->ethertype() == ProtocolId::ETHERTYPE_FPATH)
00154 return true;
00155
00156 // not raw ip -> encode layer 2
00157 bool raw = ( enc.flags & ENC_FLAG_RAW );
00158
00159 if ( !raw || (buf.size() != 0) )
00160 {
00161 // we get here for outer-most layer when not raw ip
00162 // we also get here for any encapsulated ethernet layer.
00163 if ( !buf.allocate(eth::ETH_HEADER_LEN) )
00164 return false;
00165
00166 eth::EtherHdr* ho = reinterpret_cast<eth::EtherHdr*>(buf.data());
00167 ho->ether_type = enc.ethertype_set() ?
00168 htons(to_utype(enc.next_ethertype)) : hi->ether_type;
00169
00170 if ( enc.forward() )
00171 {
00172 memcpy(ho->ether_src, hi->ether_src, sizeof(ho->ether_src));
00173
00174 if ( snort_conf->eth_dst )
00175 memcpy(ho->ether_dst, snort_conf->eth_dst, sizeof(ho->ether_dst));
00176 else
00177 memcpy(ho->ether_dst, hi->ether_dst, sizeof(ho->ether_dst));
00178 }
00179 else
00180 {
00181 memcpy(ho->ether_src, hi->ether_dst, sizeof(ho->ether_src));
00182
00183 if ( snort_conf->eth_dst )
00184 memcpy(ho->ether_dst, snort_conf->eth_dst, sizeof(ho->ether_dst));
00185 else
00186 memcpy(ho->ether_dst, hi->ether_src, sizeof(ho->ether_dst));
00187 }
00188 }
00189
00190 enc.next_ethertype = ProtocolId::ETHERTYPE_NOT_SET;
00191 enc.next_proto = IpProtocol::PROTO_NOT_SET;
00192 return true;
00193 }
00194
00195 void EthCodec::format(bool reverse, uint8_t* raw_pkt, DecodeData&)
00196 {
00197 eth::EtherHdr* ch = reinterpret_cast<eth::EtherHdr*>(raw_pkt);
00198
00199 // If the ethertype is FabricPath, then this is not Ethernet Data.
00200 if ( reverse && (ch->ethertype() != ProtocolId::ETHERTYPE_FPATH) )
00201 {
00202 uint8_t tmp_addr[6];
00203
00204 memcpy(tmp_addr, ch->ether_dst, sizeof(ch->ether_dst));
00205 memcpy(ch->ether_dst, ch->ether_src, sizeof(ch->ether_src));
00206 memcpy(ch->ether_src, tmp_addr, sizeof(ch->ether_src));
00207 }
00208 }
00209
00210 void EthCodec::update(const ip::IpApi&, const EncodeFlags, uint8_t* raw_pkt,
00211 uint16_t lyr_len, uint32_t& updated_len)
00212 {
00213 const eth::EtherHdr* const eth = reinterpret_cast<eth::EtherHdr*>(raw_pkt);
00214
00215 if ( eth->ethertype() != ProtocolId::ETHERTYPE_FPATH )
00216 updated_len += lyr_len;
00217 }
00218
00219 //-------------------------------------------------------------------------
00220 // api
00221 //-------------------------------------------------------------------------
00222
00223 static Module* mod_ctor()
00224 { return new EthModule; }
00225
00226 static void mod_dtor(Module* m)
00227 { delete m; }
00228
00229 static Codec* ctor(Module*)
00230 { return new EthCodec(); }
00231
00232 static void dtor(Codec* cd)
00233 { delete cd; }
00234
00235 static const CodecApi eth_api =
00236 {
00237 {
00238 PT_CODEC,
00239 sizeof(CodecApi),
00240 CDAPI_VERSION,
00241 0,
00242 API_RESERVED,
00243 API_OPTIONS,
00244 CD_ETH_NAME,
00245 CD_ETH_HELP,
00246 mod_ctor,
00247 mod_dtor,
00248 },
00249 nullptr, // pinit
00250 nullptr, // pterm
00251 nullptr, // tinit
00252 nullptr, // tterm
00253 ctor, // ctor
00254 dtor, // dtor
00255 };
00256
00257 #ifdef BUILDING_SO
00258 SO_PUBLIC const BaseApi* snort_plugins[] =
00259 #else
00260 const BaseApi* cd_eth[] =
00261 #endif
00262 {
00263 ð_api.base,
00264 nullptr
00265 };
00266
END OF CODE