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  * \file
26  *
27  * \author Breno Silva Pinto <breno.silva@gmail.com>
28  *
29  * Decode PPP
30  */
31 
32 #include "suricata-common.h"
33 #include "decode.h"
34 #include "decode-ppp.h"
35 #include "decode-events.h"
36 
37 #include "flow.h"
38 
39 #include "util-validate.h"
40 #include "util-unittest.h"
41 #include "util-debug.h"
42 
43 static int DecodePPPCompressedProto(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,
44  const uint8_t *pkt, uint32_t len, uint16_t proto_offset)
45 {
46  const uint32_t data_offset = proto_offset + 1;
47  switch (*(pkt + proto_offset)) {
48  case 0x21: { /* PPP_IP */
49  if (unlikely(len < (data_offset + IPV4_HEADER_LEN))) {
51  return TM_ECODE_FAILED;
52  }
53  DEBUG_VALIDATE_BUG_ON(len < data_offset);
54  uint16_t iplen = (uint16_t)MIN((uint32_t)USHRT_MAX, len - data_offset);
55  return DecodeIPV4(tv, dtv, p, pkt + data_offset, iplen);
56  }
57  case 0x57: { /* PPP_IPV6 */
58  if (unlikely(len < (data_offset + IPV6_HEADER_LEN))) {
60  return TM_ECODE_FAILED;
61  }
62  DEBUG_VALIDATE_BUG_ON(len < data_offset);
63  uint16_t iplen = (uint16_t)MIN((uint32_t)USHRT_MAX, len - data_offset);
64  return DecodeIPV6(tv, dtv, p, pkt + data_offset, iplen);
65  }
66  case 0x2f: /* PPP_VJ_UCOMP */
67  if (unlikely(len < (data_offset + IPV4_HEADER_LEN))) {
69  return TM_ECODE_FAILED;
70  }
71 
72  if (unlikely(len > data_offset + USHRT_MAX)) {
73  return TM_ECODE_FAILED;
74  }
75 
76  if (likely(IPV4_GET_RAW_VER((IPV4Hdr *)(pkt + data_offset)) == 4)) {
77  p->flags |= PKT_PPP_VJ_UCOMP;
78  return DecodeIPV4(tv, dtv, p, pkt + data_offset, (uint16_t)(len - data_offset));
79  } else
80  return TM_ECODE_FAILED;
81  break;
82 
83  default:
85  return TM_ECODE_OK;
86  }
87 }
88 
89 static int DecodePPPUncompressedProto(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,
90  const uint8_t *pkt, uint32_t len, const uint16_t proto, const uint32_t data_offset)
91 {
92  switch (proto) {
93  case PPP_VJ_UCOMP:
94  if (unlikely(len < (data_offset + IPV4_HEADER_LEN))) {
96  return TM_ECODE_FAILED;
97  }
98 
99  if (unlikely(len > data_offset + USHRT_MAX)) {
100  return TM_ECODE_FAILED;
101  }
102 
103  if (likely(IPV4_GET_RAW_VER((IPV4Hdr *)(pkt + data_offset)) == 4)) {
104  return DecodeIPV4(tv, dtv, p, pkt + data_offset, (uint16_t)(len - data_offset));
105  } else
106  return TM_ECODE_FAILED;
107  break;
108 
109  case PPP_IP:
110  if (unlikely(len < (data_offset + IPV4_HEADER_LEN))) {
112  return TM_ECODE_FAILED;
113  }
114  if (unlikely(len > data_offset + USHRT_MAX)) {
115  return TM_ECODE_FAILED;
116  }
117 
118  return DecodeIPV4(tv, dtv, p, pkt + data_offset, (uint16_t)(len - data_offset));
119 
120  /* PPP IPv6 was not tested */
121  case PPP_IPV6:
122  if (unlikely(len < (data_offset + IPV6_HEADER_LEN))) {
124  return TM_ECODE_FAILED;
125  }
126  if (unlikely(len > data_offset + USHRT_MAX)) {
127  return TM_ECODE_FAILED;
128  }
129 
130  return DecodeIPV6(tv, dtv, p, pkt + data_offset, (uint16_t)(len - data_offset));
131 
132  case PPP_IPCP:
133  case PPP_IPV6CP:
134  case PPP_LCP:
135  case PPP_PAP:
136  case PPP_CHAP:
137  case PPP_CCP:
138  case PPP_LQM:
139  case PPP_CBCP:
140  case PPP_COMP_DGRAM:
141  case PPP_CDPCP:
142  /* Valid types to be in PPP but don't inspect validity. */
143  return TM_ECODE_OK;
144 
145  case PPP_VJ_COMP:
146  case PPP_IPX:
147  case PPP_OSI:
148  case PPP_NS:
149  case PPP_DECNET:
150  case PPP_APPLE:
151  case PPP_BRPDU:
152  case PPP_STII:
153  case PPP_VINES:
154  case PPP_HELLO:
155  case PPP_LUXCOM:
156  case PPP_SNS:
157  case PPP_MPLS_UCAST:
158  case PPP_MPLS_MCAST:
159  case PPP_OSICP:
160  case PPP_NSCP:
161  case PPP_DECNETCP:
162  case PPP_APPLECP:
163  case PPP_IPXCP:
164  case PPP_STIICP:
165  case PPP_VINESCP:
166  case PPP_MPLSCP:
168  return TM_ECODE_OK;
169 
170  default:
171  SCLogDebug("unknown PPP protocol: %x", proto);
173  return TM_ECODE_OK;
174  }
175 }
176 
177 int DecodePPP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
178 {
179  DEBUG_VALIDATE_BUG_ON(pkt == NULL);
180 
182  if (unlikely(len < 1)) {
184  return TM_ECODE_FAILED;
185  }
186 
187  uint16_t proto_offset = 0;
188  /* 0xff means we have a HDLC header: proto will start at offset 2 */
189  if (*pkt == 0xff) {
190  proto_offset = 2;
191  /* make sure the proto field at the offset fits */
192  if (len < 3) {
194  return TM_ECODE_FAILED;
195  }
196  }
197  uint8_t proto_size = 0;
198  uint8_t proto_byte = *(pkt + proto_offset);
199  /* check if compressed protocol bit is set. */
200  if (proto_byte & 0x01) {
201  proto_size = 1;
202  } else {
203  proto_size = 2;
204  }
205  if (len < (proto_size + proto_offset)) {
207  return TM_ECODE_FAILED;
208  }
209  if (!PacketIncreaseCheckLayers(p)) {
210  return TM_ECODE_FAILED;
211  }
212 
213  const uint32_t data_offset = proto_offset + proto_size;
214  if (data_offset != 4) {
215  if (proto_size == 1) {
216  return DecodePPPCompressedProto(tv, dtv, p, pkt, len, proto_offset);
217  } else {
218  const uint16_t proto = SCNtohs(*(uint16_t *)(pkt + proto_offset));
219  return DecodePPPUncompressedProto(tv, dtv, p, pkt, len, proto, data_offset);
220  }
221  }
222  /* implied proto_offset + proto_size == 4, so continue below */
223 
224  const PPPHdr *ppph = (PPPHdr *)pkt;
225  SCLogDebug(
226  "p %p pkt %p PPP protocol %04x Len: %" PRIu32 "", p, pkt, SCNtohs(ppph->protocol), len);
227  return DecodePPPUncompressedProto(tv, dtv, p, pkt, len, SCNtohs(ppph->protocol), data_offset);
228 }
229 
230 /* TESTS BELOW */
231 #ifdef UNITTESTS
232 
233 /* DecodePPPtest01
234  * Decode malformed ip layer PPP packet
235  * Expected test value: 1
236  */
237 static int DecodePPPtest01(void)
238 {
239  uint8_t raw_ppp[] = { 0xff, 0x03, 0x00, 0x21, 0x45, 0xc0, 0x00 };
240  Packet *p = PacketGetFromAlloc();
241  if (unlikely(p == NULL))
242  return 0;
243  ThreadVars tv;
245 
246  memset(&tv, 0, sizeof(ThreadVars));
247  memset(&dtv, 0, sizeof(DecodeThreadVars));
248 
249  DecodePPP(&tv, &dtv, p, raw_ppp, sizeof(raw_ppp));
250 
251  /* Function my returns here with expected value */
252 
254  SCFree(p);
255  return 1;
256  }
257 
258  SCFree(p);
259  return 0;
260 }
261 
262 /* DecodePPPtest02
263  * Decode malformed ppp layer packet
264  * Expected test value: 1
265  */
266 static int DecodePPPtest02(void)
267 {
268  uint8_t raw_ppp[] = { 0xff, 0x03, 0x00, 0xff, 0x45, 0xc0, 0x00, 0x2c, 0x4d, 0xed, 0x00, 0x00,
269  0xff, 0x06, 0xd5, 0x17, 0xbf, 0x01, 0x0d, 0x01, 0xbf, 0x01, 0x0d, 0x03, 0xea, 0x37, 0x00,
270  0x17, 0x6d, 0x0b, 0xba, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x60, 0x02, 0x10, 0x20, 0xdd, 0xe1,
271  0x00, 0x00 };
272  Packet *p = PacketGetFromAlloc();
273  if (unlikely(p == NULL))
274  return 0;
275  ThreadVars tv;
277 
278  memset(&tv, 0, sizeof(ThreadVars));
279  memset(&dtv, 0, sizeof(DecodeThreadVars));
280 
281  DecodePPP(&tv, &dtv, p, raw_ppp, sizeof(raw_ppp));
282 
283  /* Function must returns here */
284 
286  SCFree(p);
287  return 1;
288  }
289 
290  SCFree(p);
291  return 0;
292 }
293 
294 /** DecodePPPtest03
295  * \brief Decode good PPP packet, additionally the IPv4 packet inside is
296  * 4 bytes short.
297  * \retval 0 Test failed
298  * \retval 1 Test succeeded
299  */
300 static int DecodePPPtest03(void)
301 {
302  uint8_t raw_ppp[] = { 0xff, 0x03, 0x00, 0x21, 0x45, 0xc0, 0x00, 0x2c, 0x4d, 0xed, 0x00, 0x00,
303  0xff, 0x06, 0xd5, 0x17, 0xbf, 0x01, 0x0d, 0x01, 0xbf, 0x01, 0x0d, 0x03, 0xea, 0x37, 0x00,
304  0x17, 0x6d, 0x0b, 0xba, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x60, 0x02, 0x10, 0x20, 0xdd, 0xe1,
305  0x00, 0x00 };
306  Packet *p = PacketGetFromAlloc();
307  if (unlikely(p == NULL))
308  return 0;
309  ThreadVars tv;
311 
312  memset(&tv, 0, sizeof(ThreadVars));
313  memset(&dtv, 0, sizeof(DecodeThreadVars));
314 
316 
317  DecodePPP(&tv, &dtv, p, raw_ppp, sizeof(raw_ppp));
318 
319  FlowShutdown();
320 
322  SCFree(p);
323  return 0;
324  }
325 
327  SCFree(p);
328  return 0;
329  }
330 
332  SCFree(p);
333  return 0;
334  }
335 
336  if (!(ENGINE_ISSET_EVENT(p, IPV4_TRUNC_PKT))) {
337  SCFree(p);
338  return 0;
339  }
340  /* Function must return here */
341 
342  SCFree(p);
343  return 1;
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, 0xed, 0x00, 0x00,
354  0xff, 0x06, 0xd5, 0x17, 0xbf, 0x01, 0x0d, 0x01, 0xbf, 0x01, 0x0d, 0x03, 0xea, 0x37, 0x00,
355  0x17, 0x6d, 0x0b, 0xba, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x60, 0x02, 0x10, 0x20, 0xdd, 0xe1,
356  0x00, 0x00 };
357  Packet *p = PacketGetFromAlloc();
358  if (unlikely(p == NULL))
359  return 0;
360  ThreadVars tv;
362 
363  memset(&tv, 0, sizeof(ThreadVars));
364  memset(&dtv, 0, sizeof(DecodeThreadVars));
365 
367 
368  DecodePPP(&tv, &dtv, p, raw_ppp, sizeof(raw_ppp));
369 
370  FlowShutdown();
371 
372  if (!(ENGINE_ISSET_EVENT(p, IPV4_TRUNC_PKT))) {
373  SCFree(p);
374  return 0;
375  }
376 
377  /* Function must returns here */
378 
379  SCFree(p);
380  return 1;
381 }
382 #endif /* UNITTESTS */
383 
385 {
386 #ifdef UNITTESTS
387  UtRegisterTest("DecodePPPtest01", DecodePPPtest01);
388  UtRegisterTest("DecodePPPtest02", DecodePPPtest02);
389  UtRegisterTest("DecodePPPtest03", DecodePPPtest03);
390  UtRegisterTest("DecodePPPtest04", DecodePPPtest04);
391 #endif /* UNITTESTS */
392 }
393 
394 /**
395  * @}
396  */
proto_size
uint8_t proto_size
Definition: decode-arp.h:3
PPP_WRONG_TYPE
@ PPP_WRONG_TYPE
Definition: decode-events.h:126
ENGINE_SET_EVENT
#define ENGINE_SET_EVENT(p, e)
Definition: decode.h:1186
PPP_MPLS_MCAST
#define PPP_MPLS_MCAST
Definition: decode-ppp.h:47
PPPIPV4_PKT_TOO_SMALL
@ PPPIPV4_PKT_TOO_SMALL
Definition: decode-events.h:124
len
uint8_t len
Definition: app-layer-dnp3.h:2
PPP_PAP
#define PPP_PAP
Definition: decode-ppp.h:60
PPPVJU_PKT_TOO_SMALL
@ PPPVJU_PKT_TOO_SMALL
Definition: decode-events.h:123
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
PPP_UNSUP_PROTO
@ PPP_UNSUP_PROTO
Definition: decode-events.h:127
PPP_LQM
#define PPP_LQM
Definition: decode-ppp.h:61
DecodePPP
int DecodePPP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition: decode-ppp.c:177
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
PPP_CDPCP
#define PPP_CDPCP
Definition: decode-ppp.h:57
ENGINE_ISSET_EVENT
#define ENGINE_ISSET_EVENT(p, e)
Definition: decode.h:1199
PPP_COMP_DGRAM
#define PPP_COMP_DGRAM
Definition: decode-ppp.h:65
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:275
PPP_NSCP
#define PPP_NSCP
Definition: decode-ppp.h:50
DecodePPPRegisterTests
void DecodePPPRegisterTests(void)
Definition: decode-ppp.c:384
PPP_VINES
#define PPP_VINES
Definition: decode-ppp.h:42
PPP_CBCP
#define PPP_CBCP
Definition: decode-ppp.h:64
Packet_::flags
uint32_t flags
Definition: decode.h:544
MIN
#define MIN(x, y)
Definition: suricata-common.h:408
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:82
PPP_BRPDU
#define PPP_BRPDU
Definition: decode-ppp.h:40
util-unittest.h
TM_ECODE_OK
@ TM_ECODE_OK
Definition: tm-threads-common.h:81
PPP_LUXCOM
#define PPP_LUXCOM
Definition: decode-ppp.h:44
FlowInitConfig
void FlowInitConfig(bool quiet)
initialize the configuration
Definition: flow.c:546
PPP_PKT_TOO_SMALL
@ PPP_PKT_TOO_SMALL
Definition: decode-events.h:122
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:998
decode-ppp.h
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
PPP_IPCP
#define PPP_IPCP
Definition: decode-ppp.h:48
PPPIPV6_PKT_TOO_SMALL
@ PPPIPV6_PKT_TOO_SMALL
Definition: decode-events.h:125
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:58
Packet_
Definition: decode.h:501
DecodeIPV6
int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len)
Definition: decode-ipv6.c:562
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:431
suricata-common.h
FlowShutdown
void FlowShutdown(void)
shutdown the flow engine
Definition: flow.c:690
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:63
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
IPV4_TRUNC_PKT
@ IPV4_TRUNC_PKT
Definition: decode-events.h:37
PKT_PPP_VJ_UCOMP
#define PKT_PPP_VJ_UCOMP
Definition: decode.h:1249
util-validate.h
PacketGetFromAlloc
Packet * PacketGetFromAlloc(void)
Get a malloced packet.
Definition: decode.c:258
PPP_IPV6
#define PPP_IPV6
Definition: decode-ppp.h:29
SCFree
#define SCFree(p)
Definition: util-mem.h:61
DecodeThreadVars_
Structure to hold thread specific data for all decode modules.
Definition: decode.h:963
PPP_STII
#define PPP_STII
Definition: decode-ppp.h:41
PPP_CHAP
#define PPP_CHAP
Definition: decode-ppp.h:62
PPP_APPLECP
#define PPP_APPLECP
Definition: decode-ppp.h:52
ENGINE_SET_INVALID_EVENT
#define ENGINE_SET_INVALID_EVENT(p, e)
Definition: decode.h:1194
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:59