##! Saves all input traffic in Spicy's batch format. module SpicyBatch; export { const filename = "batch.dat" &redef; } redef tcp_content_deliver_all_orig=T; redef tcp_content_deliver_all_resp=T; redef udp_content_deliver_all_orig=T; redef udp_content_deliver_all_resp=T; global output: file; global conns: set[conn_id]; global num_conns = 0; function id(c: connection) : string { local cid = c$id; local proto = "???"; if ( is_tcp_port(cid$orig_p) ) proto = "tcp"; else if ( is_udp_port(cid$orig_p) ) proto = "udp"; else if ( is_icmp_port(cid$orig_p) ) proto = "icmp"; return fmt("%s-%d-%s-%d-%s", cid$orig_h, cid$orig_p, cid$resp_h, cid$resp_p, proto); } function begin(c: connection, type_: string) { add conns[c$id]; ++num_conns; print fmt("tracking %s", c$id); local id_ = id(c); print output, fmt("@begin-conn %s %s %s-orig %s%%orig %s-resp %s%%resp\n", id_, type_, id_, c$id$resp_p, id_, c$id$resp_p); } event zeek_init() { output = open(filename); enable_raw_output(output); print output, "!spicy-batch v2\n"; } event new_connection_contents(c: connection) { begin(c, "stream"); } event tcp_contents(c: connection, is_orig: bool, seq: count, contents: string) { print output, fmt("@data %s-%s %d\n", id(c), (is_orig ? "orig" : "resp"), |contents|); print output, contents; print output, "\n"; } event content_gap(c: connection, is_orig: bool, seq: count, length: count) { print output, fmt("@gap %s-%s %d\n", id(c), (is_orig ? "orig" : "resp"), length); } event udp_contents(c: connection, is_orig: bool, contents: string) { if ( c$id !in conns ) begin(c, "block"); print output, fmt("@data %s-%s %d\n", id(c), (is_orig ? "orig" : "resp"), |contents|); print output, contents; print output, "\n"; } event connection_state_remove(c: connection) { if ( c$id !in conns ) return; print output, fmt("@end-conn %s\n", id(c)); } event zeek_done() { close(output); print fmt("recorded %d session%s total", num_conns, (num_conns > 1 ? "s" : "")); print fmt("output in %s", filename); }