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_pgm.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 #include "checksum.h"
29
30 using namespace snort;
31
32 namespace
33 {
34 #define CD_PGM_NAME "pgm"
35 #define CD_PGM_HELP "support for pragmatic general multicast"
36
37 static const RuleMap pgm_rules[] =
38 {
39 { DECODE_PGM_NAK_OVERFLOW, "PGM nak list overflow attempt" },
40 { 0, nullptr }
41 };
42
43 class PgmModule : public BaseCodecModule
44 {
45 public:
PgmModule()46 PgmModule() : BaseCodecModule(CD_PGM_NAME, CD_PGM_HELP) { }
47
get_rules() const48 const RuleMap* get_rules() const override
49 { return pgm_rules; }
50 };
51
52 class PgmCodec : public Codec
53 {
54 public:
PgmCodec()55 PgmCodec() : Codec(CD_PGM_NAME) { }
56
57 bool decode(const RawData&, CodecData&, DecodeData&) override;
58 void get_protocol_ids(std::vector<ProtocolId>&) override;
59 };
60
61 static const int PGM_NAK_ERR = -1;
62 static const int PGM_NAK_OK = 0;
63 static const int PGM_NAK_VULN = 1;
64
65 struct PGM_NAK_OPT
66 {
67 uint8_t type; /* 02 = vuln */
68 uint8_t len;
69 uint8_t res[2];
70 uint32_t seq[1]; /* could be many many more, but 1 is sufficient */
71 };
72
73 struct PGM_NAK
74 {
75 uint32_t seqnum;
76 uint16_t afil1;
77 uint16_t res1;
78 uint32_t src;
79 uint16_t afi2;
80 uint16_t res2;
81 uint32_t multi;
82 PGM_NAK_OPT opt;
83 };
84
85 struct PgmHeader
86 {
87 uint16_t srcport;
88 uint16_t dstport;
89 uint8_t type;
90 uint8_t opt;
91 uint16_t checksum;
92 uint8_t gsd[6];
93 uint16_t length;
94 PGM_NAK nak;
95 };
96 } // namespace
97
98 /* This PGM NAK function started off as an SO rule, sid 8351. */
pgm_nak_detect(const RawData & raw)99 static inline int pgm_nak_detect(const RawData& raw)
100 {
101 /* request must be bigger than 44 bytes to cause vuln,
102 and length must be divisible by 4 */
103 if (raw.len <= sizeof(PgmHeader) or (raw.len & 0x03) != 0)
104 {
105 return PGM_NAK_ERR;
106 }
107
108 const PgmHeader* const header =
109 reinterpret_cast<const PgmHeader*>(raw.data);
110
111 if (8 != header->type)
112 return PGM_NAK_ERR;
113
114 if (2 != header->nak.opt.type)
115 return PGM_NAK_ERR;
116
117 /*
118 * alert if the amount of data after the options is more than the length
119 * specified.
120 */
121 const uint16_t data_left = raw.len - 36;
122
123 if (data_left > header->nak.opt.len)
124 {
125 /* checksum is expensive... do that only if the length is bad */
126 if (header->checksum != 0)
127 {
128 const uint16_t checksum =
129 checksum::cksum_add((const uint16_t*)raw.data, raw.len);
130
131 if (checksum != 0)
132 return PGM_NAK_ERR;
133 }
134
135 return PGM_NAK_VULN;
136 }
137
138 return PGM_NAK_OK;
139 }
140
141 //-------------------------------------------------------------------------
142 // private functions
143 //-------------------------------------------------------------------------
144
decode(const RawData & raw,CodecData & codec,DecodeData &)145 bool PgmCodec::decode(const RawData& raw, CodecData& codec, DecodeData&)
146 {
147 if ( pgm_nak_detect(raw) == PGM_NAK_VULN )
148 codec_event(codec, DECODE_PGM_NAK_OVERFLOW);
149 return true;
150 }
151
get_protocol_ids(std::vector<ProtocolId> & v)152 void PgmCodec::get_protocol_ids(std::vector<ProtocolId>& v)
153 {
154 v.emplace_back(ProtocolId::PGM);
155 }
156
157 //-------------------------------------------------------------------------
158 // api
159 //-------------------------------------------------------------------------
160
mod_ctor()161 static Module* mod_ctor()
162 { return new PgmModule; }
163
mod_dtor(Module * m)164 static void mod_dtor(Module* m)
165 { delete m; }
166
ctor(Module *)167 static Codec* ctor(Module*)
168 { return new PgmCodec(); }
169
dtor(Codec * cd)170 static void dtor(Codec* cd)
171 { delete cd; }
172
173 static const CodecApi pgm_api =
174 {
175 {
176 PT_CODEC,
177 sizeof(CodecApi),
178 CDAPI_VERSION,
179 0,
180 API_RESERVED,
181 API_OPTIONS,
182 CD_PGM_NAME,
183 CD_PGM_HELP,
184 mod_ctor,
185 mod_dtor,
186 },
187 nullptr, // pinit
188 nullptr, // pterm
189 nullptr, // tinit
190 nullptr, // tterm
191 ctor, // ctor
192 dtor, // dtor
193 };
194
195 #ifdef BUILDING_SO
196 SO_PUBLIC const BaseApi* snort_plugins[] =
197 #else
198 const BaseApi* cd_pgm[] =
199 #endif
200 {
201 &pgm_api.base,
202 nullptr
203 };
204