• 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

4.62
/src/log-tcp-data.c
1
/* Copyright (C) 2014 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 Victor Julien <victor@inliniac.net>
22
 */
23

24
#include "suricata-common.h"
25
#include "log-tcp-data.h"
26

27
#include "threadvars.h"
28

29
#include "util-conf.h"
30
#include "util-logopenfile.h"
31
#include "util-path.h"
32
#include "util-print.h"
33

UNCOV
34
#define DEFAULT_LOG_FILENAME "tcp-data.log"
×
35

36
#define MODULE_NAME "LogTcpDataLog"
4✔
37

UNCOV
38
#define OUTPUT_BUFFER_SIZE 65535
×
39

40
TmEcode LogTcpDataLogThreadInit(ThreadVars *, const void *, void **);
41
TmEcode LogTcpDataLogThreadDeinit(ThreadVars *, void *);
42
static void LogTcpDataLogDeInitCtx(OutputCtx *);
43

44
int LogTcpDataLogger(ThreadVars *tv, void *thread_data, const Flow *f, const uint8_t *data, uint32_t data_len, uint64_t tx_id, uint8_t flags);
45

46
void LogTcpDataLogRegister (void) {
2✔
47
    OutputRegisterStreamingModule(LOGGER_TCP_DATA, MODULE_NAME, "tcp-data", LogTcpDataLogInitCtx,
2✔
48
            LogTcpDataLogger, STREAMING_TCP_DATA, LogTcpDataLogThreadInit,
2✔
49
            LogTcpDataLogThreadDeinit);
2✔
50
    OutputRegisterStreamingModule(LOGGER_TCP_DATA, MODULE_NAME, "http-body-data",
2✔
51
            LogTcpDataLogInitCtx, LogTcpDataLogger, STREAMING_HTTP_BODIES, LogTcpDataLogThreadInit,
2✔
52
            LogTcpDataLogThreadDeinit);
2✔
53
}
2✔
54

55
typedef struct LogTcpDataFileCtx_ {
56
    LogFileCtx *file_ctx;
57
    enum SCOutputStreamingType type;
58
    const char *log_dir;
59
    int file;
60
    int dir;
61
} LogTcpDataFileCtx;
62

63
typedef struct LogTcpDataLogThread_ {
64
    LogTcpDataFileCtx *tcpdatalog_ctx;
65
    /** LogFileCtx has the pointer to the file and a mutex to allow multithreading */
66
    MemBuffer *buffer;
67
} LogTcpDataLogThread;
68

69
static int LogTcpDataLoggerDir(ThreadVars *tv, void *thread_data, const Flow *f,
70
        const uint8_t *data, uint32_t data_len, uint64_t tx_id, uint8_t flags)
71
{
×
72
    SCEnter();
×
73
    LogTcpDataLogThread *aft = thread_data;
×
74
    LogTcpDataFileCtx *td = aft->tcpdatalog_ctx;
×
75
    const char *mode = "a";
×
76

77
    if (flags & OUTPUT_STREAMING_FLAG_OPEN)
×
78
        mode = "w";
×
79

80
    if (data && data_len) {
×
81
        char srcip[46] = "", dstip[46] = "";
×
82
        if (FLOW_IS_IPV4(f)) {
×
83
            PrintInet(AF_INET, (const void *)&f->src.addr_data32[0], srcip, sizeof(srcip));
×
84
            PrintInet(AF_INET, (const void *)&f->dst.addr_data32[0], dstip, sizeof(dstip));
×
85
        } else if (FLOW_IS_IPV6(f)) {
×
86
            PrintInetIPv6((const void *)f->src.addr_data32, srcip, sizeof(srcip),
×
87
                    td->file_ctx->compress_ipv6);
×
88
            PrintInetIPv6((const void *)f->dst.addr_data32, dstip, sizeof(dstip),
×
89
                    td->file_ctx->compress_ipv6);
×
90
        }
×
91

92
        char name[PATH_MAX];
×
93

94
        char tx[64] = { 0 };
×
95
        if (flags & OUTPUT_STREAMING_FLAG_TRANSACTION) {
×
96
            snprintf(tx, sizeof(tx), "%"PRIu64, tx_id);
×
97
        }
×
98

99
        snprintf(name, sizeof(name), "%s/%s/%s_%u-%s_%u-%s-%s.data",
×
100
                td->log_dir,
×
101
                td->type == STREAMING_HTTP_BODIES ? "http" : "tcp",
×
102
                srcip, f->sp, dstip, f->dp, tx,
×
103
                flags & OUTPUT_STREAMING_FLAG_TOSERVER ? "ts" : "tc");
×
104

105
        FILE *fp = fopen(name, mode);
×
106
        BUG_ON(fp == NULL);
×
107

108
        // PrintRawDataFp(stdout, (uint8_t *)data, data_len);
109
        fwrite(data, data_len, 1, fp);
×
110

111
        fclose(fp);
×
112
    }
×
113
    SCReturnInt(TM_ECODE_OK);
×
114
}
×
115

