70#define MAX_SIZE_HEADER_NAME 256
71#define MAX_SIZE_HEADER_VALUE 2048
73#define LOG_HTTP_DEFAULT 0
74#define LOG_HTTP_EXTENDED 1
75#define LOG_HTTP_REQUEST 2
76#define LOG_HTTP_ARRAY 4
77#define LOG_HTTP_REQ_HEADERS 8
78#define LOG_HTTP_RES_HEADERS 16
163 {
"accept_range",
"accept-range", 0 },
165 {
"allow",
"allow", 0 },
166 {
"connection",
"connection", 0 },
167 {
"content_encoding",
"content-encoding", 0 },
168 {
"content_language",
"content-language", 0 },
169 {
"content_length",
"content-length", 0 },
170 {
"content_location",
"content-location", 0 },
171 {
"content_md5",
"content-md5", 0 },
172 {
"content_range",
"content-range", 0 },
173 {
"content_type",
"content-type", 0 },
174 {
"date",
"date", 0 },
175 {
"etag",
"etags", 0 },
176 {
"expires",
"expires", 0 },
177 {
"last_modified",
"last-modified", 0 },
178 {
"link",
"link", 0 },
179 {
"location",
"location", 0 },
180 {
"proxy_authenticate",
"proxy-authenticate", 0 },
182 {
"refresh",
"refresh", 0 },
183 {
"retry_after",
"retry-after", 0 },
184 {
"server",
"server", 0 },
185 {
"set_cookie",
"set-cookie", 0 },
186 {
"trailer",
"trailer", 0 },
187 {
"transfer_encoding",
"transfer-encoding", 0 },
188 {
"upgrade",
"upgrade", 0 },
189 {
"vary",
"vary", 0 },
190 {
"warning",
"warning", 0 },
191 {
"www_authenticate",
"www-authenticate", 0 },
197static void EveHttpLogJSONBasic(SCJsonBuilder *js, htp_tx_t *tx)
200 if (htp_tx_request_hostname(tx) != NULL) {
201 SCJbSetStringFromBytes(js,
"hostname", bstr_ptr(htp_tx_request_hostname(tx)),
202 (uint32_t)bstr_len(htp_tx_request_hostname(tx)));
211 if (htp_tx_request_port_number(tx) >= 0) {
212 SCJbSetUint(js,
"http_port", htp_tx_request_port_number(tx));
216 if (htp_tx_request_uri(tx) != NULL) {
217 SCJbSetStringFromBytes(js,
"url", bstr_ptr(htp_tx_request_uri(tx)),
218 (uint32_t)bstr_len(htp_tx_request_uri(tx)));
221 if (htp_tx_request_headers(tx) != NULL) {
223 const htp_header_t *h_user_agent = htp_tx_request_header(tx,
"user-agent");
224 if (h_user_agent != NULL) {
225 SCJbSetStringFromBytes(js,
"http_user_agent", htp_header_value_ptr(h_user_agent),
226 (uint32_t)htp_header_value_len(h_user_agent));
230 const htp_header_t *h_x_forwarded_for = htp_tx_request_header(tx,
"x-forwarded-for");
231 if (h_x_forwarded_for != NULL) {
232 SCJbSetStringFromBytes(js,
"xff", htp_header_value_ptr(h_x_forwarded_for),
233 (uint32_t)htp_header_value_len(h_x_forwarded_for));
238 if (htp_tx_response_headers(tx) != NULL) {
239 const htp_header_t *h_content_type = htp_tx_response_header(tx,
"content-type");
240 if (h_content_type != NULL) {
241 const size_t size = htp_header_value_len(h_content_type) * 2 + 1;
244 htp_header_value_len(h_content_type),
string, size);
245 char *p = strchr(
string,
';');
248 SCJbSetString(js,
"http_content_type",
string);
250 const htp_header_t *h_content_range = htp_tx_response_header(tx,
"content-range");
251 if (h_content_range != NULL) {
252 SCJbOpenObject(js,
"content_range");
253 SCJbSetStringFromBytes(js,
"raw", htp_header_value_ptr(h_content_range),
254 (uint32_t)htp_header_value_len(h_content_range));
255 HTTPContentRange crparsed;
257 if (crparsed.start >= 0)
258 SCJbSetUint(js,
"start", crparsed.start);
259 if (crparsed.end >= 0)
260 SCJbSetUint(js,
"end", crparsed.end);
261 if (crparsed.size >= 0)
262 SCJbSetUint(js,
"size", crparsed.size);
269static void EveHttpLogJSONExtended(SCJsonBuilder *js, htp_tx_t *tx)
272 const htp_header_t *h_referer = NULL;
273 if (htp_tx_request_headers(tx) != NULL) {
274 h_referer = htp_tx_request_header(tx,
"referer");
276 if (h_referer != NULL) {
277 SCJbSetStringFromBytes(js,
"http_refer", htp_header_value_ptr(h_referer),
278 (uint32_t)htp_header_value_len(h_referer));
282 if (htp_tx_request_method(tx) != NULL) {
283 SCJbSetStringFromBytes(js,
"http_method", bstr_ptr(htp_tx_request_method(tx)),
284 (uint32_t)bstr_len(htp_tx_request_method(tx)));
288 if (htp_tx_request_protocol(tx) != NULL) {
289 SCJbSetStringFromBytes(js,
"protocol", bstr_ptr(htp_tx_request_protocol(tx)),
290 (uint32_t)bstr_len(htp_tx_request_protocol(tx)));
294 const int resp = htp_tx_response_status_number(tx);
296 SCJbSetUint(js,
"status", (uint32_t)resp);
297 }
else if (htp_tx_response_status(tx) != NULL) {
298 SCJbSetStringFromBytes(js,
"status_string", bstr_ptr(htp_tx_response_status(tx)),
299 (uint32_t)bstr_len(htp_tx_response_status(tx)));
302 const htp_header_t *h_location = htp_tx_response_header(tx,
"location");
303 if (h_location != NULL) {
304 SCJbSetStringFromBytes(js,
"redirect", htp_header_value_ptr(h_location),
305 (uint32_t)htp_header_value_len(h_location));
309 SCJbSetUint(js,
"length", htp_tx_response_message_len(tx));
312static void EveHttpLogJSONHeaders(
313 SCJsonBuilder *js, uint32_t direction, htp_tx_t *tx,
LogHttpFileCtx *http_ctx)
316 : htp_tx_response_headers(tx);
319 size_t n = htp_headers_size(headers);
320 SCJsonBuilderMark mark = { 0, 0, 0 };
321 SCJbGetMark(js, &mark);
322 bool array_empty =
true;
324 for (
size_t i = 0; i < n; i++) {
325 const htp_header_t *h = htp_headers_get_index(headers, i);
326 if ((http_ctx->
flags & direction) == 0 && http_ctx->
fields != 0) {
329 if ((http_ctx->
fields & (1ULL << f)) != 0) {
349 ? htp_header_name_len(h)
351 memcpy(
name, htp_header_name_ptr(h), size_name);
352 name[size_name] =
'\0';
353 SCJbSetString(js,
"name",
name);
355 ? htp_header_value_len(h)
357 memcpy(value, htp_header_value_ptr(h), size_value);
358 value[size_value] =
'\0';
359 SCJbSetString(js,
"value", value);
363 SCJbRestoreMark(js, &mark);
370static void BodyPrintableBuffer(SCJsonBuilder *js,
HtpBody *body,
const char *key)
374 const uint8_t *body_data;
375 uint32_t body_data_len;
376 uint64_t body_offset;
379 &body_data_len, &body_offset) == 0) {
383 uint8_t printable_buf[body_data_len + 1];
386 SCJbSetString(js, key, (
char *)printable_buf);
398 BodyPrintableBuffer(js, &htud->
request_body,
"http_request_body_printable");
399 BodyPrintableBuffer(js, &htud->
response_body,
"http_response_body_printable");
404static void BodyBase64Buffer(SCJsonBuilder *js,
HtpBody *body,
const char *key)
407 const uint8_t *body_data;
408 uint32_t body_data_len;
409 uint64_t body_offset;
412 &body_data_len, &body_offset) == 0) {
416 SCJbSetBase64(js, key, body_data, body_data_len);
427 BodyBase64Buffer(js, &htud->
request_body,
"http_request_body");
428 BodyBase64Buffer(js, &htud->
response_body,
"http_response_body");
434static void EveHttpLogJSON(
JsonHttpLogThread *aft, SCJsonBuilder *js, htp_tx_t *tx, uint64_t tx_id)
437 SCJbOpenObject(js,
"http");
439 EveHttpLogJSONBasic(js, tx);
441 EveHttpLogJSONExtended(js, tx);
450static int JsonHttpLogger(
ThreadVars *
tv,
void *thread_data,
const Packet *p,
Flow *f,
void *alstate,
void *txptr, uint64_t tx_id)
454 htp_tx_t *tx = txptr;
462 SCLogDebug(
"got a HTTP request and now logging !!");
464 EveHttpLogJSON(jhl, js, tx, tx_id);
477 SCJbSetString(js,
"xff", buffer);
481 SCJbSetString(js,
"dest_ip", buffer);
483 SCJbSetString(js,
"src_ip", buffer);
502 EveHttpLogJSONBasic(js, tx);
503 EveHttpLogJSONExtended(js, tx);
511static void OutputHttpLogDeinitSub(
OutputCtx *output_ctx)
529 memset(http_ctx, 0x00,
sizeof(*http_ctx));
543 if (extended != NULL) {
550 if (all_headers != NULL) {
551 if (strncmp(all_headers,
"both", 4) == 0) {
554 }
else if (strncmp(all_headers,
"request", 7) == 0) {
556 }
else if (strncmp(all_headers,
"response", 8) == 0) {
564 SCLogWarning(
"No need for custom as dump-all-headers is already present");
572 http_ctx->
fields |= (1ULL << f);
582 if (http_ctx->
xff_cfg != NULL) {
589 output_ctx->
data = http_ctx;
590 output_ctx->
DeInit = OutputHttpLogDeinitSub;
595 result.
ctx = output_ctx;
600static TmEcode JsonHttpLogThreadInit(
ThreadVars *t,
const void *initdata,
void **data)
608 SCLogDebug(
"Error getting context for EveLogHTTP. \"initdata\" argument NULL");
648 OutputHttpLogInitSub,
ALPROTO_HTTP1, JsonHttpLogger, JsonHttpLogThreadInit,
649 JsonHttpLogThreadDeinit);
int HTPParseContentRange(const bstr *rawvalue, HTTPContentRange *range)
int HttpXFFGetIPFromTx(const Flow *f, uint64_t tx_id, HttpXFFCfg *xff_cfg, char *dstbuf, int dstbuflen)
Function to return XFF IP if any in the selected transaction. The caller needs to lock the flow.
void HttpXFFGetCfg(SCConfNode *conf, HttpXFFCfg *result)
Function to return XFF configuration from a configuration node.
struct HtpBodyChunk_ * next
void * AppLayerParserGetTx(uint8_t ipproto, AppProto alproto, void *alstate, uint64_t tx_id)
void SCAppLayerParserRegisterLogger(uint8_t ipproto, AppProto alproto)
SCConfNode * SCConfNodeLookupChild(const SCConfNode *node, const char *name)
Lookup a child configuration node by name.
int SCConfValIsTrue(const char *val)
Check if a value is true.
const char * SCConfNodeLookupChildValue(const SCConfNode *node, const char *name)
Lookup the value of a child configuration node by name.
#define FLOW_PKT_TOCLIENT
OutputJsonThreadCtx * CreateEveThreadCtx(ThreadVars *t, OutputJsonCtx *ctx)
void FreeEveThreadCtx(OutputJsonThreadCtx *ctx)
const char * config_field
struct LogHttpFileCtx_ LogHttpFileCtx
void EveHttpLogJSONBodyPrintable(SCJsonBuilder *js, Flow *f, uint64_t tx_id)
#define LOG_HTTP_EXTENDED
#define LOG_HTTP_REQ_HEADERS
struct @144 http_fields[]
bool EveHttpAddMetadata(const Flow *f, uint64_t tx_id, SCJsonBuilder *js)
void EveHttpLogJSONBodyBase64(SCJsonBuilder *js, Flow *f, uint64_t tx_id)
void JsonHttpLogRegister(void)
@ HTTP_FIELD_CONTENT_ENCODING
@ HTTP_FIELD_CONTENT_TYPE
@ HTTP_FIELD_X_BLUECOAT_VIA
@ HTTP_FIELD_X_REQUESTED_WITH
@ HTTP_FIELD_CONTENT_LOCATION
@ HTTP_FIELD_CACHE_CONTROL
@ HTTP_FIELD_X_AUTHENTICATED_USER
@ HTTP_FIELD_LAST_MODIFIED
@ HTTP_FIELD_PROXY_AUTHORIZATION
@ HTTP_FIELD_ACCEPT_RANGES
@ HTTP_FIELD_X_FLASH_VERSION
@ HTTP_FIELD_X_FORWARDED_PROTO
@ HTTP_FIELD_CONTENT_LENGTH
@ HTTP_FIELD_CONTENT_LANGUAGE
@ HTTP_FIELD_AUTHORIZATION
@ HTTP_FIELD_PROXY_AUTHENTICATE
@ HTTP_FIELD_CONTENT_RANGE
@ HTTP_FIELD_TRUE_CLIENT_IP
@ HTTP_FIELD_MAX_FORWARDS
@ HTTP_FIELD_WWW_AUTHENTICATE
@ HTTP_FIELD_ACCEPT_LANGUAGE
@ HTTP_FIELD_TRANSFER_ENCODING
@ HTTP_FIELD_ACCEPT_ENCODING
@ HTTP_FIELD_ACCEPT_CHARSET
@ HTTP_FIELD_ACCEPT_DATETIME
#define MAX_SIZE_HEADER_NAME
#define MAX_SIZE_HEADER_VALUE
struct JsonHttpLogThread_ JsonHttpLogThread
#define LOG_HTTP_RES_HEADERS
void OutputJsonBuilderBuffer(ThreadVars *tv, const Packet *p, Flow *f, SCJsonBuilder *js, OutputJsonThreadCtx *ctx)
SCJsonBuilder * CreateEveHeaderWithTxId(const Packet *p, enum SCOutputJsonLogDirection dir, const char *event_type, JsonAddrInfo *addr, uint64_t tx_id, OutputJsonCtx *eve_ctx)
void OutputRegisterTxSubModule(LoggerId id, const char *parent_name, const char *name, const char *conf_name, OutputInitSubFunc InitFunc, AppProto alproto, TxLogger TxLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit)
#define TAILQ_FOREACH(var, head, field)
OutputJsonThreadCtx * ctx
LogHttpFileCtx * httplog_ctx
HttpXFFCfg * parent_xff_cfg
void(* DeInit)(struct OutputCtx_ *)
StreamingBufferRegion region
Per thread variable structure.
void BytesToStringBuffer(const uint8_t *bytes, size_t nbytes, char *outstr, size_t outlen)
Turn byte array into string.
#define SCLogWarning(...)
Macro used to log WARNING messages.
void PrintStringsToBuffer(uint8_t *dst_buf, uint32_t *dst_buf_offset_ptr, uint32_t dst_buf_size, const uint8_t *src_buf, const uint32_t src_buf_len)
int StreamingBufferGetData(const StreamingBuffer *sb, const uint8_t **data, uint32_t *data_len, uint64_t *stream_offset)