Coverage Report

Created: 2026-09-06 07:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata8/src/detect-icmpv6-mtu.c
Line
Count
Source
1
/* Copyright (C) 2020 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
 * \file
20
 *
21
 * \author Philippe Antoine <p.antoine@catenacyber.fr>
22
 *
23
 */
24
25
#include "suricata-common.h"
26
27
#include "detect.h"
28
#include "detect-parse.h"
29
30
#include "detect-icmpv6-mtu.h"
31
#include "detect-engine-uint.h"
32
33
/* prototypes */
34
static int DetectICMPv6mtuMatch (DetectEngineThreadCtx *, Packet *,
35
        const Signature *, const SigMatchCtx *);
36
static int DetectICMPv6mtuSetup (DetectEngineCtx *, Signature *, const char *);
37
void DetectICMPv6mtuFree (DetectEngineCtx *de_ctx, void *);
38
#ifdef UNITTESTS
39
void DetectICMPv6mtuRegisterTests (void);
40
#endif
41
static int PrefilterSetupIcmpv6mtu(DetectEngineCtx *de_ctx, SigGroupHead *sgh);
42
static bool PrefilterIcmpv6mtuIsPrefilterable(const Signature *s);
43
44
/**
45
 * \brief Registration function for icmpv6.mtu: keyword
46
 */
47
48
void DetectICMPv6mtuRegister(void)
49
79
{
50
79
    sigmatch_table[DETECT_ICMPV6MTU].name = "icmpv6.mtu";
51
79
    sigmatch_table[DETECT_ICMPV6MTU].desc = "match on ICMPv6 MTU field";
52
79
    sigmatch_table[DETECT_ICMPV6MTU].url = "/rules/header-keywords.html#icmpv6mtu";
53
79
    sigmatch_table[DETECT_ICMPV6MTU].Match = DetectICMPv6mtuMatch;
54
79
    sigmatch_table[DETECT_ICMPV6MTU].Setup = DetectICMPv6mtuSetup;
55
79
    sigmatch_table[DETECT_ICMPV6MTU].Free = DetectICMPv6mtuFree;
56
#ifdef UNITTESTS
57
    sigmatch_table[DETECT_ICMPV6MTU].RegisterTests = DetectICMPv6mtuRegisterTests;
58
#endif
59
79
    sigmatch_table[DETECT_ICMPV6MTU].SupportsPrefilter = PrefilterIcmpv6mtuIsPrefilterable;
60
79
    sigmatch_table[DETECT_ICMPV6MTU].SetupPrefilter = PrefilterSetupIcmpv6mtu;
61
79
}
62
63
// returns 0 on no mtu, and 1 if mtu
64
static inline int DetectICMPv6mtuGetValue(Packet *p, uint32_t *picmpv6mtu)
65
4.88k
{
66
4.88k
    if (!(PacketIsICMPv6(p)))
67
3.91k
        return 0;
68
975
    const ICMPV6Hdr *icmpv6h = PacketGetICMPv6(p);
69
975
    if (ICMPV6_GET_CODE(icmpv6h) != 0)
70
291
        return 0;
71
684
    if (!(ICMPV6_HAS_MTU(icmpv6h)))
72
589
        return 0;
73
74
95
    *picmpv6mtu = ICMPV6_GET_MTU(icmpv6h);
75
95
    return 1;
76
684
}
77
78
/**
79
 * \brief This function is used to match ICMPV6 MTU rule option on a packet with those passed via icmpv6.mtu:
80
 *
81
 * \param det_ctx pointer to the pattern matcher thread
82
 * \param p pointer to the current packet
83
 * \param s pointer to the signature unused
84
 * \param ctx pointer to the signature match context
85
 *
86
 * \retval 0 no match
87
 * \retval 1 match
88
 */
89
static int DetectICMPv6mtuMatch (DetectEngineThreadCtx *det_ctx, Packet *p,
90
        const Signature *s, const SigMatchCtx *ctx)
