mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00
277 lines
6.6 KiB
Text
277 lines
6.6 KiB
Text
# $Id:$
|
|
#
|
|
# bittorrent.bro - policy script for analyzing BitTorrent traffic
|
|
# ---------------------------------------------------------------
|
|
# This code contributed by Nadi Sarrar.
|
|
|
|
@load dpd
|
|
@load weird
|
|
|
|
module BitTorrent;
|
|
|
|
export {
|
|
# Whether to log the length of PDUs.
|
|
global log_pdu_length = T &redef;
|
|
}
|
|
|
|
redef capture_filters += { ["bittorrent"] = "tcp" };
|
|
|
|
type bt_peer_state: enum {
|
|
choked, # peer won't receive any responses to requests (initial state)
|
|
unchoked # peer may do requests
|
|
};
|
|
|
|
type bt_peer_info: record {
|
|
# Total of pure peer wire protocol overhead data (w/o pieces).
|
|
protocol_total: count &default = 0;
|
|
|
|
# State of the peer - choked or unchoked.
|
|
state: bt_peer_state &default = choked;
|
|
|
|
# Total number of seconds the peer was unchoked.
|
|
unchoked: interval &default = 0 secs;
|
|
|
|
# Time of the last received unchoke message.
|
|
time_last_unchoked: time;
|
|
};
|
|
|
|
type bt_peer_conn: record {
|
|
id: count;
|
|
orig: bt_peer_info;
|
|
resp: bt_peer_info;
|
|
weird: bool &default = F;
|
|
};
|
|
|
|
global bittorrent_log = open_log_file("bittorrent") &redef;
|
|
global bt_peer_conns : table[conn_id] of bt_peer_conn;
|
|
global peer_conn_count = 0;
|
|
|
|
function record_peer_protocol_traffic(c: connection, is_orig: bool,
|
|
protocol_len: count): count
|
|
{
|
|
if ( c$id in bt_peer_conns )
|
|
{
|
|
local pc = bt_peer_conns[c$id];
|
|
|
|
if ( is_orig )
|
|
pc$orig$protocol_total += protocol_len;
|
|
else
|
|
pc$resp$protocol_total += protocol_len;
|
|
|
|
return pc$id;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
function record_choke(pi: bt_peer_info, now: time)
|
|
{
|
|
if ( pi$state == unchoked )
|
|
{
|
|
pi$state = choked;
|
|
pi$unchoked += now - pi$time_last_unchoked;
|
|
}
|
|
}
|
|
|
|
function record_unchoke(pi: bt_peer_info, now: time)
|
|
{
|
|
if ( pi$state == choked )
|
|
{
|
|
pi$state = unchoked;
|
|
pi$time_last_unchoked = now;
|
|
}
|
|
}
|
|
|
|
function lookup_bt_peer(id: conn_id): bt_peer_conn
|
|
{
|
|
if ( id in bt_peer_conns )
|
|
return bt_peer_conns[id];
|
|
|
|
local orig: bt_peer_info;
|
|
local resp: bt_peer_info;
|
|
local pc: bt_peer_conn;
|
|
pc$orig = orig;
|
|
pc$resp = resp;
|
|
pc$id = ++peer_conn_count;
|
|
bt_peer_conns[id] = pc;
|
|
|
|
return pc;
|
|
}
|
|
|
|
function bt_log_id(id: conn_id, cid: count, tag: string, is_orig: bool): string
|
|
{
|
|
return fmt("%.6f P%d %s %s:%d %s %s:%d",
|
|
network_time(), cid, tag, id$orig_h, id$orig_p,
|
|
is_orig ? ">" : "<", id$resp_h, id$resp_p);
|
|
}
|
|
|
|
function pdu_log_len(len: count): string
|
|
{
|
|
return log_pdu_length ? fmt("[PDU-len:%d]", len) : "";
|
|
}
|
|
|
|
function log_pdu(c: connection, is_orig: bool, tag: string, len: count): count
|
|
{
|
|
local cid = record_peer_protocol_traffic(c, is_orig, len);
|
|
print bittorrent_log,
|
|
fmt("%s %s", bt_log_id(c$id, cid, tag, is_orig),
|
|
pdu_log_len(len));
|
|
|
|
return cid;
|
|
}
|
|
|
|
function log_pdu_str(c: connection, is_orig: bool, tag: string, len: count,
|
|
str: string)
|
|
{
|
|
local cid = record_peer_protocol_traffic(c, is_orig, len);
|
|
print bittorrent_log,
|
|
fmt("%s %s %s", bt_log_id(c$id, cid, tag, is_orig),
|
|
pdu_log_len(len), str);
|
|
}
|
|
|
|
function log_pdu_str_n(c: connection, is_orig: bool, tag: string, len: count,
|
|
n: count, str: string)
|
|
{
|
|
local cid = record_peer_protocol_traffic(c, is_orig, len);
|
|
print bittorrent_log,
|
|
fmt("%s %s %s", bt_log_id(c$id, cid, tag, is_orig),
|
|
pdu_log_len(n), str);
|
|
}
|
|
|
|
event bittorrent_peer_handshake(c: connection, is_orig: bool, reserved: string,
|
|
info_hash: string, peer_id: string)
|
|
{
|
|
local pc = lookup_bt_peer(c$id);
|
|
log_pdu_str(c, is_orig, "handshake", 68,
|
|
fmt("[peer_id:%s info_hash:%s reserved:%s]",
|
|
bytestring_to_hexstr(peer_id),
|
|
bytestring_to_hexstr(info_hash),
|
|
bytestring_to_hexstr(reserved)));
|
|
}
|
|
|
|
event bittorrent_peer_keep_alive(c: connection, is_orig: bool)
|
|
{
|
|
log_pdu(c, is_orig, "keep-alive", 4);
|
|
}
|
|
|
|
event bittorrent_peer_choke(c: connection, is_orig: bool)
|
|
{
|
|
local cid = log_pdu(c, is_orig, "choke", 5);
|
|
if ( cid > 0 )
|
|
{
|
|
local pc = bt_peer_conns[c$id];
|
|
record_choke(is_orig ? pc$resp : pc$orig, network_time());
|
|
}
|
|
}
|
|
|
|
event bittorrent_peer_unchoke(c: connection, is_orig: bool)
|
|
{
|
|
local cid = log_pdu(c, is_orig, "unchoke", 5);
|
|
if ( cid > 0 )
|
|
{
|
|
local pc = bt_peer_conns[c$id];
|
|
record_unchoke(is_orig ? pc$resp : pc$orig, network_time());
|
|
}
|
|
}
|
|
|
|
event bittorrent_peer_interested(c: connection, is_orig: bool)
|
|
{
|
|
log_pdu(c, is_orig, "interested", 5);
|
|
}
|
|
|
|
event bittorrent_peer_not_interested(c: connection, is_orig: bool)
|
|
{
|
|
log_pdu(c, is_orig, "not-interested", 5);
|
|
}
|
|
|
|
event bittorrent_peer_have(c: connection, is_orig: bool, piece_index: count)
|
|
{
|
|
log_pdu(c, is_orig, "have", 9);
|
|
}
|
|
|
|
event bittorrent_peer_bitfield(c: connection, is_orig: bool, bitfield: string)
|
|
{
|
|
log_pdu_str(c, is_orig, "bitfield", 5 + byte_len(bitfield),
|
|
fmt("[bitfield:%s]",
|
|
bytestring_to_hexstr(bitfield)));
|
|
}
|
|
|
|
event bittorrent_peer_request(c: connection, is_orig: bool, index: count,
|
|
begin: count, length: count)
|
|
{
|
|
log_pdu_str(c, is_orig, "request", 17,
|
|
fmt("[index:%d begin:%d length:%d]", index, begin, length));
|
|
}
|
|
|
|
event bittorrent_peer_piece(c: connection, is_orig: bool, index: count,
|
|
begin: count, piece_length: count)
|
|
{
|
|
log_pdu_str_n(c, is_orig, "piece", 13, 13 + piece_length,
|
|
fmt("[index:%d begin:%d piece_length:%d]",
|
|
index, begin, piece_length));
|
|
}
|
|
|
|
event bittorrent_peer_cancel(c: connection, is_orig: bool, index: count,
|
|
begin: count, length: count)
|
|
{
|
|
log_pdu_str(c, is_orig, "cancel", 7,
|
|
fmt("[index:%d begin:%d length:%d]",
|
|
index, begin, length));
|
|
}
|
|
|
|
event bittorrent_peer_port(c: connection, is_orig: bool, listen_port: port)
|
|
{
|
|
log_pdu_str(c, is_orig, "port", 5,
|
|
fmt("[listen_port:%s]", listen_port));
|
|
}
|
|
|
|
event bittorrent_peer_unknown(c: connection, is_orig: bool, message_id: count,
|
|
data: string)
|
|
{
|
|
log_pdu_str(c, is_orig, "<unknown>", 5 + byte_len(data),
|
|
fmt("[message_id:%d]", message_id));
|
|
}
|
|
|
|
event bittorrent_peer_weird(c: connection, is_orig: bool, msg: string)
|
|
{
|
|
local pc = lookup_bt_peer(c$id);
|
|
pc$weird = T;
|
|
|
|
print bittorrent_log,
|
|
fmt("%s [%s]", bt_log_id(c$id, pc$id, "<weird>", is_orig), msg);
|
|
|
|
event conn_weird(msg, c);
|
|
}
|
|
|
|
function log_close(c: connection, pc: bt_peer_conn, is_orig: bool)
|
|
{
|
|
local endp = is_orig ? c$orig : c$resp;
|
|
local peer_i = is_orig ? pc$orig : pc$resp;
|
|
|
|
local status =
|
|
pc$weird ?
|
|
fmt("size:%d", endp$size) :
|
|
fmt("unchoked:%.06f size_protocol:%d size_pieces:%d",
|
|
peer_i$unchoked, peer_i$protocol_total,
|
|
endp$size - peer_i$protocol_total);
|
|
|
|
print bittorrent_log,
|
|
fmt("%s [duration:%.06f %s]",
|
|
bt_log_id(c$id, pc$id, "<closed>", is_orig),
|
|
c$duration, status);
|
|
}
|
|
|
|
event connection_state_remove(c: connection)
|
|
{
|
|
if ( c$id !in bt_peer_conns )
|
|
return;
|
|
|
|
local pc = bt_peer_conns[c$id];
|
|
delete bt_peer_conns[c$id];
|
|
|
|
record_choke(pc$orig, c$start_time + c$duration);
|
|
record_choke(pc$resp, c$start_time + c$duration);
|
|
|
|
log_close(c, pc, T);
|
|
log_close(c, pc, F);
|
|
}
|