116
static int LogTcpDataLoggerFile(ThreadVars *tv, void *thread_data, const Flow *f,
117
        const uint8_t *data, uint32_t data_len, uint64_t tx_id, uint8_t flags)
UNCOV
118
{
×
UNCOV
119
    SCEnter();
×
UNCOV
120
    LogTcpDataLogThread *aft = thread_data;
×
UNCOV
121
    LogTcpDataFileCtx *td = aft->tcpdatalog_ctx;
×
122

UNCOV
123
    if (data && data_len) {
×
UNCOV
124
        MemBufferReset(aft->buffer);
×
125

UNCOV
126
        char srcip[46] = "", dstip[46] = "";
×
UNCOV
127
        if (FLOW_IS_IPV4(f)) {
×
UNCOV
128
            PrintInet(AF_INET, (const void *)&f->src.addr_data32[0], srcip, sizeof(srcip));
×
UNCOV
129
            PrintInet(AF_INET, (const void *)&f->dst.addr_data32[0], dstip, sizeof(dstip));
×
UNCOV
130
        } else if (FLOW_IS_IPV6(f)) {
×
UNCOV
131
            PrintInetIPv6((const void *)f->src.addr_data32, srcip, sizeof(srcip),
×
UNCOV
132
                    td->file_ctx->compress_ipv6);
×
UNCOV
133
            PrintInetIPv6((const void *)f->dst.addr_data32, dstip, sizeof(dstip),
×
UNCOV
134
                    td->file_ctx->compress_ipv6);
×
UNCOV
135
        }
×
136

UNCOV
137
        char name[PATH_MAX];
×
UNCOV
138
        snprintf(name, sizeof(name), "%s_%u-%s_%u-%s:",
×
UNCOV
139
                srcip, f->sp, dstip, f->dp,
×
UNCOV
140
                flags & OUTPUT_STREAMING_FLAG_TOSERVER ? "ts" : "tc");
×
141

UNCOV
142
        PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset,
×
UNCOV
143
                aft->buffer->size, (uint8_t *)name,strlen(name));
×
UNCOV
144
        MemBufferWriteString(aft->buffer, "\n");
×
145

UNCOV
146
        PrintRawDataToBuffer(aft->buffer->buffer, &aft->buffer->offset,
×
UNCOV
147
                aft->buffer->size, (uint8_t *)data,data_len);
×
148

UNCOV
149
        td->file_ctx->Write((const char *)MEMBUFFER_BUFFER(aft->buffer),
×
UNCOV
150
                MEMBUFFER_OFFSET(aft->buffer), td->file_ctx);
×
UNCOV
151
    }
×
UNCOV
152
    SCReturnInt(TM_ECODE_OK);
×
UNCOV
153
}
×
154

155
int LogTcpDataLogger(ThreadVars *tv, void *thread_data, const Flow *f,
156
        const uint8_t *data, uint32_t data_len, uint64_t tx_id, uint8_t flags)
