• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OISF / suricata / 23374838686

21 Mar 2026 07:29AM UTC coverage: 59.341% (-20.0%) from 79.315%
23374838686

Pull #15075

github

web-flow
Merge 90b4e834f into 6587e363a
Pull Request #15075: Stack 8001 v16.4

38 of 70 new or added lines in 10 files covered. (54.29%)

34165 existing lines in 563 files now uncovered.

119621 of 201584 relevant lines covered (59.34%)

650666.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

74.12
/src/detect-email.c
1
/* Copyright (C) 2025 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
#include "detect-engine.h"
19
#include "detect-engine-buffer.h"
20
#include "detect-engine-helper.h"
21
#include "detect-parse.h"
22
#include "app-layer-smtp.h"
23
#include "detect-email.h"
24
#include "rust.h"
25
#include "detect-engine-content-inspection.h"
26

27
static int g_mime_email_from_buffer_id = 0;
28
static int g_mime_email_subject_buffer_id = 0;
29
static int g_mime_email_to_buffer_id = 0;
30
static int g_mime_email_cc_buffer_id = 0;
31
static int g_mime_email_date_buffer_id = 0;
32
static int g_mime_email_message_id_buffer_id = 0;
33
static int g_mime_email_x_mailer_buffer_id = 0;
34
static int g_mime_email_url_buffer_id = 0;
35
static int g_mime_email_received_buffer_id = 0;
36
static int g_mime_email_body_md5_buffer_id = 0;
37

38
static int DetectMimeEmailFromSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
39
{
230✔
40
    if (SCDetectBufferSetActiveList(de_ctx, s, g_mime_email_from_buffer_id) < 0)
230✔
41
        return -1;
1✔
42

43
    if (SCDetectSignatureSetAppProto(s, ALPROTO_SMTP) < 0)
229✔
44
        return -1;
1✔
45

46
    return 0;
228✔
47
}
229✔
48

49
static bool GetMimeEmailFromData(
50
        const void *txv, const uint8_t _flow_flags, const uint8_t **data, uint32_t *data_len)
UNCOV
51
{
×
UNCOV
52
    SMTPTransaction *tx = (SMTPTransaction *)txv;
×
UNCOV
53
    if (tx->mime_state == NULL)
×
UNCOV
54
        return false;
×
UNCOV
55
    return (SCDetectMimeEmailGetData(tx->mime_state, data, data_len, "from") == 1);
×
UNCOV
56
}
×
57

58
static int DetectMimeEmailSubjectSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
59
{
71✔
60
    if (SCDetectBufferSetActiveList(de_ctx, s, g_mime_email_subject_buffer_id) < 0)
71✔
61
        return -1;
1✔
62

63
    if (SCDetectSignatureSetAppProto(s, ALPROTO_SMTP) < 0)
70✔
64
        return -1;
1✔
65

66
    return 0;
69✔
67
}
70✔
68

69
static bool GetMimeEmailSubjectData(
70
        const void *txv, const uint8_t _flow_flags, const uint8_t **data, uint32_t *data_len)
UNCOV
71
{
×
UNCOV
72
    SMTPTransaction *tx = (SMTPTransaction *)txv;
×
UNCOV
73
    if (tx->mime_state == NULL)
×
UNCOV
74
        return false;
×
UNCOV
75
    return (SCDetectMimeEmailGetData(tx->mime_state, data, data_len, "subject") == 1);
×
UNCOV
76
}
×
77

78
static int DetectMimeEmailToSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
79
{
203✔
80
    if (SCDetectBufferSetActiveList(de_ctx, s, g_mime_email_to_buffer_id) < 0)
203✔
81
        return -1;
1✔
82

83
    if (SCDetectSignatureSetAppProto(s, ALPROTO_SMTP) < 0)
202✔
84
        return -1;
1✔
85

86
    return 0;
201✔
87
}
202✔
88

89
static bool GetMimeEmailToData(
90
        const void *txv, const uint8_t _flow_flags, const uint8_t **data, uint32_t *data_len)
UNCOV
91
{
×
UNCOV
92
    SMTPTransaction *tx = (SMTPTransaction *)txv;
×
UNCOV
93
    if (tx->mime_state == NULL)
×
UNCOV
94
        return false;
×
UNCOV
95
    return (SCDetectMimeEmailGetData(tx->mime_state, data, data_len, "to") == 1);
×
UNCOV
96
}
×
97

98
static int DetectMimeEmailCcSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
99
{
78✔
100
    if (SCDetectBufferSetActiveList(de_ctx, s, g_mime_email_cc_buffer_id) < 0)
78✔
101
        return -1;
1✔
102

103
    if (SCDetectSignatureSetAppProto(s, ALPROTO_SMTP) < 0)
77✔
104
        return -1;
1✔
105

106
    return 0;
76✔
107
}
77✔
108

109
static bool GetMimeEmailCcData(
110
        const void *txv, const uint8_t _flow_flags, const uint8_t **data, uint32_t *data_len)
UNCOV
111
{
×
UNCOV
112
    SMTPTransaction *tx = (SMTPTransaction *)txv;
×
UNCOV
113
    if (tx->mime_state == NULL)
×
UNCOV
114
        return false;
×
UNCOV
115
    return (SCDetectMimeEmailGetData(tx->mime_state, data, data_len, "cc") == 1);
×
UNCOV
116
}
×
117

118
static int DetectMimeEmailDateSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
119
{
197✔
120
    if (SCDetectBufferSetActiveList(de_ctx, s, g_mime_email_date_buffer_id) < 0)
197✔
121
        return -1;
1✔
122

123
    if (SCDetectSignatureSetAppProto(s, ALPROTO_SMTP) < 0)
196✔
124
        return -1;
1✔
125

126
    return 0;
195✔
127
}
196✔
128

129
static bool GetMimeEmailDateData(
130
        const void *txv, const uint8_t _flow_flags, const uint8_t **data, uint32_t *data_len)
UNCOV
131
{
×
UNCOV
132
    SMTPTransaction *tx = (SMTPTransaction *)txv;
×
UNCOV
133
    if (tx->mime_state == NULL)
×
UNCOV
134
        return false;
×
UNCOV
135
    return (SCDetectMimeEmailGetData(tx->mime_state, data, data_len, "date") == 1);
×
UNCOV
136
}
×
137

138
static int DetectMimeEmailMessageIdSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
139
{
74✔
140
    if (SCDetectBufferSetActiveList(de_ctx, s, g_mime_email_message_id_buffer_id) < 0)
74✔
141
        return -1;
1✔
142

143
    if (SCDetectSignatureSetAppProto(s, ALPROTO_SMTP) < 0)
73✔
144
        return -1;
1✔
145

146
    return 0;
72✔
147
}
73✔
148

149
static bool GetMimeEmailMessageIdData(
150
        const void *txv, const uint8_t _flow_flags, const uint8_t **data, uint32_t *data_len)
UNCOV
151
{
×
UNCOV
152
    SMTPTransaction *tx = (SMTPTransaction *)txv;
×
UNCOV
153
    if (tx->mime_state == NULL)
×
UNCOV
154
        return false;
×
UNCOV
155
    return (SCDetectMimeEmailGetData(tx->mime_state, data, data_len, "message-id") == 1);
×
UNCOV
156
}
×
157

158
static int DetectMimeEmailXMailerSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
159
{
69✔
160
    if (SCDetectBufferSetActiveList(de_ctx, s, g_mime_email_x_mailer_buffer_id) < 0)
69✔
161
        return -1;
1✔
162

163
    if (SCDetectSignatureSetAppProto(s, ALPROTO_SMTP) < 0)
68✔
164
        return -1;
1✔
165

166
    return 0;
67✔
167
}
68✔
168

169
static bool GetMimeEmailXMailerData(
170
        const void *txv, const uint8_t _flow_flags, const uint8_t **data, uint32_t *data_len)
UNCOV
171
{
×
UNCOV
172
    SMTPTransaction *tx = (SMTPTransaction *)txv;
×
UNCOV
173
    if (tx->mime_state == NULL)
×
UNCOV
174
        return false;
×
UNCOV
175
    return (SCDetectMimeEmailGetData(tx->mime_state, data, data_len, "x-mailer") == 1);
×
UNCOV
176
}
×
177

178
static int DetectMimeEmailUrlSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
179
{
74✔
180
    if (SCDetectBufferSetActiveList(de_ctx, s, g_mime_email_url_buffer_id) < 0)
74✔
181
        return -1;
1✔
182

183
    if (SCDetectSignatureSetAppProto(s, ALPROTO_SMTP) < 0)
73✔
184
        return -1;
1✔
185

186
    return 0;
72✔
187
}
73✔
188

189
static bool GetMimeEmailUrlData(DetectEngineThreadCtx *det_ctx, const void *txv,
190
        const uint8_t flags, uint32_t idx, const uint8_t **buf, uint32_t *buf_len)
UNCOV
191
{
×
UNCOV
192
    SMTPTransaction *tx = (SMTPTransaction *)txv;
×
UNCOV
193
    if (tx->mime_state == NULL) {
×
UNCOV
194
        return false;
×
UNCOV
195
    }
×
196

UNCOV
197
    if (SCDetectMimeEmailGetUrl(tx->mime_state, buf, buf_len, idx) != 1) {
×
UNCOV
198
        return false;
×
UNCOV
199
    }
×
UNCOV
200
    return true;
×
UNCOV
201
}
×
202

203
static int DetectMimeEmailReceivedSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
204
{
136✔
205
    if (SCDetectBufferSetActiveList(de_ctx, s, g_mime_email_received_buffer_id) < 0)
136✔
206
        return -1;
1✔
207

208
    if (SCDetectSignatureSetAppProto(s, ALPROTO_SMTP) < 0)
135✔
209
        return -1;
7✔
210

211
    return 0;
128✔
212
}
135✔
213

214
static bool GetMimeEmailReceivedData(DetectEngineThreadCtx *det_ctx, const void *txv,
215
        const uint8_t flags, uint32_t idx, const uint8_t **buf, uint32_t *buf_len)
216
{
186✔
217
    SMTPTransaction *tx = (SMTPTransaction *)txv;
186✔
218

219
    if (tx->mime_state == NULL) {
186✔
220
        return false;
95✔
221
    }
95✔
222

223
    if (SCDetectMimeEmailGetDataArray(tx->mime_state, buf, buf_len, "received", idx) != 1) {
91✔
224
        return false;
58✔
225
    }
58✔
226
    return true;
33✔
227
}
91✔
228

229
int DETECT_EMAIL_BODY_MD5 = 0;
230

231
static int DetectMimeEmailBodyMd5Setup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
232
{
38✔
233
    if (SCDetectBufferSetActiveList(de_ctx, s, g_mime_email_body_md5_buffer_id) < 0)
38✔
234
        return -1;
1✔
235

236
    if (SCDetectSignatureSetAppProto(s, ALPROTO_SMTP) < 0)
37✔
237
        return -1;
1✔
238

239
    if (!MimeBodyMd5IsEnabled()) {
36✔
240
        // we registered the keyword if not explicitly disabled, so we are here in auto mode
241
        SCMimeSmtpConfigBodyMd5(true);
2✔
242
    }
2✔
243

244
    return 0;
36✔
245
}
37✔
246

247
static bool GetMimeEmailBodyMd5Data(
248
        const void *txv, const uint8_t _flow_flags, const uint8_t **data, uint32_t *data_len)
UNCOV
249
{
×
UNCOV
250
    SMTPTransaction *tx = (SMTPTransaction *)txv;
×
UNCOV
251
    if (tx->mime_state == NULL)
×
UNCOV
252
        return false;
×
253

UNCOV
254
    SCDetectMimeEmailGetBodyMd5(tx->mime_state, data, data_len);
×
255

UNCOV
256
    return true;
×
UNCOV
257
}
×
258

259
void DetectEmailRegister(void)
260
{
3✔
261
    SCSigTableAppLiteElmt kw = { 0 };
3✔
262

263
    kw.name = "email.from";
3✔
264
    kw.desc = "'From' field from an email";
3✔
265
    kw.url = "/rules/email-keywords.html#email.from";
3✔
266
    kw.Setup = DetectMimeEmailFromSetup;
3✔
267
    kw.flags = SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER;
3✔
268
    SCDetectHelperKeywordRegister(&kw);
3✔
269
    g_mime_email_from_buffer_id = SCDetectHelperBufferMpmRegister(
3✔
270
            "email.from", "MIME EMAIL FROM", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailFromData);
3✔
271

272
    kw.name = "email.subject";
3✔
273
    kw.desc = "'Subject' field from an email";
3✔
274
    kw.url = "/rules/email-keywords.html#email.subject";
3✔
275
    kw.Setup = DetectMimeEmailSubjectSetup;
3✔
276
    kw.flags = SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER;
3✔
277
    SCDetectHelperKeywordRegister(&kw);
3✔
278
    g_mime_email_subject_buffer_id = SCDetectHelperBufferMpmRegister("email.subject",
3✔
279
            "MIME EMAIL SUBJECT", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailSubjectData);
3✔
280

281
    kw.name = "email.to";
3✔
282
    kw.desc = "'To' field from an email";
3✔
283
    kw.url = "/rules/email-keywords.html#email.to";
3✔
284
    kw.Setup = DetectMimeEmailToSetup;
3✔
285
    kw.flags = SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER;
3✔
286
    SCDetectHelperKeywordRegister(&kw);
3✔
287
    g_mime_email_to_buffer_id = SCDetectHelperBufferMpmRegister(
3✔
288
            "email.to", "MIME EMAIL TO", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailToData);
3✔
289

290
    kw.name = "email.cc";
3✔
291
    kw.desc = "'Cc' field from an email";
3✔
292
    kw.url = "/rules/email-keywords.html#email.cc";
3✔
293
    kw.Setup = DetectMimeEmailCcSetup;
3✔
294
    kw.flags = SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER;
3✔
295
    SCDetectHelperKeywordRegister(&kw);
3✔
296
    g_mime_email_cc_buffer_id = SCDetectHelperBufferMpmRegister(
3✔
297
            "email.cc", "MIME EMAIL CC", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailCcData);
3✔
298

299
    kw.name = "email.date";
3✔
300
    kw.desc = "'Date' field from an email";
3✔
301
    kw.url = "/rules/email-keywords.html#email.date";
3✔
302
    kw.Setup = DetectMimeEmailDateSetup;
3✔
303
    kw.flags = SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER;
3✔
304
    SCDetectHelperKeywordRegister(&kw);
3✔
305
    g_mime_email_date_buffer_id = SCDetectHelperBufferMpmRegister(
3✔
306
            "email.date", "MIME EMAIL DATE", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailDateData);
3✔
307

308
    kw.name = "email.message_id";
3✔
309
    kw.desc = "'Message-Id' field from an email";
3✔
310
    kw.url = "/rules/email-keywords.html#email.message_id";
3✔
311
    kw.Setup = DetectMimeEmailMessageIdSetup;
3✔
312
    kw.flags = SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER;
3✔
313
    SCDetectHelperKeywordRegister(&kw);
3✔
314
    g_mime_email_message_id_buffer_id = SCDetectHelperBufferMpmRegister("email.message_id",
3✔
315
            "MIME EMAIL Message-Id", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailMessageIdData);
3✔
316

317
    kw.name = "email.x_mailer";
3✔
318
    kw.desc = "'X-Mailer' field from an email";
3✔
319
    kw.url = "/rules/email-keywords.html#email.x_mailer";
3✔
320
    kw.Setup = DetectMimeEmailXMailerSetup;
3✔
321
    kw.flags = SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER;
3✔
322
    SCDetectHelperKeywordRegister(&kw);
3✔
323
    g_mime_email_x_mailer_buffer_id = SCDetectHelperBufferMpmRegister("email.x_mailer",
3✔
324
            "MIME EMAIL X-Mailer", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailXMailerData);
3✔
325

326
    kw.name = "email.url";
3✔
327
    kw.desc = "'Url' extracted from an email";
3✔
328
    kw.url = "/rules/email-keywords.html#email.url";
3✔
329
    kw.Setup = DetectMimeEmailUrlSetup;
3✔
330
    kw.flags = SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER | SIGMATCH_INFO_MULTI_BUFFER;
3✔
331
    SCDetectHelperKeywordRegister(&kw);
3✔
332
    g_mime_email_url_buffer_id = SCDetectHelperMultiBufferMpmRegister(
3✔
333
            "email.url", "MIME EMAIL URL", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailUrlData);
3✔
334

335
    kw.name = "email.received";
3✔
336
    kw.desc = "'Received' field from an email";
3✔
337
    kw.url = "/rules/email-keywords.html#email.received";
3✔
338
    kw.Setup = DetectMimeEmailReceivedSetup;
3✔
339
    kw.flags = SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER | SIGMATCH_INFO_MULTI_BUFFER;
3✔
340
    SCDetectHelperKeywordRegister(&kw);
3✔
341
    g_mime_email_received_buffer_id = SCDetectHelperMultiBufferMpmRegister("email.received",
3✔
342
            "MIME EMAIL RECEIVED", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailReceivedData);
3✔
343

344
    if (!MimeBodyMd5IsDisabled()) {
3✔
345
        // do not register the keyword if explicitly disabled
346
        kw.name = "email.body_md5";
3✔
347
        kw.desc = "'md5' hash generated from an email body";
3✔
348
        kw.url = "/rules/email-keywords.html#email.body_md5";
3✔
349
        kw.Setup = DetectMimeEmailBodyMd5Setup;
3✔
350
        kw.flags = SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER;
3✔
351
        DETECT_EMAIL_BODY_MD5 = SCDetectHelperKeywordRegister(&kw);
3✔
352
        // We do not need a progress because SMTP tx has only progress 0 or 1
353
        // even if we have a MimeSmtpMd5State enumeration
354
        g_mime_email_body_md5_buffer_id = SCDetectHelperBufferMpmRegister("email.body_md5",
3✔
355
                "MIME EMAIL BODY MD5", ALPROTO_SMTP, STREAM_TOSERVER, GetMimeEmailBodyMd5Data);
3✔
356
        DetectBufferTypeRegisterValidateCallback("email.body_md5", DetectMd5ValidateCallback);
3✔
357
    }
3✔
358
}
3✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc