1 //--------------------------------------------------------------------------
2 // Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 // Copyright (C) 2002-2013 Sourcefire, Inc.
4 //
5 // This program is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU General Public License Version 2 as published
7 // by the Free Software Foundation. You may not use, modify or distribute
8 // this program under any other version of the GNU General Public License.
9 //
10 // This program is distributed in the hope that it will be useful, but
11 // WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License along
16 // with this program; if not, write to the Free Software Foundation, Inc.,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 //--------------------------------------------------------------------------
19 // cd_pppoe.cc author Josh Rosenbaum <jrosenba@cisco.com>
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "codecs/codec_module.h"
26 #include "framework/codec.h"
27
28 using namespace snort;
29
30 namespace
31 {
32 enum class PppoepktType
33 {
34 DISCOVERY,
35 SESSION,
36 };
37
38 /* PPPoEHdr Header; eth::EtherHdr plus the PPPoE Header */
39 struct PPPoEHdr
40 {
41 uint8_t ver_type; /* pppoe version/type */
42 uint8_t code; /* pppoe code CODE_* */
43 uint16_t session; /* session id */
44 uint16_t length; /* payload length */
45 /* payload follows */
46 };
47
48 //-------------------------------------------------------------------------
49 // General PPPoEpkt module.
50 //
51 // ***** NOTE: THE CODEC HAS A DIFFERENT NAME!
52 // * Additionally, this module is used for generating a rule stub ONLY!
53 // * If you want to create a module for configuration, you must change the
54 // * names of the correct PPPoEpkt codec
55 //-------------------------------------------------------------------------
56 #define CD_PPPOE_NAME "pppoe"
57 static const RuleMap pppoe_rules[] =
58 {
59 { DECODE_BAD_PPPOE, "bad PPPOE frame detected" },
60 { 0, nullptr }
61 };
62
63 #define pppoe_help \
64 "support for point-to-point protocol over ethernet"
65
66 class PPPoEModule : public BaseCodecModule
67 {
68 public:
PPPoEModule()69 PPPoEModule() : BaseCodecModule(CD_PPPOE_NAME, pppoe_help) { }
70
get_rules() const71 const RuleMap* get_rules() const override
72 { return pppoe_rules; }
73 };
74
75 class PPPoECodec : public Codec
76 {
77 public:
78 bool decode(const RawData&, CodecData&, DecodeData&) final;
79 bool encode(const uint8_t* const raw_in, const uint16_t raw_len,
80 EncState&, Buffer&, Flow*) final;
81
82 protected:
PPPoECodec(const char * s,PppoepktType type)83 PPPoECodec(const char* s, PppoepktType type) :
84 Codec(s),
85 ppp_type(type)
86 { }
87
88 private:
89 PppoepktType ppp_type;
90 };
91 } // namespace
92
93 constexpr uint16_t PPPOE_HEADER_LEN = 6;
94
decode(const RawData & raw,CodecData & codec,DecodeData &)95 bool PPPoECodec::decode(const RawData& raw,
96 CodecData& codec,
97 DecodeData&)
98 {
99 if (raw.len < PPPOE_HEADER_LEN)
100 {
101 codec_event(codec, DECODE_BAD_PPPOE);
102 return false;
103 }
104
105 if (ppp_type == PppoepktType::DISCOVERY)
106 {
107 return true;
108 }
109
110 codec.lyr_len = PPPOE_HEADER_LEN;
111 codec.next_prot_id = ProtocolId::ETHERTYPE_PPP;
112 return true;
113 }
114
115 /******************************************************************
116 ******************** E N C O D E R ******************************
117 ******************************************************************/
118
encode(const uint8_t * const raw_in,const uint16_t raw_len,EncState &,Buffer & buf,Flow *)119 bool PPPoECodec::encode(const uint8_t* const raw_in, const uint16_t raw_len,
120 EncState&, Buffer& buf, Flow*)
121 {
122 if (!buf.allocate(raw_len))
123 return false;
124
125 memcpy(buf.data(), raw_in, raw_len);
126 PPPoEHdr* const ppph = reinterpret_cast<PPPoEHdr*>(buf.data());
127 ppph->length = htons((uint16_t)buf.size());
128
129 return true;
130 }
131
132 /*******************************************************************
133 *******************************************************************
134 ************* CODECS ****************
135 *******************************************************************
136 *******************************************************************/
137
138 namespace
139 {
140 #define CD_PPPOEPKT_DISC_NAME "pppoe_disc"
141 #define CD_PPPOEPKT_DISC_HELP "support for point-to-point discovery"
142
143 #define CD_PPPOEPKT_SESS_NAME "pppoe_sess"
144 #define CD_PPPOEPKT_SESS_HELP "support for point-to-point session"
145
146 /* 'decode' and 'encode' functions are in the PPPoECodec */
147 class PPPoEDiscCodec : public PPPoECodec
148 {
149 public:
PPPoEDiscCodec()150 PPPoEDiscCodec() : PPPoECodec(CD_PPPOEPKT_DISC_NAME, PppoepktType::DISCOVERY) { }
151
get_protocol_ids(std::vector<ProtocolId> & v)152 void get_protocol_ids(std::vector<ProtocolId>& v) override
153 { v.emplace_back(ProtocolId::ETHERTYPE_PPPOE_DISC); }
154 };
155
156 class PPPoESessCodec : public PPPoECodec
157 {
158 public:
PPPoESessCodec()159 PPPoESessCodec() : PPPoECodec(CD_PPPOEPKT_SESS_NAME, PppoepktType::SESSION) { }
160
get_protocol_ids(std::vector<ProtocolId> & v)161 void get_protocol_ids(std::vector<ProtocolId>& v) override
162 { v.emplace_back(ProtocolId::ETHERTYPE_PPPOE_SESS); }
163 };
164 } // namespace
165
166 //-------------------------------------------------------------------------
167 // api
168 //-------------------------------------------------------------------------
169
170 // *** NOTE: THE CODEC AND MODULE HAVE A DIFFERENT NAME!
171 // since the module is only creating a rule stub and is NOT
172 // used for configuration, it doesn't matter. However, if you want to use the module
173 // for configuration, ensure the names are identical before continuing!
mod_ctor()174 static Module* mod_ctor()
175 { return new PPPoEModule; }
176
mod_dtor(Module * m)177 static void mod_dtor(Module* m)
178 { delete m; }
179
disc_ctor(Module *)180 static Codec* disc_ctor(Module*)
181 { return new PPPoEDiscCodec(); }
182
sess_ctor(Module *)183 static Codec* sess_ctor(Module*)
184 { return new PPPoESessCodec(); }
185
pppoe_dtor(Codec * cd)186 static void pppoe_dtor(Codec* cd)
187 { delete cd; }
188
189 static const CodecApi pppoepkt_disc_api =
190 {
191 {
192 PT_CODEC,
193 sizeof(CodecApi),
194 CDAPI_VERSION,
195 0,
196 API_RESERVED,
197 API_OPTIONS,
198 CD_PPPOEPKT_DISC_NAME,
199 CD_PPPOEPKT_DISC_HELP,
200 mod_ctor,
201 mod_dtor,
202 },
203 nullptr,
204 nullptr,
205 nullptr,
206 nullptr,
207 disc_ctor,
208 pppoe_dtor,
209 };
210
211 static const CodecApi pppoepkt_sess_api =
212 {
213 {
214 PT_CODEC,
215 sizeof(CodecApi),
216 CDAPI_VERSION,
217 0,
218 API_RESERVED,
219 API_OPTIONS,
220 CD_PPPOEPKT_SESS_NAME,
221 CD_PPPOEPKT_SESS_HELP,
222 nullptr,
223 nullptr,
224 },
225 nullptr,
226 nullptr,
227 nullptr,
228 nullptr,
229 sess_ctor,
230 pppoe_dtor,
231 };
232
233 #ifdef BUILDING_SO
234 SO_PUBLIC const BaseApi* snort_plugins[] =
235 #else
236 const BaseApi* cd_pppoepkt[] =
237 #endif
238 {
239 &pppoepkt_disc_api.base,
240 &pppoepkt_sess_api.base,
241 nullptr
242 };
243
244