From 49caf005a479326ac1acffd135e79f0c58e5d944 Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Sun, 14 Apr 2024 21:34:57 +0200 Subject: [PATCH 1/7] detect/analyzer: create tojson function for generic integers As will be needed for tcp.mss --- rust/src/detect/mod.rs | 1 + rust/src/detect/tojson/mod.rs | 79 +++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 rust/src/detect/tojson/mod.rs diff --git a/rust/src/detect/mod.rs b/rust/src/detect/mod.rs index cad086f161b5..2b1fd0e464b0 100644 --- a/rust/src/detect/mod.rs +++ b/rust/src/detect/mod.rs @@ -25,6 +25,7 @@ pub mod stream_size; pub mod uint; pub mod uri; pub mod requires; +pub mod tojson; /// EnumString trait that will be implemented on enums that /// derive StringEnum. diff --git a/rust/src/detect/tojson/mod.rs b/rust/src/detect/tojson/mod.rs new file mode 100644 index 000000000000..2c552bcfa0bc --- /dev/null +++ b/rust/src/detect/tojson/mod.rs @@ -0,0 +1,79 @@ +/* Copyright (C) 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 + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +use crate::detect::uint::{DetectIntType, DetectUintData, DetectUintMode}; +use crate::jsonbuilder::{JsonBuilder, JsonError}; + +pub fn detect_uint_to_json( + js: &mut JsonBuilder, du: &DetectUintData, +) -> Result<(), JsonError> +where + u64: From, +{ + match du.mode { + DetectUintMode::DetectUintModeEqual => { + js.set_uint("equal", du.arg1.into())?; + } + DetectUintMode::DetectUintModeNe => { + js.set_uint("diff", du.arg1.into())?; + } + DetectUintMode::DetectUintModeLt => { + js.set_uint("lt", du.arg1.into())?; + } + DetectUintMode::DetectUintModeLte => { + js.set_uint("lte", du.arg1.into())?; + } + DetectUintMode::DetectUintModeGt => { + js.set_uint("gt", du.arg1.into())?; + } + DetectUintMode::DetectUintModeGte => { + js.set_uint("gte", du.arg1.into())?; + } + DetectUintMode::DetectUintModeRange => { + js.open_object("range")?; + js.set_uint("min", du.arg1.into())?; + js.set_uint("max", du.arg2.into())?; + js.close()?; + } + DetectUintMode::DetectUintModeNegRg => { + js.open_object("negated_range")?; + js.set_uint("min", du.arg1.into())?; + js.set_uint("max", du.arg2.into())?; + js.close()?; + } + DetectUintMode::DetectUintModeBitmask => { + js.open_object("bitmask")?; + js.set_uint("mask", du.arg1.into())?; + js.set_uint("value", du.arg2.into())?; + js.close()?; + } + DetectUintMode::DetectUintModeNegBitmask => { + js.open_object("negated_bitmask")?; + js.set_uint("mask", du.arg1.into())?; + js.set_uint("value", du.arg2.into())?; + js.close()?; + } + } + Ok(()) +} + +#[no_mangle] +pub unsafe extern "C" fn SCDetectU16ToJson( + js: &mut JsonBuilder, du: &DetectUintData, +) -> bool { + return detect_uint_to_json(js, du).is_ok(); +} From bd3bed6c31b0562fff4e3a0a5a254a13970b532f Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Sun, 14 Apr 2024 21:36:17 +0200 Subject: [PATCH 2/7] detect/analyzer: add more details for tcp_mss Issue: #6355 --- src/detect-engine-analyzer.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index d0f712388004..5e5d29e92f41 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -32,6 +32,7 @@ #include "detect-engine.h" #include "detect-engine-analyzer.h" #include "detect-engine-mpm.h" +#include "detect-engine-uint.h" #include "conf.h" #include "detect-content.h" #include "detect-pcre.h" @@ -915,12 +916,18 @@ static void DumpMatches(RuleAnalyzer *ctx, JsonBuilder *js, const SigMatchData * } case DETECT_SEQ: { const DetectSeqData *cd = (const DetectSeqData *)smd->ctx; - jb_open_object(js, "seq"); jb_set_uint(js, "number", cd->seq); jb_close(js); break; } + case DETECT_TCPMSS: { + const DetectU16Data *cd = (const DetectU16Data *)smd->ctx; + jb_open_object(js, "tcp_mss"); + SCDetectU16ToJson(js, cd); + jb_close(js); + break; + } } jb_close(js); From 68092ff33ce437a6f6720dd9d7f47aa16574ccf1 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 12 Apr 2024 12:42:37 +0200 Subject: [PATCH 3/7] decode/ppp: support different header formats Support compressed proto and optional HDLC header. Bug: #6942. --- src/decode-ppp.c | 154 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 118 insertions(+), 36 deletions(-) diff --git a/src/decode-ppp.c b/src/decode-ppp.c index 5bf682bd2fc6..6507bc0a6ee9 100644 --- a/src/decode-ppp.c +++ b/src/decode-ppp.c @@ -1,4 +1,4 @@ -/* 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 @@ -41,70 +41,93 @@ #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: @@ -138,11 +161,70 @@ int DecodePPP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, 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 */ From 6067955afd225e43fa0b54c66c5b0f7f260109ed Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 12 Apr 2024 15:19:45 +0200 Subject: [PATCH 4/7] decode/ppp: remove ppph check in favor of flag As we now support variable size headers, we can't use the old pointer. Replace with a flag. --- src/decode-ipv4.c | 2 +- src/decode-ppp.c | 1 + src/decode.h | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/decode-ipv4.c b/src/decode-ipv4.c index 92d0c6ecfd5c..c1bb9cce4731 100644 --- a/src/decode-ipv4.c +++ b/src/decode-ipv4.c @@ -601,7 +601,7 @@ int DecodeIPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, } case IPPROTO_IP: /* check PPP VJ uncompressed packets and decode tcp dummy */ - if(p->ppph != NULL && SCNtohs(p->ppph->protocol) == PPP_VJ_UCOMP) { + if (p->flags & PKT_PPP_VJ_UCOMP) { DecodeTCP(tv, dtv, p, pkt + IPV4_GET_HLEN(p), IPV4_GET_IPLEN(p) - IPV4_GET_HLEN(p)); } diff --git a/src/decode-ppp.c b/src/decode-ppp.c index 6507bc0a6ee9..a05c4c3edd2f 100644 --- a/src/decode-ppp.c +++ b/src/decode-ppp.c @@ -75,6 +75,7 @@ static int DecodePPPCompressedProto(ThreadVars *tv, DecodeThreadVars *dtv, Packe } if (likely(IPV4_GET_RAW_VER((IPV4Hdr *)(pkt + data_offset)) == 4)) { + p->flags |= PKT_PPP_VJ_UCOMP; return DecodeIPV4(tv, dtv, p, pkt + data_offset, (uint16_t)(len - data_offset)); } else return TM_ECODE_FAILED; diff --git a/src/decode.h b/src/decode.h index b6b7d38b667e..a591c7e3f534 100644 --- a/src/decode.h +++ b/src/decode.h @@ -1005,7 +1005,8 @@ void DecodeUnregisterCounters(void); /** Flag to indicate that packet header or contents should not be inspected */ #define PKT_NOPACKET_INSPECTION BIT_U32(0) -// vacancy +/** Packet has a PPP_VJ_UCOMP header */ +#define PKT_PPP_VJ_UCOMP BIT_U32(1) /** Flag to indicate that packet contents should not be inspected */ #define PKT_NOPAYLOAD_INSPECTION BIT_U32(2) From 7e3f071e4967303c3424d0c0ea812afb2889bbec Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 12 Apr 2024 15:26:46 +0200 Subject: [PATCH 5/7] decode/ppp: clean up ppph pointer use No users of the pointer anymore, so remove it. --- src/decode-ppp.c | 25 ++++--------------------- src/decode.h | 1 - src/packet.c | 1 - 3 files changed, 4 insertions(+), 23 deletions(-) diff --git a/src/decode-ppp.c b/src/decode-ppp.c index a05c4c3edd2f..2e558ab5bf51 100644 --- a/src/decode-ppp.c +++ b/src/decode-ppp.c @@ -215,17 +215,10 @@ int DecodePPP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *p } /* 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; + const PPPHdr *ppph = (PPPHdr *)pkt; + SCLogDebug( + "p %p pkt %p PPP protocol %04x Len: %" PRIu32 "", p, pkt, SCNtohs(ppph->protocol), len); + return DecodePPPUncompressedProto(tv, dtv, p, pkt, len, SCNtohs(ppph->protocol), data_offset); } /* TESTS BELOW */ @@ -321,11 +314,6 @@ static int DecodePPPtest03 (void) FlowShutdown(); - if(p->ppph == NULL) { - SCFree(p); - return 0; - } - if(ENGINE_ISSET_EVENT(p,PPP_PKT_TOO_SMALL)) { SCFree(p); return 0; @@ -379,11 +367,6 @@ static int DecodePPPtest04 (void) FlowShutdown(); - if(p->ppph == NULL) { - SCFree(p); - return 0; - } - if (!(ENGINE_ISSET_EVENT(p,IPV4_TRUNC_PKT))) { SCFree(p); return 0; diff --git a/src/decode.h b/src/decode.h index a591c7e3f534..c0b1b677098d 100644 --- a/src/decode.h +++ b/src/decode.h @@ -576,7 +576,6 @@ typedef struct Packet_ ICMPV6Hdr *icmpv6h; - PPPHdr *ppph; PPPOESessionHdr *pppoesh; PPPOEDiscoveryHdr *pppoedh; diff --git a/src/packet.c b/src/packet.c index 30ef4f11b31a..a4ba2ba87f8f 100644 --- a/src/packet.c +++ b/src/packet.c @@ -138,7 +138,6 @@ void PacketReinit(Packet *p) if (p->icmpv6h != NULL) { CLEAR_ICMPV6_PACKET(p); } - p->ppph = NULL; p->pppoesh = NULL; p->pppoedh = NULL; p->greh = NULL; From 516441b6005f4200ae155f5234cfd0ad20d2dfbc Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 15 Apr 2024 12:29:12 +0200 Subject: [PATCH 6/7] decode/ppp: add missing types definitions Recognize PPP_CCP, PPP_CBCP and PPP_COMP_DGRAM. Does not implement decoders for these record types, so these are logged as unsupported types. Was "wrong_type" before. --- src/decode-ppp.c | 3 +++ src/decode-ppp.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/decode-ppp.c b/src/decode-ppp.c index 2e558ab5bf51..1d22b255893f 100644 --- a/src/decode-ppp.c +++ b/src/decode-ppp.c @@ -158,6 +158,9 @@ static int DecodePPPUncompressedProto(ThreadVars *tv, DecodeThreadVars *dtv, Pac case PPP_PAP: case PPP_LQM: case PPP_CHAP: + case PPP_CCP: + case PPP_CBCP: + case PPP_COMP_DGRAM: ENGINE_SET_EVENT(p,PPP_UNSUP_PROTO); return TM_ECODE_OK; diff --git a/src/decode-ppp.h b/src/decode-ppp.h index ee5258c69486..6ec7830acecd 100644 --- a/src/decode-ppp.h +++ b/src/decode-ppp.h @@ -59,6 +59,9 @@ #define PPP_PAP 0xc023 /* Password Authentication Protocol */ #define PPP_LQM 0xc025 /* Link Quality Monitoring */ #define PPP_CHAP 0xc223 /* Challenge Handshake Authentication Protocol */ +#define PPP_CCP 0x80fd /* Compression Control Protocol */ +#define PPP_CBCP 0xc029 /* Callback Control Protocol CBCP */ +#define PPP_COMP_DGRAM 0x00fd /* Compressed datagram */ /** PPP Packet header */ typedef struct PPPHdr_ { From c305ed149c58818779c504b6666fe9c2cb0be4ff Mon Sep 17 00:00:00 2001 From: Jeff Lucovsky Date: Mon, 15 Apr 2024 10:17:17 -0400 Subject: [PATCH 7/7] flow/inject: Select thread_id by flow flag Issue: 6957 Rather than selecting the thread_id index by packets traveling to the server, use the flow flags. If the flow has been reversed, the second slot is represents the thread id to be used. --- src/flow-timeout.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/flow-timeout.c b/src/flow-timeout.c index 0b75228ca375..63aec2f0e64a 100644 --- a/src/flow-timeout.c +++ b/src/flow-timeout.c @@ -335,9 +335,8 @@ int FlowForceReassemblyNeedReassembly(Flow *f) * The function requires flow to be locked beforehand. * * Normally, the first thread_id value should be used. This is when the flow is - * created on seeing the first packet to the server; sometimes, if the first - * packet is determined to be to the client, the second thread_id value should - * be used. + * created on seeing the first packet to the server; when the flow's reversed + * flag is set, choose the second thread_id (to client/source). * * \param f Pointer to the flow. * @@ -345,9 +344,9 @@ int FlowForceReassemblyNeedReassembly(Flow *f) */ void FlowForceReassemblyForFlow(Flow *f) { - // Have packets traveled to the server? If not, - // use the reverse direction - int idx = f->todstpktcnt > 0 ? 0 : 1; + // Choose the thread_id based on whether the flow has been + // reversed. + int idx = f->flags & FLOW_DIR_REVERSED ? 1 : 0; TmThreadsInjectFlowById(f, (const int)f->thread_id[idx]); }