mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
Merging in 'topic/robin/cleanup-rewriter'.
Removing everything related to trace rewriting. (I wasn't too careful in ensuring that I catch everything in the scripts; Seth is working on those anyway.) (Merging by cherry-picking the corresponding commit, as the branch was accidentally made off of the logging stuff).
This commit is contained in:
parent
ec1b2b4d2a
commit
a3a075174b
70 changed files with 20 additions and 5922 deletions
|
@ -1 +1 @@
|
|||
Subproject commit 106cd9782f1f9443743b49adccae26f0ee72621c
|
||||
Subproject commit c3c7ef0dfddb0746d3762e41086ba42928e68483
|
|
@ -1 +1 @@
|
|||
Subproject commit 764b6167922662051b62d269ec0fbd14e2ce0c02
|
||||
Subproject commit 98f92eeb40281045159097764abddc428fb49bf2
|
|
@ -1 +1 @@
|
|||
Subproject commit d693ba5f14c33a97e4f149e49196281cc075d289
|
||||
Subproject commit 48d473398e577893b6c7f77d605ccdf266a2f93b
|
|
@ -1 +1 @@
|
|||
Subproject commit b26dc6dc6a9080abe7a062d0882e813acbb63248
|
||||
Subproject commit 532dcd5aa51c8b29b2d71cd37e1d7c21e33cc715
|
|
@ -1 +1 @@
|
|||
Subproject commit 409bda3a003b18c4736ef168595f20118f4d0038
|
||||
Subproject commit a2b04952ae91dcd27d5e68a42d5d26c291ecb1f5
|
|
@ -53,10 +53,8 @@
|
|||
@load http-identified-files.bro
|
||||
@load http-reply
|
||||
@load http-request
|
||||
@load http-rewriter
|
||||
@load http
|
||||
@load icmp
|
||||
@load ident-rewriter
|
||||
@load ident
|
||||
@load inactivity
|
||||
@load interconn
|
||||
|
@ -111,7 +109,6 @@
|
|||
@load site
|
||||
@load smb
|
||||
@load smtp-relay
|
||||
@load smtp-rewriter
|
||||
@load smtp
|
||||
@load snort
|
||||
@load software
|
||||
|
|
|
@ -1117,14 +1117,6 @@ type bt_tracker_headers: table[string] of string;
|
|||
|
||||
@load event.bif.bro
|
||||
|
||||
@load common-rw.bif.bro
|
||||
@load finger-rw.bif.bro
|
||||
@load ftp-rw.bif.bro
|
||||
@load ident-rw.bif.bro
|
||||
@load smtp-rw.bif.bro
|
||||
@load http-rw.bif.bro
|
||||
@load dns-rw.bif.bro
|
||||
|
||||
function subst(s: string, from: pattern, to: string): string
|
||||
{
|
||||
local p = split_all(s, from);
|
||||
|
@ -1404,34 +1396,3 @@ const skip_http_data = F &redef;
|
|||
# Whether the analysis engine parses IP packets encapsulated in
|
||||
# UDP tunnels. See also: udp_tunnel_port, policy/udp-tunnel.bro.
|
||||
const parse_udp_tunnels = F &redef;
|
||||
|
||||
# Whether a commitment is required before writing the transformed
|
||||
# trace for a connection into the dump file.
|
||||
const requires_trace_commitment = F &redef;
|
||||
|
||||
# Whether IP address anonymization is enabled.
|
||||
const anonymize_ip_addr = F &redef;
|
||||
|
||||
# Whether to omit place holder packets when rewriting.
|
||||
const omit_rewrite_place_holder = T &redef;
|
||||
|
||||
# Whether trace of various protocols is being rewritten.
|
||||
const rewriting_http_trace = F &redef;
|
||||
const rewriting_smtp_trace = F &redef;
|
||||
const rewriting_ftp_trace = F &redef;
|
||||
const rewriting_ident_trace = F &redef;
|
||||
const rewriting_finger_trace = F &redef;
|
||||
const rewriting_dns_trace = F &redef;
|
||||
const rewriting_smb_trace = F &redef;
|
||||
|
||||
# Whether we dump selected original packets to the output trace.
|
||||
const dump_selected_source_packets = F &redef;
|
||||
|
||||
# If true, we dump original packets to the output trace *if and only if*
|
||||
# the connection is not rewritten; if false, the policy script can decide
|
||||
# whether to dump a particular connection by calling dump_packets_of_connection.
|
||||
#
|
||||
# NOTE: DO NOT SET THIS TO TRUE WHEN ANONYMIZING A TRACE!
|
||||
# (TODO: this variable should be disabled when using '-A' option)
|
||||
const dump_original_packets_if_not_rewriting = F &redef;
|
||||
|
||||
|
|
|
@ -1,107 +0,0 @@
|
|||
# $Id:$
|
||||
|
||||
@load dns
|
||||
@load anon
|
||||
|
||||
module DNS;
|
||||
|
||||
redef rewriting_dns_trace = T;
|
||||
|
||||
event dns_message(c: connection, is_orig: bool, msg: dns_msg, len: count)
|
||||
{
|
||||
if ( get_conn_transport_proto(c$id) == udp )
|
||||
rewrite_dns_message(c, is_orig, msg, len);
|
||||
}
|
||||
|
||||
event dns_request(c: connection, msg: dns_msg, query: string,
|
||||
qtype: count, qclass: count)
|
||||
{
|
||||
if ( get_conn_transport_proto(c$id) == udp )
|
||||
rewrite_dns_request(c, anonymize_host(query),
|
||||
msg, qtype, qclass);
|
||||
}
|
||||
|
||||
event dns_end(c: connection, msg: dns_msg)
|
||||
{
|
||||
if ( get_conn_transport_proto(c$id) == udp )
|
||||
rewrite_dns_end(c, T);
|
||||
}
|
||||
|
||||
event dns_query_reply(c: connection, msg: dns_msg, query: string,
|
||||
qtype: count, qclass: count)
|
||||
{
|
||||
rewrite_dns_reply_question(c, msg, anonymize_host(query),
|
||||
qtype, qclass);
|
||||
}
|
||||
|
||||
event dns_A_reply(c: connection, msg: dns_msg, ans: dns_answer, a: addr)
|
||||
{
|
||||
ans$query = anonymize_host(ans$query);
|
||||
rewrite_dns_A_reply(c, msg, ans, anonymize_address(a, c$id));
|
||||
}
|
||||
|
||||
#### FIXME: ANONYMIZE!
|
||||
event dns_AAAA_reply(c: connection, msg: dns_msg, ans: dns_answer,
|
||||
a: addr, astr: string)
|
||||
{
|
||||
ans$query = anonymize_host(ans$query);
|
||||
astr = "::";
|
||||
a = anonymize_address(a, c$id);
|
||||
rewrite_dns_AAAA_reply(c, msg, ans, a, astr);
|
||||
}
|
||||
|
||||
event dns_NS_reply(c: connection, msg: dns_msg, ans: dns_answer, name: string)
|
||||
{
|
||||
ans$query = anonymize_host(ans$query);
|
||||
rewrite_dns_NS_reply(c, msg, ans, anonymize_host(name));
|
||||
}
|
||||
|
||||
event dns_CNAME_reply(c: connection, msg: dns_msg, ans: dns_answer,
|
||||
name: string)
|
||||
{
|
||||
ans$query = anonymize_host(ans$query);
|
||||
rewrite_dns_CNAME_reply(c, msg, ans, anonymize_host(name));
|
||||
}
|
||||
|
||||
event dns_MX_reply(c: connection, msg: dns_msg, ans: dns_answer,
|
||||
name: string, preference: count)
|
||||
{
|
||||
ans$query = anonymize_host(ans$query);
|
||||
rewrite_dns_MX_reply(c, msg, ans, anonymize_host(name), preference);
|
||||
}
|
||||
|
||||
event dns_PTR_reply(c: connection, msg: dns_msg, ans: dns_answer, name: string)
|
||||
{
|
||||
ans$query = anonymize_host(ans$query);
|
||||
rewrite_dns_PTR_reply(c, msg, ans, anonymize_host(name));
|
||||
}
|
||||
|
||||
event dns_SOA_reply(c: connection, msg: dns_msg, ans: dns_answer, soa: dns_soa)
|
||||
{
|
||||
soa$mname = anonymize_host(soa$mname);
|
||||
soa$rname = anonymize_host(soa$rname);
|
||||
ans$query = anonymize_host(ans$query);
|
||||
rewrite_dns_SOA_reply(c, msg, ans, soa);
|
||||
}
|
||||
|
||||
event dns_TXT_reply(c: connection, msg: dns_msg, ans: dns_answer,
|
||||
str: string)
|
||||
{
|
||||
str = anonymize_string(str);
|
||||
ans$query = anonymize_host(ans$query);
|
||||
rewrite_dns_TXT_reply(c, msg, ans, str);
|
||||
}
|
||||
|
||||
event dns_EDNS_addl (c: connection, msg: dns_msg, ans: dns_edns_additional)
|
||||
{
|
||||
rewrite_dns_EDNS_addl(c, msg, ans);
|
||||
}
|
||||
|
||||
event dns_rejected(c: connection, msg: dns_msg, query: string,
|
||||
qtype: count, qclass: count)
|
||||
{
|
||||
#### Hmmm, this is probably not right - we are going to have to look
|
||||
# at the question type to determine how to anonymize this.
|
||||
rewrite_dns_reply_question(c, msg, anonymize_host(query),
|
||||
qtype, qclass);
|
||||
}
|
|
@ -60,19 +60,6 @@ event finger_request(c: connection, full: bool, username: string, hostname: stri
|
|||
req = fmt("(%s)", req);
|
||||
|
||||
append_addl_marker(c, req, " *");
|
||||
|
||||
if ( rewriting_finger_trace )
|
||||
rewrite_finger_request(c, full,
|
||||
public_user(username) ? username : "private user",
|
||||
hostname);
|
||||
}
|
||||
|
||||
event finger_reply(c: connection, reply_line: string)
|
||||
{
|
||||
local id = c$id;
|
||||
if ( rewriting_finger_trace )
|
||||
rewrite_finger_reply(c,
|
||||
authorized_client(id$orig_h) ? "finger reply ..." : reply_line);
|
||||
}
|
||||
|
||||
function is_finger_conn(c: connection): bool
|
||||
|
@ -80,10 +67,3 @@ function is_finger_conn(c: connection): bool
|
|||
return c$id$resp_p == finger;
|
||||
}
|
||||
|
||||
event connection_state_remove(c: connection)
|
||||
{
|
||||
if ( rewriting_finger_trace && requires_trace_commitment &&
|
||||
is_finger_conn(c) )
|
||||
# Commit queued packets and all packets in future.
|
||||
rewrite_commit_trace(c, T, T);
|
||||
}
|
||||
|
|
|
@ -1,846 +0,0 @@
|
|||
# $Id: ftp-anonymizer.bro 47 2004-06-11 07:26:32Z vern $
|
||||
|
||||
@load ftp
|
||||
@load anon
|
||||
|
||||
# Definitions of constants.
|
||||
|
||||
# Check if those commands carry any argument; anonymize non-empty
|
||||
# argument.
|
||||
const ftp_cmds_with_no_arg = {
|
||||
"CDUP", "QUIT", "REIN", "PASV", "STOU",
|
||||
"ABOR", "PWD", "SYST", "NOOP",
|
||||
|
||||
"FEAT", "XPWD",
|
||||
};
|
||||
|
||||
const ftp_cmds_with_file_arg = {
|
||||
"APPE", "CWD", "DELE", "LIST", "MKD",
|
||||
"NLST", "RMD", "RNFR", "RNTO", "RETR",
|
||||
"STAT", "STOR", "SMNT",
|
||||
# FTP extensions
|
||||
"SIZE", "MDTM",
|
||||
"MLSD", "MLST",
|
||||
"XCWD",
|
||||
};
|
||||
|
||||
# For following commands, we check if the argument conforms to the
|
||||
# specification -- if so, it is safe to be left in the clear.
|
||||
const ftp_cmds_with_safe_arg = {
|
||||
"TYPE", "STRU", "MODE", "ALLO", "REST",
|
||||
"HELP",
|
||||
|
||||
"MACB", # MacBinary encoding
|
||||
};
|
||||
|
||||
# ftp_other_cmds can be redefined in site/trace-specific ways.
|
||||
const ftp_other_cmds = {
|
||||
"LPRT", "OPTS", "CLNT", "RETP",
|
||||
"EPSV", "XPWD",
|
||||
"SOCK", # old FTP command (RFC 354)
|
||||
} &redef;
|
||||
|
||||
# Below defines patterns of arguments of FTP commands
|
||||
|
||||
# The following patterns are case-insensitive
|
||||
const ftp_safe_cmd_arg_pattern =
|
||||
/TYPE (([AE]( [NTC])?)|I|(L [0-9]+))/
|
||||
| /STRU [FRP]/
|
||||
| /MODE [SBC]/
|
||||
| /ALLO [0-9]+([ \t]+R[ \t]+[0-9]+)?/
|
||||
| /REST [!-~]+/
|
||||
| /MACB (E|DISABLE|ENABLE)/
|
||||
| /SITE TRUTH ON/
|
||||
&redef;
|
||||
|
||||
# The following list includes privacy-safe [cmd, arg] pairs and can be
|
||||
# customized for particular traces
|
||||
const ftp_safe_arg_list: set[string, string] = {
|
||||
} &redef;
|
||||
|
||||
# ftp_special_cmd_args offers an even more flexible way of customizing
|
||||
# argument anonymization: for each [cmd, arg] pair in the table, the
|
||||
# corresponding value will be the anonymized argument.
|
||||
const ftp_special_cmd_args: table[string, string] of string = {
|
||||
} &redef;
|
||||
|
||||
# The following words are safe to be left in the clear as the argument
|
||||
# of a HELP command.
|
||||
const ftp_help_words = {
|
||||
"USER", "PORT", "STOR", "MSAM", "RNTO", "NLST", "MKD", "CDUP",
|
||||
"PASS", "PASV", "APPE", "MRSQ", "ABOR", "SITE", "XMKD", "XCUP",
|
||||
"ACCT", "TYPE", "MLFL", "MRCP", "DELE", "SYST", "RMD", "STOU",
|
||||
"SMNT", "STRU", "MAIL", "ALLO", "CWD", "STAT", "XRMD", "SIZE",
|
||||
"REIN", "MODE", "MSND", "REST", "XCWD", "HELP", "PWD", "MDTM",
|
||||
"QUIT", "RETR", "MSOM", "RNFR", "LIST", "NOOP", "XPWD",
|
||||
} &redef;
|
||||
|
||||
const ftp_port_pat = /[0-9]+([[:blank:]]*,[[:blank:]]*[0-9]+){5}/;
|
||||
|
||||
# Pattern for the argument of EPRT command.
|
||||
# TODO: the pattern works fot the common case but is not RFC2428-complete.
|
||||
const ftp_eprt_pat = /\|1\|[0-9]{1,3}(\.[0-9]{1,3}){3}\|[0-9]{1,5}\|/;
|
||||
|
||||
# IP addresses.
|
||||
const ftp_ip_pat = /[0-9]{1,3}(\.[0-9]{1,3}){3}/;
|
||||
|
||||
# Domain names (deficiency: domain suffices of countries).
|
||||
const ftp_domain_name_pat =
|
||||
/([\-0-9a-zA-Z]+\.)+(com|edu|net|org|gov|mil|uk|fr|nl|es|jp|it)/;
|
||||
|
||||
# File names (printable characters).
|
||||
const ftp_file_name_pat = /[[:print:]]+/;
|
||||
|
||||
# File names that can be left in the clear.
|
||||
const ftp_public_files =
|
||||
/\// | /\.\./ # "/" and ".."
|
||||
| /(\/etc\/|master\.)?(passwd|shadow|s?pwd\.db)/ # ftp_hot_files
|
||||
| /\/(etc|usr\/bin|bin|sbin|kernel)(\/)?/
|
||||
| /\.rhosts/ | /\.forward/ # ftp_hot_guest_files
|
||||
&redef;
|
||||
|
||||
const ftp_sensitive_files =
|
||||
/.*(etc\/|master\.)?(passwd|shadow|s?pwd\.db)/ # ftp_hot_files
|
||||
| /\/(etc|usr\/bin|bin|sbin|kernel)\/.*/
|
||||
| /.*\.rhosts/ | /.*\.forward/ # ftp_hot_guest_files
|
||||
&redef;
|
||||
|
||||
# Public servers.
|
||||
const ftp_public_servers: set[addr] = {} &redef;
|
||||
|
||||
# Whether we keep all file names (valid or invalid) for public servers.
|
||||
const ftp_keep_all_files_for_public_servers = F &redef;
|
||||
|
||||
# Public files.
|
||||
const ftp_known_public_files: set[addr, string] = {} &redef;
|
||||
|
||||
# Hidden file/directory.
|
||||
const ftp_hidden_file = /.*\/\.[^.\/].*/;
|
||||
const ftp_public_hidden_file = /0/ &redef;
|
||||
|
||||
# Options for file commands (LIST, NLST) that can be left in the clear.
|
||||
const ftp_known_option = /-[[:alpha:]]{1,5}[ ]*/;
|
||||
|
||||
const ftp_known_site_cmd = {
|
||||
"UMASK", "GROUP", "INDEX", "GROUPS",
|
||||
"IDLE", "GPASS", "EXEC", "CHECKMETHOD",
|
||||
"CHMOD", "NEWER", "ALIAS", "CHECKSUM",
|
||||
"HELP", "MINFO", "CDPATH",
|
||||
|
||||
"TRUTH", "UTIME",
|
||||
} &redef;
|
||||
|
||||
const ftp_sensitive_ids: set[string] = {
|
||||
"backdoor", "bomb", "diag", "gdm", "issadmin", "msql", "netfrack",
|
||||
"netphrack", "own", "r00t", "root", "ruut", "smtp", "sundiag", "sync",
|
||||
"sys", "sysadm", "sysdiag", "sysop", "sysoper", "system", "toor", "tour",
|
||||
"y0uar3ownd",
|
||||
};
|
||||
|
||||
redef anonymize_ip_addr = T;
|
||||
redef rewriting_ftp_trace = T;
|
||||
|
||||
global ftp_anon_log = open_log_file("ftp-anon") &redef;
|
||||
|
||||
# Anonymized arguments, indexed by the anonymization seed.
|
||||
global anonymized_args: table[string] of string;
|
||||
|
||||
# Arguments left in the clear, indexed by the argument and the context.
|
||||
global ftp_arg_left_in_the_clear: set[string, string];
|
||||
|
||||
# Valid files on public servers.
|
||||
global ftp_valid_public_files: set[addr, string];
|
||||
|
||||
type ftp_cmd_arg_anon_result: record {
|
||||
anonymized: bool;
|
||||
cmd: string;
|
||||
arg: string;
|
||||
};
|
||||
|
||||
|
||||
# Whether anonymize_trace_specific_cmd_arg is defined:
|
||||
const trace_specific_cmd_arg_anonymization = F &redef;
|
||||
|
||||
# This function is to be defined in a trace-specific script. By
|
||||
# default, use ftp-anonymizer-trace.bro.
|
||||
|
||||
global anonymize_trace_specific_cmd_arg:
|
||||
function(session: ftp_session_info, cmd: string, arg: string):
|
||||
ftp_cmd_arg_anon_result;
|
||||
|
||||
|
||||
# Anonymize FTP replies by message patterns.
|
||||
const process_ftp_reply_by_message_pattern = F &redef;
|
||||
global anonymize_ftp_reply_by_msg_pattern:
|
||||
function(code: count, act_msg: string,
|
||||
cmd_arg: ftp_cmd_arg, session: ftp_session_info): string;
|
||||
|
||||
|
||||
# Anonymize an argument *completely* with a hash value of the string,
|
||||
# and log the anonymization.
|
||||
function anonymize_arg(typ: string, session: ftp_session_info, cmd: string, arg: string, seed: string): string
|
||||
{
|
||||
if ( arg == "" )
|
||||
return ""; # an empty argument is safe
|
||||
|
||||
local arg_seed = string_cat(typ, seed, arg);
|
||||
|
||||
if ( arg_seed in anonymized_args )
|
||||
return anonymized_args[arg_seed];
|
||||
|
||||
local a = anonymize_string(arg_seed);
|
||||
anonymized_args[arg_seed] = a;
|
||||
|
||||
print ftp_anon_log,
|
||||
fmt("anonymize_arg: (%s) {%s} %s \"%s\" to \"%s\" in [%s]",
|
||||
typ, seed, cmd,
|
||||
to_string_literal(arg), to_string_literal(a),
|
||||
id_string(session$connection_id));
|
||||
return a;
|
||||
}
|
||||
|
||||
# This function is called whenever an argument is to be left in the
|
||||
# clear. It logs the action if it hasn't occurred before.
|
||||
function leave_in_the_clear(msg: string, session: ftp_session_info,
|
||||
arg: string, context: string): string
|
||||
{
|
||||
if ( [arg, context] !in ftp_arg_left_in_the_clear )
|
||||
{
|
||||
add ftp_arg_left_in_the_clear[arg, context];
|
||||
print ftp_anon_log, fmt("leave_in_the_clear: (%s) \"%s\" [%s] in [%s]",
|
||||
msg, to_string_literal(arg), context,
|
||||
id_string(session$connection_id));
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
|
||||
|
||||
# Sometimes the argument of a file command contains an option string
|
||||
# before the file name, such as in 'LIST -l /xyz/', the following
|
||||
# function identifies such option strings and separate the argument
|
||||
# accordingly.
|
||||
|
||||
type separate_option_str_result: record {
|
||||
opt_str: string;
|
||||
file_name: string;
|
||||
};
|
||||
|
||||
function separate_option_str(file_name: string): separate_option_str_result
|
||||
{
|
||||
local ret: separate_option_str_result;
|
||||
if ( file_name == /-[[:alpha:]]+( .*)?/ )
|
||||
{
|
||||
local parts = split_all(file_name, /-[[:alpha:]]+[ ]*/);
|
||||
ret$opt_str = string_cat(parts[1], parts[2]);
|
||||
parts[1] = ""; parts[2] = "";
|
||||
ret$file_name = cat_string_array(parts);
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
return [$opt_str = "", $file_name = file_name];
|
||||
}
|
||||
|
||||
|
||||
# Anonymize a user id
|
||||
type login_status_type: enum {
|
||||
LOGIN_PENDING,
|
||||
LOGIN_SUCCESSFUL,
|
||||
LOGIN_FAILED,
|
||||
LOGIN_UNKNOWN,
|
||||
};
|
||||
|
||||
function anonymize_user_id(session: ftp_session_info, id: string, login_status: login_status_type, msg: string): string
|
||||
{
|
||||
if ( id in ftp_guest_ids )
|
||||
{
|
||||
leave_in_the_clear("guest_id", session, id, msg);
|
||||
return id;
|
||||
}
|
||||
|
||||
else if ( id in ftp_sensitive_ids && login_status == LOGIN_FAILED )
|
||||
{
|
||||
leave_in_the_clear("sensitive_id", session, id, msg);
|
||||
return id;
|
||||
}
|
||||
|
||||
else
|
||||
return anonymize_arg("user_name", session, "USER", id, cat(session$connection_id$resp_h, login_status));
|
||||
}
|
||||
|
||||
# Anonymize a file name argument.
|
||||
function anonymize_file_name_arg(session: ftp_session_info, cmd: string, arg: string, valid_file_name: bool): string
|
||||
{
|
||||
local file_name = arg;
|
||||
local opt_str = "";
|
||||
if ( cmd == /LIST|NLST/ )
|
||||
{
|
||||
# Separate the option from file name if there is one
|
||||
|
||||
local ret = separate_option_str(file_name);
|
||||
if ( ret$opt_str != "" )
|
||||
{
|
||||
opt_str = ret$opt_str;
|
||||
|
||||
# Shall we anonymize the option string?
|
||||
if ( opt_str != ftp_known_option )
|
||||
{
|
||||
# Anonymize the option conservatively
|
||||
print ftp_anon_log, fmt("option_anonymized: \"%s\" from (%s %s)",
|
||||
to_string_literal(opt_str), cmd, file_name);
|
||||
opt_str = "-<option>";
|
||||
}
|
||||
else
|
||||
# Leave in the clear
|
||||
print ftp_anon_log, fmt("option_left_in_the_clear: \"%s\" from (%s %s)",
|
||||
to_string_literal(opt_str), cmd, file_name);
|
||||
|
||||
file_name = ret$file_name;
|
||||
}
|
||||
}
|
||||
|
||||
if ( file_name == "" )
|
||||
return opt_str;
|
||||
|
||||
if ( file_name != ftp_file_name_pat )
|
||||
{
|
||||
# Log special file names (e.g. those containing
|
||||
# control characters) for manual inspection -- such
|
||||
# file names are rare and may present problems in
|
||||
# reply anonymization.
|
||||
|
||||
print ftp_anon_log, fmt("unrecognized_file_name: \"%s\" (%s) [%s]",
|
||||
to_string_literal(file_name), cmd, id_string(session$connection_id));
|
||||
}
|
||||
|
||||
|
||||
if ( strstr(file_name, " ") > 0 )
|
||||
{
|
||||
# Log file names that contain spaces (for debugging only)
|
||||
|
||||
print ftp_anon_log, fmt("space_in_file_name: \"%s\" (%s) [%s]",
|
||||
to_string_literal(file_name), cmd, id_string(session$connection_id));
|
||||
}
|
||||
|
||||
# Compute the absolute and clean (without '..' and duplicate
|
||||
# '/') path
|
||||
local abs_path = absolute_path(session, file_name);
|
||||
local resp_h = session$connection_id$resp_h;
|
||||
local known_public_file =
|
||||
[resp_h, abs_path] in ftp_known_public_files ||
|
||||
[resp_h, abs_path] in ftp_valid_public_files;
|
||||
|
||||
if ( file_name == ftp_public_files || abs_path == ftp_public_files )
|
||||
{
|
||||
leave_in_the_clear("public_path_name", session,
|
||||
arg, fmt("(%s %s) %s", cmd, file_name, abs_path));
|
||||
}
|
||||
|
||||
else if ( resp_h in ftp_public_servers &&
|
||||
(abs_path != ftp_hidden_file ||
|
||||
abs_path == ftp_public_hidden_file) &&
|
||||
(ftp_keep_all_files_for_public_servers || valid_file_name ||
|
||||
known_public_file) )
|
||||
{
|
||||
if ( valid_file_name && ! known_public_file )
|
||||
{
|
||||
add ftp_valid_public_files[resp_h, abs_path];
|
||||
print ftp_anon_log,
|
||||
fmt("valid_public_file: [%s, \"%s\"]",
|
||||
resp_h, to_string_literal(abs_path));
|
||||
}
|
||||
|
||||
leave_in_the_clear("file_on_public_server", session, arg,
|
||||
fmt("%s %s:%s", cmd, session$connection_id$resp_h, abs_path));
|
||||
}
|
||||
else
|
||||
{
|
||||
local anon_type: string;
|
||||
|
||||
if ( file_name == ftp_sensitive_files ||
|
||||
abs_path == ftp_sensitive_files )
|
||||
anon_type = "sensitive_path_name";
|
||||
|
||||
else if ( abs_path == ftp_hidden_file )
|
||||
anon_type = "hidden_path_name";
|
||||
|
||||
else if ( resp_h in ftp_public_servers )
|
||||
anon_type = "invalid_public_file";
|
||||
|
||||
else
|
||||
anon_type = "path_name";
|
||||
|
||||
file_name = anonymize_arg(anon_type, session, cmd, abs_path, cat("file:", session$connection_id$resp_h));
|
||||
}
|
||||
|
||||
# concatenate the option string with the file_name
|
||||
return string_cat(opt_str, file_name);
|
||||
}
|
||||
|
||||
|
||||
# The argument is presumably privacy-safe, but we should not assume
|
||||
# that it is the case. Instead, we check if the argument is legal and
|
||||
# thus privacy-free.
|
||||
function check_safe_arg(session: ftp_session_info, cmd: string,
|
||||
arg: string): string
|
||||
{
|
||||
if ( cmd == "HELP" )
|
||||
return ( arg in ftp_help_words ) ?
|
||||
leave_in_the_clear("known_help_word", session,
|
||||
arg,
|
||||
fmt("%s %s", cmd, arg))
|
||||
: anonymize_arg("unknown_help_string", session, cmd, arg, cmd);
|
||||
|
||||
else
|
||||
# Note that we have already checked the (cmd, arg)
|
||||
# against ftp_safe_cmd_arg_pattern. So the argument
|
||||
# here must have an unrecognized pattern and should be
|
||||
# anonymized.
|
||||
return anonymize_arg("illegal_argument", session, cmd, arg, cmd);
|
||||
}
|
||||
|
||||
function check_site_arg(session: ftp_session_info, cmd: string,
|
||||
arg: string): string
|
||||
{
|
||||
local site_cmd_arg = split1(arg, /[ \t]*/);
|
||||
|
||||
local site_cmd = site_cmd_arg[1];
|
||||
local site_cmd_upper = to_upper(site_cmd);
|
||||
|
||||
if ( site_cmd_upper in ftp_known_site_cmd )
|
||||
{
|
||||
if ( length(site_cmd_arg) > 1 )
|
||||
{
|
||||
# If the there is an argument after "SITE <cmd>"
|
||||
local site_arg = site_cmd_arg[2];
|
||||
site_arg =
|
||||
anonymize_arg(fmt("arg_of_site_%s", site_cmd),
|
||||
session, cmd, site_arg, cmd);
|
||||
return string_cat(site_cmd, " ", site_arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
return leave_in_the_clear("known_site_command", session,
|
||||
site_cmd,
|
||||
fmt("%s %s", cmd, arg));
|
||||
}
|
||||
}
|
||||
else
|
||||
return anonymize_arg("site_arg", session, cmd, arg, cmd);
|
||||
}
|
||||
|
||||
function anonymize_port_arg(session: ftp_session_info, cmd: string,
|
||||
arg: string): string
|
||||
{
|
||||
local data = parse_ftp_port(arg);
|
||||
|
||||
if ( data$valid )
|
||||
{
|
||||
local a: addr;
|
||||
# Anonymize the address part
|
||||
a = anonymize_address(data$h, session$connection_id);
|
||||
return fmt_ftp_port(a, data$p);
|
||||
}
|
||||
else
|
||||
return anonymize_arg("unrecognized_ftp_port", session, cmd, arg, "");
|
||||
}
|
||||
|
||||
# EPRT is an extension to the PORT command
|
||||
function anonymize_eprt_arg(session: ftp_session_info, cmd: string,
|
||||
arg: string): string
|
||||
{
|
||||
if ( arg != ftp_eprt_pat )
|
||||
return anonymize_arg("unrecognized_EPRT_arg", session, cmd, arg, "");
|
||||
|
||||
local parts = split(arg, /\|/);
|
||||
# Anonymize the address part
|
||||
local a = parse_dotted_addr(parts[3]);
|
||||
a = anonymize_address(a, session$connection_id);
|
||||
return fmt("|%s|%s|%s|", parts[2], a, parts[4]);
|
||||
}
|
||||
|
||||
# Anonymize arguments of commands that we do not understand
|
||||
function anonymize_other_arg(session: ftp_session_info, cmd: string, arg: string): string
|
||||
{
|
||||
local anon: string;
|
||||
|
||||
# Try to guess what the arg is
|
||||
|
||||
local data = parse_ftp_port(arg);
|
||||
if ( arg == ftp_port_pat && data$valid )
|
||||
# Here we do not check whether data$h == session$connection_id$orig_h
|
||||
# because sometimes it's not the case, but we will try to anonymize it anyway.
|
||||
{
|
||||
anon = anonymize_port_arg(session, cmd, arg);
|
||||
print ftp_anon_log, fmt("anonymize_arg: (%s) {} %s \"%s\" to \"%s\" in [%s]",
|
||||
"port arg of non-port command",
|
||||
cmd, arg, anon, id_string(session$connection_id));
|
||||
}
|
||||
|
||||
else if ( arg == ftp_ip_pat )
|
||||
{
|
||||
local a = parse_dotted_addr(arg);
|
||||
a = anonymize_address(a, session$connection_id);
|
||||
anon = cat(a);
|
||||
}
|
||||
|
||||
else if ( arg == ftp_domain_name_pat )
|
||||
{
|
||||
anon = "<domain name>";
|
||||
}
|
||||
|
||||
else if ( arg == "." )
|
||||
{
|
||||
anon = arg;
|
||||
leave_in_the_clear(".", session, arg, fmt("%s %s", cmd, arg));
|
||||
}
|
||||
|
||||
else
|
||||
# Anonymize by default.
|
||||
anon = anonymize_arg("cannot_understand_arg",
|
||||
session, cmd, arg, cmd);
|
||||
|
||||
return anon;
|
||||
}
|
||||
|
||||
# Anonymize the command and argument, and put the results in
|
||||
# cmd_arg$anonymized_{cmd, arg}
|
||||
function anonymize_ftp_cmd_arg(session: ftp_session_info,
|
||||
cmd_arg: ftp_cmd_arg)
|
||||
{
|
||||
local cmd = cmd_arg$cmd;
|
||||
local arg = cmd_arg$arg;
|
||||
local anon : string;
|
||||
|
||||
cmd_arg$anonymized_cmd = cmd;
|
||||
|
||||
local ret: ftp_cmd_arg_anon_result;
|
||||
|
||||
if ( trace_specific_cmd_arg_anonymization )
|
||||
ret = anonymize_trace_specific_cmd_arg(session, cmd, arg);
|
||||
else
|
||||
ret$anonymized = F;
|
||||
|
||||
if ( ret$anonymized )
|
||||
{
|
||||
# If the trace-specific anonymization applies to the cmd_arg
|
||||
print ftp_anon_log, fmt("anonymize_arg: (%s) \"%s %s\" to \"%s %s\" in [%s]",
|
||||
"trace-specific",
|
||||
cmd, to_string_literal(arg),
|
||||
ret$cmd, to_string_literal(ret$arg),
|
||||
id_string(session$connection_id));
|
||||
cmd_arg$anonymized_cmd = ret$cmd;
|
||||
anon = ret$arg;
|
||||
}
|
||||
|
||||
else if ( [cmd, arg] in ftp_special_cmd_args )
|
||||
{
|
||||
anon = ftp_special_cmd_args[cmd, arg];
|
||||
print ftp_anon_log, fmt("anonymize_arg: (%s) [%s] \"%s\" to \"%s\" in [%s]",
|
||||
"special_arg_transformation",
|
||||
cmd,
|
||||
to_string_literal(arg),
|
||||
to_string_literal(anon),
|
||||
id_string(session$connection_id));
|
||||
}
|
||||
|
||||
else if ( to_upper(string_cat(cmd, " ", arg)) == ftp_safe_cmd_arg_pattern ||
|
||||
[cmd, arg] in ftp_safe_arg_list )
|
||||
{
|
||||
leave_in_the_clear("safe_arg", session, arg, fmt("%s %s", cmd, arg));
|
||||
anon = arg;
|
||||
}
|
||||
|
||||
else if ( cmd == "USER" || cmd == "ACCT" )
|
||||
anon = (arg in ftp_guest_ids) ?
|
||||
arg : anonymize_user_id(session, arg, LOGIN_PENDING, "");
|
||||
|
||||
else if ( cmd == "PASS" )
|
||||
anon = "<password>";
|
||||
|
||||
else if ( cmd in ftp_cmds_with_no_arg )
|
||||
anon = (arg == "") ?
|
||||
"" :
|
||||
anonymize_arg("should_have_been_empty",
|
||||
session, cmd, arg, cmd);
|
||||
|
||||
else if ( cmd in ftp_cmds_with_file_arg )
|
||||
{
|
||||
if ( session$user in ftp_guest_ids )
|
||||
anon = ( arg == "" ) ? "" : anonymize_file_name_arg(session, cmd, arg, F);
|
||||
else
|
||||
anon = "<path>";
|
||||
}
|
||||
|
||||
else if ( cmd in ftp_cmds_with_safe_arg )
|
||||
anon = check_safe_arg(session, cmd, arg);
|
||||
|
||||
else if ( cmd == "SITE" )
|
||||
anon = check_site_arg(session, cmd, arg);
|
||||
|
||||
else if ( cmd == "PORT" )
|
||||
anon = anonymize_port_arg(session, cmd, arg);
|
||||
|
||||
else if ( cmd == "EPRT" )
|
||||
anon = anonymize_eprt_arg(session, cmd, arg);
|
||||
|
||||
else if ( cmd == "AUTH" )
|
||||
anon = anonymize_arg("rejected_auth_arg", session, cmd, arg, cmd);
|
||||
|
||||
else
|
||||
{
|
||||
if ( cmd == /<.*>/ )
|
||||
cmd_arg$anonymized_cmd = "";
|
||||
|
||||
else if ( cmd !in ftp_other_cmds )
|
||||
{
|
||||
local a = anonymize_string(string_cat("cmd:", cmd));
|
||||
print ftp_anon_log, fmt("anonymize_cmd: (%s) \"%s\" [%s] to \"%s\" in [%s]",
|
||||
"unrecognized command", to_string_literal(cmd),
|
||||
to_string_literal(arg), a,
|
||||
id_string(session$connection_id));
|
||||
cmd_arg$anonymized_cmd = a;
|
||||
}
|
||||
|
||||
anon = anonymize_other_arg(session, cmd, arg);
|
||||
}
|
||||
|
||||
if ( cmd == "USER" )
|
||||
session$anonymized_user = anon;
|
||||
|
||||
cmd_arg$anonymized_arg = anon;
|
||||
}
|
||||
|
||||
|
||||
# We delay anonymization of certain requests till we see the reply:
|
||||
# when the argument of a USER command is a sensitive user ID, we
|
||||
# anonymize the ID if the login is successful and leave the ID in the
|
||||
# clear otherwise.
|
||||
#
|
||||
# The function returns T if the decision should be delayed.
|
||||
|
||||
function delay_rewriting_request(session: ftp_session_info, cmd: string,
|
||||
arg: string): bool
|
||||
{
|
||||
return (cmd == "USER" && arg !in ftp_guest_ids) ||
|
||||
(cmd == "AUTH") ||
|
||||
(cmd in ftp_cmds_with_file_arg &&
|
||||
session$connection_id$resp_h in ftp_public_servers);
|
||||
}
|
||||
|
||||
function ftp_request_rewrite(c: connection, session: ftp_session_info,
|
||||
cmd_arg: ftp_cmd_arg): bool
|
||||
{
|
||||
local cmd = cmd_arg$cmd;
|
||||
local arg = cmd_arg$arg;
|
||||
|
||||
if ( delay_rewriting_request(session, cmd, arg) )
|
||||
{
|
||||
cmd_arg$rewrite_slot = reserve_rewrite_slot(c);
|
||||
session$delayed_request_rewrite[cmd_arg$seq] = cmd_arg;
|
||||
return F;
|
||||
}
|
||||
else
|
||||
{
|
||||
anonymize_ftp_cmd_arg(session, cmd_arg);
|
||||
rewrite_ftp_request(c, cmd_arg$anonymized_cmd,
|
||||
cmd_arg$anonymized_arg);
|
||||
return T;
|
||||
}
|
||||
}
|
||||
|
||||
function do_rewrite_delayed_ftp_request(c: connection, delayed: ftp_cmd_arg)
|
||||
{
|
||||
seek_rewrite_slot(c, delayed$rewrite_slot);
|
||||
|
||||
rewrite_ftp_request(c, delayed$cmd == /<.*>/ ? "" : delayed$cmd,
|
||||
delayed$anonymized_arg);
|
||||
release_rewrite_slot(c, delayed$rewrite_slot);
|
||||
|
||||
delayed$rewrite_slot = 0;
|
||||
}
|
||||
|
||||
function delayed_ftp_request_rewrite(c: connection, session: ftp_session_info,
|
||||
delayed: ftp_cmd_arg,
|
||||
current: ftp_cmd_arg,
|
||||
reply_code: count)
|
||||
{
|
||||
local cmd = delayed$cmd;
|
||||
local arg = delayed$arg;
|
||||
|
||||
if ( cmd == "USER" )
|
||||
{
|
||||
delayed$anonymized_cmd = cmd;
|
||||
|
||||
local login_status: login_status_type;
|
||||
|
||||
if ( reply_code == 0 )
|
||||
login_status = LOGIN_UNKNOWN;
|
||||
|
||||
else if ( delayed$seq == current$seq ||
|
||||
current$cmd == "PASS" ||
|
||||
current$cmd == "ACCT" )
|
||||
{
|
||||
if ( reply_code >= 330 && reply_code < 340 ) # need PASS/ACCT
|
||||
login_status = LOGIN_PENDING; # wait to see outcome of PASS
|
||||
|
||||
else if ( reply_code >= 400 && reply_code < 600 )
|
||||
login_status = LOGIN_FAILED;
|
||||
|
||||
else if ( reply_code >= 230 && reply_code < 240 )
|
||||
login_status = LOGIN_SUCCESSFUL;
|
||||
|
||||
else
|
||||
login_status = LOGIN_UNKNOWN;
|
||||
}
|
||||
|
||||
else if ( current$cmd == "USER" ) # another login attempt
|
||||
login_status = LOGIN_FAILED;
|
||||
|
||||
else if ( reply_code == 230 )
|
||||
login_status = LOGIN_SUCCESSFUL;
|
||||
|
||||
else if ( reply_code == 530 )
|
||||
login_status = LOGIN_FAILED;
|
||||
|
||||
else
|
||||
login_status = LOGIN_UNKNOWN;
|
||||
|
||||
if ( login_status != LOGIN_PENDING )
|
||||
{
|
||||
delayed$anonymized_arg =
|
||||
anonymize_user_id(session, arg, login_status,
|
||||
fmt("(%s %s) %s %s -> %d", cmd, arg, current$cmd, current$arg, reply_code));
|
||||
do_rewrite_delayed_ftp_request(c, delayed);
|
||||
}
|
||||
}
|
||||
|
||||
else if ( cmd == "AUTH" )
|
||||
{
|
||||
delayed$anonymized_cmd = cmd;
|
||||
|
||||
if ( reply_code >= 500 && reply_code < 600 )
|
||||
# if AUTH fails
|
||||
{
|
||||
anonymize_ftp_cmd_arg(session, delayed);
|
||||
do_rewrite_delayed_ftp_request(c, delayed);
|
||||
}
|
||||
|
||||
else if ( reply_code >= 300 && reply_code < 400 )
|
||||
;
|
||||
else # otherwise always anonymize the argument
|
||||
{
|
||||
delayed$anonymized_arg = "<auth_mechanism>";
|
||||
do_rewrite_delayed_ftp_request(c, delayed);
|
||||
}
|
||||
}
|
||||
|
||||
else if ( cmd in ftp_cmds_with_file_arg && session$connection_id$resp_h in ftp_public_servers )
|
||||
{
|
||||
delayed$anonymized_cmd = cmd;
|
||||
|
||||
# The argument represents a valid file name on a
|
||||
# public server only if the operation is successful.
|
||||
delayed$anonymized_arg =
|
||||
anonymize_file_name_arg(session, cmd, arg,
|
||||
(cmd != "LIST" && cmd != "NLST" &&
|
||||
reply_code >= 100 && reply_code < 300));
|
||||
do_rewrite_delayed_ftp_request(c, delayed);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
print ftp_anon_log, "ERROR! unrecognizable delayed ftp request rewrite";
|
||||
|
||||
anonymize_ftp_cmd_arg(session, delayed);
|
||||
do_rewrite_delayed_ftp_request(c, delayed);
|
||||
}
|
||||
}
|
||||
|
||||
function process_delayed_rewrites(c: connection, session: ftp_session_info, reply_code: count, cmd_arg: ftp_cmd_arg)
|
||||
{
|
||||
local written: table[count] of ftp_cmd_arg;
|
||||
|
||||
for ( s in session$delayed_request_rewrite )
|
||||
{
|
||||
local ca = session$delayed_request_rewrite[s];
|
||||
delayed_ftp_request_rewrite(c, session, ca, cmd_arg,
|
||||
reply_code);
|
||||
|
||||
if ( ca$rewrite_slot == 0 )
|
||||
written[ca$seq] = ca;
|
||||
}
|
||||
|
||||
for ( s in written )
|
||||
delete session$delayed_request_rewrite[s];
|
||||
}
|
||||
|
||||
function ftp_reply_rewrite(c: connection, session: ftp_session_info,
|
||||
code: count, msg: string, cont_resp: bool,
|
||||
cmd_arg: ftp_cmd_arg)
|
||||
{
|
||||
local actual_code = session$reply_code;
|
||||
local xyz = parse_ftp_reply_code(actual_code);
|
||||
|
||||
process_delayed_rewrites(c, session, actual_code, cmd_arg);
|
||||
|
||||
if ( process_ftp_reply_by_message_pattern )
|
||||
{
|
||||
# See *ftp-reply-pattern.bro* for reply anonymization
|
||||
local anon_msg = anonymize_ftp_reply_by_msg_pattern(actual_code, msg,
|
||||
cmd_arg, session);
|
||||
rewrite_ftp_reply(c, code, anon_msg, cont_resp);
|
||||
}
|
||||
else
|
||||
rewrite_ftp_reply(c, code, "<ftp reply message stripped out>", cont_resp);
|
||||
}
|
||||
|
||||
|
||||
const eliminate_scans = F &redef;
|
||||
const port_scanners: set[addr] &redef;
|
||||
global eliminate_scan_for_host: table[addr] of bool;
|
||||
|
||||
function eliminate_scan(id: conn_id): bool
|
||||
{
|
||||
local h = id$resp_h;
|
||||
|
||||
if ( h !in eliminate_scan_for_host )
|
||||
{
|
||||
# if the hash string starts with [0-7], i.e. with probability of 50%
|
||||
eliminate_scan_for_host[h] = (/^[0-7]/ in md5_hmac(h));
|
||||
if ( eliminate_scan_for_host[h] )
|
||||
print ftp_anon_log, fmt("eliminate_scans_for_host %s", h);
|
||||
}
|
||||
|
||||
return eliminate_scan_for_host[h];
|
||||
}
|
||||
|
||||
redef call_ftp_connection_remove = T;
|
||||
|
||||
function ftp_connection_remove(c: connection)
|
||||
{
|
||||
if ( c$id in ftp_sessions )
|
||||
{
|
||||
local session = ftp_sessions[c$id];
|
||||
process_delayed_rewrites(c, session, 0, find_ftp_pending_cmd(session$pending_requests, 0, ""));
|
||||
}
|
||||
|
||||
if ( eliminate_scans && ! requires_trace_commitment )
|
||||
print ftp_anon_log,
|
||||
fmt("ERROR: requires_trace_commitment must be set to true in order to allow scan elimination");
|
||||
|
||||
if ( requires_trace_commitment )
|
||||
{
|
||||
local id = c$id;
|
||||
local eliminate = F;
|
||||
|
||||
if ( eliminate_scans &&
|
||||
# To check if the connection is part of a port scan
|
||||
(id !in ftp_sessions ||
|
||||
ftp_sessions[id]$num_requests == 0 ||
|
||||
id$orig_h in port_scanners) &&
|
||||
eliminate_scan(id) )
|
||||
rewrite_commit_trace(c, F, T);
|
||||
else
|
||||
rewrite_commit_trace(c, T, T);
|
||||
}
|
||||
}
|
|
@ -348,12 +348,6 @@ event ftp_excessive_filename(session: ftp_session_info,
|
|||
session$log_it = T;
|
||||
}
|
||||
|
||||
global ftp_request_rewrite: function(c: connection, session: ftp_session_info,
|
||||
cmd_arg: ftp_cmd_arg);
|
||||
global ftp_reply_rewrite: function(c: connection, session: ftp_session_info,
|
||||
code: count, msg: string,
|
||||
cont_resp: bool, cmd_arg: ftp_cmd_arg);
|
||||
|
||||
# Returns true if the given string is at least 25% composed of 8-bit
|
||||
# characters.
|
||||
function is_string_binary(s: string): bool
|
||||
|
@ -518,9 +512,6 @@ event ftp_request(c: connection, command: string, arg: string)
|
|||
}
|
||||
}
|
||||
|
||||
if ( rewriting_ftp_trace )
|
||||
ftp_request_rewrite(c, session, cmd_arg);
|
||||
|
||||
if ( command in ftp_all_cmds )
|
||||
{
|
||||
if ( command in ftp_untested_cmds )
|
||||
|
@ -761,11 +752,6 @@ event ftp_reply(c: connection, code: count, msg: string, cont_resp: bool)
|
|||
do_ftp_reply(c, session, code, msg, cmd_arg$cmd, cmd_arg$arg);
|
||||
}
|
||||
|
||||
if ( rewriting_ftp_trace )
|
||||
{
|
||||
ftp_reply_rewrite(c, session, code, msg, cont_resp, cmd_arg);
|
||||
}
|
||||
|
||||
if ( ! cont_resp )
|
||||
{
|
||||
if ( ftp_cmd_pending(session$pending_requests) )
|
||||
|
|
|
@ -1,433 +0,0 @@
|
|||
# $Id:$
|
||||
|
||||
# We can't do HTTP rewriting unless we process everything in the connection.
|
||||
@load http-reply
|
||||
@load http-entity
|
||||
@load http-anon-server
|
||||
@load http-anon-useragent
|
||||
@load http-anon-utils
|
||||
@load http-abstract
|
||||
|
||||
@load anon
|
||||
|
||||
module HTTP;
|
||||
|
||||
redef rewriting_http_trace = T;
|
||||
redef http_entity_data_delivery_size = 18874368;
|
||||
redef abstract_max_length = 18874368;
|
||||
|
||||
const rewrite_header_in_position = F;
|
||||
|
||||
const http_response_reasons = {
|
||||
"no content", "ok", "moved permanently", "not modified",
|
||||
"use local copy", "object not found", "forbidden", "okay",
|
||||
"object moved", "found", "http", "redirecting to main server",
|
||||
"internal server error", "not found", "unauthorized", "moved",
|
||||
"redirected", "continue", "access forbidden", "partial content",
|
||||
"redirect", "<empty>", "authorization required",
|
||||
"request time-out", "moved temporarily", "",
|
||||
};
|
||||
|
||||
const keep_alive_pat = /(([0-9]+|timeout=[0-9]+|max=[0-9]+),?)*/ ;
|
||||
|
||||
const content_type =
|
||||
/video\/(x-flv)(;)?/ # video
|
||||
| /audio\/(x-scpls)/
|
||||
| /image\/(gif|bmp|jpeg|pjpeg|tiff|png|x-icon)(;)?(qs\=[0-9](\.[0-9])?)?,?/
|
||||
| /application\/(octet-stream|x-www-form-urlencoded|x-javascript|rss\+xml|x-gzip|x-ns-proxy-autoconfig|pdf|pkix-crl|x-shockwave-flash|postscript|xml|rdf\+xml|excel|msword|x-wais-source)(;)?(charset=(iso-8859-1|iso8859-1|gb2312|windows-1251|windows-1252|utf-8))?/
|
||||
| /text\/(plain|js|html|\*|css|xml|javascript);?(charset=(iso-8859-1|iso8859-1|gb2312|windows-1251|windows-1252|utf-8))?/
|
||||
| /^unknown$/
|
||||
;
|
||||
|
||||
const accept_enc_pat =
|
||||
/(((x-)?deflate|(x-)?compress|\*|identity|(x-)?gzip|bzip|bzip2)(\; *q\=[0-9](\.[0-9])?)?,?)*/ ;
|
||||
const accept_charset_pat =
|
||||
/((windows-(1252|1251)|big5|iso-8859-(1|15)|\*|utf-(8|16))(\; *q\=[0-9](\.[0-9])?)?,?)*/ ;
|
||||
const connection_pat = /((close|keep\-alive|transfer\-encoding|te),?)*/ ;
|
||||
|
||||
const http_methods =
|
||||
/get|put|post|head|propfind|connect|options|proppatch|lock|unlock|move|delete|mkcol/ ;
|
||||
|
||||
const http_version = /(1\.0|1\.1)/ ;
|
||||
|
||||
const last_modified_pat =
|
||||
/(Sun|Mon|Tue|Wed|Thu|Fri|Sat), [0-9]+ (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) [0-9][0-9][0-9][0-9] .*/
|
||||
| /(-)?[0-9]+/
|
||||
;
|
||||
|
||||
const vary_pat =
|
||||
/((\*| *|accept|accept\-charset|negotiate|host|user\-agent|accept\-language|accept\-encoding|cookie),?)*/ ;
|
||||
|
||||
const accept_lang_pat =
|
||||
/(( *|tw|cs|mx|tr|ru|sk|au|hn|sv|no|bg|en|ko|kr|ca|pl|nz|fr|ch|jo|gb|zh|hk|cn|lv|de|nl|dk|fi|nl|es|pe|it|pt|br|ve|cl|ja|jp|he|ha|ar|us|en-us|da)(\; *q\=[0-9](\.[0-9]+)?)?(,|-|\_)?)*/ ;
|
||||
|
||||
const accept_pat =
|
||||
/(( *|audio|application|\*|gif|xml|xhtml\+xml|x-rgb|x-xbm|video|x-gsarcade-launch|mpeg|sgml|tiff|x-rgb|x-xbm|postscript|text|html|x-xbitmap|pjpeg|vnd.ms-powerpoint|vnd.ms-excel|msword|salt\+html|xhtml|plain|jpeg|jpg|x-shockwave-flash|x-|css|image|png|\*)(\; *q\=[0-9]*(\.[0-9]+)?)?(,|\/|\+)?)*/ ;
|
||||
|
||||
const tcn_pat = /list|choice|adhoc|re-choose|keep/;
|
||||
|
||||
const date_pat =
|
||||
/(sun|mon|tue|wed|thu|fri|sat)\,*[0-9]+ *(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec) *[0-9]+ ([0-9]+:)*[0-9]+ gmt/
|
||||
| /(sun|mon|tue|wed|thu|fri|sat)*(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec) *[0-9]+ *([0-9]+:)*[0-9]+(am|pm)?( *[0-9]+)?( *gmt)?/ ;
|
||||
|
||||
const content_encoding_pat = /gzip|deflate|x-compress|x-gzip/;
|
||||
|
||||
const hashed_headers =
|
||||
/COOKIE/
|
||||
| /AUTHOR/
|
||||
| /CACHE-CONTROL/
|
||||
| /ETAG/
|
||||
| /VIA/
|
||||
| /X-VIA/
|
||||
| /IISEXPORT/
|
||||
| /SET-COOKIE/
|
||||
| /X-JUNK/
|
||||
| /PRAGMA/
|
||||
| /AUTHORIZATION/
|
||||
| /X-POWERED-BY/
|
||||
| /X-CACHE/
|
||||
| /X-FORWARDED-FOR/
|
||||
| /X-PAD/
|
||||
| /X-C/
|
||||
| /XSERVER/
|
||||
| /FROM/
|
||||
| /CONTENT-DISPOSITION/
|
||||
| /X-ASPNET-VERSION/
|
||||
| /GUID/
|
||||
| /REGIONDATA/
|
||||
| /CLIENTID/
|
||||
| /X-CACHE-HEADERS-SET-BY/
|
||||
| /X-CACHE-LOOKUP/
|
||||
| /WARNING/
|
||||
| /MICROSOFTOFFICEWEBSERVER/
|
||||
| /IF-NONE-MATCH/
|
||||
| /X-AMZ-ID-[0-9]/
|
||||
| /X-N/
|
||||
| /X-TR/
|
||||
| /X-RSN/
|
||||
#| /X-POOKIE/ # these are weird ... next two are from slashdot
|
||||
#| /X-FRY/
|
||||
#| /X-BENDER/
|
||||
| /RANGE/
|
||||
| /IF-RANGE/
|
||||
| /CONTENT-RANGE/
|
||||
| /AD-REACH/
|
||||
| /HMSERVER/
|
||||
| /STATUS/
|
||||
| /X-SERVED/
|
||||
| /WWW-AUTHENTICATE/
|
||||
| /X-RESPONDING-SERVER/
|
||||
| /MAX-AGE/
|
||||
| /POST-CHECK/
|
||||
| /PRE-CHECK/
|
||||
| /X-CONTENT-ENCODED-BY/
|
||||
| /X-USER-IP/
|
||||
| /X-ICAP-VERSION/
|
||||
| /X-DELPHI/
|
||||
| /AUTHENTICATION-INFO/
|
||||
| /PPSERVER/
|
||||
| /EDGE-CONTROL/
|
||||
| /COMPRESSION-CONTROL/
|
||||
| /CONTENT-MD5/
|
||||
| /X-HOST/
|
||||
| /P3P/
|
||||
;
|
||||
|
||||
event http_request(c: connection, method: string,
|
||||
original_URI: string, unescaped_URI: string, version: string)
|
||||
{
|
||||
if (! rewriting_trace() )
|
||||
return;
|
||||
|
||||
print http_anon_log,
|
||||
fmt(" > %s %s %s ", method, original_URI, version);
|
||||
|
||||
if ( to_lower(method) != http_methods )
|
||||
{
|
||||
print http_anon_log, fmt("*** Unknown method %s", method);
|
||||
method = string_cat(" (anon-unknown) ", anonymize_string(method));
|
||||
}
|
||||
|
||||
original_URI = anonymize_http_URI(original_URI);
|
||||
|
||||
if ( version != http_version )
|
||||
{
|
||||
print http_anon_log, fmt("*** Unknown version %s ", version);
|
||||
version = string_cat(" (anon-unknown) ", anonymize_string(version));
|
||||
}
|
||||
|
||||
print http_anon_log, fmt(" < %s %s %s ", method, original_URI, version);
|
||||
|
||||
rewrite_http_request(c, method, original_URI, version);
|
||||
}
|
||||
|
||||
event http_reply(c: connection, version: string, code: count, reason: string)
|
||||
{
|
||||
if ( rewriting_trace() )
|
||||
{
|
||||
reason = to_lower(strip(reason));
|
||||
if ( reason !in http_response_reasons )
|
||||
{
|
||||
print http_anon_log,
|
||||
fmt("*** Unknown reply reason %s ", reason);
|
||||
rewrite_http_reply(c, version, code,
|
||||
anonymize_string(reason));
|
||||
}
|
||||
else
|
||||
rewrite_http_reply(c, version, code, reason);
|
||||
}
|
||||
}
|
||||
|
||||
function check_pat(value: string, pat: pattern, name: string): string
|
||||
{
|
||||
if ( value == pat )
|
||||
return value;
|
||||
|
||||
print http_anon_log, fmt("*** invalid %s: %s", name, value);
|
||||
return "(anon-unknown): ";
|
||||
}
|
||||
|
||||
function check_pat2(value: string, pat: pattern, name: string): string
|
||||
{
|
||||
if ( value == pat )
|
||||
return value;
|
||||
|
||||
print http_anon_log, fmt("*** invalid %s: %s", name, value);
|
||||
return fmt("(anon-unknown): %s", anonymize_string(value));
|
||||
}
|
||||
|
||||
function check_pat3(value: string, pat: pattern): string
|
||||
{
|
||||
if ( value == pat )
|
||||
return value;
|
||||
|
||||
return fmt("(anon-unknown): %s", anonymize_string(value));
|
||||
}
|
||||
|
||||
event http_header(c: connection, is_orig: bool, name: string, value: string)
|
||||
{
|
||||
if ( ! rewriting_trace() )
|
||||
return;
|
||||
|
||||
# Only rewrite top-level headers.
|
||||
local s = lookup_http_request_stream(c);
|
||||
local msg = get_http_message(s, is_orig);
|
||||
|
||||
if ( msg$entity_level != 1 )
|
||||
return;
|
||||
|
||||
value = strip(value);
|
||||
|
||||
if ( name == "CONTENT-LENGTH" )
|
||||
{
|
||||
# if ( rewrite_header_in_position )
|
||||
# {
|
||||
# local p = current_packet(c);
|
||||
# if ( p$is_orig == is_orig )
|
||||
# {
|
||||
# # local s = lookup_http_request_stream(c);
|
||||
# # local msg = get_http_message(s, is_orig);
|
||||
# if ( msg$header_slot == 0 )
|
||||
# msg$header_slot = reserve_rewrite_slot(c);
|
||||
# }
|
||||
# else
|
||||
# print fmt("cannot reserve a slot at %.6f", network_time());
|
||||
# }
|
||||
print http_anon_log,
|
||||
fmt("X-Original-Content-Length: %s --", value);
|
||||
name = "X-Original-Content-Length";
|
||||
}
|
||||
|
||||
else if ( name == "TRANSFER-ENCODING" || name == "TE" )
|
||||
{
|
||||
print http_anon_log, fmt("TRANSFER-ENCOODING: %s --", value);
|
||||
name = "X-Original-Transfer-Encoding";
|
||||
}
|
||||
|
||||
else if ( name == "HOST" )
|
||||
{
|
||||
local anon_host = "";
|
||||
|
||||
if ( value == simple_filename )
|
||||
anon_host = anonymize_path(value);
|
||||
else
|
||||
anon_host = anonymize_host(value);
|
||||
|
||||
print http_anon_log, fmt("HOST: %s > %s", value, anon_host);
|
||||
value = anon_host;
|
||||
}
|
||||
|
||||
else if ( name == "REFERER" )
|
||||
{
|
||||
local anon_ref = anonymize_http_URI(value);
|
||||
print http_anon_log, fmt("REFERER: %s > %s", value, anon_ref);
|
||||
value = anon_ref;
|
||||
}
|
||||
|
||||
else if ( name == "LOCATION" || name == "CONTENT-LOCATION" )
|
||||
value = anonymize_http_URI(value);
|
||||
|
||||
else if ( name == "SERVER" )
|
||||
value = filter_in_http_server(to_lower(value));
|
||||
|
||||
else if ( name == "USER-AGENT" )
|
||||
value = filter_in_http_useragent(to_lower(value));
|
||||
|
||||
else if ( name == "KEEP-ALIVE" )
|
||||
value = check_pat(value, keep_alive_pat, "keep-alive");
|
||||
|
||||
else if ( name == "DATE" || name == "IF-MODIFIED-SINCE" ||
|
||||
name == "UNLESS-MODIFIED-SINCE" )
|
||||
value = check_pat2(to_lower(value), date_pat, "date");
|
||||
|
||||
else if ( name == "ACCEPT-CHARSET" )
|
||||
value = check_pat(to_lower(value), accept_charset_pat,
|
||||
"accept-charset");
|
||||
|
||||
else if ( name == "CONTENT-TYPE" )
|
||||
{
|
||||
value = check_pat2(to_lower(value), content_type, "content-type");
|
||||
# local stream = lookup_http_request_stream(c);
|
||||
# local the_http_msg = get_http_message(stream, is_orig);
|
||||
# the_http_msg$content_type = value;
|
||||
}
|
||||
|
||||
else if ( name == "ACCEPT-ENCODING" )
|
||||
value = check_pat2(to_lower(value), accept_enc_pat,
|
||||
"accept-encoding");
|
||||
|
||||
else if ( name == "PAGE-COMPLETION-STATUS" )
|
||||
value = check_pat2(to_lower(value), /(ab)?normal/,
|
||||
"page-completion-status");
|
||||
|
||||
else if ( name == "CONNECTION" || name == "PROXY-CONNECTION" )
|
||||
value = check_pat2(to_lower(value), connection_pat,
|
||||
"connection type");
|
||||
|
||||
else if ( name == "LAST-MODIFIED" || name == "EXPIRES" )
|
||||
value = check_pat(value, last_modified_pat, name);
|
||||
|
||||
else if (name == "ACCEPT-LANGUAGE" || name == "LANGUAGE")
|
||||
value = check_pat2(to_lower(value), accept_lang_pat,
|
||||
"accept-language");
|
||||
|
||||
else if ( name == "ACCEPT" )
|
||||
value = check_pat(to_lower(value), accept_pat, "accept");
|
||||
|
||||
else if ( name == "ACCEPT-RANGES" )
|
||||
value = check_pat2(to_lower(value), /(bytes|none) */,
|
||||
"accept-ranges");
|
||||
|
||||
else if ( name == "MIME-VERSION" )
|
||||
value = check_pat3(value, /[0-9]\.[0-9]/);
|
||||
|
||||
else if ( name == "TCN" )
|
||||
value = check_pat3(value, tcn_pat);
|
||||
|
||||
else if ( name == "CONTENT-ENCODING" )
|
||||
value = check_pat2(value, content_encoding_pat,
|
||||
"content-encoding");
|
||||
|
||||
else if ( name == "CONTENT-LANGUAGE" )
|
||||
value = check_pat2(value, accept_lang_pat, "content-language");
|
||||
|
||||
else if ( name == "ALLOW" )
|
||||
value = check_pat3(value, http_methods);
|
||||
|
||||
else if ( name == "AGE" || name == "BANDWIDTH" )
|
||||
value = check_pat3(value, /[0-9]+/);
|
||||
|
||||
else if ( name == "VARY" )
|
||||
value = check_pat2(value, vary_pat, "vary");
|
||||
|
||||
else if ( name == hashed_headers )
|
||||
value = anonymize_string(value);
|
||||
|
||||
else
|
||||
{
|
||||
print http_anon_log, fmt("unknown header: %s : %s", name, value);
|
||||
value = string_cat("(anon-unknown): ", anonymize_string(value));
|
||||
}
|
||||
|
||||
rewrite_http_header(c, is_orig, name, value);
|
||||
}
|
||||
|
||||
event http_all_headers(c: connection, is_orig: bool, hlist: mime_header_list)
|
||||
{
|
||||
if ( ! rewriting_trace() )
|
||||
return;
|
||||
|
||||
if ( rewrite_header_in_position )
|
||||
{
|
||||
local p = current_packet(c);
|
||||
if ( p$is_orig == is_orig )
|
||||
{
|
||||
local s = lookup_http_request_stream(c);
|
||||
local msg = get_http_message(s, is_orig);
|
||||
if ( msg$header_slot == 0 )
|
||||
msg$header_slot = reserve_rewrite_slot(c);
|
||||
}
|
||||
else
|
||||
print fmt("cannot reserve a slot at %.6f", network_time());
|
||||
|
||||
# An empty line to mark the end of headers.
|
||||
rewrite_http_data(c, is_orig, "\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
event http_message_done(c: connection, is_orig: bool, stat: http_message_stat)
|
||||
{
|
||||
if ( ! rewriting_trace() )
|
||||
return;
|
||||
|
||||
if ( stat$interrupted )
|
||||
{
|
||||
print http_log,
|
||||
fmt("%.6f %s message interrupted at length=%d \"%s\"",
|
||||
network_time(), id_string(c$id),
|
||||
stat$body_length, stat$finish_msg);
|
||||
}
|
||||
|
||||
local s = lookup_http_request_stream(c);
|
||||
local msg = get_http_message(s, is_orig);
|
||||
if ( msg$header_slot > 0 )
|
||||
seek_rewrite_slot(c, msg$header_slot);
|
||||
|
||||
local data_length = 0;
|
||||
local data_hash = "";
|
||||
local sanitized_abstract = "";
|
||||
|
||||
if ( ! is_orig || stat$body_length > 0 )
|
||||
{
|
||||
data_length = byte_len(msg$abstract);
|
||||
data_hash = anonymize_string(msg$abstract);
|
||||
sanitized_abstract = string_fill(data_length, data_hash);
|
||||
|
||||
data_length += stat$content_gap_length;
|
||||
|
||||
rewrite_http_header(c, is_orig, "Content-Length",
|
||||
fmt(" %d", data_length));
|
||||
|
||||
rewrite_http_header(c, is_orig, "X-anon-content-hash",
|
||||
fmt(" %s", data_hash));
|
||||
|
||||
rewrite_http_header(c, is_orig, "X-Actual-Data-Length",
|
||||
fmt(" %d; gap=%d, content-length=%s",
|
||||
stat$body_length,
|
||||
stat$content_gap_length,
|
||||
msg$content_length));
|
||||
}
|
||||
|
||||
if ( msg$header_slot > 0 )
|
||||
{
|
||||
release_rewrite_slot(c, msg$header_slot);
|
||||
msg$header_slot = 0;
|
||||
}
|
||||
|
||||
if ( ! rewrite_header_in_position )
|
||||
# An empty line to mark the end of headers.
|
||||
rewrite_http_data(c, is_orig, "\r\n");
|
||||
|
||||
if ( data_length > 0 )
|
||||
rewrite_http_data(c, is_orig, sanitized_abstract);
|
||||
}
|
|
@ -1,137 +0,0 @@
|
|||
# $Id: http-rewriter.bro 416 2004-09-17 03:52:28Z vern $
|
||||
|
||||
# We can't do HTTP rewriting unless we process everything in the connection.
|
||||
@load http-reply
|
||||
@load http-entity
|
||||
|
||||
module HTTP;
|
||||
|
||||
redef rewriting_http_trace = T;
|
||||
redef http_entity_data_delivery_size = 4096;
|
||||
|
||||
const rewrite_header_in_position = F;
|
||||
|
||||
event http_request(c: connection, method: string,
|
||||
original_URI: string, unescaped_URI: string, version: string)
|
||||
{
|
||||
if ( rewriting_trace() )
|
||||
rewrite_http_request(c, method, original_URI, version);
|
||||
}
|
||||
|
||||
event http_reply(c: connection, version: string, code: count, reason: string)
|
||||
{
|
||||
if ( rewriting_trace() )
|
||||
rewrite_http_reply(c, version, code, reason);
|
||||
}
|
||||
|
||||
event http_header(c: connection, is_orig: bool, name: string, value: string)
|
||||
{
|
||||
if ( ! rewriting_trace() )
|
||||
return;
|
||||
|
||||
# Only rewrite top-level headers.
|
||||
local s = lookup_http_request_stream(c);
|
||||
local msg = get_http_message(s, is_orig);
|
||||
|
||||
if ( msg$entity_level == 1 )
|
||||
{
|
||||
if ( name == "CONTENT-LENGTH" )
|
||||
{
|
||||
if ( rewrite_header_in_position )
|
||||
{
|
||||
local p = current_packet(c);
|
||||
if ( p$is_orig == is_orig )
|
||||
{
|
||||
# local s = lookup_http_request_stream(c);
|
||||
# local msg = get_http_message(s, is_orig);
|
||||
if ( msg$header_slot == 0 )
|
||||
msg$header_slot = reserve_rewrite_slot(c);
|
||||
}
|
||||
else
|
||||
print fmt("cannot reserve a slot at %.6f", network_time());
|
||||
}
|
||||
# rewrite_http_header(c, is_orig,
|
||||
# "X-Original-Content-Length", value);
|
||||
}
|
||||
|
||||
else if ( name == "TRANSFER-ENCODING" )
|
||||
rewrite_http_header(c, is_orig,
|
||||
"X-Original-Transfer-Encoding", value);
|
||||
|
||||
else
|
||||
rewrite_http_header(c, is_orig, name, value);
|
||||
}
|
||||
}
|
||||
|
||||
event http_all_headers(c: connection, is_orig: bool, hlist: mime_header_list)
|
||||
{
|
||||
if ( ! rewriting_trace() )
|
||||
return;
|
||||
|
||||
if ( rewrite_header_in_position )
|
||||
{
|
||||
local p = current_packet(c);
|
||||
if ( p$is_orig == is_orig )
|
||||
{
|
||||
local s = lookup_http_request_stream(c);
|
||||
local msg = get_http_message(s, is_orig);
|
||||
if ( msg$header_slot == 0 )
|
||||
msg$header_slot = reserve_rewrite_slot(c);
|
||||
}
|
||||
else
|
||||
print fmt("cannot reserve a slot at %.6f", network_time());
|
||||
|
||||
# An empty line to mark the end of headers.
|
||||
rewrite_http_data(c, is_orig, "\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
event http_message_done(c: connection, is_orig: bool, stat: http_message_stat)
|
||||
{
|
||||
if ( ! rewriting_trace() )
|
||||
return;
|
||||
|
||||
local s = lookup_http_request_stream(c);
|
||||
local msg = get_http_message(s, is_orig);
|
||||
local data_length = 0;
|
||||
|
||||
if ( stat$interrupted )
|
||||
{
|
||||
print http_log,
|
||||
fmt("%.6f %s message interrupted at length=%d \"%s\"",
|
||||
network_time(), id_string(c$id),
|
||||
stat$body_length, stat$finish_msg);
|
||||
}
|
||||
|
||||
if ( msg$header_slot > 0 )
|
||||
seek_rewrite_slot(c, msg$header_slot);
|
||||
|
||||
if ( ! is_orig || stat$body_length > 0 )
|
||||
{
|
||||
if ( include_HTTP_abstract )
|
||||
data_length = byte_len(msg$abstract);
|
||||
|
||||
data_length = data_length + stat$content_gap_length;
|
||||
|
||||
rewrite_http_header(c, is_orig, "Content-Length",
|
||||
fmt(" %d", data_length));
|
||||
}
|
||||
|
||||
rewrite_http_header(c, is_orig, "X-Actual-Data-Length",
|
||||
fmt(" %d; gap=%d, content-length=%s",
|
||||
stat$body_length,
|
||||
stat$content_gap_length,
|
||||
msg$content_length));
|
||||
if ( msg$header_slot > 0 )
|
||||
{
|
||||
release_rewrite_slot(c, msg$header_slot);
|
||||
msg$header_slot = 0;
|
||||
}
|
||||
|
||||
if ( ! rewrite_header_in_position )
|
||||
# An empty line to mark the end of headers.
|
||||
rewrite_http_data(c, is_orig, "\r\n");
|
||||
|
||||
if ( data_length > 0 )
|
||||
rewrite_http_data(c, is_orig, msg$abstract);
|
||||
}
|
|
@ -1,115 +0,0 @@
|
|||
# $Id: ident-rewriter.bro 47 2004-06-11 07:26:32Z vern $
|
||||
|
||||
@load ident
|
||||
|
||||
redef rewriting_ident_trace = T;
|
||||
|
||||
global public_ident_user_ids = { "root", } &redef;
|
||||
global public_ident_systems = { "UNIX", } &redef;
|
||||
|
||||
const delay_rewriting_request = T;
|
||||
|
||||
function public_ident_user(id: string): bool
|
||||
{
|
||||
return id in public_ident_user_ids;
|
||||
}
|
||||
|
||||
function public_system(system: string): bool
|
||||
{
|
||||
return system in public_ident_systems;
|
||||
}
|
||||
|
||||
type ident_req: record {
|
||||
lport: port;
|
||||
rport: port;
|
||||
rewrite_slot: count;
|
||||
};
|
||||
|
||||
# Does not support pipelining ....
|
||||
global ident_req_slots: table[addr, port, addr, port] of ident_req;
|
||||
|
||||
event ident_request(c: connection, lport: port, rport: port)
|
||||
{
|
||||
if ( ! rewriting_trace() )
|
||||
return;
|
||||
|
||||
local id = c$id;
|
||||
if ( delay_rewriting_request )
|
||||
{
|
||||
local slot = reserve_rewrite_slot(c);
|
||||
ident_req_slots[id$orig_h, id$orig_p, id$resp_h, id$resp_p] =
|
||||
[$lport = lport, $rport = rport, $rewrite_slot = slot];
|
||||
}
|
||||
else
|
||||
rewrite_ident_request(c, lport, rport);
|
||||
}
|
||||
|
||||
event ident_reply(c: connection, lport: port, rport: port,
|
||||
user_id: string, system: string)
|
||||
{
|
||||
if ( ! rewriting_trace() )
|
||||
return;
|
||||
|
||||
local id = c$id;
|
||||
|
||||
if ( [id$orig_h, id$orig_p, id$resp_h, id$resp_p] in ident_req_slots )
|
||||
{
|
||||
local req = ident_req_slots[id$orig_h, id$orig_p,
|
||||
id$resp_h, id$resp_p];
|
||||
|
||||
seek_rewrite_slot(c, req$rewrite_slot);
|
||||
rewrite_ident_request(c, req$lport, req$rport);
|
||||
release_rewrite_slot(c, req$rewrite_slot);
|
||||
|
||||
delete ident_req_slots[id$orig_h, id$orig_p,
|
||||
id$resp_h, id$resp_p];
|
||||
}
|
||||
|
||||
rewrite_ident_reply(c, lport, rport,
|
||||
public_system(system) ? system : "OTHER",
|
||||
public_ident_user(user_id) ? user_id : "private user");
|
||||
}
|
||||
|
||||
event ident_error(c: connection, lport: port, rport: port, line: string)
|
||||
{
|
||||
if ( ! rewriting_trace() )
|
||||
return;
|
||||
|
||||
local id = c$id;
|
||||
|
||||
if ( [id$orig_h, id$orig_p, id$resp_h, id$resp_p] in ident_req_slots )
|
||||
{
|
||||
local req = ident_req_slots[id$orig_h, id$orig_p,
|
||||
id$resp_h, id$resp_p];
|
||||
|
||||
seek_rewrite_slot(c, req$rewrite_slot);
|
||||
rewrite_ident_request(c, req$lport, req$rport);
|
||||
release_rewrite_slot(c, req$rewrite_slot);
|
||||
|
||||
delete ident_req_slots[id$orig_h, id$orig_p,
|
||||
id$resp_h, id$resp_p];
|
||||
}
|
||||
|
||||
rewrite_ident_error(c, lport, rport, line);
|
||||
}
|
||||
|
||||
event connection_state_remove(c: connection)
|
||||
{
|
||||
if ( ! rewriting_trace() )
|
||||
return;
|
||||
|
||||
local id = c$id;
|
||||
|
||||
if ( [id$orig_h, id$orig_p, id$resp_h, id$resp_p] in ident_req_slots )
|
||||
{
|
||||
local req = ident_req_slots[id$orig_h, id$orig_p,
|
||||
id$resp_h, id$resp_p];
|
||||
|
||||
seek_rewrite_slot(c, req$rewrite_slot);
|
||||
rewrite_ident_request(c, req$lport, req$rport);
|
||||
release_rewrite_slot(c, req$rewrite_slot);
|
||||
|
||||
delete ident_req_slots[id$orig_h, id$orig_p,
|
||||
id$resp_h, id$resp_p];
|
||||
}
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
# $Id:$
|
||||
|
||||
redef rewriting_smb_trace = T;
|
||||
|
||||
|
||||
event smb_message(c: connection, hdr: smb_hdr, is_orig: bool, cmd: string, body_length: count, body: string)
|
||||
{
|
||||
}
|
||||
|
||||
event smb_com_tree_connect_andx(c: connection, hdr: smb_hdr, path: string, service: string)
|
||||
{
|
||||
}
|
||||
|
||||
event smb_com_tree_disconnect(c: connection, hdr: smb_hdr)
|
||||
{
|
||||
}
|
||||
|
||||
event smb_com_nt_create_andx(c: connection, hdr: smb_hdr, name: string)
|
||||
{
|
||||
}
|
||||
|
||||
event smb_com_transaction(c: connection, hdr: smb_hdr, trans: smb_trans, data: smb_trans_data, is_orig: bool)
|
||||
{
|
||||
}
|
||||
|
||||
event smb_com_transaction2(c: connection, hdr: smb_hdr, trans: smb_trans, data: smb_trans_data, is_orig: bool)
|
||||
{
|
||||
}
|
||||
|
||||
event smb_com_trans_mailslot(c: connection, hdr: smb_hdr, trans: smb_trans, data: smb_trans_data, is_orig: bool)
|
||||
{
|
||||
}
|
||||
|
||||
event smb_com_trans_rap(c: connection, hdr: smb_hdr, trans: smb_trans, data: smb_trans_data, is_orig: bool)
|
||||
{
|
||||
}
|
||||
|
||||
event smb_com_trans_pipe(c: connection, hdr: smb_hdr, trans: smb_trans, data: smb_trans_data, is_orig: bool)
|
||||
{
|
||||
}
|
||||
|
||||
event smb_com_read_andx(c: connection, hdr: smb_hdr, data: string)
|
||||
{
|
||||
}
|
||||
|
||||
event smb_com_write_andx(c: connection, hdr: smb_hdr, data: string)
|
||||
{
|
||||
}
|
||||
|
||||
event smb_get_dfs_referral(c: connection, hdr: smb_hdr, max_referral_level: count, file_name: string)
|
||||
{
|
||||
}
|
||||
|
||||
event smb_com_negotiate(c: connection, hdr: smb_hdr)
|
||||
{
|
||||
}
|
||||
|
||||
event smb_com_negotiate_response(c: connection, hdr: smb_hdr, dialect_index: count)
|
||||
{
|
||||
}
|
||||
|
||||
event smb_com_setup_andx(c: connection, hdr: smb_hdr)
|
||||
{
|
||||
}
|
||||
|
||||
event smb_com_generic_andx(c: connection, hdr: smb_hdr)
|
||||
{
|
||||
}
|
||||
|
||||
event smb_com_close(c: connection, hdr: smb_hdr)
|
||||
{
|
||||
}
|
||||
|
||||
event smb_com_logoff_andx(c: connection, hdr: smb_hdr)
|
||||
{
|
||||
}
|
||||
|
||||
event smb_error(c: connection, hdr: smb_hdr, cmd: count, cmd_str: string, data: string)
|
||||
{
|
||||
}
|
|
@ -1,94 +0,0 @@
|
|||
# $Id: smtp-rewriter.bro 4758 2007-08-10 06:49:23Z vern $
|
||||
|
||||
@load smtp
|
||||
@load mime # need mime for content hash
|
||||
|
||||
module SMTP;
|
||||
|
||||
redef rewriting_smtp_trace = T;
|
||||
|
||||
# We want this event handler to execute *after* the one in smtp.bro.
|
||||
event smtp_request(c: connection, is_orig: bool, command: string, arg: string)
|
||||
{
|
||||
if ( ! rewriting_trace() )
|
||||
return;
|
||||
|
||||
local session = smtp_sessions[c$id];
|
||||
|
||||
if ( command != ">" )
|
||||
{
|
||||
if ( command == "." )
|
||||
{
|
||||
# A hack before we have MIME rewriter.
|
||||
# rewrite_smtp_data(c, is_orig, fmt("X-number-of-lines: %d",
|
||||
# session$num_lines_in_body));
|
||||
rewrite_smtp_data(c, is_orig, fmt("X-number-of-bytes: %d",
|
||||
session$num_bytes_in_body));
|
||||
|
||||
# Write empty line to avoid MIME analyzer complaints.
|
||||
rewrite_smtp_data(c, is_orig, "");
|
||||
rewrite_smtp_data(c, is_orig, fmt("%s", session$content_hash));
|
||||
}
|
||||
|
||||
if ( command in smtp_legal_cmds )
|
||||
{
|
||||
# Avoid the situation in which we mistake
|
||||
# mail contents for SMTP commands.
|
||||
rewrite_smtp_request(c, is_orig, command, arg);
|
||||
rewrite_push_packet(c, is_orig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
event smtp_reply(c: connection, is_orig: bool, code: count, cmd: string,
|
||||
msg: string, cont_resp: bool)
|
||||
{
|
||||
if ( ! rewriting_trace() )
|
||||
return;
|
||||
|
||||
rewrite_smtp_reply(c, is_orig, code, msg, cont_resp);
|
||||
}
|
||||
|
||||
function starts_with_leading_whitespace(s: string): bool
|
||||
{
|
||||
return /^[ \t]/ in s;
|
||||
}
|
||||
|
||||
function rewrite_smtp_header_line(c: connection, is_orig: bool,
|
||||
session: smtp_session_info, line: string)
|
||||
{
|
||||
if ( starts_with_leading_whitespace(line) )
|
||||
{ # a continuing header
|
||||
if ( session$keep_current_header )
|
||||
rewrite_smtp_data(c, is_orig, line);
|
||||
}
|
||||
else
|
||||
{
|
||||
session$keep_current_header = F;
|
||||
|
||||
local pair = split1(line, /:/);
|
||||
if ( length(pair) < 2 )
|
||||
{
|
||||
session$keep_current_header = T;
|
||||
rewrite_smtp_data(c, is_orig, line);
|
||||
}
|
||||
else
|
||||
{
|
||||
local field_name = to_upper(pair[1]);
|
||||
|
||||
# Currently, the MIME analyzer is sensitive to
|
||||
# CONTENT-TYPE and CONTENT_TRANSFER_ENCODING,
|
||||
# so we want to remove these when anonymizing,
|
||||
# because we can't ensure their integrity when
|
||||
# rewriting message bodies.
|
||||
#
|
||||
# To be conservative, however, we strip out *all*
|
||||
# CONTENT-* headers.
|
||||
if ( /^CONTENT-/ !in field_name )
|
||||
{
|
||||
session$keep_current_header = T;
|
||||
rewrite_smtp_data(c, is_orig, line);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -505,15 +505,9 @@ event connection_state_remove(c: connection)
|
|||
}
|
||||
}
|
||||
|
||||
global rewrite_smtp_header_line:
|
||||
function(c: connection, is_orig: bool,
|
||||
session: smtp_session_info, line: string);
|
||||
|
||||
function smtp_header_line(c: connection, is_orig: bool,
|
||||
session: smtp_session_info, line: string)
|
||||
{
|
||||
if ( rewriting_smtp_trace )
|
||||
rewrite_smtp_header_line(c, is_orig, session, line);
|
||||
}
|
||||
|
||||
function smtp_body_line(c: connection, is_orig: bool,
|
||||
|
|
|
@ -751,15 +751,6 @@ void Analyzer::FlipRoles()
|
|||
resp_supporters = tmp;
|
||||
}
|
||||
|
||||
int Analyzer::RewritingTrace()
|
||||
{
|
||||
LOOP_OVER_CHILDREN(i)
|
||||
if ( (*i)->RewritingTrace() )
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Analyzer::ProtocolConfirmation()
|
||||
{
|
||||
if ( protocol_confirmed )
|
||||
|
@ -904,17 +895,10 @@ void SupportAnalyzer::ForwardUndelivered(int seq, int len, bool is_orig)
|
|||
Parent()->Undelivered(seq, len, is_orig);
|
||||
}
|
||||
|
||||
TransportLayerAnalyzer::~TransportLayerAnalyzer()
|
||||
{
|
||||
delete rewriter;
|
||||
}
|
||||
|
||||
void TransportLayerAnalyzer::Done()
|
||||
{
|
||||
Analyzer::Done();
|
||||
|
||||
if ( rewriter )
|
||||
rewriter->Done();
|
||||
}
|
||||
|
||||
void TransportLayerAnalyzer::SetContentsFile(unsigned int /* direction */,
|
||||
|
@ -929,14 +913,6 @@ BroFile* TransportLayerAnalyzer::GetContentsFile(unsigned int /* direction */) c
|
|||
return 0;
|
||||
}
|
||||
|
||||
void TransportLayerAnalyzer::SetTraceRewriter(Rewriter* r)
|
||||
{
|
||||
if ( rewriter )
|
||||
rewriter->Done();
|
||||
delete rewriter;
|
||||
rewriter = r;
|
||||
}
|
||||
|
||||
void TransportLayerAnalyzer::PacketContents(const u_char* data, int len)
|
||||
{
|
||||
if ( packet_contents && len > 0 )
|
||||
|
|
|
@ -225,10 +225,6 @@ public:
|
|||
virtual void ProtocolViolation(const char* reason,
|
||||
const char* data = 0, int len = 0);
|
||||
|
||||
// Returns true if the analyzer or one of its children is rewriting
|
||||
// the trace.
|
||||
virtual int RewritingTrace();
|
||||
|
||||
virtual unsigned int MemoryAllocation() const;
|
||||
|
||||
// The following methods are proxies: calls are directly forwarded
|
||||
|
@ -367,9 +363,7 @@ private:
|
|||
class TransportLayerAnalyzer : public Analyzer {
|
||||
public:
|
||||
TransportLayerAnalyzer(AnalyzerTag::Tag tag, Connection* conn)
|
||||
: Analyzer(tag, conn) { pia = 0; rewriter = 0; }
|
||||
|
||||
virtual ~TransportLayerAnalyzer();
|
||||
: Analyzer(tag, conn) { pia = 0; }
|
||||
|
||||
virtual void Done();
|
||||
virtual void UpdateEndpointVal(RecordVal* endp, int is_orig) = 0;
|
||||
|
@ -381,11 +375,6 @@ public:
|
|||
void SetPIA(PIA* arg_PIA) { pia = arg_PIA; }
|
||||
PIA* GetPIA() const { return pia; }
|
||||
|
||||
Rewriter* TraceRewriter() { return rewriter; }
|
||||
|
||||
// Takes ownership.
|
||||
void SetTraceRewriter(Rewriter* r);
|
||||
|
||||
// Raises packet_contents event.
|
||||
void PacketContents(const u_char* data, int len);
|
||||
|
||||
|
@ -394,7 +383,6 @@ protected:
|
|||
|
||||
private:
|
||||
PIA* pia;
|
||||
Rewriter* rewriter;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -130,15 +130,7 @@ set(BIF_SRCS
|
|||
event.bif
|
||||
const.bif
|
||||
types.bif
|
||||
common-rw.bif
|
||||
finger-rw.bif
|
||||
ident-rw.bif
|
||||
dns-rw.bif
|
||||
ftp-rw.bif
|
||||
smtp-rw.bif
|
||||
http-rw.bif
|
||||
strings.bif
|
||||
smb-rw.bif
|
||||
)
|
||||
|
||||
foreach (bift ${BIF_SRCS})
|
||||
|
@ -353,7 +345,6 @@ set(bro_SRCS
|
|||
TCP.cc
|
||||
TCP_Endpoint.cc
|
||||
TCP_Reassembler.cc
|
||||
TCP_Rewriter.cc
|
||||
Telnet.cc
|
||||
Timer.cc
|
||||
Traverse.cc
|
||||
|
@ -370,10 +361,7 @@ set(bro_SRCS
|
|||
md5.c
|
||||
patricia.c
|
||||
setsignal.c
|
||||
UDP_Rewriter.cc
|
||||
DNS_Rewriter.cc
|
||||
PacketDumper.cc
|
||||
Rewriter.cc
|
||||
strsep.c
|
||||
${dns_SRCS}
|
||||
${malloc_SRCS}
|
||||
|
|
10
src/Conn.cc
10
src/Conn.cc
|
@ -755,16 +755,6 @@ void Connection::FlipRoles()
|
|||
root_analyzer->FlipRoles();
|
||||
}
|
||||
|
||||
int Connection::RewritingTrace()
|
||||
{
|
||||
return root_analyzer ? root_analyzer->RewritingTrace() : 0;
|
||||
}
|
||||
|
||||
Rewriter* Connection::TraceRewriter() const
|
||||
{
|
||||
return root_analyzer ? root_analyzer->TraceRewriter() : 0;
|
||||
}
|
||||
|
||||
unsigned int Connection::MemoryAllocation() const
|
||||
{
|
||||
return padded_sizeof(*this)
|
||||
|
|
12
src/Conn.h
12
src/Conn.h
|
@ -23,7 +23,6 @@ class RuleHdrTest;
|
|||
class Specific_RE_Matcher;
|
||||
class TransportLayerAnalyzer;
|
||||
class RuleEndpointState;
|
||||
class Rewriter;
|
||||
|
||||
typedef enum {
|
||||
NUL_IN_LINE,
|
||||
|
@ -135,17 +134,6 @@ public:
|
|||
|
||||
TransportProto ConnTransport() const { return proto; }
|
||||
|
||||
// If we are rewriting the trace of the connection, then we do
|
||||
// not record original packets. We are rewriting if at least one,
|
||||
// then the analyzer is rewriting.
|
||||
int RewritingTrace();
|
||||
|
||||
// If we are rewriting trace, we need a handle to the rewriter.
|
||||
// Returns 0 if not rewriting. (Note that if multiple analyzers
|
||||
// want to rewrite, only one of them is returned. It's undefined
|
||||
// which one.)
|
||||
Rewriter* TraceRewriter() const;
|
||||
|
||||
// True if we should record subsequent packets (either headers or
|
||||
// in their entirety, depending on record_contents). We still
|
||||
// record subsequent SYN/FIN/RST, regardless of how this is set.
|
||||
|
|
|
@ -45,9 +45,6 @@
|
|||
// - We don't match signatures on connections which are completely handled
|
||||
// by the compressor. Matching would require significant additional state
|
||||
// w/o being very helpful.
|
||||
//
|
||||
// - Trace rewriting doesn't work if the compressor is turned on (this is
|
||||
// not a conceptual problem, but simply not implemented).
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
|
|
|
@ -13,8 +13,6 @@
|
|||
#include "DNS.h"
|
||||
#include "Sessions.h"
|
||||
#include "Event.h"
|
||||
#include "DNS_Rewriter.h"
|
||||
#include "TCP_Rewriter.h"
|
||||
|
||||
DNS_Interpreter::DNS_Interpreter(Analyzer* arg_analyzer)
|
||||
{
|
||||
|
@ -1134,11 +1132,6 @@ DNS_Analyzer::~DNS_Analyzer()
|
|||
|
||||
void DNS_Analyzer::Init()
|
||||
{
|
||||
if ( transformed_pkt_dump && RewritingTrace() &&
|
||||
Conn()->ConnTransport() == TRANSPORT_UDP )
|
||||
Conn()->GetRootAnalyzer()->SetTraceRewriter(
|
||||
new DNS_Rewriter(this, transformed_pkt_dump_MTU,
|
||||
transformed_pkt_dump));
|
||||
}
|
||||
|
||||
void DNS_Analyzer::Done()
|
||||
|
@ -1196,5 +1189,3 @@ void DNS_Analyzer::ExpireTimer(double t)
|
|||
ADD_ANALYZER_TIMER(&DNS_Analyzer::ExpireTimer,
|
||||
t + dns_session_timeout, 1, TIMER_DNS_EXPIRE);
|
||||
}
|
||||
|
||||
#include "dns-rw.bif.func_def"
|
||||
|
|
|
@ -265,11 +265,6 @@ public:
|
|||
virtual void Done();
|
||||
virtual void ConnectionClosed(TCP_Endpoint* endpoint,
|
||||
TCP_Endpoint* peer, int gen_event);
|
||||
virtual int RewritingTrace()
|
||||
{
|
||||
return BifConst::rewriting_dns_trace ||
|
||||
TCP_ApplicationAnalyzer::RewritingTrace();
|
||||
}
|
||||
|
||||
void ExpireTimer(double t);
|
||||
|
||||
|
|
|
@ -1,587 +0,0 @@
|
|||
// $Id:$
|
||||
//
|
||||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/nameser.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <resolv.h>
|
||||
|
||||
#include "NetVar.h"
|
||||
#include "DNS.h"
|
||||
#include "Val.h"
|
||||
#include "TCP.h"
|
||||
#include "Anon.h"
|
||||
#include "DNS_Rewriter.h"
|
||||
|
||||
DNS_Rewriter::DNS_Rewriter(Analyzer* analyzer, int arg_MTU,
|
||||
PacketDumper* dumper)
|
||||
: UDP_Rewriter(analyzer, arg_MTU, dumper)
|
||||
{
|
||||
pkt_size = 0;
|
||||
current_pkt_id = 0;
|
||||
|
||||
pkt = new u_char[DNS_PKT_SIZE + DNS_HDR_SIZE];
|
||||
}
|
||||
|
||||
void DNS_Rewriter::DnsCopyHeader(Val* msg)
|
||||
{
|
||||
// New header - reset packet size.
|
||||
pkt_size = 0;
|
||||
|
||||
// Move msg->AsRecordVal() to a RecordVal* to optimize.
|
||||
const RecordVal* msg_rec = msg->AsRecordVal();
|
||||
int id = msg_rec->Lookup(0)->AsCount();
|
||||
int opcode = msg_rec->Lookup(1)->AsCount();
|
||||
int rcode = msg_rec->Lookup(2)->AsCount();
|
||||
int QR = msg_rec->Lookup(3)->AsBool();
|
||||
int AA = msg_rec->Lookup(4)->AsBool();
|
||||
int TC = msg_rec->Lookup(5)->AsBool();
|
||||
int RD = msg_rec->Lookup(6)->AsBool();
|
||||
int RA = msg_rec->Lookup(7)->AsBool();
|
||||
int Z = msg_rec->Lookup(8)->AsCount();
|
||||
int qdcount = msg_rec->Lookup(9)->AsCount();
|
||||
int ancount = msg_rec->Lookup(10)->AsCount();
|
||||
int nscount = msg_rec->Lookup(11)->AsCount();
|
||||
int arcount = msg_rec->Lookup(12)->AsCount();
|
||||
|
||||
current_pkt_id = id;
|
||||
|
||||
// Set the DNS flags.
|
||||
uint16 flags = (QR << 15) | (AA << 10) | (TC << 9) |
|
||||
(RD << 8) | (RA << 7) | (Z << 4);
|
||||
|
||||
flags |= rcode | (opcode << 11);
|
||||
|
||||
(void) WriteShortVal(id);
|
||||
(void) WriteShortVal(flags);
|
||||
(void) WriteShortVal(qdcount);
|
||||
(void) WriteShortVal(ancount);
|
||||
(void) WriteShortVal(nscount);
|
||||
(void) WriteShortVal(arcount);
|
||||
|
||||
// We've finished the header.
|
||||
pkt_size = DNS_HDR_SIZE;
|
||||
|
||||
// Assign all the pointers for dn_comp().
|
||||
dpp = dn_ptrs;
|
||||
*dpp++ = pkt;
|
||||
*dpp++ = 0;
|
||||
|
||||
last_dn_ptr = dn_ptrs + sizeof dn_ptrs / sizeof dn_ptrs[0];
|
||||
}
|
||||
|
||||
int DNS_Rewriter::DnsCopyQuery(Val* val)
|
||||
{
|
||||
const RecordVal* val_rec = val->AsRecordVal();
|
||||
|
||||
// int type = val_rec->Lookup(0)->AsCount();
|
||||
|
||||
const BroString* query = val_rec->Lookup(1)->AsString();
|
||||
int atype = val_rec->Lookup(2)->AsCount();
|
||||
int aclass = val_rec->Lookup(3)->AsCount();
|
||||
|
||||
return DnsCopyQuery(query, atype, aclass);
|
||||
}
|
||||
|
||||
// Copy the question part of the query into memory.
|
||||
// Return the number of bytes that the query string compressed to.
|
||||
int DNS_Rewriter::DnsCopyQuery(const BroString* query, uint32 qtype,
|
||||
uint32 qclass)
|
||||
{
|
||||
int len = query->Len();
|
||||
int psize = pkt_size;
|
||||
|
||||
// Encode the query string.
|
||||
const char* dname = (char*) query->Bytes();
|
||||
len = dn_comp(dname, pkt + pkt_size, DNS_PKT_SIZE - pkt_size,
|
||||
dn_ptrs, last_dn_ptr);
|
||||
|
||||
// Can't encode in less than 2 bytes, or about to overwrite.
|
||||
if ( len < 1 || pkt_size + len + 4 > DNS_PKT_SIZE )
|
||||
{
|
||||
warn("dn_comp couldn't encode name into packet");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pkt_size += len;
|
||||
|
||||
// Set type.
|
||||
if ( ! WriteShortVal(qtype) )
|
||||
{
|
||||
pkt_size = psize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Set class.
|
||||
if ( ! WriteShortVal(qclass) )
|
||||
{
|
||||
pkt_size = psize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
// PTR, NS and CNAME are all the same.
|
||||
void DNS_Rewriter::DnsCopyPTR(Val* ans, const BroString* name)
|
||||
{
|
||||
DnsCopyCNAME(ans, name);
|
||||
}
|
||||
|
||||
// Copy an NS RR into the packet.
|
||||
void DNS_Rewriter::DnsCopyNS( Val* ans, const BroString* name)
|
||||
{
|
||||
DnsCopyCNAME(ans, name);
|
||||
}
|
||||
|
||||
// Copy an A RR into the packet.
|
||||
void DNS_Rewriter::DnsCopyA(Val* ans, uint32 addr)
|
||||
{
|
||||
int psize = pkt_size;
|
||||
|
||||
// Put query part into packet.
|
||||
int len = DnsCopyQuery(ans);
|
||||
|
||||
if ( ! len )
|
||||
return;
|
||||
|
||||
double TTL = ans->AsRecordVal()->Lookup(4)->AsInterval();
|
||||
if ( ! WriteDoubleAsInt(TTL) )
|
||||
{
|
||||
pkt_size = psize;
|
||||
return;
|
||||
}
|
||||
|
||||
// Now we put in how long the resource data is (A rec is always 4).
|
||||
if ( ! WriteShortVal(4) )
|
||||
{
|
||||
pkt_size = psize;
|
||||
return;
|
||||
}
|
||||
|
||||
// Stick in the address (already in network byte order).
|
||||
if ( ! WriteVal(uint32(ntohl(addr))) )
|
||||
{
|
||||
pkt_size = psize;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy an AAAA RR into the packet.
|
||||
void DNS_Rewriter::DnsCopyAAAA(Val* ans, addr_type addr, const BroString* addrstr)
|
||||
{
|
||||
int psize = pkt_size;
|
||||
|
||||
|
||||
// Put query part into packet.
|
||||
int len = DnsCopyQuery(ans);
|
||||
if ( ! len || pkt_size + 6 > DNS_PKT_SIZE )
|
||||
return;
|
||||
|
||||
double TTL = ans->AsRecordVal()->Lookup(4)->AsInterval();
|
||||
if ( ! WriteDoubleAsInt(TTL))
|
||||
{
|
||||
pkt_size = psize;
|
||||
return;
|
||||
}
|
||||
|
||||
// Now we put in how long the resource data is (AAAA rec is always 16).
|
||||
if ( ! WriteShortVal(16) )
|
||||
{
|
||||
pkt_size = psize;
|
||||
return;
|
||||
}
|
||||
#ifdef BROv6
|
||||
if ( ! WriteVal(addr) )
|
||||
{
|
||||
pkt_size = psize;
|
||||
return;
|
||||
}
|
||||
#else
|
||||
uint32 addr_copy[4];
|
||||
char* addr_tmp = addrstr->Render(BroString::ESC_NONE);
|
||||
inet_pton(AF_INET6, addr_tmp, addr_copy);
|
||||
|
||||
if ( ! WriteVal(addr_copy) )
|
||||
{
|
||||
pkt_size = psize;
|
||||
return;
|
||||
}
|
||||
|
||||
delete addr_tmp;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
// Copy a CNAME RR into the packet.
|
||||
void DNS_Rewriter::DnsCopyCNAME(Val* ans, const BroString* name)
|
||||
{
|
||||
int psize = pkt_size;
|
||||
|
||||
// Put query part into packet.
|
||||
int len = DnsCopyQuery(ans);
|
||||
if ( ! len || pkt_size + 6 > DNS_PKT_SIZE )
|
||||
return;
|
||||
|
||||
double TTL = ans->AsRecordVal()->Lookup(4)->AsInterval();
|
||||
if ( ! WriteDoubleAsInt(TTL))
|
||||
{
|
||||
pkt_size = psize;
|
||||
return;
|
||||
}
|
||||
|
||||
// Resource length (domain name length in packet).
|
||||
// Have to skip till it's encoded, remember this spot.
|
||||
u_char* resource_len = pkt + pkt_size;
|
||||
pkt_size += 2;
|
||||
|
||||
// Encode the domain name.
|
||||
const char* dname = (char*) name->CheckString();
|
||||
len = dn_comp(dname, pkt + pkt_size, DNS_PKT_SIZE - pkt_size,
|
||||
dn_ptrs, last_dn_ptr);
|
||||
|
||||
if ( len < 1 )
|
||||
{
|
||||
pkt_size = psize;
|
||||
return;
|
||||
}
|
||||
|
||||
pkt_size += len;
|
||||
|
||||
// Now we put in how long the name was to encode.
|
||||
uint16 net_rdlen = htons(short(len));
|
||||
memcpy(resource_len, &net_rdlen, sizeof(uint16));
|
||||
}
|
||||
|
||||
// Copy a CNAME RR into the packet.
|
||||
void DNS_Rewriter::DnsCopyTXT(Val* ans, const BroString* name)
|
||||
{
|
||||
int psize = pkt_size;
|
||||
|
||||
// Put query part into packet.
|
||||
int len = DnsCopyQuery(ans);
|
||||
if ( ! len || pkt_size + 6 > DNS_PKT_SIZE )
|
||||
return;
|
||||
|
||||
double TTL = ans->AsRecordVal()->Lookup(4)->AsInterval();
|
||||
if ( ! WriteDoubleAsInt(TTL))
|
||||
{
|
||||
pkt_size = psize;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! WriteShortVal(name->Len()+1))
|
||||
{
|
||||
pkt_size = psize;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! WriteVal(uint8(name->Len())))
|
||||
{
|
||||
pkt_size = psize;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! WriteVal(name))
|
||||
{
|
||||
pkt_size = psize;
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Copy an MX RR into the packet.
|
||||
void DNS_Rewriter::DnsCopyMX(Val* ans, const BroString* name, uint32 preference)
|
||||
{
|
||||
int psize = pkt_size;
|
||||
|
||||
// Put query part into packet.
|
||||
int len = DnsCopyQuery(ans);
|
||||
|
||||
if ( ! len || pkt_size + len + 6 > DNS_PKT_SIZE )
|
||||
{
|
||||
warn("DnsCopyMX: packet too large");
|
||||
return;
|
||||
}
|
||||
|
||||
double TTL = ans->AsRecordVal()->Lookup(4)->AsInterval();
|
||||
if ( ! WriteDoubleAsInt(TTL) )
|
||||
{
|
||||
pkt_size = psize;
|
||||
warn("DnsCopyMX: packet too large");
|
||||
return;
|
||||
}
|
||||
|
||||
// Resource length (domain name length in packet).
|
||||
// Have to skip till it's, remember this spot.
|
||||
u_char* resource_len = pkt + pkt_size;
|
||||
pkt_size += 2;
|
||||
|
||||
if ( ! WriteShortVal(preference))
|
||||
{
|
||||
pkt_size = psize;
|
||||
warn("DnsCopyMX: packet too large");
|
||||
return;
|
||||
}
|
||||
|
||||
// Encode the domain name.
|
||||
const char* dname = (char*) name->CheckString();
|
||||
len += dn_comp(dname, pkt + pkt_size, DNS_PKT_SIZE - pkt_size,
|
||||
dn_ptrs, last_dn_ptr);
|
||||
|
||||
if ( len < 1 )
|
||||
{
|
||||
pkt_size = psize;
|
||||
warn("DnsCopyMX: packet too large");
|
||||
return;
|
||||
}
|
||||
|
||||
pkt_size += len;
|
||||
|
||||
// 2 bytes for the preference size above.
|
||||
len += 2;
|
||||
|
||||
// Now we put in how long the name was to encode.
|
||||
uint16 net_rdlen = htons(short(len));
|
||||
memcpy(resource_len, &net_rdlen, sizeof(uint16));
|
||||
}
|
||||
|
||||
// Copy an SOA RR into the packet.
|
||||
void DNS_Rewriter::DnsCopySOA(Val* ans, Val* soa)
|
||||
{
|
||||
u_char* resource_len;
|
||||
int resource_offset = 0;
|
||||
int psize = pkt_size;
|
||||
|
||||
const RecordVal* soa_rec = soa->AsRecordVal();
|
||||
|
||||
const BroString* mname = soa_rec->Lookup(0)->AsString();
|
||||
const BroString* rname = soa_rec->Lookup(1)->AsString();
|
||||
uint32 serial = soa_rec->Lookup(2)->AsCount();
|
||||
double refresh = soa_rec->Lookup(3)->AsInterval();
|
||||
double retry = soa_rec->Lookup(4)->AsInterval();
|
||||
double expire = soa_rec->Lookup(5)->AsInterval();
|
||||
double minimum = soa_rec->Lookup(6)->AsInterval();
|
||||
|
||||
// Put query part into packet.
|
||||
int len = DnsCopyQuery(ans);
|
||||
|
||||
if ( ! len || len + 6 > DNS_PKT_SIZE )
|
||||
return;
|
||||
|
||||
double TTL = ans->AsRecordVal()->Lookup(4)->AsInterval();
|
||||
if ( ! WriteDoubleAsInt(TTL) )
|
||||
{
|
||||
pkt_size = psize;
|
||||
return;
|
||||
}
|
||||
|
||||
// Resource length: have to skip till it's encoded.
|
||||
// Remember this spot and offset.
|
||||
resource_len = pkt + pkt_size;
|
||||
pkt_size += 2;
|
||||
|
||||
// Start counting from here (after rdlength).
|
||||
resource_offset = pkt_size;
|
||||
|
||||
// Encode the domain name.
|
||||
const char* dname = (char*) mname->CheckString();
|
||||
len = dn_comp(dname, pkt + pkt_size, DNS_PKT_SIZE - pkt_size,
|
||||
dn_ptrs, last_dn_ptr);
|
||||
|
||||
if ( len < 1 )
|
||||
{
|
||||
pkt_size = psize;
|
||||
return;
|
||||
}
|
||||
|
||||
pkt_size += len;
|
||||
|
||||
// Encode the domain name.
|
||||
dname = (char*) rname->CheckString();
|
||||
len = dn_comp(dname, pkt + pkt_size, DNS_PKT_SIZE - pkt_size,
|
||||
dn_ptrs, last_dn_ptr);
|
||||
if ( len < 1 )
|
||||
{
|
||||
pkt_size = psize;
|
||||
return;
|
||||
}
|
||||
|
||||
pkt_size += len;
|
||||
|
||||
if ( ! WriteVal(serial) || ! WriteDoubleAsInt(refresh) ||
|
||||
! WriteDoubleAsInt(retry) || ! WriteDoubleAsInt(expire) ||
|
||||
! WriteDoubleAsInt(minimum) )
|
||||
{
|
||||
pkt_size = psize;
|
||||
return;
|
||||
}
|
||||
|
||||
// Now we put in how long this packet was.
|
||||
uint16 net_rdlen = htons(short(pkt_size - resource_offset));
|
||||
memcpy(resource_len, &net_rdlen, sizeof(uint16));
|
||||
}
|
||||
|
||||
void DNS_Rewriter::DnsCopyEDNSaddl(Val* ans)
|
||||
{
|
||||
const RecordVal* ans_rec = ans->AsRecordVal();
|
||||
|
||||
int ans_type = ans_rec->Lookup(0)->AsCount();
|
||||
// BroString* query_name = ans_rec->Lookup(1)->AsString();
|
||||
int atype = ans_rec->Lookup(2)->AsCount();
|
||||
int aclass = ans_rec->Lookup(3)->AsCount();
|
||||
int return_error = ans_rec->Lookup(4)->AsCount();
|
||||
int version = ans_rec->Lookup(5)->AsCount();
|
||||
int z = ans_rec->Lookup(6)->AsCount();
|
||||
double ttl = ans_rec->Lookup(7)->AsInterval();
|
||||
int is_query = ans_rec->Lookup(8)->AsCount();
|
||||
|
||||
int rcode = return_error;
|
||||
int ecode = 0;
|
||||
|
||||
int psize = pkt_size;
|
||||
|
||||
if ( return_error > 0xff )
|
||||
{
|
||||
rcode &= 0xff;
|
||||
ecode = return_error >> 8;
|
||||
}
|
||||
|
||||
// Stick the version onto the ecode.
|
||||
ecode = (ecode << 8) | version;
|
||||
|
||||
// Write fixed part of OPT RR
|
||||
// Name '0'.
|
||||
memset(pkt + pkt_size, 0, 1);
|
||||
++pkt_size;
|
||||
|
||||
// Type (either 29 or 41).
|
||||
if ( ! WriteShortVal(atype) )
|
||||
{
|
||||
pkt_size = psize;
|
||||
return;
|
||||
}
|
||||
|
||||
// UDP playload size
|
||||
if ( ! WriteShortVal(aclass) )
|
||||
{
|
||||
pkt_size = psize;
|
||||
return;
|
||||
}
|
||||
|
||||
// Extended rcode + version.
|
||||
if ( ! WriteShortVal(ecode) )
|
||||
{
|
||||
pkt_size = psize;
|
||||
return;
|
||||
}
|
||||
|
||||
// Z field.
|
||||
if ( ! WriteShortVal(z) )
|
||||
{
|
||||
pkt_size = psize;
|
||||
return;
|
||||
}
|
||||
|
||||
// Data length (XXX:for now its zero!).
|
||||
if ( ! WriteShortVal(0) )
|
||||
{
|
||||
pkt_size = psize;
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't write data (XXX:we don't have it!).
|
||||
}
|
||||
|
||||
// Does this packet match the current packet being worked on?
|
||||
int DNS_Rewriter::DnsPktMatch(Val* msg)
|
||||
{
|
||||
return msg->AsRecordVal()->Lookup(0)->AsInt() == current_pkt_id;
|
||||
}
|
||||
|
||||
// Supports copying of TXT values.
|
||||
int DNS_Rewriter::WriteVal(const BroString* val)
|
||||
{
|
||||
int n = val->Len();
|
||||
|
||||
if ( pkt_size + n > DNS_PKT_SIZE )
|
||||
{
|
||||
warn("WriteVal: couldn't write data into packet");
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* new_val = val->Render(BroString::ESC_NONE);
|
||||
memcpy(pkt + pkt_size, new_val, n);
|
||||
pkt_size += n;
|
||||
|
||||
delete[] new_val;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int DNS_Rewriter::WriteVal(const uint32* val)
|
||||
{
|
||||
if ( pkt_size + 16 > DNS_PKT_SIZE )
|
||||
{
|
||||
warn("WriteVal: couldn't write data into packet");
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(pkt + pkt_size, &val[0], sizeof(uint32)); pkt_size += 4;
|
||||
memcpy(pkt + pkt_size, &val[1], sizeof(uint32)); pkt_size += 4;
|
||||
memcpy(pkt + pkt_size, &val[2], sizeof(uint32)); pkt_size += 4;
|
||||
memcpy(pkt + pkt_size, &val[3], sizeof(uint32)); pkt_size += 4;
|
||||
|
||||
return sizeof(uint32) * 4;
|
||||
}
|
||||
|
||||
// Write a 32 bit value given in host order to the packet.
|
||||
int DNS_Rewriter::WriteVal(uint32 val)
|
||||
{
|
||||
if ( pkt_size + 4 > DNS_PKT_SIZE )
|
||||
{
|
||||
warn("WriteVal: couldn't write data into packet");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32 net_val = htonl(val);
|
||||
memcpy(pkt + pkt_size, &net_val, sizeof(uint32));
|
||||
pkt_size += 4;
|
||||
|
||||
return sizeof(uint32);
|
||||
}
|
||||
|
||||
// Write a 16 bit value given in host order to the packet.
|
||||
int DNS_Rewriter::WriteVal(uint16 val)
|
||||
{
|
||||
if ( pkt_size + 2 > DNS_PKT_SIZE )
|
||||
{
|
||||
warn("WriteShortVal: couldn't write data into packet");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16 net_val = htons(val);
|
||||
memcpy(pkt + pkt_size, &net_val, sizeof(uint16));
|
||||
pkt_size += 2;
|
||||
|
||||
return sizeof(uint16);
|
||||
}
|
||||
|
||||
// Write a 8 bit value given in host order to the packet.
|
||||
int DNS_Rewriter::WriteVal(uint8 val)
|
||||
{
|
||||
if ( pkt_size + 1 > DNS_PKT_SIZE )
|
||||
{
|
||||
warn("WriteVal: couldn't write data into packet");
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(pkt + pkt_size, &val, sizeof(uint8));
|
||||
pkt_size += sizeof(uint8);
|
||||
|
||||
return sizeof(uint8);
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
// $Id:$
|
||||
//
|
||||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#ifndef dns_rewriter_h
|
||||
#define dns_rewriter_h
|
||||
|
||||
#include "UDP.h"
|
||||
#include "UDP_Rewriter.h"
|
||||
#include "Rewriter.h"
|
||||
|
||||
#define DNS_HDR_SIZE 12
|
||||
|
||||
// DNS packets size. 512 is the *normal* size, but some packets are bigger
|
||||
// than this, and the anonymization process can expand packets, so we
|
||||
// pad this way out.
|
||||
#define DNS_PKT_SIZE (512*4)
|
||||
|
||||
class DNS_Rewriter: public UDP_Rewriter {
|
||||
public:
|
||||
DNS_Rewriter(Analyzer* analyzer, int arg_MTU, PacketDumper* dumper);
|
||||
virtual ~DNS_Rewriter() { delete pkt;}
|
||||
|
||||
void DnsCopyHeader(Val* val);
|
||||
|
||||
int DnsCopyQuery(const BroString* query, uint32 qtype, uint32 qclass);
|
||||
int DnsCopyQuery(Val* val);
|
||||
|
||||
void DnsCopyNS(Val* ans, const BroString* name);
|
||||
void DnsCopyPTR(Val* ans, const BroString* name);
|
||||
void DnsCopyCNAME(Val* ans, const BroString* name);
|
||||
void DnsCopyTXT(Val* ans, const BroString* name);
|
||||
void DnsCopyA(Val* ans, uint32 addr);
|
||||
|
||||
// AAAA is weird, because the address is an IPv4 type.
|
||||
// If we don't have IPv6, and if it's IPv6, it's a pointer
|
||||
// to valid data.
|
||||
void DnsCopyAAAA(Val* ans, addr_type addr, const BroString* addrstr);
|
||||
|
||||
void DnsCopyMX(Val* ans, const BroString* name, uint32 preference);
|
||||
void DnsCopySOA(Val* ans, Val* soa);
|
||||
void DnsCopyEDNSaddl(Val* ans);
|
||||
|
||||
int DnsPktMatch(Val* val);
|
||||
const u_char* Packet() const { return pkt; }
|
||||
int PacketSize() const { return pkt_size; }
|
||||
void SetOrig( int orig ) { is_orig = orig; }
|
||||
int IsOrig() { return is_orig; }
|
||||
|
||||
int WriteDoubleAsInt(double d) { return WriteVal(uint32(d)); }
|
||||
int WriteShortVal(uint16 val) { return WriteVal(uint16(val)); }
|
||||
int WriteVal(uint32 val);
|
||||
int WriteVal(uint16 val);
|
||||
int WriteVal(uint8 val);
|
||||
int WriteVal(const uint32* val);
|
||||
int WriteVal(const BroString* val);
|
||||
|
||||
private:
|
||||
u_char* pkt; // the DNS packet
|
||||
int pkt_size; // size of the packet
|
||||
int current_pkt_id; // current ID (sanity checking)
|
||||
|
||||
int is_orig;
|
||||
|
||||
u_char* dn_ptrs[30]; // pointer to names in DNS packet
|
||||
u_char** dpp; // points to current position in DNS packet
|
||||
u_char** last_dn_ptr; // points to last entry in dn_ptrs
|
||||
};
|
||||
|
||||
#endif
|
|
@ -120,9 +120,6 @@ void EventMgr::Drain()
|
|||
|
||||
// Note: we might eventually need a general way to specify things to
|
||||
// do after draining events.
|
||||
extern void flush_rewriter_packet();
|
||||
flush_rewriter_packet();
|
||||
|
||||
draining = false;
|
||||
|
||||
// We evaluate Triggers here. While this is somewhat unrelated to event
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include "FTP.h"
|
||||
#include "NVT.h"
|
||||
#include "Event.h"
|
||||
#include "TCP_Rewriter.h"
|
||||
|
||||
FTP_Analyzer::FTP_Analyzer(Connection* conn)
|
||||
: TCP_ApplicationAnalyzer(AnalyzerTag::FTP, conn)
|
||||
|
@ -169,5 +168,3 @@ void FTP_Analyzer::DeliverStream(int length, const u_char* data, bool orig)
|
|||
ConnectionEvent(f, vl);
|
||||
}
|
||||
|
||||
|
||||
#include "ftp-rw.bif.func_def"
|
||||
|
|
|
@ -14,11 +14,6 @@ public:
|
|||
|
||||
virtual void Done();
|
||||
virtual void DeliverStream(int len, const u_char* data, bool orig);
|
||||
virtual int RewritingTrace()
|
||||
{
|
||||
return BifConst::rewriting_ftp_trace ||
|
||||
TCP_ApplicationAnalyzer::RewritingTrace();
|
||||
}
|
||||
|
||||
static Analyzer* InstantiateAnalyzer(Connection* conn)
|
||||
{
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
#include "NetVar.h"
|
||||
#include "Finger.h"
|
||||
#include "Event.h"
|
||||
#include "TCP_Rewriter.h"
|
||||
#include "ContentLine.h"
|
||||
|
||||
Finger_Analyzer::Finger_Analyzer(Connection* conn)
|
||||
|
@ -87,5 +86,3 @@ void Finger_Analyzer::DeliverStream(int length, const u_char* data, bool is_orig
|
|||
ConnectionEvent(finger_reply, vl);
|
||||
}
|
||||
}
|
||||
|
||||
#include "finger-rw.bif.func_def"
|
||||
|
|
|
@ -17,8 +17,6 @@ public:
|
|||
virtual void Done();
|
||||
// Line-based input.
|
||||
virtual void DeliverStream(int len, const u_char* data, bool orig);
|
||||
virtual int RewritingTrace()
|
||||
{ return BifConst::rewriting_finger_trace || TCP_ApplicationAnalyzer::RewritingTrace(); }
|
||||
|
||||
static Analyzer* InstantiateAnalyzer(Connection* conn)
|
||||
{ return new Finger_Analyzer(conn); }
|
||||
|
|
16
src/Func.cc
16
src/Func.cc
|
@ -497,15 +497,7 @@ void builtin_run_time(const char* msg, BroObj* arg)
|
|||
}
|
||||
|
||||
#include "bro.bif.func_h"
|
||||
|
||||
#include "common-rw.bif.func_h"
|
||||
#include "finger-rw.bif.func_h"
|
||||
#include "ftp-rw.bif.func_h"
|
||||
#include "http-rw.bif.func_h"
|
||||
#include "ident-rw.bif.func_h"
|
||||
#include "smtp-rw.bif.func_h"
|
||||
#include "strings.bif.func_h"
|
||||
#include "dns-rw.bif.func_h"
|
||||
|
||||
#include "bro.bif.func_def"
|
||||
#include "strings.bif.func_def"
|
||||
|
@ -519,15 +511,7 @@ void init_builtin_funcs()
|
|||
gap_info = internal_type("gap_info")->AsRecordType();
|
||||
|
||||
#include "bro.bif.func_init"
|
||||
|
||||
#include "common-rw.bif.func_init"
|
||||
#include "finger-rw.bif.func_init"
|
||||
#include "ftp-rw.bif.func_init"
|
||||
#include "http-rw.bif.func_init"
|
||||
#include "ident-rw.bif.func_init"
|
||||
#include "smtp-rw.bif.func_init"
|
||||
#include "strings.bif.func_init"
|
||||
#include "dns-rw.bif.func_init"
|
||||
|
||||
did_builtin_init = true;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include "HTTP.h"
|
||||
#include "Event.h"
|
||||
#include "MIME.h"
|
||||
#include "TCP_Rewriter.h"
|
||||
|
||||
const bool DEBUG_http = false;
|
||||
|
||||
|
@ -1756,5 +1755,3 @@ BroString* unescape_URI(const u_char* line, const u_char* line_end,
|
|||
|
||||
return new BroString(1, decoded_URI, URI_p - decoded_URI);
|
||||
}
|
||||
|
||||
#include "http-rw.bif.func_def"
|
||||
|
|
|
@ -169,8 +169,6 @@ public:
|
|||
virtual void Done();
|
||||
virtual void DeliverStream(int len, const u_char* data, bool orig);
|
||||
virtual void Undelivered(int seq, int len, bool orig);
|
||||
virtual int RewritingTrace()
|
||||
{ return BifConst::rewriting_http_trace || TCP_ApplicationAnalyzer::RewritingTrace(); }
|
||||
|
||||
// Overriden from TCP_ApplicationAnalyzer
|
||||
virtual void EndpointEOF(bool is_orig);
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
#include "NetVar.h"
|
||||
#include "Ident.h"
|
||||
#include "Event.h"
|
||||
#include "TCP_Rewriter.h"
|
||||
|
||||
Ident_Analyzer::Ident_Analyzer(Connection* conn)
|
||||
: TCP_ApplicationAnalyzer(AnalyzerTag::Ident, conn)
|
||||
|
@ -245,6 +244,3 @@ void Ident_Analyzer::BadReply(int length, const char* line)
|
|||
did_bad_reply = 1;
|
||||
}
|
||||
}
|
||||
|
||||
#include "ident-rw.bif.func_def"
|
||||
|
||||
|
|
|
@ -14,11 +14,6 @@ public:
|
|||
virtual void Done();
|
||||
|
||||
virtual void DeliverStream(int length, const u_char* data, bool is_orig);
|
||||
virtual int RewritingTrace()
|
||||
{
|
||||
return BifConst::rewriting_ident_trace ||
|
||||
TCP_ApplicationAnalyzer::RewritingTrace();
|
||||
}
|
||||
|
||||
static Analyzer* InstantiateAnalyzer(Connection* conn)
|
||||
{ return new Ident_Analyzer(conn); }
|
||||
|
|
49
src/Net.cc
49
src/Net.cc
|
@ -28,7 +28,6 @@
|
|||
#include "Var.h"
|
||||
#include "Logger.h"
|
||||
#include "Net.h"
|
||||
#include "TCP_Rewriter.h"
|
||||
#include "Anon.h"
|
||||
#include "PacketSort.h"
|
||||
#include "Serializer.h"
|
||||
|
@ -47,13 +46,6 @@ PList(PktSrc) pkt_srcs;
|
|||
// FIXME: We should really merge PktDumper and PacketDumper.
|
||||
// It's on my to-do [Robin].
|
||||
PktDumper* pkt_dumper = 0;
|
||||
PktDumper* pkt_transformed_dumper = 0;
|
||||
|
||||
// For trace of rewritten packets
|
||||
PacketDumper* transformed_pkt_dump = 0;
|
||||
// For trace of original packets from selected connections
|
||||
PacketDumper* source_pkt_dump = 0;
|
||||
int transformed_pkt_dump_MTU = 1514;
|
||||
|
||||
int reading_live = 0;
|
||||
int reading_traces = 0;
|
||||
|
@ -162,9 +154,8 @@ RETSIGTYPE watchdog(int /* signo */)
|
|||
|
||||
void net_init(name_list& interfaces, name_list& readfiles,
|
||||
name_list& netflows, name_list& flowfiles,
|
||||
const char* writefile, const char* transformed_writefile,
|
||||
const char* filter, const char* secondary_filter,
|
||||
int do_watchdog)
|
||||
const char* writefile, const char* filter,
|
||||
const char* secondary_filter, int do_watchdog)
|
||||
{
|
||||
init_net_var();
|
||||
|
||||
|
@ -320,37 +311,7 @@ void net_init(name_list& interfaces, name_list& readfiles,
|
|||
id->SetVal(new StringVal(writefile));
|
||||
}
|
||||
|
||||
if ( transformed_writefile )
|
||||
{
|
||||
pkt_transformed_dumper = new PktDumper(transformed_writefile);
|
||||
if ( pkt_transformed_dumper->IsError() )
|
||||
{
|
||||
fprintf(stderr, "%s: can't open trace transformation write file \"%s\" - %s\n",
|
||||
prog, writefile,
|
||||
pkt_transformed_dumper->ErrorMsg());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
transformed_pkt_dump =
|
||||
new PacketDumper(pkt_transformed_dumper->PcapDumper());
|
||||
|
||||
// If both -A and -w are specified, -A will be the transformed
|
||||
// trace file and -w will be the source packet trace file.
|
||||
// Otherwise the packets will go to the same file.
|
||||
if ( pkt_dumper )
|
||||
source_pkt_dump =
|
||||
new PacketDumper(pkt_dumper->PcapDumper());
|
||||
}
|
||||
|
||||
else if ( pkt_dumper )
|
||||
transformed_pkt_dump =
|
||||
new PacketDumper(pkt_dumper->PcapDumper());
|
||||
|
||||
if ( BifConst::anonymize_ip_addr )
|
||||
init_ip_addr_anonymizers();
|
||||
else
|
||||
for ( int i = 0; i < NUM_ADDR_ANONYMIZATION_METHODS; ++i )
|
||||
ip_anonymizer[i] = 0;
|
||||
|
||||
if ( packet_sort_window > 0 )
|
||||
packet_sorter = new PacketSortGlobalPQ();
|
||||
|
@ -627,7 +588,6 @@ void net_finish(int drain_events)
|
|||
}
|
||||
|
||||
delete pkt_dumper;
|
||||
delete pkt_transformed_dumper;
|
||||
|
||||
// fprintf(stderr, "uhash: %d/%d\n", hash_cnt_uhash, hash_cnt_all);
|
||||
|
||||
|
@ -648,11 +608,6 @@ void net_delete()
|
|||
delete sessions;
|
||||
delete packet_sorter;
|
||||
|
||||
// Can't put this in net_finish() because packets might be
|
||||
// dumped when connections are deleted.
|
||||
if ( transformed_pkt_dump )
|
||||
delete transformed_pkt_dump;
|
||||
|
||||
for ( int i = 0; i < NUM_ADDR_ANONYMIZATION_METHODS; ++i )
|
||||
delete ip_anonymizer[i];
|
||||
}
|
||||
|
|
|
@ -15,9 +15,8 @@
|
|||
|
||||
extern void net_init(name_list& interfaces, name_list& readfiles,
|
||||
name_list& netflows, name_list& flowfiles,
|
||||
const char* writefile, const char* transformed_writefile,
|
||||
const char* filter, const char* secondary_filter,
|
||||
int do_watchdog);
|
||||
const char* writefile, const char* filter,
|
||||
const char* secondary_filter, int do_watchdog);
|
||||
extern void net_run();
|
||||
extern void net_get_final_stats();
|
||||
extern void net_finish(int drain_events);
|
||||
|
@ -91,7 +90,6 @@ declare(PList,PktSrc);
|
|||
extern PList(PktSrc) pkt_srcs;
|
||||
|
||||
extern PktDumper* pkt_dumper; // where to save packets
|
||||
extern PktDumper* pkt_transformed_dumper;
|
||||
|
||||
extern char* writefile;
|
||||
|
||||
|
|
|
@ -41,8 +41,4 @@ struct ltipid {
|
|||
typedef set<IP_ID, ltipid> IP_IDSet;
|
||||
uint16 NextIP_ID(const uint32 src_addr, const uint16 id);
|
||||
|
||||
extern PacketDumper* transformed_pkt_dump;
|
||||
extern PacketDumper* source_pkt_dump;
|
||||
extern int transformed_pkt_dump_MTU;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
// $Id:$
|
||||
//
|
||||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "TCP_Rewriter.h"
|
||||
#include "UDP_Rewriter.h"
|
||||
|
||||
// The following two are called from .bif's to obtain handle of Rewriter.
|
||||
Rewriter* get_trace_rewriter(Val* conn_val)
|
||||
{
|
||||
Connection* conn = (Connection*) conn_val->AsRecordVal()->GetOrigin();
|
||||
return get_trace_rewriter(conn);
|
||||
}
|
||||
|
||||
Rewriter* get_trace_rewriter(Connection* conn)
|
||||
{
|
||||
if ( ! conn ||
|
||||
(conn->ConnTransport() != TRANSPORT_TCP &&
|
||||
conn->ConnTransport() != TRANSPORT_UDP) )
|
||||
internal_error("connection for the trace rewriter does not exist");
|
||||
|
||||
Rewriter* rewriter = conn->TraceRewriter();
|
||||
if ( rewriter )
|
||||
return rewriter;
|
||||
|
||||
if ( ! transformed_pkt_dump )
|
||||
return 0; // okay if we don't have an output file
|
||||
|
||||
else if ( ! conn->RewritingTrace() )
|
||||
builtin_run_time("flag rewriting_..._trace is not set properly");
|
||||
else
|
||||
internal_error("trace rewriter not initialized");
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
// $Id:$
|
||||
//
|
||||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#ifndef rewriter_h
|
||||
#define rewriter_h
|
||||
|
||||
class TracePacket;
|
||||
|
||||
class Rewriter {
|
||||
public:
|
||||
virtual ~Rewriter() {};
|
||||
|
||||
virtual void Done() {};
|
||||
|
||||
virtual void WriteData(int is_orig, int len, const u_char* data) = 0;
|
||||
virtual void WriteData(int is_orig, const char* data) = 0;
|
||||
virtual void WriteData(int is_orig, int len, const char* data) = 0;
|
||||
virtual void WriteData(int is_orig, const BroString* str) = 0;
|
||||
|
||||
virtual void Push(int is_orig) = 0;
|
||||
|
||||
virtual void AbortPackets(int apply_to_future) = 0;
|
||||
virtual void CommitPackets(int apply_to_future) = 0;
|
||||
|
||||
virtual unsigned int ReserveSlot() = 0;
|
||||
virtual int SeekSlot(unsigned int slot) = 0;
|
||||
virtual int ReturnFromSlot() = 0;
|
||||
virtual int ReleaseSlot(unsigned int slot) = 0;
|
||||
|
||||
// Needed by all rewriters.
|
||||
virtual TracePacket* CurrentPacket() const = 0;
|
||||
virtual TracePacket* RewritePacket() const = 0;
|
||||
|
||||
// Whether to not anonymize client/server IP addresses.
|
||||
virtual int LeaveAddrInTheClear(int is_orig) = 0;
|
||||
};
|
||||
|
||||
extern Rewriter* get_trace_rewriter(Val* conn_val);
|
||||
extern Rewriter* get_trace_rewriter(Connection* conn);
|
||||
|
||||
// This is the actual packet.
|
||||
class TracePacket {
|
||||
public:
|
||||
virtual ~TracePacket() { }
|
||||
|
||||
virtual RecordVal* PacketVal() = 0;
|
||||
virtual double TimeStamp() const = 0;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -206,8 +206,6 @@ public:
|
|||
DCE_RPC_Session::any_dce_rpc_event();
|
||||
}
|
||||
|
||||
int RewritingTrace() { return BifConst::rewriting_smb_trace; }
|
||||
|
||||
protected:
|
||||
SMB_Session* smb_session;
|
||||
Contents_SMB* o_smb;
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include "SMTP.h"
|
||||
#include "Event.h"
|
||||
#include "ContentLine.h"
|
||||
#include "TCP_Rewriter.h"
|
||||
|
||||
#undef SMTP_CMD_DEF
|
||||
#define SMTP_CMD_DEF(cmd) #cmd,
|
||||
|
@ -885,5 +884,3 @@ void SMTP_Analyzer::EndData()
|
|||
mail = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#include "smtp-rw.bif.func_def"
|
||||
|
|
|
@ -46,8 +46,6 @@ public:
|
|||
virtual void DeliverStream(int len, const u_char* data, bool orig);
|
||||
virtual void ConnectionFinished(int half_finished);
|
||||
virtual void Undelivered(int seq, int len, bool orig);
|
||||
virtual int RewritingTrace()
|
||||
{ return BifConst::rewriting_smtp_trace || TCP_ApplicationAnalyzer::RewritingTrace(); }
|
||||
|
||||
void SkipData() { skip_data = 1; } // skip delivery of data lines
|
||||
|
||||
|
|
|
@ -632,13 +632,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
|
|||
record_packet, record_content,
|
||||
hdr, pkt, hdr_size);
|
||||
|
||||
// Override content record setting according to
|
||||
// flags set by the policy script.
|
||||
if ( BifConst::dump_original_packets_if_not_rewriting )
|
||||
record_packet = record_content = 1;
|
||||
if ( BifConst::dump_selected_source_packets )
|
||||
record_packet = record_content = 0;
|
||||
|
||||
if ( f )
|
||||
{
|
||||
// Above we already recorded the fragment in its entirety.
|
||||
|
@ -646,7 +639,7 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
|
|||
Remove(f); // ###
|
||||
}
|
||||
|
||||
else if ( record_packet && ! conn->RewritingTrace() )
|
||||
else if ( record_packet )
|
||||
{
|
||||
if ( record_content )
|
||||
dump_this_packet = 1; // save the whole thing
|
||||
|
|
57
src/TCP.cc
57
src/TCP.cc
|
@ -7,7 +7,6 @@
|
|||
#include "File.h"
|
||||
#include "TCP.h"
|
||||
#include "TCP_Reassembler.h"
|
||||
#include "TCP_Rewriter.h"
|
||||
#include "OSFinger.h"
|
||||
#include "Event.h"
|
||||
|
||||
|
@ -47,23 +46,12 @@ TCP_Analyzer::TCP_Analyzer(Connection* conn)
|
|||
finished = 0;
|
||||
reassembling = 0;
|
||||
first_packet_seen = 0;
|
||||
src_pkt_writer = 0;
|
||||
|
||||
orig = new TCP_Endpoint(this, 1);
|
||||
resp = new TCP_Endpoint(this, 0);
|
||||
|
||||
orig->SetPeer(resp);
|
||||
resp->SetPeer(orig);
|
||||
|
||||
if ( BifConst::dump_selected_source_packets )
|
||||
{
|
||||
if ( source_pkt_dump )
|
||||
src_pkt_writer =
|
||||
new TCP_SourcePacketWriter(this, source_pkt_dump);
|
||||
else if ( transformed_pkt_dump )
|
||||
src_pkt_writer =
|
||||
new TCP_SourcePacketWriter(this, transformed_pkt_dump);
|
||||
}
|
||||
}
|
||||
|
||||
TCP_Analyzer::~TCP_Analyzer()
|
||||
|
@ -73,7 +61,6 @@ TCP_Analyzer::~TCP_Analyzer()
|
|||
|
||||
delete orig;
|
||||
delete resp;
|
||||
delete src_pkt_writer;
|
||||
}
|
||||
|
||||
void TCP_Analyzer::Init()
|
||||
|
@ -81,12 +68,6 @@ void TCP_Analyzer::Init()
|
|||
Analyzer::Init();
|
||||
LOOP_OVER_GIVEN_CHILDREN(i, packet_children)
|
||||
(*i)->Init();
|
||||
|
||||
// Can't put this in construction because RewritingTrace() is virtual.
|
||||
if ( transformed_pkt_dump && Conn()->RewritingTrace() )
|
||||
SetTraceRewriter(new TCP_Rewriter(this, transformed_pkt_dump,
|
||||
transformed_pkt_dump_MTU,
|
||||
BifConst::requires_trace_commitment));
|
||||
}
|
||||
|
||||
void TCP_Analyzer::Done()
|
||||
|
@ -1047,16 +1028,6 @@ void TCP_Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig,
|
|||
tcp_hdr_len <= uint32(caplen) )
|
||||
ParseTCPOptions(tp, TCPOptionEvent, this, is_orig, 0);
|
||||
|
||||
if ( TraceRewriter() && current_hdr )
|
||||
{
|
||||
TCP_Rewriter* r = (TCP_Rewriter*) TraceRewriter();
|
||||
r->NextPacket(is_orig, t, current_hdr, current_pkt,
|
||||
current_hdr_size, ip->IP4_Hdr(), tp);
|
||||
}
|
||||
|
||||
if ( src_pkt_writer && current_hdr )
|
||||
src_pkt_writer->NextPacket(current_hdr, current_pkt);
|
||||
|
||||
if ( DEBUG_tcp_data_sent )
|
||||
{
|
||||
DEBUG_MSG("%.6f before DataSent: len=%d caplen=%d skip=%d\n",
|
||||
|
@ -1757,8 +1728,6 @@ void TCP_Analyzer::EndpointEOF(TCP_Reassembler* endp)
|
|||
LOOP_OVER_CONST_CHILDREN(i)
|
||||
static_cast<TCP_ApplicationAnalyzer*>(*i)->EndpointEOF(endp->IsOrig());
|
||||
|
||||
TraceRewriterEOF(endp);
|
||||
|
||||
if ( close_deferred )
|
||||
{
|
||||
if ( DataPending(endp->Endpoint()) )
|
||||
|
@ -1776,25 +1745,6 @@ void TCP_Analyzer::EndpointEOF(TCP_Reassembler* endp)
|
|||
}
|
||||
}
|
||||
|
||||
void TCP_Analyzer::TraceRewriterEOF(TCP_Reassembler* endp)
|
||||
{
|
||||
const analyzer_list& children(GetChildren());
|
||||
LOOP_OVER_CONST_CHILDREN(i)
|
||||
static_cast<TCP_ApplicationAnalyzer*>(*i)->TraceRewriterEOF(endp->IsOrig());
|
||||
|
||||
TCP_Rewriter* r = (TCP_Rewriter*) TraceRewriter();
|
||||
if ( r )
|
||||
{
|
||||
// Add a FIN packet if there is one in the original trace.
|
||||
int FIN_cnt = endp->IsOrig() ?
|
||||
endp->GetTCPAnalyzer()->Orig()->FIN_cnt :
|
||||
endp->GetTCPAnalyzer()->Resp()->FIN_cnt;
|
||||
|
||||
if ( FIN_cnt > 0 )
|
||||
r->ScheduleFIN(endp->IsOrig());
|
||||
}
|
||||
}
|
||||
|
||||
void TCP_Analyzer::PacketWithRST()
|
||||
{
|
||||
const analyzer_list& children(GetChildren());
|
||||
|
@ -1911,13 +1861,6 @@ void TCP_ApplicationAnalyzer::EndpointEOF(bool is_orig)
|
|||
static_cast<TCP_SupportAnalyzer*>(sa)->EndpointEOF(is_orig);
|
||||
}
|
||||
|
||||
void TCP_ApplicationAnalyzer::TraceRewriterEOF(bool is_orig)
|
||||
{
|
||||
SupportAnalyzer* sa = is_orig ? orig_supporters : resp_supporters;
|
||||
for ( ; sa; sa = sa->Sibling() )
|
||||
static_cast<TCP_SupportAnalyzer*>(sa)->TraceRewriterEOF(is_orig);
|
||||
}
|
||||
|
||||
void TCP_ApplicationAnalyzer::ConnectionClosed(TCP_Endpoint* endpoint,
|
||||
TCP_Endpoint* peer, int gen_event)
|
||||
{
|
||||
|
|
11
src/TCP.h
11
src/TCP.h
|
@ -7,7 +7,6 @@
|
|||
|
||||
#include "Analyzer.h"
|
||||
#include "TCP.h"
|
||||
#include "Rewriter.h"
|
||||
#include "PacketDumper.h"
|
||||
|
||||
// We define two classes here:
|
||||
|
@ -18,8 +17,6 @@
|
|||
class PIA_TCP;
|
||||
class TCP_ApplicationAnalyzer;
|
||||
class TCP_Reassembler;
|
||||
class TCP_Rewriter;
|
||||
class TCP_SourcePacketWriter;
|
||||
|
||||
class TCP_Flags {
|
||||
public:
|
||||
|
@ -75,9 +72,6 @@ public:
|
|||
virtual void SetContentsFile(unsigned int direction, BroFile* f);
|
||||
virtual BroFile* GetContentsFile(unsigned int direction) const;
|
||||
|
||||
TCP_SourcePacketWriter* SourcePacketWriter() const
|
||||
{ return src_pkt_writer; }
|
||||
|
||||
// Callback to process a TCP option.
|
||||
typedef int (*proc_tcp_option_t)(unsigned int opt, unsigned int optlen,
|
||||
const u_char* option, TCP_Analyzer* analyzer,
|
||||
|
@ -220,7 +214,6 @@ protected:
|
|||
void ConnDeleteTimer(double t) { Conn()->DeleteTimer(t); }
|
||||
|
||||
void EndpointEOF(TCP_Reassembler* endp);
|
||||
void TraceRewriterEOF(TCP_Reassembler* endp);
|
||||
void ConnectionClosed(TCP_Endpoint* endpoint,
|
||||
TCP_Endpoint* peer, int gen_event);
|
||||
void ConnectionFinished(int half_finished);
|
||||
|
@ -247,8 +240,6 @@ private:
|
|||
|
||||
analyzer_list packet_children;
|
||||
|
||||
TCP_SourcePacketWriter* src_pkt_writer;
|
||||
|
||||
unsigned int first_packet_seen: 2;
|
||||
unsigned int reassembling: 1;
|
||||
unsigned int is_partial: 1;
|
||||
|
@ -288,7 +279,6 @@ public:
|
|||
|
||||
// The given endpoint's data delivery is complete.
|
||||
virtual void EndpointEOF(bool is_orig);
|
||||
virtual void TraceRewriterEOF(bool is_orig);
|
||||
|
||||
// Called whenever an end enters TCP_ENDPOINT_CLOSED or
|
||||
// TCP_ENDPOINT_RESET. If gen_event is true and the connection
|
||||
|
@ -332,7 +322,6 @@ public:
|
|||
|
||||
// These are passed on from TCP_Analyzer.
|
||||
virtual void EndpointEOF(bool is_orig) { }
|
||||
virtual void TraceRewriterEOF(bool is_orig) { }
|
||||
virtual void ConnectionClosed(TCP_Endpoint* endpoint,
|
||||
TCP_Endpoint* peer, int gen_event) { }
|
||||
virtual void ConnectionFinished(int half_finished) { }
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#include "Net.h"
|
||||
#include "NetVar.h"
|
||||
#include "TCP.h"
|
||||
#include "TCP_Rewriter.h"
|
||||
#include "TCP_Reassembler.h"
|
||||
#include "Sessions.h"
|
||||
#include "Event.h"
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
#include "TCP_Reassembler.h"
|
||||
#include "TCP.h"
|
||||
#include "TCP_Endpoint.h"
|
||||
#include "TCP_Rewriter.h"
|
||||
|
||||
// Only needed for gap_report events.
|
||||
#include "Event.h"
|
||||
|
@ -185,10 +184,6 @@ void TCP_Reassembler::Undelivered(int up_to_seq)
|
|||
// one for filtered traces, and may fail, for example, when
|
||||
// the SYN packet carries data.
|
||||
//
|
||||
// Note, this check will confuse the EOF checker (and cause a
|
||||
// missing FIN in the rewritten trace) when the content gap
|
||||
// in the middle is discovered only after the FIN packet.
|
||||
|
||||
// Skip the undelivered part without reporting to the endpoint.
|
||||
skip_deliveries = 1;
|
||||
}
|
||||
|
@ -235,11 +230,6 @@ void TCP_Reassembler::Undelivered(int up_to_seq)
|
|||
dst_analyzer->ConnectionEvent(content_gap, vl);
|
||||
}
|
||||
|
||||
TCP_Rewriter* r = (TCP_Rewriter*)
|
||||
dst_analyzer->Conn()->TraceRewriter();
|
||||
if ( r )
|
||||
r->ContentGap(is_orig, len);
|
||||
|
||||
if ( type == Direct )
|
||||
dst_analyzer->NextUndelivered(last_reassem_seq,
|
||||
len, is_orig);
|
||||
|
|
1575
src/TCP_Rewriter.cc
1575
src/TCP_Rewriter.cc
File diff suppressed because it is too large
Load diff
|
@ -1,401 +0,0 @@
|
|||
// $Id: TCP_Rewriter.h 6916 2009-09-24 20:48:36Z vern $
|
||||
|
||||
#ifndef tcp_rewriter_h
|
||||
#define tcp_rewriter_h
|
||||
|
||||
#include <queue>
|
||||
#include <set>
|
||||
using namespace std;
|
||||
|
||||
#include <pcap.h>
|
||||
|
||||
#include "Val.h"
|
||||
#include "TCP.h"
|
||||
#include "Anon.h"
|
||||
#include "Analyzer.h"
|
||||
|
||||
#include "PacketDumper.h"
|
||||
#include "Rewriter.h"
|
||||
|
||||
class TCP_Rewriter;
|
||||
|
||||
class TCP_TracePacket : public BroObj, virtual public TracePacket {
|
||||
public:
|
||||
TCP_TracePacket(TCP_Rewriter* trace_rewriter,
|
||||
int packet_seq, double t, int is_orig,
|
||||
const struct pcap_pkthdr* hdr,
|
||||
int MTU, int initial_size);
|
||||
~TCP_TracePacket();
|
||||
|
||||
int AppendLinkHeader(const u_char* chunk, int len);
|
||||
int AppendIPHeader(const u_char* chunk, int len);
|
||||
int AppendTCPHeader(const u_char* chunk, int len);
|
||||
int AppendData(const u_char* chunk, int len);
|
||||
|
||||
// Finish() is called before dumping the packet. It sets length
|
||||
// fields and computes checksums in TCP/IP headers.
|
||||
int Finish(struct pcap_pkthdr*& hdr, const u_char*& pkt, int& length,
|
||||
ipaddr32_t anon_src, ipaddr32_t anon_dst);
|
||||
|
||||
void Reuse();
|
||||
int IsReuse() const { return reuse; }
|
||||
|
||||
double TimeStamp() const { return timestamp; }
|
||||
int IsOrig() const { return is_orig; }
|
||||
|
||||
const struct pcap_pkthdr* Header() const { return &pcap_hdr; }
|
||||
|
||||
const u_char* Buffer() const { return pkt; }
|
||||
int Length() const { return buffer_offset; }
|
||||
|
||||
// Note that Space() does not depend on buffer_size, but depends on MTU.
|
||||
int Space() const { return mtu - buffer_offset; }
|
||||
int IsEmpty() const
|
||||
{ return SeqLength() == 0 && ! GetTCP_Flag(TH_RST); }
|
||||
|
||||
uint32 GetSeq() const;
|
||||
void SetSeq(uint32 seq);
|
||||
|
||||
uint32 GetAck() const;
|
||||
void SetAck(uint32 ack);
|
||||
|
||||
int GetTCP_Flag(int which) const;
|
||||
void SetTCP_Flag(int which, int value);
|
||||
|
||||
int SeqLength() const;
|
||||
int PayloadLength() const;
|
||||
|
||||
int FINScheduled() const { return FIN_scheduled; }
|
||||
void ScheduleFIN(int fin = 1) { FIN_scheduled = fin; }
|
||||
|
||||
int OnHold() const { return on_hold; }
|
||||
void SetOnHold(int x) { on_hold = x; }
|
||||
|
||||
int HasReservedSlot() const { return has_reserved_slot; }
|
||||
void AddReservedSlot() { ++has_reserved_slot; }
|
||||
|
||||
int PredictedAsEmptyPlaceHolder() const
|
||||
{ return predicted_as_empty_place_holder; }
|
||||
void PredictAsEmptyPlaceHolder()
|
||||
{ predicted_as_empty_place_holder = 1; }
|
||||
|
||||
// Whether the ACK on this packet confirms a content gap on
|
||||
// the opposite direction.
|
||||
int SeqGap() const { return seq_gap; }
|
||||
void SetSeqGap(int len) { seq_gap = len; }
|
||||
|
||||
int PacketSeq() const { return packet_seq; }
|
||||
TCP_Rewriter* TraceRewriter() const { return trace_rewriter; }
|
||||
|
||||
RecordVal* PacketVal();
|
||||
void Describe(ODesc* d) const { packet_val->Describe(d); }
|
||||
|
||||
protected:
|
||||
int Append(const u_char* chunk, int len);
|
||||
|
||||
RecordVal* packet_val;
|
||||
TCP_Rewriter* trace_rewriter;
|
||||
double timestamp;
|
||||
int packet_seq;
|
||||
int is_orig;
|
||||
struct pcap_pkthdr pcap_hdr;
|
||||
int mtu;
|
||||
u_char* pkt; // of maximal length MTU
|
||||
int ip_offset, tcp_offset, data_offset;
|
||||
int buffer_size;
|
||||
int buffer_offset;
|
||||
int reuse; // whether it is an artificially replicated packet
|
||||
int FIN_scheduled;
|
||||
int on_hold; // do not dump it in Flush()
|
||||
int seq_gap;
|
||||
int has_reserved_slot;
|
||||
int predicted_as_empty_place_holder;
|
||||
};
|
||||
|
||||
// How a unidirectional flow ends.
|
||||
#define END_BY_FIN 1
|
||||
#define END_BY_RST 2
|
||||
#define END_BY_PEER_RST 4
|
||||
|
||||
class TCP_RewriterEndpoint {
|
||||
public:
|
||||
TCP_RewriterEndpoint(TCP_Rewriter* rewriter);
|
||||
~TCP_RewriterEndpoint();
|
||||
|
||||
void Init();
|
||||
|
||||
// A packet that contains a TCP segment.
|
||||
void NextPacket(TCP_TracePacket* p);
|
||||
void WriteData(int len, const u_char* data);
|
||||
void SkipGap(int len);
|
||||
|
||||
void Push();
|
||||
void ReqAck();
|
||||
void Flush();
|
||||
void Reset(int self);
|
||||
|
||||
uint32 NextSeq() const { return next_seq; }
|
||||
int HasPacket() const { return next_packet != 0; }
|
||||
inline TCP_Analyzer* Analyzer() const;
|
||||
|
||||
protected:
|
||||
TCP_Rewriter* rewriter; // TCP rewriter for the connection
|
||||
TCP_RewriterEndpoint* peer; // the peer TCP rewriter endpoint
|
||||
TCP_Endpoint* endp; // the corresponding TCP endpoint
|
||||
|
||||
TCP_TracePacket* next_packet;
|
||||
std::queue<BroString*> prolog;
|
||||
|
||||
double last_packet_time;
|
||||
uint32 start_seq; // start seq -- sent in SYN
|
||||
uint32 next_seq; // seq of next packet
|
||||
uint32 last_ack; // last acknowledgement seq
|
||||
|
||||
int please_flush;
|
||||
int flush_scheduled;
|
||||
int flushed;
|
||||
int established;
|
||||
int end_of_data; // is it really useful?
|
||||
int there_is_a_gap;
|
||||
|
||||
// Move onto the next packet header.
|
||||
void SetNextPacket(TCP_TracePacket* p);
|
||||
|
||||
void PurgeProlog();
|
||||
|
||||
// Pour data into the current packet (next_packet).
|
||||
void DoWriteData(int len, const u_char* data);
|
||||
|
||||
// Push the current packet (next_packet) to dumper.
|
||||
void PushPacket();
|
||||
|
||||
// Please flush this endpoint after draining events.
|
||||
void ScheduleFlush();
|
||||
|
||||
void GenerateFIN();
|
||||
|
||||
// Whether the packet is a "place holder" packet, i.e. it's
|
||||
// harmless to omit the packet (except missing the timestamp
|
||||
// it contains).
|
||||
int IsPlaceHolderPacket(TCP_TracePacket* p);
|
||||
|
||||
void Weird(const char* name) const;
|
||||
};
|
||||
|
||||
class TCP_RewriteSlot {
|
||||
public:
|
||||
TCP_RewriteSlot(TCP_TracePacket* p, unsigned int slot_number);
|
||||
|
||||
void WriteData(int is_orig, int len, const u_char* data);
|
||||
|
||||
void Dump();
|
||||
|
||||
unsigned int Number() const { return slot_number; }
|
||||
TCP_TracePacket* Packet() const { return packet; }
|
||||
|
||||
bool isEmpty() const { return buf.empty(); }
|
||||
protected:
|
||||
TCP_Rewriter* rewriter;
|
||||
TCP_TracePacket* packet;
|
||||
unsigned int slot_number;
|
||||
std::queue<BroString*> buf;
|
||||
};
|
||||
|
||||
class TCP_Rewriter : public Rewriter {
|
||||
public:
|
||||
TCP_Rewriter(TCP_Analyzer* analyzer, PacketDumper* dumper, int MTU,
|
||||
int wait_for_commitment = 0);
|
||||
virtual ~TCP_Rewriter();
|
||||
virtual void Done();
|
||||
void Funeral();
|
||||
|
||||
// Phase 1 methods: called in packet processing.
|
||||
|
||||
// A TCP/IP packet.
|
||||
void NextPacket(int is_orig, double t,
|
||||
const struct pcap_pkthdr* pcap_hdr,
|
||||
const u_char* pcap_pkt, // link level header
|
||||
int hdr_size, // link level header size
|
||||
const struct ip* ip,
|
||||
const struct tcphdr* tp);
|
||||
void ContentGap(int is_orig, int len);
|
||||
void ScheduleFIN(int is_orig);
|
||||
|
||||
|
||||
// Phase 2 methods: called in event processing.
|
||||
|
||||
void WriteData(int is_orig, int len, const u_char* data);
|
||||
void WriteData(int is_orig, const char* data)
|
||||
{ WriteData(is_orig, strlen(data), data); }
|
||||
void WriteData(int is_orig, int len, const char* data)
|
||||
{ WriteData(is_orig, len, (const u_char*) data); }
|
||||
void WriteData(int is_orig, const BroString* str)
|
||||
{ WriteData(is_orig, str->Len(), str->Bytes()); }
|
||||
void WriteData(int is_orig, StringVal* str)
|
||||
{ WriteData(is_orig, str->AsString()); }
|
||||
void Push(int is_orig);
|
||||
|
||||
// When wait_for_commitment = 1, packets are not dumped until
|
||||
// CommitPackets().
|
||||
// When apply_to_future = 1, the same decision holds for future
|
||||
// packets as well.
|
||||
//
|
||||
// Regarding why AbortPackets() takes an apply_to_future flag:
|
||||
//
|
||||
// The model is that there can be multiple commit/abort stages
|
||||
// during the course of a connection. At the end of each
|
||||
// stage, a commit or abort decision is made for packets
|
||||
// generated during the stage. A possible scenario is that
|
||||
// user may want to delete a middle part of a conversation
|
||||
// while keeping the parts before and after intact, and cannot
|
||||
// make the decision until the end of the middle part.
|
||||
|
||||
void AbortPackets(int apply_to_future);
|
||||
void CommitPackets(int apply_to_future);
|
||||
|
||||
unsigned int ReserveSlot();
|
||||
int SeekSlot(unsigned int slot);
|
||||
int ReturnFromSlot();
|
||||
int ReleaseSlot(unsigned int slot);
|
||||
|
||||
// Do not anonymize client/server IP address
|
||||
int LeaveAddrInTheClear(int is_orig);
|
||||
|
||||
|
||||
// Phase 3 methods: called in flushing after events.
|
||||
// (None, because flushing is done through accessing endpoints directly.)
|
||||
|
||||
// Other methods.
|
||||
|
||||
void DumpPacket(TCP_RewriterEndpoint* endp, TCP_TracePacket* p);
|
||||
|
||||
void Weird(const char* name) const { analyzer->Weird(name); }
|
||||
TCP_Analyzer* Analyzer() const { return analyzer; }
|
||||
|
||||
TCP_Endpoint* GetEndpoint(TCP_RewriterEndpoint* endp);
|
||||
TCP_RewriterEndpoint* GetPeer(TCP_RewriterEndpoint* endp);
|
||||
|
||||
TracePacket* CurrentPacket() const { return current_packet; }
|
||||
TracePacket* RewritePacket() const { return next_packet; }
|
||||
|
||||
// Needs to be static because it's passed as a pointer-to-function
|
||||
// rather than pointer-to-member-function.
|
||||
static int RewriteTCPOption(unsigned int opt, unsigned int optlen,
|
||||
const u_char* option, TCP_Analyzer* analyzer,
|
||||
bool is_orig, void* cookie);
|
||||
|
||||
protected:
|
||||
// Under normal circumstances, we always rewrite into the
|
||||
// "current packet" of the connection. However, sometimes we'd
|
||||
// want to look a few packets ahead before deciding what to
|
||||
// rewrite, in which case we may use {hold,release}_packet to
|
||||
// specify the packet we are writing to.
|
||||
|
||||
// rewrite_packet (next_packet) always equals to
|
||||
// current_packet under *normal mode*. hold_packet(p) dumps
|
||||
// all packets *before* p, fixes rewrite_packet at p and turns
|
||||
// the connection into *look-ahead* mode. Under look-ahead
|
||||
// mode, release_packet(c) dumps all packets of on hold
|
||||
// connection and makes the connection returns to normal mode
|
||||
// so that rewrite_packet changes along with current_packet.
|
||||
|
||||
// When a packet is held, it is illegal to write to packets on
|
||||
// the other half of the connection.
|
||||
|
||||
// Release next_packet
|
||||
void ReleaseNextPacket();
|
||||
|
||||
// Hold packet p and release all packets before p.
|
||||
void HoldPacket(TCP_TracePacket* p);
|
||||
|
||||
// Release all packets on hold and dump all the packets except
|
||||
// the last one, which will be flushed at the end of the event.
|
||||
void ReleasePacketsOnHold();
|
||||
|
||||
void CleanUpEmptyPlaceHolders();
|
||||
void DoWriteData(int is_orig, int len, const u_char* data);
|
||||
|
||||
TCP_RewriterEndpoint* Endp(int is_orig) const
|
||||
{ return is_orig ? orig : resp; }
|
||||
|
||||
TCP_Analyzer* analyzer;
|
||||
PacketDumper* dumper;
|
||||
TCP_RewriterEndpoint* orig;
|
||||
TCP_RewriterEndpoint* resp;
|
||||
int MTU;
|
||||
int wait_for_commitment;
|
||||
int discard_packets;
|
||||
std::queue<char*> uncommited_packet_queue;
|
||||
int next_packet_seq;
|
||||
int packets_rewritten;
|
||||
ipaddr32_t anon_addr[2];
|
||||
int pending_content_gap;
|
||||
|
||||
TCP_TracePacket* current_packet;
|
||||
TCP_TracePacket* next_packet;
|
||||
std::deque<TCP_TracePacket*> packets_on_hold;
|
||||
int holding_packets;
|
||||
|
||||
TCP_RewriteSlot* current_slot;
|
||||
TCP_RewriteSlot* first_slot;
|
||||
TCP_RewriteSlot* last_slot;
|
||||
std::deque<TCP_RewriteSlot*> slot_queue;
|
||||
typedef map<unsigned int, TCP_RewriteSlot*> slot_map_t;
|
||||
slot_map_t reserved_slots;
|
||||
int highest_slot_number;
|
||||
|
||||
TCP_RewriteSlot* add_slot();
|
||||
TCP_RewriteSlot* find_slot(unsigned int slot);
|
||||
|
||||
friend class TCP_RewriteSlot;
|
||||
int answered[2];
|
||||
};
|
||||
|
||||
inline TCP_Analyzer* TCP_RewriterEndpoint::Analyzer() const
|
||||
{
|
||||
return rewriter->Analyzer();
|
||||
}
|
||||
|
||||
// "Please flush the rewriter endpoint after event processing."
|
||||
extern void schedule_flush(TCP_RewriterEndpoint* endp);
|
||||
|
||||
// "Please call rewriter->Funeral() after event processing."
|
||||
extern void schedule_funeral(TCP_Rewriter* rewriter);
|
||||
|
||||
extern void flush_rewriter_packet();
|
||||
|
||||
class TCP_SourcePacket {
|
||||
public:
|
||||
TCP_SourcePacket(const struct pcap_pkthdr* pcap_hdr, const u_char* pcap_pkt);
|
||||
~TCP_SourcePacket();
|
||||
|
||||
int Len() const { return hdr.caplen; }
|
||||
const u_char* Pkt() const { return pkt; }
|
||||
const struct pcap_pkthdr* Hdr() const { return &hdr; }
|
||||
|
||||
protected:
|
||||
struct pcap_pkthdr hdr;
|
||||
u_char* pkt;
|
||||
};
|
||||
|
||||
// Write selected original packets to the trace
|
||||
class TCP_SourcePacketWriter {
|
||||
public:
|
||||
TCP_SourcePacketWriter(TCP_Analyzer* /* analyzer */,
|
||||
PacketDumper* arg_dumper);
|
||||
~TCP_SourcePacketWriter();
|
||||
|
||||
void NextPacket(const struct pcap_pkthdr* pcap_hdr,
|
||||
const u_char* pcap_pkt);
|
||||
void Dump();
|
||||
void Abort();
|
||||
|
||||
protected:
|
||||
PacketDumper* dumper;
|
||||
std::queue<TCP_SourcePacket*> source_packets;
|
||||
void Purge(bool dump);
|
||||
};
|
||||
|
||||
extern TCP_SourcePacketWriter* get_src_pkt_writer(TCP_Analyzer* analyzer);
|
||||
|
||||
#endif
|
15
src/UDP.cc
15
src/UDP.cc
|
@ -7,7 +7,6 @@
|
|||
#include "Net.h"
|
||||
#include "NetVar.h"
|
||||
#include "UDP.h"
|
||||
#include "UDP_Rewriter.h"
|
||||
|
||||
UDP_Analyzer::UDP_Analyzer(Connection* conn)
|
||||
: TransportLayerAnalyzer(AnalyzerTag::UDP, conn)
|
||||
|
@ -25,9 +24,6 @@ UDP_Analyzer::~UDP_Analyzer()
|
|||
|
||||
void UDP_Analyzer::Init()
|
||||
{
|
||||
if ( transformed_pkt_dump && RewritingTrace() )
|
||||
SetTraceRewriter(new UDP_Rewriter(this, transformed_pkt_dump_MTU,
|
||||
transformed_pkt_dump));
|
||||
}
|
||||
|
||||
void UDP_Analyzer::Done()
|
||||
|
@ -164,17 +160,6 @@ void UDP_Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig,
|
|||
|
||||
if ( caplen >= len )
|
||||
ForwardPacket(len, data, is_orig, seq, ip, caplen);
|
||||
|
||||
if ( TraceRewriter() && current_hdr )
|
||||
((UDP_Rewriter*) TraceRewriter())->NextPacket(is_orig,
|
||||
current_timestamp, current_hdr, current_pkt,
|
||||
current_hdr_size, ip->IP4_Hdr(), up);
|
||||
|
||||
#if 0
|
||||
// XXX: needs to be implemented fully!
|
||||
if ( src_pkt_writer && current_hdr )
|
||||
src_pkt_writer->NextPacket(current_hdr, current_pkt);
|
||||
#endif
|
||||
}
|
||||
|
||||
void UDP_Analyzer::UpdateEndpointVal(RecordVal* endp, int is_orig)
|
||||
|
|
|
@ -6,9 +6,6 @@
|
|||
#define udp_h
|
||||
|
||||
#include "Analyzer.h"
|
||||
#include "Rewriter.h"
|
||||
|
||||
class UDP_Rewriter;
|
||||
|
||||
typedef enum {
|
||||
UDP_INACTIVE, // no packet seen
|
||||
|
@ -27,10 +24,6 @@ public:
|
|||
|
||||
static bool Available() { return true; }
|
||||
|
||||
// -- XXX -- only want to return yes if the protocol flag is
|
||||
// on similar to TCP. (e.g. FTP_Connection etc.) /mc
|
||||
int RewritingTrace() const { return 0; }
|
||||
|
||||
protected:
|
||||
virtual void Done();
|
||||
virtual void DeliverPacket(int len, const u_char* data, bool orig,
|
||||
|
|
|
@ -1,362 +0,0 @@
|
|||
// $Id:$
|
||||
//
|
||||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Event.h"
|
||||
#include "Net.h"
|
||||
#include "UDP_Rewriter.h"
|
||||
|
||||
#define MSG_PREFIX "UDP trace rewriter: "
|
||||
#define DEBUG_MSG_A(x...)
|
||||
// #define DEBUG_MSG_A DEBUG_MSG
|
||||
|
||||
|
||||
UDP_Rewriter::UDP_Rewriter(Analyzer* arg_analyzer, int arg_MTU,
|
||||
PacketDumper* arg_dumper)
|
||||
{
|
||||
analyzer = arg_analyzer;
|
||||
MTU = arg_MTU;
|
||||
dumper = arg_dumper;
|
||||
packets_rewritten = 0;
|
||||
current_packet = next_packet = 0;
|
||||
|
||||
if ( BifConst::anonymize_ip_addr )
|
||||
{
|
||||
anon_addr[0] = anonymize_ip(to_v4_addr(analyzer->Conn()->OrigAddr()),
|
||||
ORIG_ADDR);
|
||||
anon_addr[1] = anonymize_ip(to_v4_addr(analyzer->Conn()->RespAddr()),
|
||||
RESP_ADDR);
|
||||
}
|
||||
else
|
||||
anon_addr[0] = anon_addr[1] = 0;
|
||||
}
|
||||
|
||||
void UDP_Rewriter::Done()
|
||||
{
|
||||
}
|
||||
|
||||
UDP_Rewriter::~UDP_Rewriter()
|
||||
{
|
||||
delete current_packet;
|
||||
}
|
||||
|
||||
void UDP_Rewriter::WriteData(int is_orig, int len, const u_char* data)
|
||||
{
|
||||
DoWriteData(is_orig, len, data);
|
||||
}
|
||||
|
||||
void UDP_Rewriter::DoWriteData(int is_orig, int len, const u_char* data)
|
||||
{
|
||||
struct pcap_pkthdr* hdr;
|
||||
int length = len;
|
||||
ipaddr32_t src = 0, dst = 0;
|
||||
|
||||
current_packet->AppendData(data,len);
|
||||
// Mark data to be written.
|
||||
current_packet->SetModified();
|
||||
}
|
||||
|
||||
// Compose the packet so it can be written.
|
||||
// Compute UDP/IP checksums, lengths, addresses.
|
||||
int UDP_TracePacket::BuildPacket(struct pcap_pkthdr*& hdr,
|
||||
const u_char*& arg_pkt, int& length,
|
||||
ipaddr32_t anon_src, ipaddr32_t anon_dst)
|
||||
{
|
||||
struct ip* ip = (struct ip*) (pkt + ip_offset);
|
||||
struct udphdr* up = (struct udphdr*) (pkt + udp_offset);
|
||||
uint32 sum = 0;
|
||||
|
||||
// Fix IP addresses before computing the UDP checksum
|
||||
if ( BifConst::anonymize_ip_addr )
|
||||
{
|
||||
ip->ip_src.s_addr = anon_src;
|
||||
ip->ip_dst.s_addr = anon_dst;
|
||||
}
|
||||
|
||||
// Create the IP header.
|
||||
ip->ip_off = 0;
|
||||
ip->ip_sum = 0;
|
||||
ip->ip_hl = (udp_offset - ip_offset) >> 2;
|
||||
ip->ip_len = htons(buffer_offset - ip_offset);
|
||||
ip->ip_off = 0; // DF = 0, MF = 0, offset = 0
|
||||
ip->ip_sum = 0;
|
||||
ip->ip_sum = 0xffff - ones_complement_checksum((const void*) ip,
|
||||
(udp_offset-ip_offset), sum);
|
||||
|
||||
pcap_hdr.caplen = pcap_hdr.len = buffer_offset;
|
||||
|
||||
hdr = &pcap_hdr;
|
||||
arg_pkt = pkt;
|
||||
length = buffer_offset;
|
||||
|
||||
// Create the UDP header.
|
||||
up->uh_ulen = htons(buffer_offset - udp_offset);
|
||||
up->uh_sum = 0;
|
||||
up->uh_sum = 0xffff - udp_checksum(ip, up, buffer_offset - udp_offset);
|
||||
|
||||
// Create the pcap header.
|
||||
//
|
||||
// The below works around a potential type incompatibility
|
||||
// on systems where pcap's timeval is different from the
|
||||
// system-wide one. --cpk
|
||||
//
|
||||
timeval tv_tmp = double_to_timeval(timestamp);
|
||||
pcap_hdr.ts.tv_sec = tv_tmp.tv_sec;
|
||||
pcap_hdr.ts.tv_usec = tv_tmp.tv_usec;
|
||||
pcap_hdr.caplen = pcap_hdr.len = buffer_offset;
|
||||
|
||||
hdr = &pcap_hdr;
|
||||
arg_pkt = pkt;
|
||||
length = buffer_offset;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void UDP_Rewriter::NextPacket(int is_orig, double t,
|
||||
const struct pcap_pkthdr* pcap_hdr,
|
||||
const u_char* pcap_pkt, int hdr_size,
|
||||
const struct ip* ip, const struct udphdr* up)
|
||||
{
|
||||
unsigned int ip_hdr_len = ip->ip_hl * 4;
|
||||
|
||||
// Cache the packet ....
|
||||
UDP_TracePacket* p = new UDP_TracePacket(this, t, is_orig,
|
||||
pcap_hdr, /*MTU */ 1024,
|
||||
hdr_size + ip_hdr_len + sizeof(struct udphdr));
|
||||
|
||||
if ( ! p->AppendLinkHeader(pcap_pkt, hdr_size) )
|
||||
internal_error(MSG_PREFIX "cannot append headers -- check MTU");
|
||||
|
||||
if ( ! p->AppendIPHeader((const u_char*) ip, sizeof(*ip)) )
|
||||
internal_error(MSG_PREFIX "cannot append headers -- check MTU");
|
||||
|
||||
if ( ! p->AppendUDPHeader((const u_char*) up, sizeof(*up)) )
|
||||
internal_error(MSG_PREFIX "cannot append headers -- check MTU");
|
||||
|
||||
// We only ever use one packet in UDP.
|
||||
// ### This is potentially a leak.
|
||||
next_packet = current_packet = p;
|
||||
}
|
||||
|
||||
void UDP_Rewriter::Push(int)
|
||||
{
|
||||
internal_error("UDP_Rewriter::Push not implemented");
|
||||
}
|
||||
|
||||
void UDP_Rewriter::AbortPackets(int)
|
||||
{
|
||||
internal_error("UDP_Rewriter::AbortPackets not implemented");
|
||||
}
|
||||
|
||||
unsigned int UDP_Rewriter::ReserveSlot()
|
||||
{
|
||||
internal_error("UDP_Rewriter::ReserveSlot not implemented");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UDP_Rewriter::SeekSlot(unsigned int)
|
||||
{
|
||||
internal_error("UDP_Rewriter::SeekSlot not implemented");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UDP_Rewriter::ReturnFromSlot()
|
||||
{
|
||||
internal_error("UDP_Rewriter::ReturnFromSlot not implemented");
|
||||
return 0;
|
||||
}
|
||||
int UDP_Rewriter::ReleaseSlot(unsigned int)
|
||||
{
|
||||
internal_error("UDP_Rewriter::ReleaseSlot not implemented");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UDP_Rewriter::LeaveAddrInTheClear(int is_orig)
|
||||
{
|
||||
internal_error("UDP_Rewriter::LeaveAddrInTheClear not implemented");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void UDP_Rewriter::CommitPackets(int commit)
|
||||
{
|
||||
if ( current_packet && current_packet->IsModified() )
|
||||
{
|
||||
ipaddr32_t anon_src = 0, anon_dst = 0;
|
||||
|
||||
if ( current_packet->IsOrig() )
|
||||
{
|
||||
anon_src = anon_addr[0];
|
||||
anon_dst = anon_addr[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
anon_src = anon_addr[1];
|
||||
anon_dst = anon_addr[0];
|
||||
}
|
||||
|
||||
struct pcap_pkthdr* hdr;
|
||||
const u_char* pkt;
|
||||
int len;
|
||||
current_packet->BuildPacket(hdr, pkt, len, anon_src, anon_dst);
|
||||
|
||||
dumper->DumpPacket(hdr, pkt, hdr->caplen);
|
||||
}
|
||||
|
||||
delete current_packet;
|
||||
next_packet = current_packet = 0;
|
||||
|
||||
++packets_rewritten;
|
||||
}
|
||||
|
||||
UDP_TracePacket::UDP_TracePacket(UDP_Rewriter* arg_trace_rewriter,
|
||||
double t, int arg_is_orig,
|
||||
const struct pcap_pkthdr* arg_hdr,
|
||||
int MTU, int initial_size)
|
||||
{
|
||||
trace_rewriter = arg_trace_rewriter;
|
||||
pcap_hdr = *arg_hdr;
|
||||
// packet_seq = arg_packet_seq;
|
||||
timestamp = t;
|
||||
is_orig = arg_is_orig;
|
||||
mtu = MTU;
|
||||
buffer_size = initial_size;
|
||||
buffer_offset = 0;
|
||||
|
||||
pkt = new u_char[buffer_size];
|
||||
|
||||
ip_offset = udp_offset = data_offset = -1;
|
||||
|
||||
reuse = 0;
|
||||
on_hold = 0;
|
||||
modified = 0;
|
||||
seq_gap = 0;
|
||||
|
||||
packet_val = 0;
|
||||
packet_val = PacketVal();
|
||||
}
|
||||
|
||||
UDP_TracePacket::~UDP_TracePacket()
|
||||
{
|
||||
packet_val->SetOrigin(0);
|
||||
Unref(packet_val);
|
||||
delete [] pkt;
|
||||
}
|
||||
|
||||
RecordVal* UDP_TracePacket::PacketVal()
|
||||
{
|
||||
if ( packet_val )
|
||||
Ref(packet_val);
|
||||
else
|
||||
{
|
||||
packet_val = new RecordVal(packet_type);
|
||||
packet_val->Assign(0, TraceRewriter()->GetAnalyzer()->BuildConnVal());
|
||||
packet_val->Assign(1, new Val(IsOrig(), TYPE_BOOL));
|
||||
packet_val->Assign(2, new Val(TimeStamp(), TYPE_TIME));
|
||||
packet_val->SetOrigin(this);
|
||||
}
|
||||
|
||||
return packet_val;
|
||||
}
|
||||
|
||||
int UDP_TracePacket::AppendLinkHeader(const u_char* chunk, int len)
|
||||
{
|
||||
if ( ip_offset >= 0 && ip_offset != buffer_offset )
|
||||
internal_error(MSG_PREFIX "link header must be appended before IP header");
|
||||
|
||||
if ( ! Append(chunk, len) )
|
||||
return 0;
|
||||
|
||||
ip_offset = buffer_offset;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int UDP_TracePacket::AppendIPHeader(const u_char* chunk, int len)
|
||||
{
|
||||
if ( udp_offset >= 0 && udp_offset != buffer_offset )
|
||||
internal_error(MSG_PREFIX "IP header must be appended before udp header");
|
||||
|
||||
if ( ! Append(chunk, len) )
|
||||
return 0;
|
||||
|
||||
udp_offset = buffer_offset;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int UDP_TracePacket::AppendUDPHeader(const u_char* chunk, int len)
|
||||
{
|
||||
if ( data_offset >= 0 && data_offset != buffer_offset )
|
||||
internal_error(MSG_PREFIX "tcp header must be appended before payload");
|
||||
|
||||
if ( udp_offset == buffer_offset )
|
||||
{ // first UDP header chunk
|
||||
int extra = (udp_offset - ip_offset) % 4;
|
||||
if ( extra )
|
||||
{
|
||||
DEBUG_MSG(MSG_PREFIX "padding IP header");
|
||||
if ( ! AppendIPHeader(0, 4 - extra) )
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! Append(chunk, len) )
|
||||
return 0;
|
||||
|
||||
data_offset = buffer_offset;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int UDP_TracePacket::AppendData(const u_char* chunk, int len)
|
||||
{
|
||||
// All headers must be appended before any data.
|
||||
ASSERT(ip_offset >= 0 && udp_offset >= 0 && data_offset >= 0);
|
||||
|
||||
if ( data_offset == buffer_offset )
|
||||
{ // first data chunk
|
||||
int extra = (data_offset - udp_offset) % 4;
|
||||
if ( extra )
|
||||
{
|
||||
if ( ! AppendUDPHeader(0, 4 - extra) )
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! Append(chunk, len) )
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int UDP_TracePacket::Append(const u_char* chunk, int len)
|
||||
{
|
||||
if ( buffer_offset + len > buffer_size )
|
||||
{
|
||||
if ( buffer_offset + len > mtu )
|
||||
return 0;
|
||||
|
||||
u_char* tmp = new u_char[mtu];
|
||||
for ( int i = 0 ; i < buffer_size; ++i )
|
||||
tmp[i] = pkt[i];
|
||||
|
||||
delete [] pkt;
|
||||
pkt = tmp;
|
||||
buffer_size = mtu;
|
||||
}
|
||||
|
||||
ASSERT(buffer_offset + len <= buffer_size);
|
||||
|
||||
if ( chunk )
|
||||
memcpy(pkt + buffer_offset, chunk, len);
|
||||
else
|
||||
// Fill with 0.
|
||||
memset(pkt + buffer_offset, 0, len);
|
||||
|
||||
buffer_offset += len;
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -1,138 +0,0 @@
|
|||
// $Id:$
|
||||
//
|
||||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#ifndef udp_rewriter_h
|
||||
#define udp_rewriter_h
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include <queue>
|
||||
#include <set>
|
||||
|
||||
#include <pcap.h>
|
||||
|
||||
#include "Val.h"
|
||||
#include "UDP.h"
|
||||
#include "Anon.h"
|
||||
#include "Rewriter.h"
|
||||
#include "PacketDumper.h"
|
||||
|
||||
class UDP_TracePacket : public BroObj, virtual public TracePacket {
|
||||
public:
|
||||
UDP_TracePacket(UDP_Rewriter* trace_rewriter, double t, int is_orig,
|
||||
const struct pcap_pkthdr* hdr, int MTU, int initial_size);
|
||||
~UDP_TracePacket();
|
||||
|
||||
int AppendLinkHeader(const u_char* chunk, int len);
|
||||
int AppendIPHeader(const u_char* chunk, int len);
|
||||
int AppendUDPHeader(const u_char* chunk, int len);
|
||||
int AppendData(const u_char* chunk, int len);
|
||||
|
||||
void Reuse();
|
||||
int IsReuse() const { return reuse; }
|
||||
|
||||
double TimeStamp() const { return timestamp; }
|
||||
int IsOrig() const { return is_orig; }
|
||||
|
||||
const struct pcap_pkthdr* Header() const { return &pcap_hdr; }
|
||||
|
||||
const u_char* Buffer() const { return pkt; }
|
||||
int Length() const { return buffer_offset; }
|
||||
|
||||
// Note that Space() does not depend on buffer_size, but depends on MTU.
|
||||
int Space() const { return mtu - buffer_offset; }
|
||||
|
||||
void Describe(ODesc* d) const { packet_val->Describe(d); }
|
||||
RecordVal* PacketVal();
|
||||
UDP_Rewriter* TraceRewriter() const { return trace_rewriter;}
|
||||
|
||||
// has the packet been written to?
|
||||
int IsModified() const { return modified; }
|
||||
void SetModified() { modified = 1; }
|
||||
|
||||
// BuildPacket() is called before dumping the packet. It sets length
|
||||
// fields and computes checksums in UDP/IP headers.
|
||||
int BuildPacket(struct pcap_pkthdr*& hdr, const u_char*& arg_pkt,
|
||||
int& length, ipaddr32_t anon_src, ipaddr32_t anon_dst);
|
||||
|
||||
private:
|
||||
int Append(const u_char* chunk, int len);
|
||||
|
||||
RecordVal* packet_val;
|
||||
UDP_Rewriter* trace_rewriter;
|
||||
double timestamp;
|
||||
int packet_seq;
|
||||
int is_orig;
|
||||
struct pcap_pkthdr pcap_hdr;
|
||||
int mtu;
|
||||
u_char* pkt; // of maximal length MTU
|
||||
int ip_offset, udp_offset, data_offset;
|
||||
int buffer_size;
|
||||
int buffer_offset;
|
||||
int reuse; // whether it is an artificially replicated packet
|
||||
int on_hold; // do not dump it in Flush()
|
||||
int seq_gap;
|
||||
int modified;
|
||||
};
|
||||
|
||||
class UDP_Rewriter: public Rewriter {
|
||||
public:
|
||||
UDP_Rewriter(Analyzer* analyzer, int arg_MTU, PacketDumper* dumper);
|
||||
|
||||
virtual ~UDP_Rewriter();
|
||||
|
||||
void Done();
|
||||
|
||||
// these are the virt funcs in Rewriter....
|
||||
void WriteData(int is_orig, int len, const u_char* data);
|
||||
|
||||
void WriteData(int is_orig, const char* data)
|
||||
{ WriteData(is_orig, strlen(data), data); }
|
||||
|
||||
void WriteData(int is_orig, int len, const char* data)
|
||||
{ WriteData(is_orig, len, (const u_char*) data); }
|
||||
|
||||
void WriteData(int is_orig, const BroString* str)
|
||||
{ WriteData(is_orig, str->Len(), str->Bytes()); }
|
||||
|
||||
Analyzer* GetAnalyzer() const { return analyzer; }
|
||||
|
||||
// Not need for udp, but declared in the virtual
|
||||
// and might be useful
|
||||
void Push(int);
|
||||
void AbortPackets(int);
|
||||
void CommitPackets(int);
|
||||
unsigned int ReserveSlot();
|
||||
int SeekSlot(unsigned int);
|
||||
int ReturnFromSlot();
|
||||
int ReleaseSlot(unsigned int);
|
||||
|
||||
TracePacket* CurrentPacket() const { return current_packet; };
|
||||
TracePacket* RewritePacket() const { return next_packet; };
|
||||
|
||||
// A UDP/IP packet.
|
||||
void NextPacket(int is_orig, double t,
|
||||
const struct pcap_pkthdr* pcap_hdr,
|
||||
const u_char* pcap_pkt, // link level header
|
||||
int hdr_size, // link level header size
|
||||
const struct ip* ip, const struct udphdr* tp);
|
||||
|
||||
// Do not anonymize client/server IP address.
|
||||
int LeaveAddrInTheClear(int is_orig);
|
||||
|
||||
protected:
|
||||
void DoWriteData(int is_orig, int len, const u_char* data);
|
||||
|
||||
Analyzer* analyzer;
|
||||
PacketDumper* dumper;
|
||||
|
||||
int packets_rewritten;
|
||||
int MTU;
|
||||
ipaddr32_t anon_addr[2];
|
||||
|
||||
UDP_TracePacket* current_packet;
|
||||
UDP_TracePacket* next_packet;
|
||||
};
|
||||
|
||||
#endif
|
15
src/bro.bif
15
src/bro.bif
|
@ -1587,21 +1587,6 @@ function global_ids%(%): id_table
|
|||
return ids;
|
||||
%}
|
||||
|
||||
%%{
|
||||
#include "TCP_Rewriter.h"
|
||||
|
||||
// Trace rewriting functions.
|
||||
class PacketDumper;
|
||||
extern PacketDumper* transformed_pkt_dump;
|
||||
extern void commit_trace(Val* conn_val, int commit, int future);
|
||||
%%}
|
||||
|
||||
# True if we're rewriting (anonymizing), false otherwise.
|
||||
function rewriting_trace%(%): bool
|
||||
%{
|
||||
return new Val(transformed_pkt_dump != 0, TYPE_BOOL);
|
||||
%}
|
||||
|
||||
%%{
|
||||
#include "Anon.h"
|
||||
%%}
|
||||
|
|
|
@ -68,7 +68,6 @@ HEX [0-9a-fA-F]+
|
|||
"%)" return check_c_mode(TOK_RPP);
|
||||
"..." return check_c_mode(TOK_VAR_ARG);
|
||||
"function" return check_c_mode(TOK_FUNCTION);
|
||||
"rewriter" return check_c_mode(TOK_REWRITER);
|
||||
"event" return check_c_mode(TOK_EVENT);
|
||||
"const" return check_c_mode(TOK_CONST);
|
||||
"enum" return check_c_mode(TOK_ENUM);
|
||||
|
@ -83,11 +82,6 @@ HEX [0-9a-fA-F]+
|
|||
"@ARGS@" return TOK_ARGS;
|
||||
"@ARGC@" return TOK_ARGC;
|
||||
|
||||
"@WRITE@" return TOK_WRITE;
|
||||
"@PUSH@" return TOK_PUSH;
|
||||
"@EOF@" return TOK_EOF;
|
||||
"@TRACE@" return TOK_TRACE;
|
||||
|
||||
"T" yylval.val = 1; return TOK_BOOL;
|
||||
"F" yylval.val = 0; return TOK_BOOL;
|
||||
|
||||
|
|
|
@ -35,7 +35,6 @@ string type_name;
|
|||
enum {
|
||||
C_SEGMENT_DEF,
|
||||
FUNC_DEF,
|
||||
REWRITER_DEF,
|
||||
EVENT_DEF,
|
||||
TYPE_DEF,
|
||||
CONST_DEF,
|
||||
|
@ -102,17 +101,6 @@ void set_decl_name(const char *name)
|
|||
decl.c_fullname = "BifConst::";
|
||||
break;
|
||||
|
||||
case REWRITER_DEF:
|
||||
// XXX: Legacy. No module names / namespaces supported
|
||||
// If support for namespaces is desired: add a namespace
|
||||
// to c_namespace_* and bro_fullname and get rid of
|
||||
// the hack to bro_name.
|
||||
decl.c_namespace_start = "";
|
||||
decl.c_namespace_end = "";
|
||||
decl.bare_name = "rewrite_" + decl.bare_name;
|
||||
decl.bro_name = "rewrite_";
|
||||
break;
|
||||
|
||||
case FUNC_DEF:
|
||||
decl.c_namespace_start = "namespace BifFunc { ";
|
||||
decl.c_namespace_end = " } ";
|
||||
|
@ -155,7 +143,6 @@ void set_decl_name(const char *name)
|
|||
}
|
||||
|
||||
const char* arg_list_name = "BiF_ARGS";
|
||||
const char* trace_rewriter_name = "trace_rewriter";
|
||||
|
||||
#include "bif_arg.h"
|
||||
|
||||
|
@ -282,9 +269,8 @@ void print_event_c_body(FILE *fp)
|
|||
|
||||
%token TOK_LPP TOK_RPP TOK_LPB TOK_RPB TOK_LPPB TOK_RPPB TOK_VAR_ARG
|
||||
%token TOK_BOOL
|
||||
%token TOK_FUNCTION TOK_REWRITER TOK_EVENT TOK_CONST TOK_ENUM
|
||||
%token TOK_FUNCTION TOK_EVENT TOK_CONST TOK_ENUM
|
||||
%token TOK_TYPE TOK_RECORD TOK_SET TOK_VECTOR TOK_TABLE TOK_MODULE
|
||||
%token TOK_WRITE TOK_PUSH TOK_EOF TOK_TRACE
|
||||
%token TOK_ARGS TOK_ARG TOK_ARGC
|
||||
%token TOK_ID TOK_ATTR TOK_CSTR TOK_LF TOK_WS TOK_COMMENT
|
||||
%token TOK_ATOM TOK_INT TOK_C_TOKEN
|
||||
|
@ -335,7 +321,6 @@ definitions: definitions definition opt_ws
|
|||
|
||||
definition: event_def
|
||||
| func_def
|
||||
| rewriter_def
|
||||
| c_code_segment
|
||||
| enum_def
|
||||
| const_def
|
||||
|
@ -395,9 +380,6 @@ event_def: event_prefix opt_ws plain_head opt_attr end_of_head ';'
|
|||
func_def: func_prefix opt_ws typed_head end_of_head body
|
||||
;
|
||||
|
||||
rewriter_def: rewriter_prefix opt_ws plain_head end_of_head body
|
||||
;
|
||||
|
||||
enum_def: enum_def_1 enum_list TOK_RPB
|
||||
{
|
||||
// First, put an end to the enum type decl.
|
||||
|
@ -490,10 +472,6 @@ func_prefix: TOK_FUNCTION
|
|||
{ set_definition_type(FUNC_DEF, 0); }
|
||||
;
|
||||
|
||||
rewriter_prefix: TOK_REWRITER
|
||||
{ set_definition_type(REWRITER_DEF, 0); }
|
||||
;
|
||||
|
||||
event_prefix: TOK_EVENT
|
||||
{ set_definition_type(EVENT_DEF, 0); }
|
||||
;
|
||||
|
@ -515,12 +493,9 @@ plain_head: head_1 args arg_end opt_ws
|
|||
fprintf(fp_bro_init, "va_args: any");
|
||||
else
|
||||
{
|
||||
if ( definition_type == REWRITER_DEF )
|
||||
fprintf(fp_bro_init, "c: connection");
|
||||
|
||||
for ( int i = 0; i < (int) args.size(); ++i )
|
||||
{
|
||||
if ( i > 0 || definition_type == REWRITER_DEF )
|
||||
if ( i > 0 )
|
||||
fprintf(fp_bro_init, ", ");
|
||||
args[i]->PrintBro(fp_bro_init);
|
||||
}
|
||||
|
@ -538,7 +513,7 @@ head_1: TOK_ID opt_ws arg_begin
|
|||
const char* method_type = 0;
|
||||
set_decl_name($1);
|
||||
|
||||
if ( definition_type == FUNC_DEF || definition_type == REWRITER_DEF )
|
||||
if ( definition_type == FUNC_DEF )
|
||||
{
|
||||
method_type = "function";
|
||||
print_line_directive(fp_func_def);
|
||||
|
@ -551,7 +526,7 @@ head_1: TOK_ID opt_ws arg_begin
|
|||
"global %s: %s%s(",
|
||||
decl.bro_name.c_str(), method_type, $2);
|
||||
|
||||
if ( definition_type == FUNC_DEF || definition_type == REWRITER_DEF )
|
||||
if ( definition_type == FUNC_DEF )
|
||||
{
|
||||
fprintf(fp_func_init,
|
||||
"\t(void) new BuiltinFunc(%s, \"%s\", 0);\n",
|
||||
|
@ -646,11 +621,6 @@ body_start: TOK_LPB c_code_begin
|
|||
int argc = args.size();
|
||||
|
||||
fprintf(fp_func_def, "{");
|
||||
if ( definition_type == REWRITER_DEF )
|
||||
{
|
||||
implicit_arg = 1;
|
||||
++argc;
|
||||
}
|
||||
|
||||
if ( argc > 0 || ! var_arg )
|
||||
fprintf(fp_func_def, "\n");
|
||||
|
@ -676,15 +646,6 @@ body_start: TOK_LPB c_code_begin
|
|||
fprintf(fp_func_def, "\t\t}\n");
|
||||
}
|
||||
|
||||
if ( definition_type == REWRITER_DEF )
|
||||
{
|
||||
fprintf(fp_func_def,
|
||||
"\tRewriter* %s = get_trace_rewriter((*%s)[0]);\n",
|
||||
trace_rewriter_name,
|
||||
arg_list_name);
|
||||
fprintf(fp_func_def, "\tif ( ! trace_rewriter )\n");
|
||||
fprintf(fp_func_def, "\t\treturn 0;\n");
|
||||
}
|
||||
for ( int i = 0; i < (int) args.size(); ++i )
|
||||
args[i]->PrintCDef(fp_func_def, i + implicit_arg);
|
||||
print_line_directive(fp_func_def);
|
||||
|
@ -693,8 +654,6 @@ body_start: TOK_LPB c_code_begin
|
|||
|
||||
body_end: TOK_RPB c_code_end
|
||||
{
|
||||
if ( definition_type == REWRITER_DEF )
|
||||
fprintf(fp_func_def, "\n\treturn 0;\n");
|
||||
fprintf(fp_func_def, "}");
|
||||
}
|
||||
;
|
||||
|
@ -718,14 +677,6 @@ c_atom: TOK_ID
|
|||
{ fprintf(fp_func_def, "%s", arg_list_name); }
|
||||
| TOK_ARGC
|
||||
{ fprintf(fp_func_def, "%s->length()", arg_list_name); }
|
||||
| TOK_TRACE
|
||||
{ fprintf(fp_func_def, "%s", trace_rewriter_name); }
|
||||
| TOK_WRITE
|
||||
{ fprintf(fp_func_def, "%s->WriteData", trace_rewriter_name); }
|
||||
| TOK_PUSH
|
||||
{ fprintf(fp_func_def, "%s->Push", trace_rewriter_name); }
|
||||
| TOK_EOF
|
||||
{ fprintf(fp_func_def, "%s->EndOfData", trace_rewriter_name); }
|
||||
| TOK_CSTR
|
||||
{ fprintf(fp_func_def, "%s", $1); }
|
||||
| TOK_ATOM
|
||||
|
|
|
@ -1,107 +0,0 @@
|
|||
%%{
|
||||
#include "TCP_Rewriter.h"
|
||||
%%}
|
||||
|
||||
rewriter commit_trace%(commit: bool, future: bool%)
|
||||
%{
|
||||
if ( commit )
|
||||
@TRACE@->CommitPackets(future);
|
||||
else
|
||||
@TRACE@->AbortPackets(future);
|
||||
%}
|
||||
|
||||
rewriter push_packet%(is_orig: bool%)
|
||||
%{
|
||||
@PUSH@(is_orig);
|
||||
%}
|
||||
|
||||
rewriter leave_addr_in_the_clear%(is_orig: bool%)
|
||||
%{
|
||||
if ( ! @TRACE@->LeaveAddrInTheClear(is_orig) )
|
||||
builtin_run_time("cannot leave IP address in the clear"
|
||||
" (probably because some packets have already been rewritten before this call)");
|
||||
%}
|
||||
|
||||
function current_packet%(c: connection%): packet
|
||||
%{
|
||||
Rewriter* rewriter = get_trace_rewriter(c);
|
||||
if ( ! rewriter )
|
||||
{
|
||||
builtin_run_time("current_packet is not supported without specifying an output file");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return rewriter->CurrentPacket()->PacketVal();
|
||||
%}
|
||||
|
||||
function current_rewrite_packet%(c: connection%): packet
|
||||
%{
|
||||
Rewriter* rewriter = get_trace_rewriter(c);
|
||||
if ( ! rewriter )
|
||||
{
|
||||
builtin_run_time("current_rewrite_packet is not supported without specifying an output file");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return rewriter->RewritePacket()->PacketVal();
|
||||
%}
|
||||
|
||||
# Reserve a slot in the current packet of the trace so that the
|
||||
# slot can be filled later by seeking to it.
|
||||
function reserve_rewrite_slot%(c: connection%): count
|
||||
%{
|
||||
Rewriter* rewriter = get_trace_rewriter(c);
|
||||
if ( ! rewriter )
|
||||
return new Val(0, TYPE_COUNT);
|
||||
|
||||
unsigned int slot = rewriter->ReserveSlot();
|
||||
if ( slot == 0 )
|
||||
builtin_run_time("reserve_rewrite_slot returning 0");
|
||||
|
||||
return new Val(slot, TYPE_COUNT);
|
||||
%}
|
||||
|
||||
# Seek to a previously reserved slot so that rewrites afterwards
|
||||
# will go into the slot instead of the current packet.
|
||||
function seek_rewrite_slot%(c: connection, slot: count%): any
|
||||
%{
|
||||
Rewriter* rewriter = get_trace_rewriter(c);
|
||||
if ( ! rewriter->SeekSlot(slot) )
|
||||
builtin_run_time("cannot seek the rewrite slot");
|
||||
|
||||
return 0;
|
||||
%}
|
||||
|
||||
# Return from any reserved slot to bring the rewrite pointer back to
|
||||
# the current packet.
|
||||
function return_from_rewrite_slot%(c: connection%): any
|
||||
%{
|
||||
Rewriter* rewriter = get_trace_rewriter(c);
|
||||
rewriter->ReturnFromSlot();
|
||||
return 0;
|
||||
%}
|
||||
|
||||
# Release a rewrite slot and dump the slot to the trace (it cannot be
|
||||
# seek'd again). If the rewrite pointer is currently at the slot, it
|
||||
# will return to the current packet.
|
||||
function release_rewrite_slot%(c: connection, slot: count%): any
|
||||
%{
|
||||
Rewriter* rewriter = get_trace_rewriter(c);
|
||||
rewriter->ReleaseSlot(slot);
|
||||
return 0;
|
||||
%}
|
||||
|
||||
# Dump original packets on the connection up to this point to the
|
||||
# output trace, if any.
|
||||
function dump_packets_of_connection%(c: connection%): any
|
||||
%{
|
||||
Analyzer* tc = c->FindAnalyzer(AnalyzerTag::TCP);
|
||||
if ( ! tc )
|
||||
run_time("connection does not have TCP analyzer");
|
||||
|
||||
TCP_SourcePacketWriter* pkt_writer = get_src_pkt_writer((TCP_Analyzer*) tc);
|
||||
if ( pkt_writer )
|
||||
pkt_writer->Dump();
|
||||
|
||||
return 0;
|
||||
%}
|
|
@ -5,15 +5,3 @@
|
|||
const ignore_keep_alive_rexmit: bool;
|
||||
const skip_http_data: bool;
|
||||
const parse_udp_tunnels: bool;
|
||||
const requires_trace_commitment: bool;
|
||||
const anonymize_ip_addr: bool;
|
||||
const omit_rewrite_place_holder: bool;
|
||||
const rewriting_http_trace :bool;
|
||||
const rewriting_smtp_trace: bool;
|
||||
const rewriting_ftp_trace: bool;
|
||||
const rewriting_ident_trace: bool;
|
||||
const rewriting_finger_trace: bool;
|
||||
const rewriting_dns_trace: bool;
|
||||
const rewriting_smb_trace: bool;
|
||||
const dump_selected_source_packets: bool;
|
||||
const dump_original_packets_if_not_rewriting: bool;
|
||||
|
|
|
@ -1,99 +0,0 @@
|
|||
# $Id: dns-rw.bif,v 1.1.2.6 2006/01/11 21:20:09 jason Exp $
|
||||
|
||||
# This is called for every message - snake out the header.
|
||||
rewriter dns_message%(is_orig: bool, msg: dns_msg, len: count%)
|
||||
%{
|
||||
DNS_Rewriter* dnsrewriter = ((DNS_Rewriter*) @TRACE@);
|
||||
dnsrewriter->SetOrig(is_orig);
|
||||
dnsrewriter->DnsCopyHeader(msg);
|
||||
%}
|
||||
|
||||
# Rewrite an DNS request.
|
||||
rewriter dns_request%(query: string, msg: dns_msg, qtype: count, qclass: count%)
|
||||
%{
|
||||
DNS_Rewriter* dnsrewriter = ((DNS_Rewriter*) @TRACE@);
|
||||
dnsrewriter->DnsCopyQuery(query->AsString(), qtype, qclass);
|
||||
%}
|
||||
|
||||
# Called for every reply, contains the query part.
|
||||
rewriter dns_reply_question%(msg: dns_msg,
|
||||
qname: string, qtype: count, qclass: count%)
|
||||
%{
|
||||
DNS_Rewriter* dnsrewriter = ((DNS_Rewriter*) @TRACE@);
|
||||
dnsrewriter->DnsCopyQuery(qname->AsString(), qtype, qclass);
|
||||
%}
|
||||
|
||||
|
||||
# Rewrite an DNS NS reply.
|
||||
rewriter dns_NS_reply%(msg: dns_msg, dns_ans: dns_answer, name: string%)
|
||||
%{
|
||||
DNS_Rewriter* dnsrewriter = ((DNS_Rewriter*) @TRACE@);
|
||||
dnsrewriter->DnsCopyNS(dns_ans, name->AsString());
|
||||
%}
|
||||
|
||||
|
||||
rewriter dns_A_reply%(msg: dns_msg, ans: dns_answer, a: addr%)
|
||||
%{
|
||||
DNS_Rewriter* dnsrewriter = ((DNS_Rewriter*) @TRACE@);
|
||||
#ifdef BROv6
|
||||
dnsrewriter->DnsCopyA(ans, to_v4_addr(a));
|
||||
#else
|
||||
dnsrewriter->DnsCopyA(ans, a);
|
||||
#endif
|
||||
%}
|
||||
|
||||
rewriter dns_AAAA_reply%(msg: dns_msg, ans: dns_answer, a: addr, astr: string%)
|
||||
%{
|
||||
DNS_Rewriter* dnsrewriter = ((DNS_Rewriter*) @TRACE@);
|
||||
dnsrewriter->DnsCopyAAAA(ans, a, astr->AsString());
|
||||
%}
|
||||
|
||||
rewriter dns_CNAME_reply%(msg: dns_msg, ans: dns_answer, name: string%)
|
||||
%{
|
||||
DNS_Rewriter* dnsrewriter = ((DNS_Rewriter*) @TRACE@);
|
||||
dnsrewriter->DnsCopyCNAME(ans, name->AsString());
|
||||
%}
|
||||
|
||||
rewriter dns_TXT_reply%(msg: dns_msg, ans: dns_answer, content: string%)
|
||||
%{
|
||||
DNS_Rewriter* dnsrewriter = ((DNS_Rewriter*) @TRACE@);
|
||||
dnsrewriter->DnsCopyTXT(ans, content->AsString());
|
||||
%}
|
||||
|
||||
rewriter dns_PTR_reply%(msg: dns_msg, ans: dns_answer, name: string%)
|
||||
%{
|
||||
DNS_Rewriter* dnsrewriter = ((DNS_Rewriter*) @TRACE@);
|
||||
dnsrewriter->DnsCopyPTR(ans, name->AsString());
|
||||
%}
|
||||
|
||||
rewriter dns_MX_reply%(msg: dns_msg, ans: dns_answer,
|
||||
name: string, preference: count%)
|
||||
%{
|
||||
DNS_Rewriter* dnsrewriter = ((DNS_Rewriter*) @TRACE@);
|
||||
dnsrewriter->DnsCopyMX(ans, name->AsString(), preference);
|
||||
%}
|
||||
|
||||
rewriter dns_SOA_reply%(msg: dns_msg, ans: dns_answer, soa: dns_soa%)
|
||||
%{
|
||||
DNS_Rewriter* dnsrewriter = ((DNS_Rewriter*) @TRACE@);
|
||||
dnsrewriter->DnsCopySOA(ans, soa);
|
||||
%}
|
||||
|
||||
rewriter dns_EDNS_addl%(msg: dns_msg, ans: dns_edns_additional%)
|
||||
%{
|
||||
DNS_Rewriter* dnsrewriter = ((DNS_Rewriter*) @TRACE@);
|
||||
dnsrewriter->DnsCopyEDNSaddl(ans);
|
||||
%}
|
||||
|
||||
|
||||
# Call this at end of processing a DNS packet.
|
||||
rewriter dns_end%(commit: bool%)
|
||||
%{
|
||||
DNS_Rewriter* dnsrewriter = ((DNS_Rewriter*) @TRACE@);
|
||||
|
||||
// We have been building the packet in the DNS rewriter, now
|
||||
// write the whole packet here at once, then commit it.
|
||||
@WRITE@(dnsrewriter->IsOrig(), dnsrewriter->PacketSize(),
|
||||
(const u_char*) dnsrewriter->Packet());
|
||||
@TRACE@->CommitPackets(commit);
|
||||
%}
|
|
@ -1,22 +0,0 @@
|
|||
# Write a finger request to trace.
|
||||
rewriter finger_request %(full: bool, username: string, hostpart: string%)
|
||||
%{
|
||||
const int is_orig = 1;
|
||||
if ( full )
|
||||
@WRITE@(is_orig, "/W ");
|
||||
@WRITE@(is_orig, username->AsString());
|
||||
if ( hostpart->Len() > 0 )
|
||||
{
|
||||
@WRITE@(is_orig, "@");
|
||||
@WRITE@(is_orig, hostpart->AsString());
|
||||
}
|
||||
@WRITE@(is_orig, "\r\n");
|
||||
%}
|
||||
|
||||
# Write a finger reply to trace.
|
||||
rewriter finger_reply %(reply: string%)
|
||||
%{
|
||||
const int is_orig = 0;
|
||||
@WRITE@(is_orig, reply->AsString());
|
||||
@WRITE@(is_orig, "\r\n");
|
||||
%}
|
|
@ -1,27 +0,0 @@
|
|||
# Rewrite an FTP request.
|
||||
rewriter ftp_request%(command: string, arg: string%)
|
||||
%{
|
||||
const int is_orig = 1;
|
||||
@WRITE@(is_orig, command->AsString());
|
||||
if ( command->Len() > 0 && arg->Len() > 0 )
|
||||
@WRITE@(is_orig, " ");
|
||||
@WRITE@(is_orig, arg->AsString());
|
||||
@WRITE@(is_orig, "\r\n");
|
||||
%}
|
||||
|
||||
# Rewrite an FTP reply.
|
||||
rewriter ftp_reply%(code: count, msg: string, cont_resp: bool%)
|
||||
%{
|
||||
const int is_orig = 0;
|
||||
|
||||
if ( code > 0 )
|
||||
{
|
||||
@WRITE@(is_orig, fmt("%03lu", (unsigned long) code));
|
||||
if ( cont_resp )
|
||||
@WRITE@(is_orig, "-");
|
||||
else
|
||||
@WRITE@(is_orig, " ");
|
||||
}
|
||||
@WRITE@(is_orig, msg->AsString());
|
||||
@WRITE@(is_orig, "\r\n");
|
||||
%}
|
|
@ -1,61 +0,0 @@
|
|||
%%{
|
||||
#include "HTTP.h"
|
||||
|
||||
BroString* encode_URI(BroString* URI)
|
||||
{
|
||||
byte_vec encoded_URI = new unsigned char[URI->Len() * 3 + 1];
|
||||
byte_vec end_of_URI = URI->Bytes() + URI->Len();
|
||||
|
||||
byte_vec q = encoded_URI;
|
||||
for ( byte_vec p = URI->Bytes(); p < end_of_URI; ++p )
|
||||
{
|
||||
if ( is_reserved_URI_char(*p) ||
|
||||
is_unreserved_URI_char(*p) || *p == '%' )
|
||||
*q++ = *p;
|
||||
else
|
||||
escape_URI_char(*p, q);
|
||||
}
|
||||
*q = '\0';
|
||||
return new BroString(1, encoded_URI, q - encoded_URI);
|
||||
}
|
||||
%%}
|
||||
|
||||
rewriter http_request%(method: string, URI: string, version: string%)
|
||||
%{
|
||||
const int is_orig = 1;
|
||||
|
||||
@WRITE@(is_orig, method->AsString());
|
||||
@WRITE@(is_orig, " ");
|
||||
|
||||
@WRITE@(is_orig, URI->AsString());
|
||||
|
||||
@WRITE@(is_orig, " HTTP/");
|
||||
@WRITE@(is_orig, version->AsString());
|
||||
@WRITE@(is_orig, "\r\n");
|
||||
%}
|
||||
|
||||
rewriter http_reply%(version: string, code: count, reason: string%)
|
||||
%{
|
||||
const int is_orig = 0;
|
||||
|
||||
@WRITE@(is_orig, "HTTP/");
|
||||
@WRITE@(is_orig, version->AsString());
|
||||
@WRITE@(is_orig, " ");
|
||||
@WRITE@(is_orig, fmt("%lu", (unsigned long) code));
|
||||
@WRITE@(is_orig, " ");
|
||||
@WRITE@(is_orig, reason->AsString());
|
||||
@WRITE@(is_orig, "\r\n");
|
||||
%}
|
||||
|
||||
rewriter http_header%(is_orig: bool, name: string, value: string%)
|
||||
%{
|
||||
@WRITE@(is_orig, name->AsString());
|
||||
@WRITE@(is_orig, ":");
|
||||
@WRITE@(is_orig, value->AsString());
|
||||
@WRITE@(is_orig, "\r\n");
|
||||
%}
|
||||
|
||||
rewriter http_data%(is_orig: bool, data: string%)
|
||||
%{
|
||||
@WRITE@(is_orig, data->AsString());
|
||||
%}
|
|
@ -1,23 +0,0 @@
|
|||
rewriter ident_request %(lport: port, rport: port%)
|
||||
%{
|
||||
const int is_orig = 1;
|
||||
@WRITE@(is_orig, fmt("%u, %u\r\n", rport->Port(), lport->Port()));
|
||||
%}
|
||||
|
||||
rewriter ident_reply %(lport: port, rport: port, sys_str: string, id_str: string%)
|
||||
%{
|
||||
const int is_orig = 0;
|
||||
@WRITE@(is_orig, fmt("%u, %u : USERID : ", rport->Port(), lport->Port()));
|
||||
@WRITE@(is_orig, sys_str->AsString());
|
||||
@WRITE@(is_orig, " : ");
|
||||
@WRITE@(is_orig, id_str->AsString());
|
||||
@WRITE@(is_orig, "\r\n");
|
||||
%}
|
||||
|
||||
rewriter ident_error %(lport: port, rport: port, msg_str: string%)
|
||||
%{
|
||||
const int is_orig = 0;
|
||||
@WRITE@(is_orig, fmt("%u, %u : ERROR : ", rport->Port(), lport->Port()));
|
||||
@WRITE@(is_orig, msg_str->AsString());
|
||||
@WRITE@(is_orig, "\r\n");
|
||||
%}
|
11
src/main.cc
11
src/main.cc
|
@ -152,7 +152,6 @@ void usage()
|
|||
fprintf(stderr, " -v|--version | print version and exit\n");
|
||||
fprintf(stderr, " -x|--print-state <file.bst> | print contents of state file\n");
|
||||
fprintf(stderr, " -z|--analyze <analysis> | run the specified policy file analysis\n");
|
||||
fprintf(stderr, " -A|--transfile <writefile> | write transformed trace to given tcpdump file\n");
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, " -B|--debug <dbgstreams> | Enable debugging output for selected streams\n");
|
||||
#endif
|
||||
|
@ -339,7 +338,6 @@ int main(int argc, char** argv)
|
|||
name_list netflows;
|
||||
name_list flow_files;
|
||||
name_list rule_files;
|
||||
char* transformed_writefile = 0;
|
||||
char* bst_file = 0;
|
||||
char* id_name = 0;
|
||||
char* events_file = 0;
|
||||
|
@ -371,7 +369,6 @@ int main(int argc, char** argv)
|
|||
{"version", no_argument, 0, 'v'},
|
||||
{"print-state", required_argument, 0, 'x'},
|
||||
{"analyze", required_argument, 0, 'z'},
|
||||
{"transfile", required_argument, 0, 'A'},
|
||||
{"no-checksums", no_argument, 0, 'C'},
|
||||
{"dfa-cache", required_argument, 0, 'D'},
|
||||
{"force-dns", no_argument, 0, 'F'},
|
||||
|
@ -434,7 +431,7 @@ int main(int argc, char** argv)
|
|||
opterr = 0;
|
||||
|
||||
char opts[256];
|
||||
safe_strncpy(opts, "A:B:D:e:f:I:i:K:n:p:R:r:s:T:t:U:w:x:X:y:Y:z:CFGHLOPSWdghlv",
|
||||
safe_strncpy(opts, "B:D:e:f:I:i:K:n:p:R:r:s:T:t:U:w:x:X:y:Y:z:CFGHLOPSWdghlv",
|
||||
sizeof(opts));
|
||||
|
||||
#ifdef USE_PERFTOOLS
|
||||
|
@ -504,10 +501,6 @@ int main(int argc, char** argv)
|
|||
}
|
||||
break;
|
||||
|
||||
case 'A':
|
||||
transformed_writefile = optarg;
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
override_ignore_checksums = 1;
|
||||
break;
|
||||
|
@ -795,7 +788,7 @@ int main(int argc, char** argv)
|
|||
|
||||
if ( dns_type != DNS_PRIME )
|
||||
net_init(interfaces, read_files, netflows, flow_files,
|
||||
writefile, transformed_writefile,
|
||||
writefile,
|
||||
user_pcap_filter ? user_pcap_filter : "tcp or udp",
|
||||
secondary_path->Filter(), do_watchdog);
|
||||
|
||||
|
|
|
@ -37,8 +37,7 @@ int tcp_checksum(const struct ip* ip, const struct tcphdr* tp, int len)
|
|||
{
|
||||
// ### Note, this is only correct for IPv4. This routine is only
|
||||
// used by the connection compressor (which we turn off for IPv6
|
||||
// traffic) and trace rewriting (which currently doesn't support
|
||||
// IPv6 either).
|
||||
// traffic).
|
||||
|
||||
int tcp_len = tp->th_off * 4 + len;
|
||||
uint32 sum;
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
rewriter smb_header%(is_orig: bool, hdr: smb_hdr%)
|
||||
%{
|
||||
const int is_orig = 0;
|
||||
|
||||
@WRITE@(is_orig, 1, "\xff");
|
||||
@WRITE@(is_orig, 3, "SMB");
|
||||
@WRITE@(is_orig, 1, hdr->command);
|
||||
@WRITE@(is_orig, 4, hdr->error);
|
||||
@WRITE@(is_orig, 1, hdr->flags);
|
||||
@WRITE@(is_orig, 2, hdr->flags2);
|
||||
@WRITE@(is_orig, 6, "\x0\x0\x0\x0\x0\x0");
|
||||
@WRITE@(is_orig, 6, "\x0\x0\x0\x0\x0\x0");
|
||||
@WRITE@(is_orig, 2, hdr->tid);
|
||||
@WRITE@(is_orig, 2, hdr->pid);
|
||||
@WRITE@(is_orig, 2, hdr->mid);
|
||||
%}
|
|
@ -1,45 +0,0 @@
|
|||
rewriter smtp_request%(is_orig: bool, command: string, arg: string%)
|
||||
%{
|
||||
if ( command->Len() > 0 )
|
||||
{
|
||||
u_char ch = command->Bytes()[0];
|
||||
|
||||
if ( isalpha(ch) )
|
||||
{ // Do not dump artificial commands: ">", ".", "***"
|
||||
@WRITE@(is_orig, command->AsString());
|
||||
@WRITE@(is_orig, 1, " ");
|
||||
}
|
||||
}
|
||||
|
||||
@WRITE@(is_orig, arg->AsString());
|
||||
@WRITE@(is_orig, 2, "\r\n");
|
||||
%}
|
||||
|
||||
rewriter smtp_reply%(is_orig: bool, code: count, msg: string, cont_resp: bool%)
|
||||
%{
|
||||
const char* str = fmt("%lu", (unsigned long) code);
|
||||
int len = strlen(str);
|
||||
|
||||
@WRITE@(is_orig, len, str);
|
||||
|
||||
if ( cont_resp )
|
||||
@WRITE@(is_orig, "-");
|
||||
else
|
||||
@WRITE@(is_orig, " ");
|
||||
|
||||
@WRITE@(is_orig, msg->AsString());
|
||||
@WRITE@(is_orig, "\r\n");
|
||||
%}
|
||||
|
||||
# Since SMTP data is delivered by lines ending with CRLF, this
|
||||
# function takes a line without the trailing CRLF and dumps the string
|
||||
# followed by CRLF. If you want to dump multiple lines, please dump
|
||||
# them one at a time (without trailing CRLF's).
|
||||
rewriter smtp_data%(is_orig: bool, data: string%)
|
||||
%{
|
||||
if ( data->Len() > 0 && data->Bytes()[0] == '.')
|
||||
@WRITE@(is_orig, ".");
|
||||
|
||||
@WRITE@(is_orig, data->AsString());
|
||||
@WRITE@(is_orig, "\r\n");
|
||||
%}
|
Loading…
Add table
Add a link
Reference in a new issue