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 
44 static 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)) {
78  p->flags |= PKT_PPP_VJ_UCOMP;
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 
90 static 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 
174 int 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;
222  SCLogDebug(
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  */
234 static int DecodePPPtest01 (void)
235 {
236  uint8_t raw_ppp[] = { 0xff, 0x03, 0x00, 0x21, 0x45, 0xc0, 0x00 };
237  Packet *p = PacketGetFromAlloc();
238  if (unlikely(p == NULL))
239  return 0;
240  ThreadVars tv;
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  */
263 static 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 };
270  Packet *p = PacketGetFromAlloc();
271  if (unlikely(p == NULL))
272  return 0;
273  ThreadVars tv;
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  */
298 static 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 };
305  Packet *p = PacketGetFromAlloc();
306  if (unlikely(p == NULL))
307  return 0;
308  ThreadVars tv;
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 
351 static 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 };
358  Packet *p = PacketGetFromAlloc();
359  if (unlikely(p == NULL))
360  return 0;
361  ThreadVars tv;
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  */
proto_size
uint8_t proto_size
Definition: decode-arp.h:3
ENGINE_SET_EVENT
#define ENGINE_SET_EVENT(p, e)
Definition: decode.h:1150
PPP_MPLS_MCAST
#define PPP_MPLS_MCAST
Definition: decode-ppp.h:47
len
uint8_t len
Definition: app-layer-dnp3.h:2
PPP_PAP
#define PPP_PAP
Definition: decode-ppp.h:59
PPP_HELLO
#define PPP_HELLO
Definition: decode-ppp.h:43
StatsIncr
void StatsIncr(ThreadVars *tv, uint16_t id)
Increments the local counter.
Definition: counters.c:166
IPV4_TRUNC_PKT
@ IPV4_TRUNC_PKT
Definition: decode-events.h:34
PPP_LQM
#define PPP_LQM
Definition: decode-ppp.h:60
DecodePPP
int DecodePPP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition: decode-ppp.c:174
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
PPP_SNS
#define PPP_SNS
Definition: decode-ppp.h:45
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:103
PPPIPV4_PKT_TOO_SMALL
@ PPPIPV4_PKT_TOO_SMALL
Definition: decode-events.h:117
ENGINE_ISSET_EVENT
#define ENGINE_ISSET_EVENT(p, e)
Definition: decode.h:1165
PPP_COMP_DGRAM
#define PPP_COMP_DGRAM
Definition: decode-ppp.h:64
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:269
PPP_NSCP
#define PPP_NSCP
Definition: decode-ppp.h:50
DecodePPPRegisterTests
void DecodePPPRegisterTests(void)
Definition: decode-ppp.c:385
PPP_VINES
#define PPP_VINES
Definition: decode-ppp.h:42
PPP_CBCP
#define PPP_CBCP
Definition: decode-ppp.h:63
Packet_::flags
uint32_t flags
Definition: decode.h:513
PPPVJU_PKT_TOO_SMALL
@ PPPVJU_PKT_TOO_SMALL
Definition: decode-events.h:116
PPP_UNSUP_PROTO
@ PPP_UNSUP_PROTO
Definition: decode-events.h:120
MIN
#define MIN(x, y)
Definition: suricata-common.h:391
PPP_IP
#define PPP_IP
Definition: decode-ppp.h:28
proto
uint8_t proto
Definition: decode-template.h:0
TM_ECODE_FAILED
@ TM_ECODE_FAILED
Definition: tm-threads-common.h:81
PPP_BRPDU
#define PPP_BRPDU
Definition: decode-ppp.h:40
util-unittest.h
TM_ECODE_OK
@ TM_ECODE_OK
Definition: tm-threads-common.h:80
PPP_LUXCOM
#define PPP_LUXCOM
Definition: decode-ppp.h:44
FlowInitConfig
void FlowInitConfig(bool quiet)
initialize the configuration
Definition: flow.c:533
decode.h
util-debug.h
PPP_STIICP
#define PPP_STIICP
Definition: decode-ppp.h:54
PPP_IPX
#define PPP_IPX
Definition: decode-ppp.h:35
DecodeThreadVars_::counter_ppp
uint16_t counter_ppp
Definition: decode.h:966
decode-ppp.h
PPP_PKT_TOO_SMALL
@ PPP_PKT_TOO_SMALL
Definition: decode-events.h:115
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
PPP_IPCP
#define PPP_IPCP
Definition: decode-ppp.h:48
PPP_VJ_COMP
#define PPP_VJ_COMP
Definition: decode-ppp.h:34
PPP_VINESCP
#define PPP_VINESCP
Definition: decode-ppp.h:55
PPP_MPLSCP
#define PPP_MPLSCP
Definition: decode-ppp.h:57
Packet_
Definition: decode.h:476
DecodeIPV6
int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len)
Definition: decode-ipv6.c:560
IPV4_GET_RAW_VER
#define IPV4_GET_RAW_VER(ip4h)
Definition: decode-ipv4.h:95
PPP_DECNETCP
#define PPP_DECNETCP
Definition: decode-ppp.h:51
decode-events.h
dtv
DecodeThreadVars * dtv
Definition: fuzz_decodepcapfile.c:33
IPV4Hdr_
Definition: decode-ipv4.h:72
PPP_APPLE
#define PPP_APPLE
Definition: decode-ppp.h:39
SCNtohs
#define SCNtohs(x)
Definition: suricata-common.h:414
suricata-common.h
FlowShutdown
void FlowShutdown(void)
shutdown the flow engine
Definition: flow.c:680
PPP_MPLS_UCAST
#define PPP_MPLS_UCAST
Definition: decode-ppp.h:46
IPV4_HEADER_LEN
#define IPV4_HEADER_LEN
Definition: decode-ipv4.h:28
PPP_CCP
#define PPP_CCP
Definition: decode-ppp.h:62
PPP_NS
#define PPP_NS
Definition: decode-ppp.h:37
PPP_DECNET
#define PPP_DECNET
Definition: decode-ppp.h:38
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:32
PKT_PPP_VJ_UCOMP
#define PKT_PPP_VJ_UCOMP
Definition: decode.h:1254
util-validate.h
PacketGetFromAlloc
Packet * PacketGetFromAlloc(void)
Get a malloced packet.
Definition: decode.c:232
PPP_IPV6
#define PPP_IPV6
Definition: decode-ppp.h:29
PPPIPV6_PKT_TOO_SMALL
@ PPPIPV6_PKT_TOO_SMALL
Definition: decode-events.h:118
SCFree
#define SCFree(p)
Definition: util-mem.h:61
DecodeThreadVars_
Structure to hold thread specific data for all decode modules.
Definition: decode.h:932
PPP_WRONG_TYPE
@ PPP_WRONG_TYPE
Definition: decode-events.h:119
PPP_STII
#define PPP_STII
Definition: decode-ppp.h:41
PPP_CHAP
#define PPP_CHAP
Definition: decode-ppp.h:61
PPP_APPLECP
#define PPP_APPLECP
Definition: decode-ppp.h:52
ENGINE_SET_INVALID_EVENT
#define ENGINE_SET_INVALID_EVENT(p, e)
Definition: decode.h:1158
FLOW_QUIET
#define FLOW_QUIET
Definition: flow.h:43
PPP_IPXCP
#define PPP_IPXCP
Definition: decode-ppp.h:53
IPV6_HEADER_LEN
#define IPV6_HEADER_LEN
Definition: decode-ipv6.h:27
likely
#define likely(expr)
Definition: util-optimize.h:32
PPP_VJ_UCOMP
#define PPP_VJ_UCOMP
Definition: decode-ppp.h:30
flow.h
DecodeIPV4
int DecodeIPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len)
Definition: decode-ipv4.c:520
PPP_IPV6CP
#define PPP_IPV6CP
Definition: decode-ppp.h:56
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:102
PPP_OSI
#define PPP_OSI
Definition: decode-ppp.h:36
PPP_OSICP
#define PPP_OSICP
Definition: decode-ppp.h:49
PPP_LCP
#define PPP_LCP
Definition: decode-ppp.h:58