91
4.35k
{
92
4.35k
    DEBUG_VALIDATE_BUG_ON(PKT_IS_PSEUDOPKT(p));
93
94
4.35k
    uint32_t picmpv6mtu;
95
4.35k
    if (DetectICMPv6mtuGetValue(p, &picmpv6mtu) == 0) {
96
4.26k
        return 0;
97
4.26k
    }
98
99
95
    const DetectU32Data *du32 = (const DetectU32Data *)ctx;
100
95
    return DetectU32Match(picmpv6mtu, du32);
101
4.35k
}
102
103
/**
104
 * \brief this function is used to attach the parsed icmpv6.mtu data into the current signature
105
 *
106
 * \param de_ctx pointer to the Detection Engine Context
107
 * \param s pointer to the Current Signature
108
 * \param icmpv6mtustr pointer to the user provided icmpv6.mtu options
109
 *
110
 * \retval 0 on Success
111
 * \retval -1 on Failure
112
 */
113
static int DetectICMPv6mtuSetup (DetectEngineCtx *de_ctx, Signature *s, const char *icmpv6mtustr)
114
1.45k
{
115
1.45k
    DetectU32Data *icmpv6mtud = DetectU32Parse(icmpv6mtustr);
116
1.45k
    if (icmpv6mtud == NULL)
117
332
        return -1;
118
119
1.12k
    if (SCSigMatchAppendSMToList(de_ctx, s, DETECT_ICMPV6MTU, (SigMatchCtx *)icmpv6mtud,
120
1.12k
                DETECT_SM_LIST_MATCH) == NULL) {
121
0
        DetectICMPv6mtuFree(de_ctx, icmpv6mtud);
122
0
        return -1;
123
0
    }
124
1.12k
    s->flags |= SIG_FLAG_REQUIRE_PACKET;
125
1.12k
    s->proto.flags |= DETECT_PROTO_IPV6;
126
127
1.12k
    return 0;
128
1.12k
}
129
130
/**
131
 * \brief this function will free memory associated with DetectU32Data
132
 *
133
 * \param ptr pointer to DetectU32Data
134
 */
135
void DetectICMPv6mtuFree(DetectEngineCtx *de_ctx, void *ptr)
136
1.12k
{
137
1.12k
    SCDetectU32Free(ptr);
138
1.12k
}
139
140
/* prefilter code */
141
142
static void
143
PrefilterPacketIcmpv6mtuMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)
144
531
{
145
531
    DEBUG_VALIDATE_BUG_ON(PKT_IS_PSEUDOPKT(p));
146
147
531
    uint32_t picmpv6mtu;
148
531
    if (DetectICMPv6mtuGetValue(p, &picmpv6mtu) == 0) {
149
531
        return;
150
531
    }
151
152
    /* during setup Suricata will automatically see if there is another
153
     * check that can be added: alproto, sport or dport */
154
0
    const PrefilterPacketHeaderCtx *ctx = pectx;
155
0
    if (!PrefilterPacketHeaderExtraMatch(ctx, p))
156
0
        return;
157
158
    /* if we match, add all the sigs that use this prefilter. This means
159
     * that these will be inspected further */
160
0
    DetectU32Data du32;
161
0
    du32.mode = ctx->v1.u8[0];
162
0
    du32.arg1 = ctx->v1.u32[1];
163
0
    du32.arg2 = ctx->v1.u32[2];
164
0
    if (DetectU32Match(picmpv6mtu, &du32))
165
0
    {
166
0
        SCLogDebug("packet matches icmpv6.mtu/hl %u", picmpv6mtu);
167
0
        PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt);
168
0
    }
169
0
}
170
171
static int PrefilterSetupIcmpv6mtu(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
172
1.92k
{
173
1.92k
    return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_ICMPV6MTU, SIG_MASK_REQUIRE_REAL_PKT,
174
1.92k
            PrefilterPacketU32Set, PrefilterPacketU32Compare, PrefilterPacketIcmpv6mtuMatch);
175
1.92k
}
176
177
static bool PrefilterIcmpv6mtuIsPrefilterable(const Signature *s)
178
0
{
179
0
    return PrefilterIsPrefilterableById(s, DETECT_ICMPV6MTU);
180
0
}
181
182
#ifdef UNITTESTS
183
#include "tests/detect-icmpv6-mtu.c"
184
#endif