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  return DecodeIPV6(tv, dtv, p, pkt + data_offset, len - data_offset);
64  }
65  case 0x2f: /* PPP_VJ_UCOMP */
66  if (unlikely(len < (data_offset + IPV4_HEADER_LEN))) {
68  return TM_ECODE_FAILED;
69  }
70 
71  if (unlikely(len > data_offset + USHRT_MAX)) {
72  return TM_ECODE_FAILED;
73  }
74 
75  if (likely(IPV4_GET_RAW_VER((IPV4Hdr *)(pkt + data_offset)) == 4)) {
77  return DecodeIPV4(tv, dtv, p, pkt + data_offset, (uint16_t)(len - data_offset));
78  } else
79  return TM_ECODE_FAILED;
80  break;
81 
82  default:
84  return TM_ECODE_OK;
85  }
86 }
87 
88 static int DecodePPPUncompressedProto(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,
89  const uint8_t *pkt, uint32_t len, const uint16_t proto, const uint32_t data_offset)
90 {
91  switch (proto) {
92  case PPP_VJ_UCOMP:
93  if (unlikely(len < (data_offset + IPV4_HEADER_LEN))) {
95  return TM_ECODE_FAILED;
96  }
97 
98  if (unlikely(len > data_offset + USHRT_MAX)) {
99  return TM_ECODE_FAILED;
100  }
101 
102  if (likely(IPV4_GET_RAW_VER((IPV4Hdr *)(pkt + data_offset)) == 4)) {
103  return DecodeIPV4(tv, dtv, p, pkt + data_offset, (uint16_t)(len - data_offset));
104  } else
105  return TM_ECODE_FAILED;
106  break;
107 
108  case PPP_IP:
109  if (unlikely(len < (data_offset + IPV4_HEADER_LEN))) {
111  return TM_ECODE_FAILED;
112  }
113  if (unlikely(len > data_offset + USHRT_MAX)) {
114  return TM_ECODE_FAILED;
115  }
116 
117  return DecodeIPV4(tv, dtv, p, pkt + data_offset, (uint16_t)(len - data_offset));
118 
119  /* PPP IPv6 was not tested */
120  case PPP_IPV6:
121  if (unlikely(len < (data_offset + IPV6_HEADER_LEN))) {
123  return TM_ECODE_FAILED;
124  }
125  return DecodeIPV6(tv, dtv, p, pkt + data_offset, len - data_offset);
126 
127  case PPP_IPCP:
128  case PPP_IPV6CP:
129  case PPP_LCP:
130  case PPP_PAP:
131  case PPP_CHAP:
132  case PPP_CCP:
133  case PPP_LQM:
134  case PPP_CBCP:
135  case PPP_COMP_DGRAM:
136  case PPP_CDPCP:
137  /* Valid types to be in PPP but don't inspect validity. */
138  return TM_ECODE_OK;
139 
140  case PPP_VJ_COMP:
141  case PPP_IPX:
142  case PPP_OSI:
143  case PPP_NS:
144  case PPP_DECNET:
145  case PPP_APPLE:
146  case PPP_BRPDU:
147  case PPP_STII:
148  case PPP_VINES:
149  case PPP_HELLO:
150  case PPP_LUXCOM:
151  case PPP_SNS:
152  case PPP_MPLS_UCAST:
153  case PPP_MPLS_MCAST:
154  case PPP_OSICP:
155  case PPP_NSCP:
156  case PPP_DECNETCP:
157  case PPP_APPLECP:
158  case PPP_IPXCP:
159  case PPP_STIICP:
160  case PPP_VINESCP:
161  case PPP_MPLSCP:
163  return TM_ECODE_OK;
164 
165  default:
166  SCLogDebug("unknown PPP protocol: %x", proto);
168  return TM_ECODE_OK;
169  }
170 }
171 
172 int DecodePPP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
173 {
174  DEBUG_VALIDATE_BUG_ON(pkt == NULL);
175 
177  if (unlikely(len < 1)) {
179  return TM_ECODE_FAILED;
180  }
181 
182  uint16_t proto_offset = 0;
183  /* 0xff means we have a HDLC header: proto will start at offset 2 */
184  if (*pkt == 0xff) {
185  proto_offset = 2;
186  /* make sure the proto field at the offset fits */
187  if (len < 3) {
189  return TM_ECODE_FAILED;
190  }
191  }
192  uint8_t proto_size = 0;
193  uint8_t proto_byte = *(pkt + proto_offset);
194  /* check if compressed protocol bit is set. */
195  if (proto_byte & 0x01) {
196  proto_size = 1;
197  } else {
198  proto_size = 2;
199  }
200  if (len < (proto_size + proto_offset)) {
202  return TM_ECODE_FAILED;
203  }
204  if (!PacketIncreaseCheckLayers(p)) {
205  return TM_ECODE_FAILED;
206  }
207 
208  const uint32_t data_offset = proto_offset + proto_size;
209  if (data_offset != 4) {
210  if (proto_size == 1) {
211  return DecodePPPCompressedProto(tv, dtv, p, pkt, len, proto_offset);
212  } else {
213  const uint16_t proto = SCNtohs(*(uint16_t *)(pkt + proto_offset));
214  return DecodePPPUncompressedProto(tv, dtv, p, pkt, len, proto, data_offset);
215  }
216  }
217  /* implied proto_offset + proto_size == 4, so continue below */
218 
219  const PPPHdr *ppph = (PPPHdr *)pkt;
220  SCLogDebug(
221  "p %p pkt %p PPP protocol %04x Len: %" PRIu32 "", p, pkt, SCNtohs(ppph->protocol), len);
222  return DecodePPPUncompressedProto(tv, dtv, p, pkt, len, SCNtohs(ppph->protocol), data_offset);
223 }
224 
225 /* TESTS BELOW */
226 #ifdef UNITTESTS
227 
228 /* DecodePPPtest01
229  * Decode malformed ip layer PPP packet
230  * Expected test value: 1
231  */
232 static int DecodePPPtest01(void)
233 {
234  uint8_t raw_ppp[] = { 0xff, 0x03, 0x00, 0x21, 0x45, 0xc0, 0x00 };
236  if (unlikely(p == NULL))
237  return 0;
238  ThreadVars tv;
240 
241  memset(&tv, 0, sizeof(ThreadVars));
242  memset(&dtv, 0, sizeof(DecodeThreadVars));
243 
244  DecodePPP(&tv, &dtv, p, raw_ppp, sizeof(raw_ppp));
245 
246  /* Function my returns here with expected value */
247 
249  PacketFree(p);
250  PASS;
251 }
252 
253 /* DecodePPPtest02
254  * Decode malformed ppp layer packet
255  * Expected test value: 1
256  */
257 static int DecodePPPtest02(void)
258 {
259  uint8_t raw_ppp[] = { 0xff, 0x03, 0x00, 0xff, 0x45, 0xc0, 0x00, 0x2c, 0x4d, 0xed, 0x00, 0x00,
260  0xff, 0x06, 0xd5, 0x17, 0xbf, 0x01, 0x0d, 0x01, 0xbf, 0x01, 0x0d, 0x03, 0xea, 0x37, 0x00,
261  0x17, 0x6d, 0x0b, 0xba, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x60, 0x02, 0x10, 0x20, 0xdd, 0xe1,
262  0x00, 0x00 };
264  if (unlikely(p == NULL))
265  return 0;
266  ThreadVars tv;
268 
269  memset(&tv, 0, sizeof(ThreadVars));
270  memset(&dtv, 0, sizeof(DecodeThreadVars));
271 
272  DecodePPP(&tv, &dtv, p, raw_ppp, sizeof(raw_ppp));
273 
274  /* Function must returns here */
275 
277 
278  PacketFree(p);
279  PASS;
280 }
281 
282 /** DecodePPPtest03
283  * \brief Decode good PPP packet, additionally the IPv4 packet inside is
284  * 4 bytes short.
285  * \retval 0 Test failed
286  * \retval 1 Test succeeded
287  */
288 static int DecodePPPtest03(void)
289 {
290  uint8_t raw_ppp[] = { 0xff, 0x03, 0x00, 0x21, 0x45, 0xc0, 0x00, 0x2c, 0x4d, 0xed, 0x00, 0x00,
291  0xff, 0x06, 0xd5, 0x17, 0xbf, 0x01, 0x0d, 0x01, 0xbf, 0x01, 0x0d, 0x03, 0xea, 0x37, 0x00,
292  0x17, 0x6d, 0x0b, 0xba, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x60, 0x02, 0x10, 0x20, 0xdd, 0xe1,
293  0x00, 0x00 };
295  if (unlikely(p == NULL))
296  return 0;
297  ThreadVars tv;
299 
300  memset(&tv, 0, sizeof(ThreadVars));
301  memset(&dtv, 0, sizeof(DecodeThreadVars));
302 
304 
305  DecodePPP(&tv, &dtv, p, raw_ppp, sizeof(raw_ppp));
306 
311 
312  PacketFree(p);
313  FlowShutdown();
314  PASS;
315 }
316 
317 /* DecodePPPtest04
318  * Check if ppp header is null
319  * Expected test value: 1
320  */
321 
322 static int DecodePPPtest04(void)
323 {
324  uint8_t raw_ppp[] = { 0xff, 0x03, 0x00, 0x21, 0x45, 0xc0, 0x00, 0x2c, 0x4d, 0xed, 0x00, 0x00,
325  0xff, 0x06, 0xd5, 0x17, 0xbf, 0x01, 0x0d, 0x01, 0xbf, 0x01, 0x0d, 0x03, 0xea, 0x37, 0x00,
326  0x17, 0x6d, 0x0b, 0xba, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x60, 0x02, 0x10, 0x20, 0xdd, 0xe1,
327  0x00, 0x00 };
329  if (unlikely(p == NULL))
330  return 0;
331  ThreadVars tv;
333 
334  memset(&tv, 0, sizeof(ThreadVars));
335  memset(&dtv, 0, sizeof(DecodeThreadVars));
336 
338 
339  DecodePPP(&tv, &dtv, p, raw_ppp, sizeof(raw_ppp));
340 
341  FlowShutdown();
342 
344 
345  /* Function must returns here */
346 
347  PacketFree(p);
348  PASS;
349 }
350 #endif /* UNITTESTS */
351 
353 {
354 #ifdef UNITTESTS
355  UtRegisterTest("DecodePPPtest01", DecodePPPtest01);
356  UtRegisterTest("DecodePPPtest02", DecodePPPtest02);
357  UtRegisterTest("DecodePPPtest03", DecodePPPtest03);
358  UtRegisterTest("DecodePPPtest04", DecodePPPtest04);
359 #endif /* UNITTESTS */
360 }
361 
362 /**
363  * @}
364  */
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:172
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: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:352
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:422
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
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:576
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:58
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:164
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:445
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:720
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:44
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:121
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