UNCOV
157
{
×
UNCOV
158
    SCEnter();
×
UNCOV
159
    LogTcpDataLogThread *aft = thread_data;
×
UNCOV
160
    LogTcpDataFileCtx *td = aft->tcpdatalog_ctx;
×
161

UNCOV
162
    if (td->dir == 1)
×
163
        LogTcpDataLoggerDir(tv, thread_data, f, data, data_len, tx_id, flags);
×
UNCOV
164
    if (td->file == 1)
×
UNCOV
165
        LogTcpDataLoggerFile(tv, thread_data, f, data, data_len, tx_id, flags);
×
166

UNCOV
167
    SCReturnInt(TM_ECODE_OK);
×
UNCOV
168
}
×
169

170
TmEcode LogTcpDataLogThreadInit(ThreadVars *t, const void *initdata, void **data)
UNCOV
171
{
×
UNCOV
172
    LogTcpDataLogThread *aft = SCCalloc(1, sizeof(LogTcpDataLogThread));
×
UNCOV
173
    if (unlikely(aft == NULL))
×
174
        return TM_ECODE_FAILED;
×
175

UNCOV
176
    if(initdata == NULL)
×
177
    {
×
178
        SCLogDebug("Error getting context. \"initdata\" argument NULL");
×
179
        SCFree(aft);
×
180
        return TM_ECODE_FAILED;
×
181
    }
×
182

UNCOV
183
    aft->buffer = MemBufferCreateNew(OUTPUT_BUFFER_SIZE);
×
UNCOV
184
    if (aft->buffer == NULL) {
×
185
        SCFree(aft);
×
186
        return TM_ECODE_FAILED;
×
187
    }
×
188

189
    /* Use the Output Context (file pointer and mutex) */
UNCOV
190
    aft->tcpdatalog_ctx= ((OutputCtx *)initdata)->data;
×
191

UNCOV
192
    *data = (void *)aft;
×
UNCOV
193
    return TM_ECODE_OK;
×
UNCOV
194
}
×
195

196
TmEcode LogTcpDataLogThreadDeinit(ThreadVars *t, void *data)
UNCOV
197
{
×
UNCOV
198
    LogTcpDataLogThread *aft = (LogTcpDataLogThread *)data;
×
UNCOV
199
    if (aft == NULL) {
×
200
        return TM_ECODE_OK;
×
201
    }
×
202

UNCOV
203
    MemBufferFree(aft->buffer);
×
204
    /* clear memory */
UNCOV
205
    memset(aft, 0, sizeof(LogTcpDataLogThread));
×
206

UNCOV
207
    SCFree(aft);
×
UNCOV
208
    return TM_ECODE_OK;
×
UNCOV
209
}
×
210

211
/** \brief Create a new http log LogFileCtx.
212
 *  \param conf Pointer to ConfNode containing this loggers configuration.
213
 *  \return NULL if failure, LogFileCtx* to the file_ctx if succesful
214
 * */
