1 //--------------------------------------------------------------------------
2 // Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 //
4 // This program is free software; you can redistribute it and/or modify it
5 // under the terms of the GNU General Public License Version 2 as published
6 // by the Free Software Foundation. You may not use, modify or distribute
7 // this program under any other version of the GNU General Public License.
8 //
9 // This program is distributed in the hope that it will be useful, but
10 // WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License along
15 // with this program; if not, write to the Free Software Foundation, Inc.,
16 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 //--------------------------------------------------------------------------
18 // cd_llc.cc author Josh Rosenbaum <jrosenba@cisco.com>
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "codecs/codec_module.h"
25 #include "framework/codec.h"
26 #include "log/text_log.h"
27
28 using namespace snort;
29
30 #define LLC_NAME "llc"
31 #define LLC_HELP "support for logical link control"
32
33 namespace
34 {
35 static const RuleMap llc_rules[] =
36 {
37 { DECODE_BAD_LLC_HEADER, "bad LLC header" },
38 { DECODE_BAD_LLC_OTHER, "bad extra LLC info"},
39 { 0, nullptr }
40 };
41
42 class LlcModule : public BaseCodecModule
43 {
44 public:
LlcModule()45 LlcModule() : BaseCodecModule(LLC_NAME, LLC_HELP) {}
46
get_rules() const47 const RuleMap* get_rules() const override
48 { return llc_rules; }
49 };
50
51 class LlcCodec : public Codec
52 {
53 public:
LlcCodec()54 LlcCodec() : Codec(LLC_NAME) { }
55
56 bool decode(const RawData&, CodecData&, DecodeData&) override;
57 void log(TextLog* const, const uint8_t* pkt, const uint16_t len) override;
58 void get_protocol_ids(std::vector<ProtocolId>&) override;
59 };
60
61 struct EthLlc
62 {
63 uint8_t dsap;
64 uint8_t ssap;
65 uint8_t ctrl;
66 };
67
68 struct EthLlcOther
69 {
70 uint8_t org_code[3];
71 uint8_t proto_id[2];
72
proto__anon2994217d0111::EthLlcOther73 ProtocolId proto() const
74 {
75 #ifdef __GNUC__
76 // fixing the type_punned pointer problem
77 const uint8_t* tmp1 = &proto_id[0];
78 const uint16_t* const tmp2 = reinterpret_cast<const uint16_t*>(tmp1);
79 return (ProtocolId)ntohs(*tmp2);
80 #else
81 return (ProtocolId)ntohs(*((uint16_t*)(&proto_id[0])));
82 #endif
83 }
84 };
85
86 #define ETH_DSAP_SNA 0x08 /* SNA */
87 #define ETH_SSAP_SNA 0x00 /* SNA */
88 #define ETH_DSAP_STP 0x42 /* Spanning Tree Protocol */
89 #define ETH_SSAP_STP 0x42 /* Spanning Tree Protocol */
90 #define ETH_DSAP_IP 0xaa /* IP */
91 #define ETH_SSAP_IP 0xaa /* IP */
92
93 #define ETH_ORG_CODE_ETHR 0x000000 /* Encapsulated Ethernet */
94 #define ETH_ORG_CODE_CDP 0x00000c /* Cisco Discovery Proto */
95 } // namespace
96
get_protocol_ids(std::vector<ProtocolId> & v)97 void LlcCodec::get_protocol_ids(std::vector<ProtocolId>& v)
98 { v.emplace_back(ProtocolId::ETHERNET_LLC); }
99
decode(const RawData & raw,CodecData & codec,DecodeData &)100 bool LlcCodec::decode(const RawData& raw, CodecData& codec, DecodeData&)
101 {
102 if (raw.len < sizeof(EthLlc))
103 {
104 // FIXIT-L need a better alert for llc len
105 codec_event(codec, DECODE_BAD_LLC_HEADER);
106 return false;
107 }
108
109 const EthLlc* ehllc = reinterpret_cast<const EthLlc*>(raw.data);
110
111 if (ehllc->dsap == ETH_DSAP_IP &&
112 ehllc->ssap == ETH_SSAP_IP)
113 {
114 if (raw.len < sizeof(EthLlc) + sizeof(EthLlcOther))
115 {
116 codec_event(codec, DECODE_BAD_LLC_OTHER);
117 return false;
118 }
119
120 const EthLlcOther* ehllcother = reinterpret_cast<const EthLlcOther*>(raw.data +
121 sizeof(EthLlc));
122
123 if (ehllcother->org_code[0] == 0 &&
124 ehllcother->org_code[1] == 0 &&
125 ehllcother->org_code[2] == 0)
126 {
127 codec.lyr_len = sizeof(EthLlc) + sizeof(EthLlcOther);
128 codec.next_prot_id = ehllcother->proto();
129 codec.codec_flags |= CODEC_ETHER_NEXT;
130 }
131 }
132
133 return true;
134 }
135
log(TextLog * const text_log,const uint8_t * raw_pkt,const uint16_t)136 void LlcCodec::log(TextLog* const text_log, const uint8_t* raw_pkt,
137 const uint16_t /*lyr_len*/)
138 {
139 const EthLlc* ehllc = reinterpret_cast<const EthLlc*>(raw_pkt);
140
141 TextLog_Print(text_log, "DSAP:0x%X SSAP:0x%X CTRL:0x%X",
142 ehllc->dsap, ehllc->ssap, ehllc->ctrl);
143
144 // Assuming that if these three conditions are met, this is SNAP.
145 if (ehllc->dsap == ETH_DSAP_IP &&
146 ehllc->ssap == ETH_SSAP_IP)
147 {
148 const EthLlcOther* other = reinterpret_cast<const EthLlcOther*>(raw_pkt + sizeof(EthLlc));
149 const ProtocolId proto = other->proto();
150
151 TextLog_Print(text_log, " ORG:0x%02X%02X%02X PROTO:0x%04X",
152 other->org_code[0], other->org_code[1], other->org_code[2],
153 static_cast<uint16_t>(proto));
154 }
155 }
156
157 //-------------------------------------------------------------------------
158 // api
159 //-------------------------------------------------------------------------
160
161
mod_ctor()162 static Module* mod_ctor()
163 { return new LlcModule; }
164
mod_dtor(Module * m)165 static void mod_dtor(Module* m)
166 { delete m; }
167
ctor(Module *)168 static Codec* ctor(Module*)
169 { return new LlcCodec(); }
170
dtor(Codec * cd)171 static void dtor(Codec* cd)
172 { delete cd; }
173
174 static const CodecApi llc_api =
175 {
176 {
177 PT_CODEC,
178 sizeof(CodecApi),
179 CDAPI_VERSION,
180 0,
181 API_RESERVED,
182 API_OPTIONS,
183 LLC_NAME,
184 LLC_HELP,
185 mod_ctor,
186 mod_dtor
187 },
188 nullptr,
189 nullptr,
190 nullptr,
191 nullptr,
192 ctor,
193 dtor,
194 };
195
196 #ifdef BUILDING_SO
197 SO_PUBLIC const BaseApi* snort_plugins[] =
198 #else
199 const BaseApi* cd_llc[] =
200 #endif
201 {
202 &llc_api.base,
203 nullptr
204 };
205
206