suricata
decode-ppp.c
Go to the documentation of this file.
1/* Copyright (C) 2007-2024 Open Information Security Foundation
2 *
3 * You can copy, redistribute or modify this Program under the terms of
4 * the GNU General Public License version 2 as published by the Free
5 * Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * version 2 along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 */
17
18/**
19 * \ingroup decode
20 *
21 * @{
22 */
23
24
25/**
26 * \file
27 *
28 * \author Breno Silva Pinto <breno.silva@gmail.com>
29 *
30 * Decode PPP
31 */
32
33#include "suricata-common.h"
34#include "decode.h"
35#include "decode-ppp.h"
36#include "decode-events.h"
37
38#include "flow.h"
39
40#include "util-validate.h"
41#include "util-unittest.h"
42#include "util-debug.h"
43
44static int DecodePPPCompressedProto(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,
45 const uint8_t *pkt, uint32_t len, uint16_t proto_offset)
46{
47 const uint32_t data_offset = proto_offset + 1;
48 switch (*(pkt + proto_offset)) {
49 case 0x21: { /* PPP_IP */
50 if (unlikely(len < (data_offset + IPV4_HEADER_LEN))) {
52 return TM_ECODE_FAILED;
53 }
54 DEBUG_VALIDATE_BUG_ON(len < data_offset);
55 uint16_t iplen = (uint16_t)MIN((uint32_t)USHRT_MAX, len - data_offset);
56 return DecodeIPV4(tv, dtv, p, pkt + data_offset, iplen);
57 }
58 case 0x57: { /* PPP_IPV6 */
59 if (unlikely(len < (data_offset + IPV6_HEADER_LEN))) {
61 return TM_ECODE_FAILED;
62 }
63 DEBUG_VALIDATE_BUG_ON(len < data_offset);
64 uint16_t iplen = (uint16_t)MIN((uint32_t)USHRT_MAX, len - data_offset);
65 return DecodeIPV6(tv, dtv, p, pkt + data_offset, iplen);
66 }
67 case 0x2f: /* PPP_VJ_UCOMP */
68 if (unlikely(len < (data_offset + IPV4_HEADER_LEN))) {
70 return TM_ECODE_FAILED;
71 }
72
73 if (unlikely(len > data_offset + USHRT_MAX)) {
74 return TM_ECODE_FAILED;
75 }
76
77 if (likely(IPV4_GET_RAW_VER((IPV4Hdr *)(pkt + data_offset)) == 4)) {
79 return DecodeIPV4(tv, dtv, p, pkt + data_offset, (uint16_t)(len - data_offset));
80 } else
81 return TM_ECODE_FAILED;
82 break;
83
84 default:
86 return TM_ECODE_OK;
87 }
88}
89
90static int DecodePPPUncompressedProto(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,
91 const uint8_t *pkt, uint32_t len, const uint16_t proto, const uint32_t data_offset)
92{
93 switch (proto) {
94 case PPP_VJ_UCOMP:
95 if (unlikely(len < (data_offset + IPV4_HEADER_LEN))) {
97 return TM_ECODE_FAILED;
98 }
99
100 if (unlikely(len > data_offset + USHRT_MAX)) {
101 return TM_ECODE_FAILED;
102 }
103
104 if (likely(IPV4_GET_RAW_VER((IPV4Hdr *)(pkt + data_offset)) == 4)) {
105 return DecodeIPV4(tv, dtv, p, pkt + data_offset, (uint16_t)(len - data_offset));
106 } else
107 return TM_ECODE_FAILED;
108 break;
109
110 case PPP_IP:
111 if (unlikely(len < (data_offset + IPV4_HEADER_LEN))) {
113 return TM_ECODE_FAILED;
114 }
115 if (unlikely(len > data_offset + USHRT_MAX)) {
116 return TM_ECODE_FAILED;
117 }
118
119 return DecodeIPV4(tv, dtv, p, pkt + data_offset, (uint16_t)(len - data_offset));
120
121 /* PPP IPv6 was not tested */
122 case PPP_IPV6:
123 if (unlikely(len < (data_offset + IPV6_HEADER_LEN))) {
125 return TM_ECODE_FAILED;
126 }
127 if (unlikely(len > data_offset + USHRT_MAX)) {
128 return TM_ECODE_FAILED;
129 }
130
131 return DecodeIPV6(tv, dtv, p, pkt + data_offset, (uint16_t)(len - data_offset));
132
133 case PPP_VJ_COMP:
134 case PPP_IPX:
135 case PPP_OSI:
136 case PPP_NS:
137 case PPP_DECNET:
138 case PPP_APPLE:
139 case PPP_BRPDU:
140 case PPP_STII:
141 case PPP_VINES:
142 case PPP_HELLO:
143 case PPP_LUXCOM:
144 case PPP_SNS:
145 case PPP_MPLS_UCAST:
146 case PPP_MPLS_MCAST:
147 case PPP_IPCP:
148 case PPP_OSICP:
149 case PPP_NSCP:
150 case PPP_DECNETCP:
151 case PPP_APPLECP:
152 case PPP_IPXCP:
153 case PPP_STIICP:
154 case PPP_VINESCP:
155 case PPP_IPV6CP:
156 case PPP_MPLSCP:
157 case PPP_LCP:
158 case PPP_PAP:
159 case PPP_LQM:
160 case PPP_CHAP:
161 case PPP_CCP:
162 case PPP_CBCP:
163 case PPP_COMP_DGRAM:
165 return TM_ECODE_OK;
166
167 default:
168 SCLogDebug("unknown PPP protocol: %x", proto);
170 return TM_ECODE_OK;
171 }
172}
173
174int DecodePPP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
175{
176 DEBUG_VALIDATE_BUG_ON(pkt == NULL);
177
179 if (unlikely(len < 1)) {
181 return TM_ECODE_FAILED;
182 }
183
184 uint16_t proto_offset = 0;
185 /* 0xff means we have a HDLC header: proto will start at offset 2 */
186 if (*pkt == 0xff) {
187 proto_offset = 2;
188 /* make sure the proto field at the offset fits */
189 if (len < 3) {
191 return TM_ECODE_FAILED;
192 }
193 }
194 uint8_t proto_size = 0;
195 uint8_t proto_byte = *(pkt + proto_offset);
196 /* check if compressed protocol bit is set. */
197 if (proto_byte & 0x01) {
198 proto_size = 1;
199 } else {
200 proto_size = 2;
201 }
202 if (len < (proto_size + proto_offset)) {
204 return TM_ECODE_FAILED;
205 }
206 if (!PacketIncreaseCheckLayers(p)) {
207 return TM_ECODE_FAILED;
208 }
209
210 const uint32_t data_offset = proto_offset + proto_size;
211 if (data_offset != 4) {
212 if (proto_size == 1) {
213 return DecodePPPCompressedProto(tv, dtv, p, pkt, len, proto_offset);
214 } else {
215 const uint16_t proto = SCNtohs(*(uint16_t *)(pkt + proto_offset));
216 return DecodePPPUncompressedProto(tv, dtv, p, pkt, len, proto, data_offset);
217 }
218 }
219 /* implied proto_offset + proto_size == 4, so continue below */
220
221 const PPPHdr *ppph = (PPPHdr *)pkt;
223 "p %p pkt %p PPP protocol %04x Len: %" PRIu32 "", p, pkt, SCNtohs(ppph->protocol), len);
224 return DecodePPPUncompressedProto(tv, dtv, p, pkt, len, SCNtohs(ppph->protocol), data_offset);
225}
226
227/* TESTS BELOW */
228#ifdef UNITTESTS
229
230/* DecodePPPtest01
231 * Decode malformed ip layer PPP packet
232 * Expected test value: 1
233 */
234static int DecodePPPtest01 (void)
235{
236 uint8_t raw_ppp[] = { 0xff, 0x03, 0x00, 0x21, 0x45, 0xc0, 0x00 };
238 if (unlikely(p == NULL))
239 return 0;
242
243 memset(&tv, 0, sizeof(ThreadVars));
244 memset(&dtv, 0, sizeof(DecodeThreadVars));
245
246 DecodePPP(&tv, &dtv, p, raw_ppp, sizeof(raw_ppp));
247
248 /* Function my returns here with expected value */
249
251 SCFree(p);
252 return 1;
253 }
254
255 SCFree(p);
256 return 0;
257}
258
259/* DecodePPPtest02
260 * Decode malformed ppp layer packet
261 * Expected test value: 1
262 */
263static int DecodePPPtest02 (void)
264{
265 uint8_t raw_ppp[] = { 0xff, 0x03, 0x00, 0xff, 0x45, 0xc0, 0x00, 0x2c, 0x4d,
266 0xed, 0x00, 0x00, 0xff, 0x06, 0xd5, 0x17, 0xbf, 0x01,
267 0x0d, 0x01, 0xbf, 0x01, 0x0d, 0x03, 0xea, 0x37, 0x00,
268 0x17, 0x6d, 0x0b, 0xba, 0xc3, 0x00, 0x00, 0x00, 0x00,
269 0x60, 0x02, 0x10, 0x20, 0xdd, 0xe1, 0x00, 0x00 };
271 if (unlikely(p == NULL))
272 return 0;
275
276 memset(&tv, 0, sizeof(ThreadVars));
277 memset(&dtv, 0, sizeof(DecodeThreadVars));
278
279 DecodePPP(&tv, &dtv, p, raw_ppp, sizeof(raw_ppp));
280
281 /* Function must returns here */
282
284 SCFree(p);
285 return 1;
286 }
287
288 SCFree(p);
289 return 0;
290}
291
292/** DecodePPPtest03
293 * \brief Decode good PPP packet, additionally the IPv4 packet inside is
294 * 4 bytes short.
295 * \retval 0 Test failed
296 * \retval 1 Test succeeded
297 */
298static int DecodePPPtest03 (void)
299{
300 uint8_t raw_ppp[] = { 0xff, 0x03, 0x00, 0x21, 0x45, 0xc0, 0x00, 0x2c, 0x4d,
301 0xed, 0x00, 0x00, 0xff, 0x06, 0xd5, 0x17, 0xbf, 0x01,
302 0x0d, 0x01, 0xbf, 0x01, 0x0d, 0x03, 0xea, 0x37, 0x00,
303 0x17, 0x6d, 0x0b, 0xba, 0xc3, 0x00, 0x00, 0x00, 0x00,
304 0x60, 0x02, 0x10, 0x20, 0xdd, 0xe1, 0x00, 0x00 };
306 if (unlikely(p == NULL))
307 return 0;
310
311 memset(&tv, 0, sizeof(ThreadVars));
312 memset(&dtv, 0, sizeof(DecodeThreadVars));
313
315
316 DecodePPP(&tv, &dtv, p, raw_ppp, sizeof(raw_ppp));
317
318 FlowShutdown();
319
321 SCFree(p);
322 return 0;
323 }
324
326 SCFree(p);
327 return 0;
328 }
329
331 SCFree(p);
332 return 0;
333 }
334
336 SCFree(p);
337 return 0;
338 }
339 /* Function must return here */
340
341 SCFree(p);
342 return 1;
343}
344
345
346/* DecodePPPtest04
347 * Check if ppp header is null
348 * Expected test value: 1
349 */
350
351static int DecodePPPtest04 (void)
352{
353 uint8_t raw_ppp[] = { 0xff, 0x03, 0x00, 0x21, 0x45, 0xc0, 0x00, 0x2c, 0x4d,
354 0xed, 0x00, 0x00, 0xff, 0x06, 0xd5, 0x17, 0xbf, 0x01,
355 0x0d, 0x01, 0xbf, 0x01, 0x0d, 0x03, 0xea, 0x37, 0x00,
356 0x17, 0x6d, 0x0b, 0xba, 0xc3, 0x00, 0x00, 0x00, 0x00,
357 0x60, 0x02, 0x10, 0x20, 0xdd, 0xe1, 0x00, 0x00 };
359 if (unlikely(p == NULL))
360 return 0;
363
364 memset(&tv, 0, sizeof(ThreadVars));
365 memset(&dtv, 0, sizeof(DecodeThreadVars));
366
368
369 DecodePPP(&tv, &dtv, p, raw_ppp, sizeof(raw_ppp));
370
371 FlowShutdown();
372
374 SCFree(p);
375 return 0;
376 }
377
378 /* Function must returns here */
379
380 SCFree(p);
381 return 1;
382}
383#endif /* UNITTESTS */
384
386{
387#ifdef UNITTESTS
388 UtRegisterTest("DecodePPPtest01", DecodePPPtest01);
389 UtRegisterTest("DecodePPPtest02", DecodePPPtest02);
390 UtRegisterTest("DecodePPPtest03", DecodePPPtest03);
391 UtRegisterTest("DecodePPPtest04", DecodePPPtest04);
392#endif /* UNITTESTS */
393}
394
395/**
396 * @}
397 */
uint8_t len
void StatsIncr(ThreadVars *tv, uint16_t id)
Increments the local counter.
Definition counters.c:166
uint8_t proto_size
Definition decode-arp.h:3
@ PPPIPV4_PKT_TOO_SMALL
@ PPPVJU_PKT_TOO_SMALL
@ IPV4_TRUNC_PKT
@ PPP_PKT_TOO_SMALL
@ PPPIPV6_PKT_TOO_SMALL
@ PPP_WRONG_TYPE
@ PPP_UNSUP_PROTO
int DecodeIPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len)
#define IPV4_HEADER_LEN
Definition decode-ipv4.h:28
#define IPV4_GET_RAW_VER(ip4h)
Definition decode-ipv4.h:95
int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len)
#define IPV6_HEADER_LEN
Definition decode-ipv6.h:27
int DecodePPP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition decode-ppp.c:174
void DecodePPPRegisterTests(void)
Definition decode-ppp.c:385
#define PPP_VJ_UCOMP
Definition decode-ppp.h:30
#define PPP_VINESCP
Definition decode-ppp.h:55
#define PPP_VINES
Definition decode-ppp.h:42
#define PPP_SNS
Definition decode-ppp.h:45
#define PPP_IPV6CP
Definition decode-ppp.h:56
#define PPP_IPXCP
Definition decode-ppp.h:53
#define PPP_APPLECP
Definition decode-ppp.h:52
#define PPP_IP
Definition decode-ppp.h:28
#define PPP_CBCP
Definition decode-ppp.h:63
#define PPP_OSI
Definition decode-ppp.h:36
#define PPP_IPX
Definition decode-ppp.h:33
#define PPP_DECNET
Definition decode-ppp.h:38
#define PPP_IPCP
Definition decode-ppp.h:48
#define PPP_STII
Definition decode-ppp.h:41
#define PPP_COMP_DGRAM
Definition decode-ppp.h:64
#define PPP_IPV6
Definition decode-ppp.h:29
#define PPP_NS
Definition decode-ppp.h:37
#define PPP_DECNETCP
Definition decode-ppp.h:51
#define PPP_CCP
Definition decode-ppp.h:62
#define PPP_VJ_COMP
Definition decode-ppp.h:34
#define PPP_BRPDU
Definition decode-ppp.h:40
#define PPP_LQM
Definition decode-ppp.h:60
#define PPP_PAP
Definition decode-ppp.h:59
#define PPP_OSICP
Definition decode-ppp.h:49
#define PPP_STIICP
Definition decode-ppp.h:54
#define PPP_LCP
Definition decode-ppp.h:58
#define PPP_HELLO
Definition decode-ppp.h:43
#define PPP_LUXCOM
Definition decode-ppp.h:44
#define PPP_MPLS_MCAST
Definition decode-ppp.h:47
#define PPP_NSCP
Definition decode-ppp.h:50
#define PPP_MPLS_UCAST
Definition decode-ppp.h:46
#define PPP_MPLSCP
Definition decode-ppp.h:57
#define PPP_CHAP
Definition decode-ppp.h:61
#define PPP_APPLE
Definition decode-ppp.h:39
uint8_t proto
#define PKT_PPP_VJ_UCOMP
Definition decode.h:1249
#define ENGINE_SET_INVALID_EVENT(p, e)
Definition decode.h:1194
#define ENGINE_ISSET_EVENT(p, e)
Definition decode.h:1199
#define ENGINE_SET_EVENT(p, e)
Definition decode.h:1186
void FlowInitConfig(bool quiet)
initialize the configuration
Definition flow.c:547
void FlowShutdown(void)
shutdown the flow engine
Definition flow.c:691
#define FLOW_QUIET
Definition flow.h:43
DecodeThreadVars * dtv
ThreadVars * tv
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Packet * PacketGetFromAlloc(void)
Get a malloced packet.
Definition decode.c:258
Structure to hold thread specific data for all decode modules.
Definition decode.h:963
uint16_t counter_ppp
Definition decode.h:998
uint32_t flags
Definition decode.h:544
Per thread variable structure.
Definition threadvars.h:58
#define SCNtohs(x)
#define MIN(x, y)
@ TM_ECODE_FAILED
@ TM_ECODE_OK
#define SCLogDebug(...)
Definition util-debug.h:275
#define SCFree(p)
Definition util-mem.h:61
#define likely(expr)
#define unlikely(expr)
#define DEBUG_VALIDATE_BUG_ON(exp)