215
OutputInitResult LogTcpDataLogInitCtx(SCConfNode *conf)
UNCOV
216
{
×
UNCOV
217
    OutputInitResult result = { NULL, false };
×
UNCOV
218
    char filename[PATH_MAX] = "";
×
UNCOV
219
    char dirname[32] = "";
×
UNCOV
220
    strlcpy(filename, DEFAULT_LOG_FILENAME, sizeof(filename));
×
221

UNCOV
222
    LogFileCtx *file_ctx = LogFileNewCtx();
×
UNCOV
223
    if(file_ctx == NULL) {
×
224
        SCLogError("couldn't create new file_ctx");
×
225
        return result;
×
226
    }
×
227

UNCOV
228
    LogTcpDataFileCtx *tcpdatalog_ctx = SCCalloc(1, sizeof(LogTcpDataFileCtx));
×
UNCOV
229
    if (unlikely(tcpdatalog_ctx == NULL)) {
×
230
        LogFileFreeCtx(file_ctx);
×
231
        return result;
×
232
    }
×
233

UNCOV
234
    tcpdatalog_ctx->file_ctx = file_ctx;
×
235

UNCOV
236
    if (conf) {
×
UNCOV
237
        if (conf->name) {
×
UNCOV
238
            if (strcmp(conf->name, "tcp-data") == 0) {
×
UNCOV
239
                tcpdatalog_ctx->type = STREAMING_TCP_DATA;
×
UNCOV
240
                snprintf(filename, sizeof(filename), "%s.log", conf->name);
×
UNCOV
241
                strlcpy(dirname, "tcp", sizeof(dirname));
×
UNCOV
242
            } else if (strcmp(conf->name, "http-body-data") == 0) {
×
243
                tcpdatalog_ctx->type = STREAMING_HTTP_BODIES;
×
244
                snprintf(filename, sizeof(filename), "%s.log", conf->name);
×
245
                strlcpy(dirname, "http", sizeof(dirname));
×
246
            }
×
UNCOV
247
        }
×
248

UNCOV
249
        const char *logtype = SCConfNodeLookupChildValue(conf, "type");
×
UNCOV
250
        if (logtype == NULL)
×
251
            logtype = "file";
×
252

UNCOV
253
        if (strcmp(logtype, "file") == 0) {
×
UNCOV
254
            tcpdatalog_ctx->file = 1;
×
UNCOV
255
        } else if (strcmp(logtype, "dir") == 0) {
×
256
            tcpdatalog_ctx->dir = 1;
×
257
        } else if (strcmp(logtype, "both") == 0) {
×
258
            tcpdatalog_ctx->file = 1;
×
259
            tcpdatalog_ctx->dir = 1;
×
260
        }
×
UNCOV
261
    } else {
×
262
        tcpdatalog_ctx->file = 1;
×
263
        tcpdatalog_ctx->dir = 0;
×
264
    }
×
265

UNCOV
266
    if (tcpdatalog_ctx->file == 1) {
×
UNCOV
267
        SCLogInfo("opening logfile");
×
UNCOV
268
        if (SCConfLogOpenGeneric(conf, file_ctx, filename, 1) < 0) {
×
269
            LogFileFreeCtx(file_ctx);
×
270
            SCFree(tcpdatalog_ctx);
×
271
            return result;
×
272
        }
×
UNCOV
273
    }
×
274

UNCOV
275
    if (tcpdatalog_ctx->dir == 1) {
×
276
        tcpdatalog_ctx->log_dir = SCConfigGetLogDirectory();
×
277
        char dirfull[PATH_MAX];
×
278

279
        /* create the filename to use */
280
        snprintf(dirfull, PATH_MAX, "%s/%s", tcpdatalog_ctx->log_dir, dirname);
×
281

282
        SCLogInfo("using directory %s", dirfull);
×
283

284
        /* if mkdir fails file open will fail, so deal with errors there */
285
        (void)SCMkDir(dirfull, 0700);
×
286
    }
×
287

UNCOV
288
    OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx));
×
UNCOV
289
    if (unlikely(output_ctx == NULL)) {
×
290
        goto parsererror;
×
291
    }
×
292

UNCOV
293
    output_ctx->data = tcpdatalog_ctx;
×
UNCOV
294
    output_ctx->DeInit = LogTcpDataLogDeInitCtx;
×
295

UNCOV
296
    SCLogDebug("Streaming log output initialized");
×
UNCOV
297
    result.ctx = output_ctx;
×
UNCOV
298
    result.ok = true;
×
UNCOV
299
    return result;
×
300

301
parsererror:
×
302
    LogFileFreeCtx(file_ctx);
×
303
    SCFree(tcpdatalog_ctx);
×
304
    SCLogError("Syntax error in custom http log format string.");
×
305
    return result;
×
306

UNCOV
307
}
×
308

309
static void LogTcpDataLogDeInitCtx(OutputCtx *output_ctx)
UNCOV
310
{
×
UNCOV
311
    LogTcpDataFileCtx *tcpdatalog_ctx = (LogTcpDataFileCtx *)output_ctx->data;
×
UNCOV
312
    LogFileFreeCtx(tcpdatalog_ctx->file_ctx);
×
UNCOV
313
    SCFree(tcpdatalog_ctx);
×
UNCOV
314
    SCFree(output_ctx);
×
UNCOV
315
}
×
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