Coverage Report

Created: 2026-11-12 06:59

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