zeek/policy/http.bro
Robin Sommer 127ed569a6 Merge commit 'b8ab0ebc22'
* commit 'b8ab0ebc22':
  Removing expire timer from http_sessions.
2011-01-19 16:38:34 -08:00

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);
# }