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  PacketFree(p);
255  PASS;
256 }
257 
258 /* DecodePPPtest02
259  * Decode malformed ppp layer packet
260  * Expected test value: 1
261  */
262 static int DecodePPPtest02(void)
263 {
264  uint8_t raw_ppp[] = { 0xff, 0x03, 0x00, 0xff, 0x45, 0xc0, 0x00, 0x2c, 0x4d, 0xed, 0x00, 0x00,
265  0xff, 0x06, 0xd5, 0x17, 0xbf, 0x01, 0x0d, 0x01, 0xbf, 0x01, 0x0d, 0x03, 0xea, 0x37, 0x00,
266  0x17, 0x6d, 0x0b, 0xba, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x60, 0x02, 0x10, 0x20, 0xdd, 0xe1,
267  0x00, 0x00 };
268  Packet *p = PacketGetFromAlloc();
269  if (unlikely(p == NULL))
270  return 0;
271  ThreadVars tv;
273 
274  memset(&tv, 0, sizeof(ThreadVars));
275  memset(&dtv, 0, sizeof(DecodeThreadVars));
276 
277  DecodePPP(&tv, &dtv, p, raw_ppp, sizeof(raw_ppp));
278 
279  /* Function must returns here */
280 
282 
283  PacketFree(p);
284  PASS;
285 }
286 
287 /** DecodePPPtest03
288  * \brief Decode good PPP packet, additionally the IPv4 packet inside is
289  * 4 bytes short.
290  * \retval 0 Test failed
291  * \retval 1 Test succeeded
292  */
293 static int DecodePPPtest03(void)
294 {
295  uint8_t raw_ppp[] = { 0xff, 0x03, 0x00, 0x21, 0x45, 0xc0, 0x00, 0x2c, 0x4d, 0xed, 0x00, 0x00,
296  0xff, 0x06, 0xd5, 0x17, 0xbf, 0x01, 0x0d, 0x01, 0xbf, 0x01, 0x0d, 0x03, 0xea, 0x37, 0x00,
297  0x17, 0x6d, 0x0b, 0xba, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x60, 0x02, 0x10, 0x20, 0xdd, 0xe1,
298  0x00, 0x00 };
299  Packet *p = PacketGetFromAlloc();
300  if (unlikely(p == NULL))
301  return 0;
302  ThreadVars tv;
304 
305  memset(&tv, 0, sizeof(ThreadVars));
306  memset(&dtv, 0, sizeof(DecodeThreadVars));
307 
309 
310  DecodePPP(&tv, &dtv, p, raw_ppp, sizeof(raw_ppp));
311 
316 
317  PacketFree(p);
318  FlowShutdown();
319  PASS;
320 }
321 
322 /* DecodePPPtest04
323  * Check if ppp header is null
324  * Expected test value: 1
325  */
326 
327 static int DecodePPPtest04(void)
328 {
329  uint8_t raw_ppp[] = { 0xff, 0x03, 0x00, 0x21, 0x45, 0xc0, 0x00, 0x2c, 0x4d, 0xed, 0x00, 0x00,
330  0xff, 0x06, 0xd5, 0x17, 0xbf, 0x01, 0x0d, 0x01, 0xbf, 0x01, 0x0d, 0x03, 0xea, 0x37, 0x00,
331  0x17, 0x6d, 0x0b, 0xba, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x60, 0x02, 0x10, 0x20, 0xdd, 0xe1,
332  0x00, 0x00 };
333  Packet *p = PacketGetFromAlloc();
334  if (unlikely(p == NULL))
335  return 0;
336  ThreadVars tv;
338 
339  memset(&tv, 0, sizeof(ThreadVars));
340  memset(&dtv, 0, sizeof(DecodeThreadVars));
341 
343 
344  DecodePPP(&tv, &dtv, p, raw_ppp, sizeof(raw_ppp));
345 
346  FlowShutdown();
347 
349 
350  /* Function must returns here */
351 
352  PacketFree(p);
353  PASS;
354 }
355 #endif /* UNITTESTS */
356 
358 {
359 #ifdef UNITTESTS
360  UtRegisterTest("DecodePPPtest01", DecodePPPtest01);
361  UtRegisterTest("DecodePPPtest02", DecodePPPtest02);
362  UtRegisterTest("DecodePPPtest03", DecodePPPtest03);
363  UtRegisterTest("DecodePPPtest04", DecodePPPtest04);
364 #endif /* UNITTESTS */
365 }
366 
367 /**
368  * @}
369  */
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:1188
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:1201
PPP_COMP_DGRAM
#define PPP_COMP_DGRAM
Definition: decode-ppp.h:65
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:279
PPP_NSCP
#define PPP_NSCP
Definition: decode-ppp.h:50
DecodePPPRegisterTests
void DecodePPPRegisterTests(void)
Definition: decode-ppp.c:357
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
FAIL_IF_NOT
#define FAIL_IF_NOT(expr)
Fail a test if expression evaluates to false.
Definition: util-unittest.h:82
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:547
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
PASS
#define PASS
Pass the test.
Definition: util-unittest.h:105
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
PacketFree
void PacketFree(Packet *p)
Return a malloced packet.
Definition: decode.c:219
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:549
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
FAIL_IF
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
Definition: util-unittest.h:71
SCNtohs
#define SCNtohs(x)
Definition: suricata-common.h:431
suricata-common.h
FlowShutdown
void FlowShutdown(void)
shutdown the flow engine
Definition: flow.c:691
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:1251
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
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:1196
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:515
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