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