-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
dcc-send.zeek
146 lines (122 loc) · 3.99 KB
/
dcc-send.zeek
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
##! File extraction and introspection for DCC transfers over IRC.
##!
##! There is a major problem with this script in the cluster context because
##! we might see A send B a message that a DCC connection is to be expected,
##! but that connection will actually be between B and C which could be
##! analyzed on a different worker.
##!
# Example line from IRC server indicating that the DCC SEND is about to start:
# PRIVMSG my_nick :^ADCC SEND whateverfile.zip 3640061780 1026 41709^A
@load ./main
@load base/utils/files
@load base/frameworks/cluster
@load base/protocols/conn/removal-hooks
module IRC;
export {
redef record Info += {
## DCC filename requested.
dcc_file_name: string &log &optional;
## Size of the DCC transfer as indicated by the sender.
dcc_file_size: count &log &optional;
## Sniffed mime type of the file.
dcc_mime_type: string &log &optional;
};
## IRC DCC data finalization hook. Remaining expected IRC DCC state may be
## purged when it's called.
global finalize_irc_data: Conn::RemovalHook;
}
global dcc_expected_transfers: table[addr, port] of Info &read_expire=5mins;
function dcc_relay_topic(): string &is_used
{
local rval = Cluster::rr_topic(Cluster::proxy_pool, "dcc_transfer_rr_key");
if ( rval == "" )
# No proxy is alive, so relay via manager instead.
return Cluster::manager_topic;
return rval;
}
event dcc_transfer_add(host: addr, p: port, info: Info) &is_used
{
@if ( Cluster::local_node_type() == Cluster::PROXY ||
Cluster::local_node_type() == Cluster::MANAGER )
Broker::publish(Cluster::worker_topic, dcc_transfer_add, host, p, info);
@else
dcc_expected_transfers[host, p] = info;
Analyzer::schedule_analyzer(0.0.0.0, host, p,
Analyzer::ANALYZER_IRC_DATA, 5 min);
@endif
}
event dcc_transfer_remove(host: addr, p: port) &is_used
{
@if ( Cluster::local_node_type() == Cluster::PROXY ||
Cluster::local_node_type() == Cluster::MANAGER )
Broker::publish(Cluster::worker_topic, dcc_transfer_remove, host, p);
@else
delete dcc_expected_transfers[host, p];
@endif
}
function log_dcc(f: fa_file)
{
if ( ! f?$conns ) return;
for ( cid, c in f$conns )
{
if ( [cid$resp_h, cid$resp_p] !in dcc_expected_transfers ) next;
local irc = dcc_expected_transfers[cid$resp_h, cid$resp_p];
local tmp = irc$command;
irc$command = "DCC";
Log::write(IRC::LOG, irc);
irc$command = tmp;
# Delete these values in case another DCC transfer
# happens during the IRC session.
delete irc$dcc_file_name;
delete irc$dcc_file_size;
delete irc$dcc_mime_type;
delete dcc_expected_transfers[cid$resp_h, cid$resp_p];
@if ( Cluster::is_enabled() )
Broker::publish(dcc_relay_topic(), dcc_transfer_remove,
cid$resp_h, cid$resp_p);
@endif
return;
}
}
event file_new(f: fa_file) &priority=-5
{
if ( f$source == "IRC_DATA" )
log_dcc(f);
}
event irc_dcc_message(c: connection, is_orig: bool,
prefix: string, target: string,
dcc_type: string, argument: string,
address: addr, dest_port: count, size: count) &priority=5
{
set_session(c);
if ( dcc_type != "SEND" )
return;
c$irc$dcc_file_name = argument;
c$irc$dcc_file_size = size;
local p = count_to_port(dest_port, tcp);
Analyzer::schedule_analyzer(0.0.0.0, address, p, Analyzer::ANALYZER_IRC_DATA, 5 min);
dcc_expected_transfers[address, p] = c$irc;
@if ( Cluster::is_enabled() )
Broker::publish(dcc_relay_topic(), dcc_transfer_add, address, p, c$irc);
@endif
}
event scheduled_analyzer_applied(c: connection, a: Analyzer::Tag) &priority=10
{
local id = c$id;
if ( [id$resp_h, id$resp_p] in dcc_expected_transfers )
{
add c$service["irc-dcc-data"];
Conn::register_removal_hook(c, finalize_irc_data);
}
}
hook finalize_irc_data(c: connection)
{
if ( [c$id$resp_h, c$id$resp_p] in dcc_expected_transfers )
{
delete dcc_expected_transfers[c$id$resp_h, c$id$resp_p];
@if ( Cluster::is_enabled() )
Broker::publish(dcc_relay_topic(), dcc_transfer_remove,
c$id$resp_h, c$id$resp_p);
@endif
}
}