-/* Copyright (C) 2007-2021 Open Information Security Foundation
+/* Copyright (C) 2007-2024 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
#include "util-unittest.h"
#include "util-debug.h"
-int DecodePPP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,
- const uint8_t *pkt, uint32_t len)
+static int DecodePPPCompressedProto(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,
+ const uint8_t *pkt, uint32_t len, uint16_t proto_offset)
{
- DEBUG_VALIDATE_BUG_ON(pkt == NULL);
-
- StatsIncr(tv, dtv->counter_ppp);
+ const uint32_t data_offset = proto_offset + 1;
+ switch (*(pkt + proto_offset)) {
+ case 0x21: { /* PPP_IP */
+ if (unlikely(len < (data_offset + IPV4_HEADER_LEN))) {
+ ENGINE_SET_INVALID_EVENT(p, PPPVJU_PKT_TOO_SMALL);
+ return TM_ECODE_FAILED;
+ }
+ DEBUG_VALIDATE_BUG_ON(len < data_offset);
+ uint16_t iplen = MIN(USHRT_MAX, (uint16_t)(len - data_offset));
+ return DecodeIPV4(tv, dtv, p, pkt + data_offset, iplen);
+ }
+ case 0x57: { /* PPP_IPV6 */
+ if (unlikely(len < (data_offset + IPV6_HEADER_LEN))) {
+ ENGINE_SET_INVALID_EVENT(p, PPPIPV6_PKT_TOO_SMALL);
+ return TM_ECODE_FAILED;
+ }
+ DEBUG_VALIDATE_BUG_ON(len < data_offset);
+ uint16_t iplen = MIN(USHRT_MAX, (uint16_t)(len - data_offset));
+ return DecodeIPV6(tv, dtv, p, pkt + data_offset, iplen);
+ }
+ case 0x2f: /* PPP_VJ_UCOMP */
+ if (unlikely(len < (data_offset + IPV4_HEADER_LEN))) {
+ ENGINE_SET_INVALID_EVENT(p, PPPVJU_PKT_TOO_SMALL);
+ return TM_ECODE_FAILED;
+ }
- if (unlikely(len < PPP_HEADER_LEN)) {
- ENGINE_SET_INVALID_EVENT(p, PPP_PKT_TOO_SMALL);
- return TM_ECODE_FAILED;
- }
- if (!PacketIncreaseCheckLayers(p)) {
- return TM_ECODE_FAILED;
- }
+ if (unlikely(len > data_offset + USHRT_MAX)) {
+ return TM_ECODE_FAILED;
+ }
- p->ppph = (PPPHdr *)pkt;
+ if (likely(IPV4_GET_RAW_VER((IPV4Hdr *)(pkt + data_offset)) == 4)) {
+ return DecodeIPV4(tv, dtv, p, pkt + data_offset, (uint16_t)(len - data_offset));
+ } else
+ return TM_ECODE_FAILED;
+ break;
- SCLogDebug("p %p pkt %p PPP protocol %04x Len: %" PRIu32 "",
- p, pkt, SCNtohs(p->ppph->protocol), len);
+ default:
+ ENGINE_SET_EVENT(p, PPP_UNSUP_PROTO);
+ return TM_ECODE_OK;
+ }
+}
- switch (SCNtohs(p->ppph->protocol))
- {
+static int DecodePPPUncompressedProto(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,
+ const uint8_t *pkt, uint32_t len, const uint16_t proto, const uint32_t data_offset)
+{
+ switch (proto) {
case PPP_VJ_UCOMP:
- if (unlikely(len < (PPP_HEADER_LEN + IPV4_HEADER_LEN))) {
- ENGINE_SET_INVALID_EVENT(p,PPPVJU_PKT_TOO_SMALL);
- p->ppph = NULL;
+ if (unlikely(len < (data_offset + IPV4_HEADER_LEN))) {
+ ENGINE_SET_INVALID_EVENT(p, PPPVJU_PKT_TOO_SMALL);
return TM_ECODE_FAILED;
}
- if (unlikely(len > PPP_HEADER_LEN + USHRT_MAX)) {
+ if (unlikely(len > data_offset + USHRT_MAX)) {
return TM_ECODE_FAILED;
}
- if (likely(IPV4_GET_RAW_VER((IPV4Hdr *)(pkt + PPP_HEADER_LEN)) == 4)) {
- return DecodeIPV4(
- tv, dtv, p, pkt + PPP_HEADER_LEN, (uint16_t)(len - PPP_HEADER_LEN));
+ if (likely(IPV4_GET_RAW_VER((IPV4Hdr *)(pkt + data_offset)) == 4)) {
+ return DecodeIPV4(tv, dtv, p, pkt + data_offset, (uint16_t)(len - data_offset));
} else
return TM_ECODE_FAILED;
break;
case PPP_IP:
- if (unlikely(len < (PPP_HEADER_LEN + IPV4_HEADER_LEN))) {
- ENGINE_SET_INVALID_EVENT(p,PPPIPV4_PKT_TOO_SMALL);
- p->ppph = NULL;
+ if (unlikely(len < (data_offset + IPV4_HEADER_LEN))) {
+ ENGINE_SET_INVALID_EVENT(p, PPPIPV4_PKT_TOO_SMALL);
return TM_ECODE_FAILED;
}
- if (unlikely(len > PPP_HEADER_LEN + USHRT_MAX)) {
+ if (unlikely(len > data_offset + USHRT_MAX)) {
return TM_ECODE_FAILED;
}
- return DecodeIPV4(tv, dtv, p, pkt + PPP_HEADER_LEN, (uint16_t)(len - PPP_HEADER_LEN));
+ return DecodeIPV4(tv, dtv, p, pkt + data_offset, (uint16_t)(len - data_offset));
/* PPP IPv6 was not tested */
case PPP_IPV6:
- if (unlikely(len < (PPP_HEADER_LEN + IPV6_HEADER_LEN))) {
- ENGINE_SET_INVALID_EVENT(p,PPPIPV6_PKT_TOO_SMALL);
- p->ppph = NULL;
+ if (unlikely(len < (data_offset + IPV6_HEADER_LEN))) {
+ ENGINE_SET_INVALID_EVENT(p, PPPIPV6_PKT_TOO_SMALL);
return TM_ECODE_FAILED;
}
- if (unlikely(len > PPP_HEADER_LEN + USHRT_MAX)) {
+ if (unlikely(len > data_offset + USHRT_MAX)) {
return TM_ECODE_FAILED;
}
- return DecodeIPV6(tv, dtv, p, pkt + PPP_HEADER_LEN, (uint16_t)(len - PPP_HEADER_LEN));
+ return DecodeIPV6(tv, dtv, p, pkt + data_offset, (uint16_t)(len - data_offset));
case PPP_VJ_COMP:
case PPP_IPX:
return TM_ECODE_OK;
default:
- SCLogDebug("unknown PPP protocol: %" PRIx32 "",SCNtohs(p->ppph->protocol));
+ SCLogDebug("unknown PPP protocol: %x", proto);
ENGINE_SET_INVALID_EVENT(p, PPP_WRONG_TYPE);
return TM_ECODE_OK;
}
+}
+int DecodePPP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
+{
+ DEBUG_VALIDATE_BUG_ON(pkt == NULL);
+
+ StatsIncr(tv, dtv->counter_ppp);
+ if (unlikely(len < 1)) {
+ ENGINE_SET_INVALID_EVENT(p, PPP_PKT_TOO_SMALL);
+ return TM_ECODE_FAILED;
+ }
+
+ uint16_t proto_offset = 0;
+ /* 0xff means we have a HDLC header: proto will start at offset 2 */
+ if (*pkt == 0xff) {
+ proto_offset = 2;
+ /* make sure the proto field at the offset fits */
+ if (len < 3) {
+ ENGINE_SET_INVALID_EVENT(p, PPP_PKT_TOO_SMALL);
+ return TM_ECODE_FAILED;
+ }
+ }
+ uint8_t proto_size = 0;
+ uint8_t proto_byte = *(pkt + proto_offset);
+ /* check if compressed protocol bit is set. */
+ if (proto_byte & 0x01) {
+ proto_size = 1;
+ } else {
+ proto_size = 2;
+ }
+ if (len < (proto_size + proto_offset)) {
+ ENGINE_SET_INVALID_EVENT(p, PPP_PKT_TOO_SMALL);
+ return TM_ECODE_FAILED;
+ }
+ if (!PacketIncreaseCheckLayers(p)) {
+ return TM_ECODE_FAILED;
+ }
+
+ const uint32_t data_offset = proto_offset + proto_size;
+ if (data_offset != 4) {
+ if (proto_size == 1) {
+ return DecodePPPCompressedProto(tv, dtv, p, pkt, len, proto_offset);
+ } else {
+ const uint16_t proto = SCNtohs(*(uint16_t *)(pkt + proto_offset));
+ return DecodePPPUncompressedProto(tv, dtv, p, pkt, len, proto, data_offset);
+ }
+ }
+ /* implied proto_offset + proto_size == 4, so continue below */
+
+ p->ppph = (PPPHdr *)pkt;
+
+ SCLogDebug("p %p pkt %p PPP protocol %04x Len: %" PRIu32 "", p, pkt, SCNtohs(p->ppph->protocol),
+ len);
+
+ int r = DecodePPPUncompressedProto(
+ tv, dtv, p, pkt, len, SCNtohs(p->ppph->protocol), data_offset);
+ if (r < 0) {
+ p->ppph = NULL;
+ }
+ return r;
}
/* TESTS BELOW */