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-debug.h"
41 
42 static int DecodePPPCompressedProto(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,
43  const uint8_t *pkt, uint32_t len, uint16_t proto_offset)
44 {
45  const uint32_t data_offset = proto_offset + 1;
46  switch (*(pkt + proto_offset)) {
47  case 0x21: { /* PPP_IP */
48  if (unlikely(len < (data_offset + IPV4_HEADER_LEN))) {
50  return TM_ECODE_FAILED;
51  }
52  DEBUG_VALIDATE_BUG_ON(len < data_offset);
53  uint16_t iplen = (uint16_t)MIN((uint32_t)USHRT_MAX, len - data_offset);
54  return DecodeIPV4(tv, dtv, p, pkt + data_offset, iplen);
55  }
56  case 0x57: { /* PPP_IPV6 */
57  if (unlikely(len < (data_offset + IPV6_HEADER_LEN))) {
59  return TM_ECODE_FAILED;
60  }
61  DEBUG_VALIDATE_BUG_ON(len < data_offset);
62  return DecodeIPV6(tv, dtv, p, pkt + data_offset, len - data_offset);
63  }
64  case 0x2f: /* PPP_VJ_UCOMP */
65  if (unlikely(len < (data_offset + IPV4_HEADER_LEN))) {
67  return TM_ECODE_FAILED;
68  }
69 
70  if (unlikely(len > data_offset + USHRT_MAX)) {
71  return TM_ECODE_FAILED;
72  }
73 
74  if (likely(IPV4_GET_RAW_VER((IPV4Hdr *)(pkt + data_offset)) == 4)) {
76  return DecodeIPV4(tv, dtv, p, pkt + data_offset, (uint16_t)(len - data_offset));
77  } else
78  return TM_ECODE_FAILED;
79  break;
80 
81  default:
83  return TM_ECODE_OK;
84  }
85 }
86 
87 static int DecodePPPUncompressedProto(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,
88  const uint8_t *pkt, uint32_t len, const uint16_t proto, const uint32_t data_offset)
89 {
90  switch (proto) {
91  case PPP_VJ_UCOMP:
92  if (unlikely(len < (data_offset + IPV4_HEADER_LEN))) {
94  return TM_ECODE_FAILED;
95  }
96 
97  if (unlikely(len > data_offset + USHRT_MAX)) {
98  return TM_ECODE_FAILED;
99  }
100 
101  if (likely(IPV4_GET_RAW_VER((IPV4Hdr *)(pkt + data_offset)) == 4)) {
102  return DecodeIPV4(tv, dtv, p, pkt + data_offset, (uint16_t)(len - data_offset));
103  } else
104  return TM_ECODE_FAILED;
105  break;
106 
107  case PPP_IP:
108  if (unlikely(len < (data_offset + IPV4_HEADER_LEN))) {
110  return TM_ECODE_FAILED;
111  }
112  if (unlikely(len > data_offset + USHRT_MAX)) {
113  return TM_ECODE_FAILED;
114  }
115 
116  return DecodeIPV4(tv, dtv, p, pkt + data_offset, (uint16_t)(len - data_offset));
117 
118  /* PPP IPv6 was not tested */
119  case PPP_IPV6:
120  if (unlikely(len < (data_offset + IPV6_HEADER_LEN))) {
122  return TM_ECODE_FAILED;
123  }
124  return DecodeIPV6(tv, dtv, p, pkt + data_offset, len - data_offset);
125 
126  case PPP_IPCP:
127  case PPP_IPV6CP:
128  case PPP_LCP:
129  case PPP_PAP:
130  case PPP_CHAP:
131  case PPP_CCP:
132  case PPP_LQM:
133  case PPP_CBCP:
134  case PPP_COMP_DGRAM:
135  case PPP_CDPCP:
136  /* Valid types to be in PPP but don't inspect validity. */
137  return TM_ECODE_OK;
138 
139  case PPP_VJ_COMP:
140  case PPP_IPX:
141  case PPP_OSI:
142  case PPP_NS:
143  case PPP_DECNET:
144  case PPP_APPLE:
145  case PPP_BRPDU:
146  case PPP_STII:
147  case PPP_VINES:
148  case PPP_HELLO:
149  case PPP_LUXCOM:
150  case PPP_SNS:
151  case PPP_MPLS_UCAST:
152  case PPP_MPLS_MCAST:
153  case PPP_OSICP:
154  case PPP_NSCP:
155  case PPP_DECNETCP:
156  case PPP_APPLECP:
157  case PPP_IPXCP:
158  case PPP_STIICP:
159  case PPP_VINESCP:
160  case PPP_MPLSCP:
162  return TM_ECODE_OK;
163 
164  default:
165  SCLogDebug("unknown PPP protocol: %x", proto);
167  return TM_ECODE_OK;
168  }
169 }
170 
171 int DecodePPP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
172 {
173  DEBUG_VALIDATE_BUG_ON(pkt == NULL);
174 
176  if (unlikely(len < 1)) {
178  return TM_ECODE_FAILED;
179  }
180 
181  uint16_t proto_offset = 0;
182  /* 0xff means we have a HDLC header: proto will start at offset 2 */
183  if (*pkt == 0xff) {
184  proto_offset = 2;
185  /* make sure the proto field at the offset fits */
186  if (len < 3) {
188  return TM_ECODE_FAILED;
189  }
190  }
191  uint8_t proto_size = 0;
192  uint8_t proto_byte = *(pkt + proto_offset);
193  /* check if compressed protocol bit is set. */
194  if (proto_byte & 0x01) {
195  proto_size = 1;
196  } else {
197  proto_size = 2;
198  }
199  if (len < (proto_size + proto_offset)) {
201  return TM_ECODE_FAILED;
202  }
203  if (!PacketIncreaseCheckLayers(p)) {
204  return TM_ECODE_FAILED;
205  }
206 
207  const uint32_t data_offset = proto_offset + proto_size;
208  if (data_offset != 4) {
209  if (proto_size == 1) {
210  return DecodePPPCompressedProto(tv, dtv, p, pkt, len, proto_offset);
211  } else {
212  const uint16_t proto = SCNtohs(*(uint16_t *)(pkt + proto_offset));
213  return DecodePPPUncompressedProto(tv, dtv, p, pkt, len, proto, data_offset);
214  }
215  }
216  /* implied proto_offset + proto_size == 4, so continue below */
217 
218  const PPPHdr *ppph = (PPPHdr *)pkt;
219  SCLogDebug(
220  "p %p pkt %p PPP protocol %04x Len: %" PRIu32 "", p, pkt, SCNtohs(ppph->protocol), len);
221  return DecodePPPUncompressedProto(tv, dtv, p, pkt, len, SCNtohs(ppph->protocol), data_offset);
222 }
223 
224 /* TESTS BELOW */
225 #ifdef UNITTESTS
226 
227 /* DecodePPPtest01
228  * Decode malformed ip layer PPP packet
229  * Expected test value: 1
230  */
231 static int DecodePPPtest01(void)
232 {
233  uint8_t raw_ppp[] = { 0xff, 0x03, 0x00, 0x21, 0x45, 0xc0, 0x00 };
235  if (unlikely(p == NULL))
236  return 0;
237  ThreadVars tv;
239 
240  memset(&tv, 0, sizeof(ThreadVars));
241  memset(&dtv, 0, sizeof(DecodeThreadVars));
242 
243  DecodePPP(&tv, &dtv, p, raw_ppp, sizeof(raw_ppp));
244 
245  /* Function my returns here with expected value */
246 
248  PacketFree(p);
249  PASS;
250 }
251 
252 /* DecodePPPtest02
253  * Decode malformed ppp layer packet
254  * Expected test value: 1
255  */
256 static int DecodePPPtest02(void)
257 {
258  uint8_t raw_ppp[] = { 0xff, 0x03, 0x00, 0xff, 0x45, 0xc0, 0x00, 0x2c, 0x4d, 0xed, 0x00, 0x00,
259  0xff, 0x06, 0xd5, 0x17, 0xbf, 0x01, 0x0d, 0x01, 0xbf, 0x01, 0x0d, 0x03, 0xea, 0x37, 0x00,
260  0x17, 0x6d, 0x0b, 0xba, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x60, 0x02, 0x10, 0x20, 0xdd, 0xe1,
261  0x00, 0x00 };
263  if (unlikely(p == NULL))
264  return 0;
265  ThreadVars tv;
267 
268  memset(&tv, 0, sizeof(ThreadVars));
269  memset(&dtv, 0, sizeof(DecodeThreadVars));
270 
271  DecodePPP(&tv, &dtv, p, raw_ppp, sizeof(raw_ppp));
272 
273  /* Function must returns here */
274 
276 
277  PacketFree(p);
278  PASS;
279 }
280 
281 /** DecodePPPtest03
282  * \brief Decode good PPP packet, additionally the IPv4 packet inside is
283  * 4 bytes short.
284  * \retval 0 Test failed
285  * \retval 1 Test succeeded
286  */
287 static int DecodePPPtest03(void)
288 {
289  uint8_t raw_ppp[] = { 0xff, 0x03, 0x00, 0x21, 0x45, 0xc0, 0x00, 0x2c, 0x4d, 0xed, 0x00, 0x00,
290  0xff, 0x06, 0xd5, 0x17, 0xbf, 0x01, 0x0d, 0x01, 0xbf, 0x01, 0x0d, 0x03, 0xea, 0x37, 0x00,
291  0x17, 0x6d, 0x0b, 0xba, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x60, 0x02, 0x10, 0x20, 0xdd, 0xe1,
292  0x00, 0x00 };
294  if (unlikely(p == NULL))
295  return 0;
296  ThreadVars tv;
298 
299  memset(&tv, 0, sizeof(ThreadVars));
300  memset(&dtv, 0, sizeof(DecodeThreadVars));
301 
303 
304  DecodePPP(&tv, &dtv, p, raw_ppp, sizeof(raw_ppp));
305 
310 
311  PacketFree(p);
312  FlowShutdown();
313  PASS;
314 }
315 
316 /* DecodePPPtest04
317  * Check if ppp header is null
318  * Expected test value: 1
319  */
320 
321 static int DecodePPPtest04(void)
322 {
323  uint8_t raw_ppp[] = { 0xff, 0x03, 0x00, 0x21, 0x45, 0xc0, 0x00, 0x2c, 0x4d, 0xed, 0x00, 0x00,
324  0xff, 0x06, 0xd5, 0x17, 0xbf, 0x01, 0x0d, 0x01, 0xbf, 0x01, 0x0d, 0x03, 0xea, 0x37, 0x00,
325  0x17, 0x6d, 0x0b, 0xba, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x60, 0x02, 0x10, 0x20, 0xdd, 0xe1,
326  0x00, 0x00 };
328  if (unlikely(p == NULL))
329  return 0;
330  ThreadVars tv;
332 
333  memset(&tv, 0, sizeof(ThreadVars));
334  memset(&dtv, 0, sizeof(DecodeThreadVars));
335 
337 
338  DecodePPP(&tv, &dtv, p, raw_ppp, sizeof(raw_ppp));
339 
340  FlowShutdown();
341 
343 
344  /* Function must returns here */
345 
346  PacketFree(p);
347  PASS;
348 }
349 #endif /* UNITTESTS */
350 
352 {
353 #ifdef UNITTESTS
354  UtRegisterTest("DecodePPPtest01", DecodePPPtest01);
355  UtRegisterTest("DecodePPPtest02", DecodePPPtest02);
356  UtRegisterTest("DecodePPPtest03", DecodePPPtest03);
357  UtRegisterTest("DecodePPPtest04", DecodePPPtest04);
358 #endif /* UNITTESTS */
359 }
360 
361 /**
362  * @}
363  */
proto_size
uint8_t proto_size
Definition: decode-arp.h:3
ENGINE_SET_EVENT
#define ENGINE_SET_EVENT(p, e)
Definition: decode.h:1231
PPP_MPLS_MCAST
#define PPP_MPLS_MCAST
Definition: decode-ppp.h:47
PPPVJU_PKT_TOO_SMALL
@ PPPVJU_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
PPP_HELLO
#define PPP_HELLO
Definition: decode-ppp.h:43
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:171
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:101
PPP_CDPCP
#define PPP_CDPCP
Definition: decode-ppp.h:57
ENGINE_ISSET_EVENT
#define ENGINE_ISSET_EVENT(p, e)
Definition: decode.h:1244
PPP_COMP_DGRAM
#define PPP_COMP_DGRAM
Definition: decode-ppp.h:65
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:282
PPP_NSCP
#define PPP_NSCP
Definition: decode-ppp.h:50
DecodePPPRegisterTests
void DecodePPPRegisterTests(void)
Definition: decode-ppp.c:351
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:562
MIN
#define MIN(x, y)
Definition: suricata-common.h:413
PPP_IP
#define PPP_IP
Definition: decode-ppp.h:28
p
Packet * p
Definition: fuzz_dataset.c:30
proto
uint8_t proto
Definition: decode-template.h:0
TM_ECODE_FAILED
@ TM_ECODE_FAILED
Definition: tm-threads-common.h:82
PPP_WRONG_TYPE
@ PPP_WRONG_TYPE
Definition: decode-events.h:127
PPP_BRPDU
#define PPP_BRPDU
Definition: decode-ppp.h:40
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:574
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
PPPIPV4_PKT_TOO_SMALL
@ PPPIPV4_PKT_TOO_SMALL
Definition: decode-events.h:125
decode-ppp.h
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:57
PPP_IPCP
#define PPP_IPCP
Definition: decode-ppp.h:48
IPV4_TRUNC_PKT
@ IPV4_TRUNC_PKT
Definition: decode-events.h:37
StatsCounterIncr
void StatsCounterIncr(StatsThreadContext *stats, StatsCounterId id)
Increments the local counter.
Definition: counters.c:163
PacketFree
void PacketFree(Packet *p)
Return a malloced packet.
Definition: decode.c:221
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:516
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
DecodeIPV6
int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition: decode-ipv6.c:551
decode-events.h
dtv
DecodeThreadVars * dtv
Definition: fuzz_decodepcapfile.c:35
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
DecodeThreadVars_::counter_ppp
StatsCounterId counter_ppp
Definition: decode.h:1036
SCNtohs
#define SCNtohs(x)
Definition: suricata-common.h:436
PPP_PKT_TOO_SMALL
@ PPP_PKT_TOO_SMALL
Definition: decode-events.h:123
suricata-common.h
FlowShutdown
void FlowShutdown(void)
shutdown the flow engine
Definition: flow.c:718
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:34
PKT_PPP_VJ_UCOMP
#define PKT_PPP_VJ_UCOMP
Definition: decode.h:1294
util-validate.h
PacketGetFromAlloc
Packet * PacketGetFromAlloc(void)
Get a malloced packet.
Definition: decode.c:260
PPP_UNSUP_PROTO
@ PPP_UNSUP_PROTO
Definition: decode-events.h:128
PPP_IPV6
#define PPP_IPV6
Definition: decode-ppp.h:29
DecodeThreadVars_
Structure to hold thread specific data for all decode modules.
Definition: decode.h:995
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
PPPIPV6_PKT_TOO_SMALL
@ PPPIPV6_PKT_TOO_SMALL
Definition: decode-events.h:126
ENGINE_SET_INVALID_EVENT
#define ENGINE_SET_INVALID_EVENT(p, e)
Definition: decode.h:1239
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
ThreadVars_::stats
StatsThreadContext stats
Definition: threadvars.h:120
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:109
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