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(); +} 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 5bf682bd2fc6..1d22b255893f 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,94 @@ #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)) { + p->flags |= PKT_PPP_VJ_UCOMP; + 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: @@ -134,15 +158,70 @@ int DecodePPP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, 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; 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 */ + + 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 */ @@ -238,11 +317,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; @@ -296,11 +370,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-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_ { diff --git a/src/decode.h b/src/decode.h index b6b7d38b667e..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; @@ -1005,7 +1004,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) 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); 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]); } 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;