suricata
output-json-ftp.c
Go to the documentation of this file.
1/* Copyright (C) 2017-2021 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 Jeff Lucovsky <jeff@lucovsky.org>
22 *
23 * Implement JSON/eve logging app-layer FTP.
24 */
25
26#include "suricata-common.h"
27#include "detect.h"
28#include "pkt-var.h"
29#include "conf.h"
30
31#include "threads.h"
32#include "threadvars.h"
33#include "tm-threads.h"
34
35#include "util-unittest.h"
36#include "util-buffer.h"
37#include "util-debug.h"
38#include "util-mem.h"
39
40#include "output.h"
41#include "output-json.h"
42
43#include "app-layer.h"
44#include "app-layer-parser.h"
45
46#include "app-layer-ftp.h"
47#include "output-json-ftp.h"
48
49bool EveFTPLogCommand(void *vtx, SCJsonBuilder *jb)
50{
51 FTPTransaction *tx = vtx;
52 /* Preallocate array objects to simplify failure case */
53 SCJsonBuilder *js_resplist = NULL;
54 if (!TAILQ_EMPTY(&tx->response_list)) {
55 js_resplist = SCJbNewArray();
56
57 if (unlikely(js_resplist == NULL)) {
58 return false;
59 }
60 }
61 const char *command_name = NULL;
62 uint8_t command_name_length;
63 if (tx->command_descriptor.command_code != FTP_COMMAND_UNKNOWN) {
64 if (!SCGetFtpCommandInfo(tx->command_descriptor.command_index, &command_name, NULL,
65 &command_name_length)) {
66 SCLogDebug("Unable to fetch info for FTP command code %d [index %d]",
68 return false;
69 }
70 }
71 SCJbOpenObject(jb, "ftp");
72 if (command_name) {
73 SCJbSetString(jb, "command", command_name);
74 uint32_t min_length = command_name_length + 1; /* command + space */
75 if (tx->request_length > min_length) {
76 SCJbSetStringFromBytes(jb, "command_data", (const uint8_t *)tx->request + min_length,
77 tx->request_length - min_length - 1);
78 if (tx->request_truncated) {
79 JB_SET_TRUE(jb, "command_truncated");
80 } else {
81 JB_SET_FALSE(jb, "command_truncated");
82 }
83 }
84 }
85
86 bool reply_truncated = false;
87
88 if (!TAILQ_EMPTY(&tx->response_list)) {
89 int resp_cnt = 0;
90 FTPResponseWrapper *wrapper;
91 bool is_cc_array_open = false;
92 TAILQ_FOREACH (wrapper, &tx->response_list, next) {
93 /* handle multiple lines within the response, \r\n delimited */
94 if (!wrapper->response) {
95 continue;
96 }
97 FTPResponseLine *response = wrapper->response;
98
99 if (!reply_truncated && response->truncated) {
100 reply_truncated = true;
101 }
102 if (response->code_length > 0) {
103 if (!is_cc_array_open) {
104 SCJbOpenArray(jb, "completion_code");
105 is_cc_array_open = true;
106 }
107 SCJbAppendStringFromBytes(
108 jb, (const uint8_t *)response->code, (uint32_t)response->code_length);
109 }
110 if (response->length) {
111 SCJbAppendStringFromBytes(js_resplist, (const uint8_t *)response->response,
112 (uint32_t)response->length);
113 resp_cnt++;
114 }
115 }
116
117 if (is_cc_array_open) {
118 SCJbClose(jb);
119 }
120 if (resp_cnt) {
121 SCJbClose(js_resplist);
122 SCJbSetObject(jb, "reply", js_resplist);
123 }
124 SCJbFree(js_resplist);
125 }
126
127 if (tx->dyn_port) {
128 SCJbSetUint(jb, "dynamic_port", tx->dyn_port);
129 }
130
131 switch (tx->command_descriptor.command_code) {
132 case FTP_COMMAND_PORT:
133 case FTP_COMMAND_EPRT:
134 case FTP_COMMAND_PASV:
135 case FTP_COMMAND_EPSV:
136 if (tx->active) {
137 JB_SET_STRING(jb, "mode", "active");
138 } else {
139 JB_SET_STRING(jb, "mode", "passive");
140 }
141 default:
142 break;
143 }
144
145 if (tx->done) {
146 JB_SET_STRING(jb, "reply_received", "yes");
147 } else {
148 JB_SET_STRING(jb, "reply_received", "no");
149 }
150
151 if (reply_truncated) {
152 JB_SET_TRUE(jb, "reply_truncated");
153 } else {
154 JB_SET_FALSE(jb, "reply_truncated");
155 }
156 SCJbClose(jb);
157 return true;
158}
struct HtpBodyChunk_ * next
bool EveFTPLogCommand(void *vtx, SCJsonBuilder *jb)
#define TAILQ_FOREACH(var, head, field)
Definition queue.h:252
#define TAILQ_EMPTY(head)
Definition queue.h:248
#define JB_SET_TRUE(jb, key)
Definition rust.h:27
#define JB_SET_STRING(jb, key, val)
Definition rust.h:26
#define JB_SET_FALSE(jb, key)
Definition rust.h:28
FTPResponseLine * response
FtpCommandInfo command_descriptor
uint8_t * request
uint32_t request_length
uint8_t command_index
FtpRequestCommand command_code
#define SCLogDebug(...)
Definition util-debug.h:275
#define unlikely(expr)