mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00
203 lines
4.8 KiB
Text
203 lines
4.8 KiB
Text
# $Id: http.bro 6726 2009-06-07 22:09:55Z vern $
|
|
|
|
@load notice
|
|
@load site
|
|
@load conn-id
|
|
|
|
module HTTP;
|
|
|
|
export {
|
|
redef enum Notice += {
|
|
HTTP_SensitiveURI, # sensitive URI in GET/POST/HEAD
|
|
};
|
|
}
|
|
|
|
# DPM configuration.
|
|
global http_ports = {
|
|
80/tcp, 81/tcp, 631/tcp, 1080/tcp, 3138/tcp,
|
|
8000/tcp, 8080/tcp, 8888/tcp,
|
|
};
|
|
redef dpd_config += { [ANALYZER_HTTP] = [$ports = http_ports] };
|
|
redef dpd_config += { [ANALYZER_HTTP_BINPAC] = [$ports = http_ports] };
|
|
|
|
# HTTP processing options.
|
|
export {
|
|
const process_HTTP_replies = F &redef;
|
|
const process_HTTP_data = F &redef;
|
|
const include_HTTP_abstract = F &redef;
|
|
const log_HTTP_data = F &redef;
|
|
}
|
|
|
|
type http_pending_request: record {
|
|
method: string;
|
|
URI: string;
|
|
log_it: bool;
|
|
|
|
# Whether we determined it's an attempted passwd file fetch.
|
|
passwd_req: bool;
|
|
};
|
|
|
|
# Eventually we will combine http_pending_request and http_message.
|
|
|
|
type http_message: record {
|
|
initiated: bool;
|
|
code: count; # for HTTP reply message
|
|
reason: string; # for HTTP reply message
|
|
entity_level: count; # depth of enclosing MIME entities
|
|
data_length: count; # actual length of data delivered
|
|
content_length: string; # length specified in CONTENT-LENGTH header
|
|
header_slot: count; # rewrite slot at the end of headers
|
|
abstract: string; # data abstract
|
|
skip_abstract: bool; # to skip abstract for certain content types
|
|
host: string; # host indicated in Host header
|
|
};
|
|
|
|
type http_pending_request_stream: record {
|
|
# Number of first pending request.
|
|
first_pending_request: count &default = 0;
|
|
|
|
# Total number of pending requests.
|
|
num_pending_requests: count &default = 0;
|
|
|
|
# Indexed from [first_pending_request ..
|
|
# (first_pending_request + num_pending_requests - 1)]
|
|
requests: table[count] of http_pending_request;
|
|
|
|
next_request: http_message; # the on-going request
|
|
next_reply: http_message; # the on-going reply
|
|
|
|
# len_next_reply: count; # 0 means unspecified
|
|
# len_next_request: count;
|
|
|
|
id: string; # repeated from http_session_info, for convenience
|
|
};
|
|
|
|
type http_session_info: record {
|
|
id: string;
|
|
request_stream: http_pending_request_stream;
|
|
};
|
|
|
|
const http_log = open_log_file("http") &redef;
|
|
|
|
export {
|
|
global http_sessions: table[conn_id] of http_session_info;
|
|
}
|
|
|
|
global http_session_id = 0;
|
|
|
|
function init_http_message(msg: http_message)
|
|
{
|
|
msg$initiated = F;
|
|
msg$code = 0;
|
|
msg$reason = "";
|
|
msg$entity_level = 0;
|
|
msg$data_length = 0;
|
|
msg$content_length = "";
|
|
msg$header_slot = 0;
|
|
msg$abstract = "";
|
|
msg$skip_abstract = F;
|
|
msg$host = "";
|
|
}
|
|
|
|
function new_http_message(): http_message
|
|
{
|
|
local msg: http_message;
|
|
init_http_message(msg);
|
|
return msg;
|
|
}
|
|
|
|
function new_http_session(c: connection): http_session_info
|
|
{
|
|
local session = c$id;
|
|
local new_id = ++http_session_id;
|
|
|
|
local info: http_session_info;
|
|
info$id = fmt("%%%s", prefixed_id(new_id));
|
|
|
|
local rs: http_pending_request_stream;
|
|
|
|
rs$first_pending_request = 1;
|
|
rs$num_pending_requests = 0;
|
|
rs$id = info$id;
|
|
|
|
rs$next_request = new_http_message();
|
|
rs$next_reply = new_http_message();
|
|
rs$requests = table();
|
|
|
|
info$request_stream = rs;
|
|
|
|
http_sessions[session] = info;
|
|
|
|
print http_log, fmt("%.6f %s start %s:%d > %s:%d", network_time(),
|
|
info$id, c$id$orig_h,
|
|
c$id$orig_p, c$id$resp_h, c$id$resp_p);
|
|
|
|
return info;
|
|
}
|
|
|
|
function lookup_http_session(c: connection): http_session_info
|
|
{
|
|
local s: http_session_info;
|
|
local id = c$id;
|
|
|
|
s = id in http_sessions ? http_sessions[id] : new_http_session(c);
|
|
|
|
append_addl(c, s$id);
|
|
|
|
return s;
|
|
}
|
|
|
|
function lookup_http_request_stream(c: connection): http_pending_request_stream
|
|
{
|
|
local s = lookup_http_session(c);
|
|
|
|
return s$request_stream;
|
|
}
|
|
|
|
function get_http_message(s: http_pending_request_stream, is_orig: bool): http_message
|
|
{
|
|
return is_orig ? s$next_request : s$next_reply;
|
|
}
|
|
|
|
function finish_stream(session: conn_id, id: string,
|
|
rs: http_pending_request_stream)
|
|
{
|
|
### We really want to do this in sequential order, not table order.
|
|
for ( i in rs$requests )
|
|
{
|
|
local req = rs$requests[i];
|
|
|
|
if ( req$log_it )
|
|
NOTICE([$note=HTTP_SensitiveURI,
|
|
$src=session$orig_h, $dst=session$resp_h,
|
|
$URL=req$URI,
|
|
$method=req$method,
|
|
$msg=fmt("%s:%d -> %s:%d %s: <no reply>",
|
|
session$orig_h, session$orig_p,
|
|
session$resp_h, session$resp_p, id)]);
|
|
|
|
local msg = fmt("%s %s <no reply>", req$method, req$URI);
|
|
print http_log, fmt("%.6f %s %s", network_time(), rs$id, msg);
|
|
}
|
|
}
|
|
|
|
event connection_state_remove(c: connection)
|
|
{
|
|
local id = c$id;
|
|
|
|
if ( id !in http_sessions )
|
|
return;
|
|
|
|
local s = http_sessions[id];
|
|
finish_stream(id, s$id, s$request_stream);
|
|
delete http_sessions[c$id];
|
|
}
|
|
|
|
|
|
# event http_stats(c: connection, stats: http_stats_rec)
|
|
# {
|
|
# if ( stats$num_requests == 0 && stats$num_replies == 0 )
|
|
# return;
|
|
#
|
|
# c$addl = fmt("%s (%d v%.1f v%.1f)", c$addl, stats$num_requests, stats$request_version, stats$reply_version);
|
|
# }
|