Merge remote-tracking branch 'origin/master' into topic/vladg/sip

This commit is contained in:
Vlad Grigorescu 2014-04-22 18:55:26 -04:00
commit 25d7b71c50
1460 changed files with 70473 additions and 191398 deletions

View file

@ -0,0 +1 @@
Support for connection (TCP, UDP, or ICMP) analysis.

View file

@ -16,12 +16,12 @@
module Conn;
export {
## The prefix given to files containing extracted connections as they are
## opened on disk.
## The prefix given to files containing extracted connections as they
## are opened on disk.
const extraction_prefix = "contents" &redef;
## If this variable is set to ``T``, then all contents of all connections
## will be extracted.
## If this variable is set to ``T``, then all contents of all
## connections will be extracted.
const default_extract = F &redef;
}

View file

@ -1,7 +1,7 @@
##! This script manages the tracking/logging of general information regarding
##! TCP, UDP, and ICMP traffic. For UDP and ICMP, "connections" are to
##! be interpreted using flow semantics (sequence of packets from a source
##! host/post to a destination host/port). Further, ICMP "ports" are to
##! host/port to a destination host/port). Further, ICMP "ports" are to
##! be interpreted as the source port meaning the ICMP message type and
##! the destination port being the ICMP message code.
@ -23,7 +23,7 @@ export {
id: conn_id &log;
## The transport layer protocol of the connection.
proto: transport_proto &log;
## An identification of an application protocol being sent over the
## An identification of an application protocol being sent over
## the connection.
service: string &log &optional;
## How long the connection lasted. For 3-way or 4-way connection
@ -31,9 +31,10 @@ export {
duration: interval &log &optional;
## The number of payload bytes the originator sent. For TCP
## this is taken from sequence numbers and might be inaccurate
## (e.g., due to large connections)
## (e.g., due to large connections).
orig_bytes: count &log &optional;
## The number of payload bytes the responder sent. See ``orig_bytes``.
## The number of payload bytes the responder sent. See
## *orig_bytes*.
resp_bytes: count &log &optional;
## ========== ===============================================
@ -55,20 +56,20 @@ export {
## ========== ===============================================
conn_state: string &log &optional;
## If the connection is originated locally, this value will be T. If
## it was originated remotely it will be F. In the case that the
## :bro:id:`Site::local_nets` variable is undefined, this field will
## be left empty at all times.
## If the connection is originated locally, this value will be T.
## If it was originated remotely it will be F. In the case that
## the :bro:id:`Site::local_nets` variable is undefined, this
## field will be left empty at all times.
local_orig: bool &log &optional;
## Indicates the number of bytes missed in content gaps, which is
## representative of packet loss. A value other than zero will
## normally cause protocol analysis to fail but some analysis may
## have been completed prior to the packet loss.
## Indicates the number of bytes missed in content gaps, which
## is representative of packet loss. A value other than zero
## will normally cause protocol analysis to fail but some
## analysis may have been completed prior to the packet loss.
missed_bytes: count &log &default=0;
## Records the state history of connections as a string of letters.
## The meaning of those letters is:
## Records the state history of connections as a string of
## letters. The meaning of those letters is:
##
## ====== ====================================================
## Letter Meaning
@ -83,24 +84,25 @@ export {
## i inconsistent packet (e.g. SYN+RST bits both set)
## ====== ====================================================
##
## If the event comes from the originator, the letter is in upper-case; if it comes
## from the responder, it's in lower-case. Multiple packets of the same type will
## only be noted once (e.g. we only record one "d" in each direction, regardless of
## how many data packets were seen.)
## If the event comes from the originator, the letter is in
## upper-case; if it comes from the responder, it's in
## lower-case. Multiple packets of the same type will only be
## noted once (e.g. we only record one "d" in each direction,
## regardless of how many data packets were seen.)
history: string &log &optional;
## Number of packets that the originator sent.
## Only set if :bro:id:`use_conn_size_analyzer` = T
## Only set if :bro:id:`use_conn_size_analyzer` = T.
orig_pkts: count &log &optional;
## Number of IP level bytes that the originator sent (as seen on the wire,
## taken from IP total_length header field).
## Only set if :bro:id:`use_conn_size_analyzer` = T
## Number of IP level bytes that the originator sent (as seen on
## the wire, taken from the IP total_length header field).
## Only set if :bro:id:`use_conn_size_analyzer` = T.
orig_ip_bytes: count &log &optional;
## Number of packets that the responder sent.
## Only set if :bro:id:`use_conn_size_analyzer` = T
## Only set if :bro:id:`use_conn_size_analyzer` = T.
resp_pkts: count &log &optional;
## Number og IP level bytes that the responder sent (as seen on the wire,
## taken from IP total_length header field).
## Only set if :bro:id:`use_conn_size_analyzer` = T
## Number of IP level bytes that the responder sent (as seen on
## the wire, taken from the IP total_length header field).
## Only set if :bro:id:`use_conn_size_analyzer` = T.
resp_ip_bytes: count &log &optional;
## If this connection was over a tunnel, indicate the
## *uid* values for any encapsulating parent connections

View file

@ -11,10 +11,11 @@ export {
## c: The connection to watch.
##
## callback: A callback function that takes as arguments the monitored
## *connection*, and counter *cnt* that increments each time the
## callback is called. It returns an interval indicating how long
## in the future to schedule an event which will call the
## callback. A negative return interval causes polling to stop.
## *connection*, and counter *cnt* that increments each time
## the callback is called. It returns an interval indicating
## how long in the future to schedule an event which will call
## the callback. A negative return interval causes polling
## to stop.
##
## cnt: The initial value of a counter which gets passed to *callback*.
##

View file

@ -0,0 +1 @@
Support for Dynamic Host Configuration Protocol (DHCP) analysis.

View file

@ -0,0 +1,4 @@
@load ./consts
@load ./main
@load-sigs ./dpd.sig

View file

@ -0,0 +1,20 @@
##! Types, errors, and fields for analyzing DHCP data. A helper file
##! for DHCP analysis scripts.
module DHCP;
export {
## Types of DHCP messages. See :rfc:`1533`.
const message_types = {
[1] = "DHCP_DISCOVER",
[2] = "DHCP_OFFER",
[3] = "DHCP_REQUEST",
[4] = "DHCP_DECLINE",
[5] = "DHCP_ACK",
[6] = "DHCP_NAK",
[7] = "DHCP_RELEASE",
[8] = "DHCP_INFORM",
} &default = function(n: count): string { return fmt("unknown-message-type-%d", n); };
}

View file

@ -0,0 +1,5 @@
signature dhcp_cookie {
ip-proto == udp
payload /^.*\x63\x82\x53\x63/
enable "dhcp"
}

View file

@ -0,0 +1,76 @@
##! Analyzes DHCP traffic in order to log DHCP leases given to clients.
##! This script ignores large swaths of the protocol, since it is rather
##! noisy on most networks, and focuses on the end-result: assigned leases.
##!
##! If you'd like to track known DHCP devices and to log the hostname
##! supplied by the client, see
##! :doc:`/scripts/policy/protocols/dhcp/known-devices-and-hostnames.bro`.
@load ./utils.bro
module DHCP;
export {
redef enum Log::ID += { LOG };
## The record type which contains the column fields of the DHCP log.
type Info: record {
## The earliest time at which a DHCP message over the
## associated connection is observed.
ts: time &log;
## A unique identifier of the connection over which DHCP is
## occurring.
uid: string &log;
## The connection's 4-tuple of endpoint addresses/ports.
id: conn_id &log;
## Client's hardware address.
mac: string &log &optional;
## Client's actual assigned IP address.
assigned_ip: addr &log &optional;
## IP address lease interval.
lease_time: interval &log &optional;
## A random number chosen by the client for this transaction.
trans_id: count &log;
};
## Event that can be handled to access the DHCP
## record as it is sent on to the logging framework.
global log_dhcp: event(rec: Info);
}
# Add the dhcp info to the connection record.
redef record connection += {
dhcp: Info &optional;
};
# 67/udp is the server's port, 68/udp the client.
const ports = { 67/udp, 68/udp };
redef likely_server_ports += { 67/udp };
event bro_init()
{
Log::create_stream(DHCP::LOG, [$columns=Info, $ev=log_dhcp]);
Analyzer::register_for_ports(Analyzer::ANALYZER_DHCP, ports);
}
event dhcp_ack(c: connection, msg: dhcp_msg, mask: addr, router: dhcp_router_list, lease: interval, serv_addr: addr, host_name: string)
{
local info: Info;
info$ts = network_time();
info$id = c$id;
info$uid = c$uid;
info$lease_time = lease;
info$trans_id = msg$xid;
if ( msg$h_addr != "" )
info$mac = msg$h_addr;
if ( reverse_ip(msg$yiaddr) != 0.0.0.0 )
info$assigned_ip = reverse_ip(msg$yiaddr);
else
info$assigned_ip = c$id$orig_h;
c$dhcp = info;
Log::write(DHCP::LOG, c$dhcp);
}

View file

@ -0,0 +1,19 @@
##! Utilities specific for DHCP processing.
module DHCP;
export {
## Reverse the octets of an IPv4 address.
##
## ip: An IPv4 address.
##
## Returns: A reversed IPv4 address.
global reverse_ip: function(ip: addr): addr;
}
function reverse_ip(ip: addr): addr
{
local octets = split(cat(ip), /\./);
return to_addr(cat(octets[4], ".", octets[3], ".", octets[2], ".", octets[1]));
}

View file

@ -0,0 +1 @@
Support for Distributed Network Protocol (DNP3) analysis.

View file

@ -0,0 +1,3 @@
@load ./main
@load-sigs ./dpd.sig

View file

@ -0,0 +1,49 @@
module DNP3;
export {
## Standard defined Modbus function codes.
const function_codes = {
# Requests.
[0x00] = "CONFIRM",
[0x01] = "READ",
[0x02] = "WRITE",
[0x03] = "SELECT",
[0x04] = "OPERATE",
[0x05] = "DIRECT_OPERATE",
[0x06] = "DIRECT_OPERATE_NR",
[0x07] = "IMMED_FREEZE",
[0x08] = "IMMED_FREEZE_NR",
[0x09] = "FREEZE_CLEAR",
[0x0a] = "FREEZE_CLEAR_NR",
[0x0b] = "FREEZE_AT_TIME",
[0x0c] = "FREEZE_AT_TIME_NR",
[0x0d] = "COLD_RESTART",
[0x0e] = "WARM_RESTART",
[0x0f] = "INITIALIZE_DATA",
[0x10] = "INITIALIZE_APPL",
[0x11] = "START_APPL",
[0x12] = "STOP_APPL",
[0x13] = "SAVE_CONFIG",
[0x14] = "ENABLE_UNSOLICITED",
[0x15] = "DISABLE_UNSOLICITED",
[0x16] = "ASSIGN_CLASS",
[0x17] = "DELAY_MEASURE",
[0x18] = "RECORD_CURRENT_TIME",
[0x19] = "OPEN_FILE",
[0x1a] = "CLOSE_FILE",
[0x1b] = "DELETE_FILE",
[0x1c] = "GET_FILE_INFO",
[0x1d] = "AUTHENTICATE_FILE",
[0x1e] = "ABORT_FILE",
[0x1f] = "ACTIVATE_CONFIG",
[0x20] = "AUTHENTICATE_REQ",
[0x21] = "AUTHENTICATE_ERR",
# Responses.
[0x81] = "RESPONSE",
[0x82] = "UNSOLICITED_RESPONSE",
[0x83] = "AUTHENTICATE_RESP",
} &default=function(i: count):string { return fmt("unknown-%d", i); } &redef;
}

View file

@ -0,0 +1,9 @@
# DNP3 packets always starts with 0x05 0x64 .
signature dpd_dnp3_server {
ip-proto == tcp
payload /\x05\x64/
tcp-state responder
enable "dnp3"
}

View file

@ -0,0 +1,73 @@
##! A very basic DNP3 analysis script that just logs requests and replies.
module DNP3;
@load ./consts
export {
redef enum Log::ID += { LOG };
type Info: record {
## Time of the request.
ts: time &log;
## Unique identifier for the connection.
uid: string &log;
## Identifier for the connection.
id: conn_id &log;
## The name of the function message in the request.
fc_request: string &log &optional;
## The name of the function message in the reply.
fc_reply: string &log &optional;
## The response's "internal indication number".
iin: count &log &optional;
};
## Event that can be handled to access the DNP3 record as it is sent on
## to the logging framework.
global log_dnp3: event(rec: Info);
}
redef record connection += {
dnp3: Info &optional;
};
const ports = { 20000/tcp };
redef likely_server_ports += { ports };
event bro_init() &priority=5
{
Log::create_stream(DNP3::LOG, [$columns=Info, $ev=log_dnp3]);
Analyzer::register_for_ports(Analyzer::ANALYZER_DNP3, ports);
}
event dnp3_application_request_header(c: connection, is_orig: bool, fc: count)
{
if ( ! c?$dnp3 )
c$dnp3 = [$ts=network_time(), $uid=c$uid, $id=c$id];
c$dnp3$ts = network_time();
c$dnp3$fc_request = function_codes[fc];
}
event dnp3_application_response_header(c: connection, is_orig: bool, fc: count, iin: count)
{
if ( ! c?$dnp3 )
c$dnp3 = [$ts=network_time(), $uid=c$uid, $id=c$id];
c$dnp3$ts = network_time();
c$dnp3$fc_reply = function_codes[fc];
c$dnp3$iin = iin;
Log::write(LOG, c$dnp3);
delete c$dnp3;
}
event connection_state_remove(c: connection) &priority=-5
{
if ( ! c?$dnp3 )
return;
Log::write(LOG, c$dnp3);
delete c$dnp3;
}

View file

@ -0,0 +1 @@
Support for Domain Name System (DNS) protocol analysis.

View file

@ -8,7 +8,8 @@ export {
const EDNS = 41; ##< An OPT RR TYPE value described by EDNS.
const ANY = 255; ##< A QTYPE value describing a request for all records.
## Mapping of DNS query type codes to human readable string representation.
## Mapping of DNS query type codes to human readable string
## representation.
const query_types = {
[1] = "A", [2] = "NS", [3] = "MD", [4] = "MF",
[5] = "CNAME", [6] = "SOA", [7] = "MB", [8] = "MG",
@ -64,8 +65,8 @@ export {
[32768] = "DNS_SEC_OK", # accepts DNS Sec RRs
} &default="?";
## Possible values of the CLASS field in resource records or QCLASS field
## in query messages.
## Possible values of the CLASS field in resource records or QCLASS
## field in query messages.
const classes = {
[1] = "C_INTERNET",
[2] = "C_CSNET",

View file

@ -22,8 +22,8 @@ export {
id: conn_id &log;
## The transport layer protocol of the connection.
proto: transport_proto &log;
## A 16 bit identifier assigned by the program that generated the
## DNS query. Also used in responses to match up replies to
## A 16-bit identifier assigned by the program that generated
## the DNS query. Also used in responses to match up replies to
## outstanding queries.
trans_id: count &log &optional;
## The domain name that is the subject of the DNS query.
@ -40,17 +40,17 @@ export {
rcode: count &log &optional;
## A descriptive name for the response code value.
rcode_name: string &log &optional;
## The Authoritative Answer bit for response messages specifies that
## the responding name server is an authority for the domain name
## in the question section.
## The Authoritative Answer bit for response messages specifies
## that the responding name server is an authority for the
## domain name in the question section.
AA: bool &log &default=F;
## The Truncation bit specifies that the message was truncated.
TC: bool &log &default=F;
## The Recursion Desired bit in a request message indicates that
## the client wants recursive service for this query.
RD: bool &log &default=F;
## The Recursion Available bit in a response message indicates that
## the name server supports recursive queries.
## The Recursion Available bit in a response message indicates
## that the name server supports recursive queries.
RA: bool &log &default=F;
## A reserved field that is currently supposed to be zero in all
## queries and responses.
@ -58,29 +58,32 @@ export {
## The set of resource descriptions in the query answer.
answers: vector of string &log &optional;
## The caching intervals of the associated RRs described by the
## ``answers`` field.
## *answers* field.
TTLs: vector of interval &log &optional;
## The DNS query was rejected by the server.
rejected: bool &log &default=F;
## This value indicates if this request/response pair is ready to be
## logged.
ready: bool &default=F;
## The total number of resource records in a reply message's answer
## section.
## The total number of resource records in a reply message's
## answer section.
total_answers: count &optional;
## The total number of resource records in a reply message's answer,
## authority, and additional sections.
## The total number of resource records in a reply message's
## answer, authority, and additional sections.
total_replies: count &optional;
## Whether the full DNS query has been seen.
saw_query: bool &default=F;
## Whether the full DNS reply has been seen.
saw_reply: bool &default=F;
};
## An event that can be handled to access the :bro:type:`DNS::Info`
## record as it is sent to the logging framework.
global log_dns: event(rec: Info);
## This is called by the specific dns_*_reply events with a "reply" which
## may not represent the full data available from the resource record, but
## it's generally considered a summarization of the response(s).
## This is called by the specific dns_*_reply events with a "reply"
## which may not represent the full data available from the resource
## record, but it's generally considered a summarization of the
## responses.
##
## c: The connection record for which to fill in DNS reply data.
##
@ -89,30 +92,50 @@ export {
## ans: The general information of a RR response.
##
## reply: The specific response information according to RR type/class.
global do_reply: event(c: connection, msg: dns_msg, ans: dns_answer, reply: string);
global do_reply: hook(c: connection, msg: dns_msg, ans: dns_answer, reply: string);
## A hook that is called whenever a session is being set.
## This can be used if additional initialization logic needs to happen
## when creating a new session value.
##
## c: The connection involved in the new session
## c: The connection involved in the new session.
##
## msg: The DNS message header information.
##
## is_query: Indicator for if this is being called for a query or a response.
global set_session: hook(c: connection, msg: dns_msg, is_query: bool);
## Yields a queue of :bro:see:`DNS::Info` objects for a given
## DNS message query/transaction ID.
type PendingMessages: table[count] of Queue::Queue;
## The amount of time that DNS queries or replies for a given
## query/transaction ID are allowed to be queued while waiting for
## a matching reply or query.
const pending_msg_expiry_interval = 2min &redef;
## Give up trying to match pending DNS queries or replies for a given
## query/transaction ID once this number of unmatched queries or replies
## is reached (this shouldn't happen unless either the DNS server/resolver
## is broken, Bro is not seeing all the DNS traffic, or an AXFR query
## response is ongoing).
const max_pending_msgs = 50 &redef;
## Give up trying to match pending DNS queries or replies across all
## query/transaction IDs once there is at least one unmatched query or
## reply across this number of different query IDs.
const max_pending_query_ids = 50 &redef;
## A record type which tracks the status of DNS queries for a given
## :bro:type:`connection`.
type State: record {
## Indexed by query id, returns Info record corresponding to
## query/response which haven't completed yet.
pending: table[count] of Queue::Queue;
## queries that haven't been matched with a response yet.
pending_queries: PendingMessages;
## This is the list of DNS responses that have completed based on the
## number of responses declared and the number received. The contents
## of the set are transaction IDs.
finished_answers: set[count];
## Indexed by query id, returns Info record corresponding to
## replies that haven't been matched with a query yet.
pending_replies: PendingMessages;
};
}
@ -142,6 +165,66 @@ function new_session(c: connection, trans_id: count): Info
return info;
}
function log_unmatched_msgs_queue(q: Queue::Queue)
{
local infos: vector of Info;
Queue::get_vector(q, infos);
for ( i in infos )
{
event flow_weird("dns_unmatched_msg",
infos[i]$id$orig_h, infos[i]$id$resp_h);
Log::write(DNS::LOG, infos[i]);
}
}
function log_unmatched_msgs(msgs: PendingMessages)
{
for ( trans_id in msgs )
log_unmatched_msgs_queue(msgs[trans_id]);
msgs = PendingMessages();
}
function enqueue_new_msg(msgs: PendingMessages, id: count, msg: Info)
{
if ( id !in msgs )
{
if ( |msgs| > max_pending_query_ids )
{
event flow_weird("dns_unmatched_query_id_quantity",
msg$id$orig_h, msg$id$resp_h);
# Throw away all unmatched on assumption they'll never be matched.
log_unmatched_msgs(msgs);
}
msgs[id] = Queue::init();
}
else
{
if ( Queue::len(msgs[id]) > max_pending_msgs )
{
event flow_weird("dns_unmatched_msg_quantity",
msg$id$orig_h, msg$id$resp_h);
log_unmatched_msgs_queue(msgs[id]);
# Throw away all unmatched on assumption they'll never be matched.
msgs[id] = Queue::init();
}
}
Queue::put(msgs[id], msg);
}
function pop_msg(msgs: PendingMessages, id: count): Info
{
local rval: Info = Queue::get(msgs[id]);
if ( Queue::len(msgs[id]) == 0 )
delete msgs[id];
return rval;
}
hook set_session(c: connection, msg: dns_msg, is_query: bool) &priority=5
{
if ( ! c?$dns_state )
@ -150,29 +233,39 @@ hook set_session(c: connection, msg: dns_msg, is_query: bool) &priority=5
c$dns_state = state;
}
if ( msg$id !in c$dns_state$pending )
c$dns_state$pending[msg$id] = Queue::init();
local info: Info;
# If this is either a query or this is the reply but
# no Info records are in the queue (we missed the query?)
# we need to create an Info record and put it in the queue.
if ( is_query ||
Queue::len(c$dns_state$pending[msg$id]) == 0 )
{
info = new_session(c, msg$id);
Queue::put(c$dns_state$pending[msg$id], info);
}
if ( is_query )
# If this is a query, assign the newly created info variable
# so that the world looks correct to anything else handling
# this query.
c$dns = info;
{
if ( msg$id in c$dns_state$pending_replies &&
Queue::len(c$dns_state$pending_replies[msg$id]) > 0 )
{
# Match this DNS query w/ what's at head of pending reply queue.
c$dns = pop_msg(c$dns_state$pending_replies, msg$id);
}
else
{
# Create a new DNS session and put it in the query queue so
# we can wait for a matching reply.
c$dns = new_session(c, msg$id);
enqueue_new_msg(c$dns_state$pending_queries, msg$id, c$dns);
}
}
else
# Peek at the next item in the queue for this trans_id and
# assign it to c$dns since this is a response.
c$dns = Queue::peek(c$dns_state$pending[msg$id]);
{
if ( msg$id in c$dns_state$pending_queries &&
Queue::len(c$dns_state$pending_queries[msg$id]) > 0 )
{
# Match this DNS reply w/ what's at head of pending query queue.
c$dns = pop_msg(c$dns_state$pending_queries, msg$id);
}
else
{
# Create a new DNS session and put it in the reply queue so
# we can wait for a matching query.
c$dns = new_session(c, msg$id);
event conn_weird("dns_unmatched_reply", c, "");
enqueue_new_msg(c$dns_state$pending_replies, msg$id, c$dns);
}
}
if ( ! is_query )
{
@ -182,36 +275,36 @@ hook set_session(c: connection, msg: dns_msg, is_query: bool) &priority=5
if ( ! c$dns?$total_answers )
c$dns$total_answers = msg$num_answers;
if ( c$dns?$total_replies &&
c$dns$total_replies != msg$num_answers + msg$num_addl + msg$num_auth )
{
event conn_weird("dns_changed_number_of_responses", c,
fmt("The declared number of responses changed from %d to %d",
c$dns$total_replies,
msg$num_answers + msg$num_addl + msg$num_auth));
}
else
{
# Store the total number of responses expected from the first reply.
if ( ! c$dns?$total_replies )
c$dns$total_replies = msg$num_answers + msg$num_addl + msg$num_auth;
}
if ( msg$rcode != 0 && msg$num_queries == 0 )
c$dns$rejected = T;
}
}
event dns_message(c: connection, is_orig: bool, msg: dns_msg, len: count) &priority=5
{
hook set_session(c, msg, is_orig);
if ( msg$opcode != 0 )
# Currently only standard queries are tracked.
return;
hook set_session(c, msg, ! msg$QR);
}
event DNS::do_reply(c: connection, msg: dns_msg, ans: dns_answer, reply: string) &priority=5
hook DNS::do_reply(c: connection, msg: dns_msg, ans: dns_answer, reply: string) &priority=5
{
if ( msg$opcode != 0 )
# Currently only standard queries are tracked.
return;
if ( ! msg$QR )
# This is weird: the inquirer must also be providing answers in
# the request, which is not what we want to track.
return;
if ( ans$answer_type == DNS_ANS )
{
if ( ! c?$dns )
{
event conn_weird("dns_unmatched_reply", c, "");
hook set_session(c, msg, F);
}
c$dns$AA = msg$AA;
c$dns$RA = msg$RA;
@ -225,29 +318,35 @@ event DNS::do_reply(c: connection, msg: dns_msg, ans: dns_answer, reply: string)
c$dns$TTLs = vector();
c$dns$TTLs[|c$dns$TTLs|] = ans$TTL;
}
if ( c$dns?$answers && c$dns?$total_answers &&
|c$dns$answers| == c$dns$total_answers )
{
# Indicate this request/reply pair is ready to be logged.
c$dns$ready = T;
}
}
}
event DNS::do_reply(c: connection, msg: dns_msg, ans: dns_answer, reply: string) &priority=-5
event dns_end(c: connection, msg: dns_msg) &priority=5
{
if ( c$dns$ready )
if ( ! c?$dns )
return;
if ( msg$QR )
c$dns$saw_reply = T;
else
c$dns$saw_query = T;
}
event dns_end(c: connection, msg: dns_msg) &priority=-5
{
if ( c?$dns && c$dns$saw_reply && c$dns$saw_query )
{
Log::write(DNS::LOG, c$dns);
# This record is logged and no longer pending.
Queue::get(c$dns_state$pending[c$dns$trans_id]);
delete c$dns;
}
}
event dns_request(c: connection, msg: dns_msg, query: string, qtype: count, qclass: count) &priority=5
{
if ( msg$opcode != 0 )
# Currently only standard queries are tracked.
return;
c$dns$RD = msg$RD;
c$dns$TC = msg$TC;
c$dns$qclass = qclass;
@ -260,64 +359,78 @@ event dns_request(c: connection, msg: dns_msg, query: string, qtype: count, qcla
# Note: I'm ignoring the name type for now. Not sure if this should be
# worked into the query/response in some fashion.
if ( c$id$resp_p == 137/udp )
{
query = decode_netbios_name(query);
if ( c$dns$qtype_name == "SRV" )
{
# The SRV RFC used the ID used for NetBios Status RRs.
# So if this is NetBios Name Service we name it correctly.
c$dns$qtype_name = "NBSTAT";
}
}
c$dns$query = query;
}
event dns_unknown_reply(c: connection, msg: dns_msg, ans: dns_answer) &priority=5
{
hook DNS::do_reply(c, msg, ans, fmt("<unknown type=%s>", ans$qtype));
}
event dns_A_reply(c: connection, msg: dns_msg, ans: dns_answer, a: addr) &priority=5
{
event DNS::do_reply(c, msg, ans, fmt("%s", a));
hook DNS::do_reply(c, msg, ans, fmt("%s", a));
}
event dns_TXT_reply(c: connection, msg: dns_msg, ans: dns_answer, str: string) &priority=5
{
event DNS::do_reply(c, msg, ans, str);
hook DNS::do_reply(c, msg, ans, str);
}
event dns_AAAA_reply(c: connection, msg: dns_msg, ans: dns_answer, a: addr) &priority=5
{
event DNS::do_reply(c, msg, ans, fmt("%s", a));
hook DNS::do_reply(c, msg, ans, fmt("%s", a));
}
event dns_A6_reply(c: connection, msg: dns_msg, ans: dns_answer, a: addr) &priority=5
{
event DNS::do_reply(c, msg, ans, fmt("%s", a));
hook DNS::do_reply(c, msg, ans, fmt("%s", a));
}
event dns_NS_reply(c: connection, msg: dns_msg, ans: dns_answer, name: string) &priority=5
{
event DNS::do_reply(c, msg, ans, name);
hook DNS::do_reply(c, msg, ans, name);
}
event dns_CNAME_reply(c: connection, msg: dns_msg, ans: dns_answer, name: string) &priority=5
{
event DNS::do_reply(c, msg, ans, name);
hook DNS::do_reply(c, msg, ans, name);
}
event dns_MX_reply(c: connection, msg: dns_msg, ans: dns_answer, name: string,
preference: count) &priority=5
{
event DNS::do_reply(c, msg, ans, name);
hook DNS::do_reply(c, msg, ans, name);
}
event dns_PTR_reply(c: connection, msg: dns_msg, ans: dns_answer, name: string) &priority=5
{
event DNS::do_reply(c, msg, ans, name);
hook DNS::do_reply(c, msg, ans, name);
}
event dns_SOA_reply(c: connection, msg: dns_msg, ans: dns_answer, soa: dns_soa) &priority=5
{
event DNS::do_reply(c, msg, ans, soa$mname);
hook DNS::do_reply(c, msg, ans, soa$mname);
}
event dns_WKS_reply(c: connection, msg: dns_msg, ans: dns_answer) &priority=5
{
event DNS::do_reply(c, msg, ans, "");
hook DNS::do_reply(c, msg, ans, "");
}
event dns_SRV_reply(c: connection, msg: dns_msg, ans: dns_answer) &priority=5
event dns_SRV_reply(c: connection, msg: dns_msg, ans: dns_answer, target: string, priority: count, weight: count, p: count) &priority=5
{
event DNS::do_reply(c, msg, ans, "");
hook DNS::do_reply(c, msg, ans, target);
}
# TODO: figure out how to handle these
@ -338,7 +451,8 @@ event dns_SRV_reply(c: connection, msg: dns_msg, ans: dns_answer) &priority=5
event dns_rejected(c: connection, msg: dns_msg, query: string, qtype: count, qclass: count) &priority=5
{
c$dns$rejected = T;
if ( c?$dns )
c$dns$rejected = T;
}
event connection_state_remove(c: connection) &priority=-5
@ -346,16 +460,8 @@ event connection_state_remove(c: connection) &priority=-5
if ( ! c?$dns_state )
return;
# If Bro is expiring state, we should go ahead and log all unlogged
# request/response pairs now.
for ( trans_id in c$dns_state$pending )
{
local infos: vector of Info;
Queue::get_vector(c$dns_state$pending[trans_id], infos);
for ( i in infos )
{
Log::write(DNS::LOG, infos[i]);
}
}
# If Bro is expiring state, we should go ahead and log all unmatched
# queries and replies now.
log_unmatched_msgs(c$dns_state$pending_queries);
log_unmatched_msgs(c$dns_state$pending_replies);
}

View file

@ -0,0 +1 @@
Support for File Transfer Protocol (FTP) analysis.

View file

@ -1,4 +1,5 @@
@load ./utils-commands
@load ./info
@load ./main
@load ./utils
@load ./files

View file

@ -1,3 +1,4 @@
@load ./info
@load ./main
@load ./utils
@load base/utils/conn-ids

View file

@ -4,21 +4,22 @@
##! that successfully negotiate the GSSAPI method of an AUTH request
##! and for which the exchange involved an encoded TLS/SSL handshake,
##! indicating the GSI mechanism for GSSAPI was used. This analysis
##! is all supported internally, this script simple adds the "gridftp"
##! is all supported internally, this script simply adds the "gridftp"
##! label to the *service* field of the control channel's
##! :bro:type:`connection` record.
##!
##! GridFTP data channels are identified by a heuristic that relies on
##! the fact that default settings for GridFTP clients typically
##! mutally authenticate the data channel with TLS/SSL and negotiate a
##! mutually authenticate the data channel with TLS/SSL and negotiate a
##! NULL bulk cipher (no encryption). Connections with those
##! attributes are then polled for two minutes with decreasing frequency
##! to check if the transfer sizes are large enough to indicate a
##! GridFTP data channel that would be undesireable to analyze further
##! GridFTP data channel that would be undesirable to analyze further
##! (e.g. stop TCP reassembly). A side effect is that true connection
##! sizes are not logged, but at the benefit of saving CPU cycles that
##! otherwise go to analyzing the large (and likely benign) connections.
##! would otherwise go to analyzing the large (and likely benign) connections.
@load ./info
@load ./main
@load base/protocols/conn
@load base/protocols/ssl
@ -58,8 +59,8 @@ export {
## been exceeded. This is called in a :bro:see:`ssl_established` event
## handler and by default looks for both a client and server certificate
## and for a NULL bulk cipher. One way in which this function could be
## redefined is to make it also consider client/server certificate issuer
## subjects.
## redefined is to make it also consider client/server certificate
## issuer subjects.
##
## c: The connection which may possibly be a GridFTP data channel.
##

View file

@ -0,0 +1,74 @@
##! Defines data structures for tracking and logging FTP sessions.
module FTP;
@load ./utils-commands
export {
## This setting changes if passwords used in FTP sessions are
## captured or not.
const default_capture_password = F &redef;
## The expected endpoints of an FTP data channel.
type ExpectedDataChannel: record {
## Whether PASV mode is toggled for control channel.
passive: bool &log;
## The host that will be initiating the data connection.
orig_h: addr &log;
## The host that will be accepting the data connection.
resp_h: addr &log;
## The port at which the acceptor is listening for the data
## connection.
resp_p: port &log;
};
type Info: record {
## Time when the command was sent.
ts: time &log;
## Unique ID for the connection.
uid: string &log;
## The connection's 4-tuple of endpoint addresses/ports.
id: conn_id &log;
## User name for the current FTP session.
user: string &log &default="<unknown>";
## Password for the current FTP session if captured.
password: string &log &optional;
## Command given by the client.
command: string &log &optional;
## Argument for the command if one is given.
arg: string &log &optional;
## Libmagic "sniffed" file type if the command indicates a file
## transfer.
mime_type: string &log &optional;
## Size of the file if the command indicates a file transfer.
file_size: count &log &optional;
## Reply code from the server in response to the command.
reply_code: count &log &optional;
## Reply message from the server in response to the command.
reply_msg: string &log &optional;
## Expected FTP data channel.
data_channel: ExpectedDataChannel &log &optional;
## Current working directory that this session is in. By making
## the default value '.', we can indicate that unless something
## more concrete is discovered that the existing but unknown
## directory is ok to use.
cwd: string &default=".";
## Command that is currently waiting for a response.
cmdarg: CmdArg &optional;
## Queue for commands that have been sent but not yet responded
## to are tracked here.
pending_commands: PendingCmds;
## Indicates if the session is in active or passive mode.
passive: bool &default=F;
## Determines if the password will be captured for this request.
capture_password: bool &default=default_capture_password;
};
}

View file

@ -3,6 +3,8 @@
##! will take on the full path that the client is at along with the requested
##! file name.
@load ./info
@load ./utils
@load ./utils-commands
@load base/utils/paths
@load base/utils/numbers
@ -20,74 +22,11 @@ export {
"EPSV"
} &redef;
## This setting changes if passwords used in FTP sessions are captured or not.
const default_capture_password = F &redef;
## User IDs that can be considered "anonymous".
const guest_ids = { "anonymous", "ftp", "ftpuser", "guest" } &redef;
## The expected endpoints of an FTP data channel.
type ExpectedDataChannel: record {
## Whether PASV mode is toggled for control channel.
passive: bool &log;
## The host that will be initiating the data connection.
orig_h: addr &log;
## The host that will be accepting the data connection.
resp_h: addr &log;
## The port at which the acceptor is listening for the data connection.
resp_p: port &log;
};
type Info: record {
## Time when the command was sent.
ts: time &log;
## Unique ID for the connection.
uid: string &log;
## The connection's 4-tuple of endpoint addresses/ports.
id: conn_id &log;
## User name for the current FTP session.
user: string &log &default="<unknown>";
## Password for the current FTP session if captured.
password: string &log &optional;
## Command given by the client.
command: string &log &optional;
## Argument for the command if one is given.
arg: string &log &optional;
## Libmagic "sniffed" file type if the command indicates a file transfer.
mime_type: string &log &optional;
## Size of the file if the command indicates a file transfer.
file_size: count &log &optional;
## Reply code from the server in response to the command.
reply_code: count &log &optional;
## Reply message from the server in response to the command.
reply_msg: string &log &optional;
## Expected FTP data channel.
data_channel: ExpectedDataChannel &log &optional;
## Current working directory that this session is in. By making
## the default value '.', we can indicate that unless something
## more concrete is discovered that the existing but unknown
## directory is ok to use.
cwd: string &default=".";
## Command that is currently waiting for a response.
cmdarg: CmdArg &optional;
## Queue for commands that have been sent but not yet responded to
## are tracked here.
pending_commands: PendingCmds;
## Indicates if the session is in active or passive mode.
passive: bool &default=F;
## Determines if the password will be captured for this request.
capture_password: bool &default=default_capture_password;
};
## This record is to hold a parsed FTP reply code. For example, for the
## 201 status code, the digits would be parsed as: x->2, y->0, z=>1.
## 201 status code, the digits would be parsed as: x->2, y->0, z->1.
type ReplyCode: record {
x: count;
y: count;
@ -102,8 +41,6 @@ export {
global log_ftp: event(rec: Info);
}
@load ./utils
# Add the state tracking information variable to the connection record
redef record connection += {
ftp: Info &optional;

View file

@ -1,7 +1,8 @@
##! Utilities specific for FTP processing.
@load ./main
@load ./info
@load base/utils/addrs
@load base/utils/paths
module FTP;
@ -10,14 +11,14 @@ export {
##
## rec: An :bro:type:`FTP::Info` record.
##
## Returns: A URL, not prefixed by "ftp://".
## Returns: A URL, not prefixed by ``"ftp://"``.
global build_url: function(rec: Info): string;
## Creates a URL from an :bro:type:`FTP::Info` record.
##
## rec: An :bro:type:`FTP::Info` record.
##
## Returns: A URL prefixed with "ftp://".
## Returns: A URL prefixed with ``"ftp://"``.
global build_url_ftp: function(rec: Info): string;
## Create an extremely shortened representation of a log line.

View file

@ -0,0 +1 @@
Support for Hypertext Transfer Protocol (HTTP) analysis.

View file

@ -3,4 +3,4 @@
@load ./utils
@load ./files
@load-sigs ./dpd.sig
@load-sigs ./dpd.sig

View file

@ -1,6 +1,8 @@
# List of HTTP headers pulled from:
# http://annevankesteren.nl/2007/10/http-methods
signature dpd_http_client {
ip-proto == tcp
payload /^[[:space:]]*(GET|HEAD|POST)[[:space:]]*/
payload /^[[:space:]]*(OPTIONS|GET|HEAD|POST|PUT|DELETE|TRACE|CONNECT|PROPFIND|PROPPATCH|MKCOL|COPY|MOVE|LOCK|UNLOCK|VERSION-CONTROL|REPORT|CHECKOUT|CHECKIN|UNCHECKOUT|MKWORKSPACE|UPDATE|LABEL|MERGE|BASELINE-CONTROL|MKACTIVITY|ORDERPATCH|ACL|PATCH|SEARCH|BCOPY|BDELETE|BMOVE|BPROPFIND|BPROPPATCH|NOTIFY|POLL|SUBSCRIBE|UNSUBSCRIBE|X-MS-ENUMATTS|RPC_OUT_DATA|RPC_IN_DATA)[[:space:]]*/
tcp-state originator
}

View file

@ -28,9 +28,11 @@ export {
## The current entity.
current_entity: Entity &optional;
## Current number of MIME entities in the HTTP request message body.
## Current number of MIME entities in the HTTP request message
## body.
orig_mime_depth: count &default=0;
## Current number of MIME entities in the HTTP response message body.
## Current number of MIME entities in the HTTP response message
## body.
resp_mime_depth: count &default=0;
};
}
@ -70,7 +72,7 @@ event file_over_new_connection(f: fa_file, c: connection, is_orig: bool) &priori
if ( f$is_orig )
{
if ( ! c$http?$orig_mime_types )
if ( ! c$http?$orig_fuids )
c$http$orig_fuids = string_vec(f$id);
else
c$http$orig_fuids[|c$http$orig_fuids|] = f$id;
@ -85,7 +87,7 @@ event file_over_new_connection(f: fa_file, c: connection, is_orig: bool) &priori
}
else
{
if ( ! c$http?$resp_mime_types )
if ( ! c$http?$resp_fuids )
c$http$resp_fuids = string_vec(f$id);
else
c$http$resp_fuids[|c$http$resp_fuids|] = f$id;

View file

@ -4,6 +4,7 @@
@load base/utils/numbers
@load base/utils/files
@load base/frameworks/tunnels
module HTTP;
@ -16,7 +17,8 @@ export {
EMPTY
};
## This setting changes if passwords used in Basic-Auth are captured or not.
## This setting changes if passwords used in Basic-Auth are captured or
## not.
const default_capture_password = F &redef;
type Info: record {
@ -36,8 +38,8 @@ export {
## URI used in the request.
uri: string &log &optional;
## Value of the "referer" header. The comment is deliberately
## misspelled like the standard declares, but the name used here is
## "referrer" spelled correctly.
## misspelled like the standard declares, but the name used here
## is "referrer" spelled correctly.
referrer: string &log &optional;
## Value of the User-Agent header from the client.
user_agent: string &log &optional;
@ -55,7 +57,8 @@ export {
info_code: count &log &optional;
## Last seen 1xx informational reply message returned by the server.
info_msg: string &log &optional;
## Filename given in the Content-Disposition header sent by the server.
## Filename given in the Content-Disposition header sent by the
## server.
filename: string &log &optional;
## A set of indicators of various attributes discovered and
## related to a particular request/response pair.
@ -215,6 +218,17 @@ event http_reply(c: connection, version: string, code: count, reason: string) &p
c$http$info_code = code;
c$http$info_msg = reason;
}
if ( c$http?$method && c$http$method == "CONNECT" && code == 200 )
{
# Copy this conn_id and set the orig_p to zero because in the case of CONNECT
# proxies there will be potentially many source ports since a new proxy connection
# is established for each proxied connection. We treat this as a singular
# "tunnel".
local tid = copy(c$id);
tid$orig_p = 0/tcp;
Tunnel::register([$cid=tid, $tunnel_type=Tunnel::HTTP]);
}
}
event http_header(c: connection, is_orig: bool, name: string, value: string) &priority=5

View file

@ -6,8 +6,8 @@
module HTTP;
export {
## Given a string containing a series of key-value pairs separated by "=",
## this function can be used to parse out all of the key names.
## Given a string containing a series of key-value pairs separated
## by "=", this function can be used to parse out all of the key names.
##
## data: The raw data, such as a URL or cookie value.
##
@ -17,20 +17,20 @@ export {
## Returns: A vector of strings containing the keys.
global extract_keys: function(data: string, kv_splitter: pattern): string_vec;
## Creates a URL from an :bro:type:`HTTP::Info` record. This should handle
## edge cases such as proxied requests appropriately.
## Creates a URL from an :bro:type:`HTTP::Info` record. This should
## handle edge cases such as proxied requests appropriately.
##
## rec: An :bro:type:`HTTP::Info` record.
##
## Returns: A URL, not prefixed by "http://".
## Returns: A URL, not prefixed by ``"http://"``.
global build_url: function(rec: Info): string;
## Creates a URL from an :bro:type:`HTTP::Info` record. This should handle
## edge cases such as proxied requests appropriately.
## Creates a URL from an :bro:type:`HTTP::Info` record. This should
## handle edge cases such as proxied requests appropriately.
##
## rec: An :bro:type:`HTTP::Info` record.
##
## Returns: A URL prefixed with "http://".
## Returns: A URL prefixed with ``"http://"``.
global build_url_http: function(rec: Info): string;
## Create an extremely shortened representation of a log line.

View file

@ -0,0 +1 @@
Support for Internet Relay Chat (IRC) protocol analysis.

View file

@ -15,9 +15,9 @@ export {
uid: string &log;
## The connection's 4-tuple of endpoint addresses/ports.
id: conn_id &log;
## Nick name given for the connection.
## Nickname given for the connection.
nick: string &log &optional;
## User name given for the connection.
## Username given for the connection.
user: string &log &optional;
## Command given by the client.

View file

@ -0,0 +1 @@
Support for Modbus protocol analysis.

View file

@ -10,7 +10,7 @@ export {
type Info: record {
## Time of the request.
ts: time &log;
## Unique identifier for the connnection.
## Unique identifier for the connection.
uid: string &log;
## Identifier for the connection.
id: conn_id &log;
@ -20,8 +20,8 @@ export {
exception: string &log &optional;
};
## Event that can be handled to access the Modbus record as it is sent on
## to the logging framework.
## Event that can be handled to access the Modbus record as it is sent
## on to the logging framework.
global log_modbus: event(rec: Info);
}

View file

@ -0,0 +1 @@
Support for POP3 (Post Office Protocol) protocol analysis.

View file

@ -0,0 +1,3 @@
@load ./main
@load-sigs ./dpd.sig

View file

@ -0,0 +1,5 @@
signature dpd_sip {
ip-proto == udp
payload /^( SIP\/[0-9]\.[0-9]\x0d\x0a|SIP\/[0-9]\.[0-9] [0-9][0-9][0-9] )/
enable "sip"
}

View file

@ -0,0 +1,217 @@
##! Implements base functionality for SIP analysis. The logging model is
##! to log request/response pairs and all relevant metadata together in
##! a single record.
@load base/utils/numbers
@load base/utils/files
module SIP;
export {
redef enum Log::ID += { LOG };
type Info: record {
## Timestamp for when the request happened.
ts: time &log;
## Unique ID for the connection.
uid: string &log;
## The connection's 4-tuple of endpoint addresses/ports.
id: conn_id &log;
## Represents the pipelined depth into the connection of this
## request/response transaction.
trans_depth: count &log;
## Verb used in the SIP request (INVITE, REGISTER etc.).
method: string &log &optional;
## URI used in the request.
uri: string &log &optional;
## Contents of the Date: header from the client
date: string &log &optional;
## Contents of the From: header (call sender)
## Note: The tag= value that's usually appended to the sender
## is stripped off and not logged.
from: string &log &optional;
## Contents of the To: header (call recipient)
to: string &log &optional;
## Contents of the Reply-To: header
reply_to: string &log &optional;
## Contents of the Call-ID: header from the client
call_id: string &log &optional;
## Contents of the CSeq: header from the client
seq: string &log &optional;
## Contents of the Subject: header from the client
subject: string &log &optional;
## The message transmission path, as extracted from the headers.
path: vector of string &log &optional;
## Contents of the User-Agent: header from the client
user_agent: string &log &optional;
## Status code returned by the server.
status_code: count &log &optional;
## Status message returned by the server.
status_msg: string &log &optional;
## Contents of the Warning: header
warning: string &log &optional;
## Contents of the Content-Length: header from the client
request_body_len: string &log &optional;
## Contents of the Content-Length: header from the server
response_body_len: string &log &optional;
## Contents of the Content-Type: header from the server
content_type: string &log &optional;
};
type State: record {
## Pending requests.
pending: table[count] of Info;
## Current request in the pending queue.
current_request: count &default=0;
## Current response in the pending queue.
current_response: count &default=0;
};
## A list of SIP methods. Other methods will generate a weird. Note
## that the SIP analyzer will only accept methods consisting solely
## of letters ``[A-Za-z]``.
const sip_methods: set[string] = {
"REGISTER", "INVITE", "ACK", "CANCEL", "BYE", "OPTIONS"
} &redef;
## Event that can be handled to access the SIP record as it is sent on
## to the logging framework.
global log_sip: event(rec: Info);
}
# Add the sip state tracking fields to the connection record.
redef record connection += {
sip: Info &optional;
sip_state: State &optional;
};
const ports = { 5060/udp };
event bro_init() &priority=5
{
Log::create_stream(SIP::LOG, [$columns=Info, $ev=log_sip]);
Analyzer::register_for_ports(Analyzer::ANALYZER_SIP, ports);
}
function new_sip_session(c: connection): Info
{
local tmp: Info;
tmp$ts=network_time();
tmp$uid=c$uid;
tmp$id=c$id;
# $current_request is set prior to the Info record creation so we
# can use the value directly here.
tmp$trans_depth = c$sip_state$current_request;
tmp$path = vector();
return tmp;
}
function set_state(c: connection, is_request: bool)
{
if ( ! c?$sip_state )
{
local s: State;
c$sip_state = s;
}
# These deal with new requests and responses.
if ( is_request && c$sip_state$current_request !in c$sip_state$pending )
c$sip_state$pending[c$sip_state$current_request] = new_sip_session(c);
if ( ! is_request && c$sip_state$current_response !in c$sip_state$pending )
c$sip_state$pending[c$sip_state$current_response] = new_sip_session(c);
if ( is_request )
c$sip = c$sip_state$pending[c$sip_state$current_request];
else
c$sip = c$sip_state$pending[c$sip_state$current_response];
}
event sip_request(c: connection, method: string, original_URI: string, version: string) &priority=5
{
set_state(c, T);
c$sip$method = method;
c$sip$uri = original_URI;
if ( method !in sip_methods )
event conn_weird("unknown_SIP_method", c, method);
}
event sip_reply(c: connection, version: string, code: count, reason: string) &priority=5
{
if ( c$sip_state$current_response !in c$sip_state$pending )
++c$sip_state$current_response;
set_state(c, F);
c$sip$status_code = code;
c$sip$status_msg = reason;
}
event sip_header(c: connection, is_request: bool, name: string, value: string) &priority=5
{
if ( ! c?$sip_state )
{
local s: State;
c$sip_state = s;
}
if ( is_request ) # from client
{
if ( c$sip_state$current_request !in c$sip_state$pending )
++c$sip_state$current_request;
set_state(c, is_request);
if ( name == "CALL-ID" ) c$sip$call_id = value;
else if ( name == "CONTENT-LENGTH" || name == "L" ) c$sip$request_body_len = value;
else if ( name == "CSEQ" ) c$sip$seq = value;
else if ( name == "DATE" ) c$sip$date = value;
else if ( name == "FROM" || name == "F" ) c$sip$from = split1(value, /;[ ]?tag=/)[1];
else if ( name == "REPLY-TO" ) c$sip$reply_to = value;
else if ( name == "SUBJECT" || name == "S" ) c$sip$subject = value;
else if ( name == "TO" || name == "T" ) c$sip$to = value;
else if ( name == "USER-AGENT" ) c$sip$user_agent = value;
else if ( name == "VIA" || name == "V" ) c$sip$path[|c$sip$path|] = split1(value, /;[ ]?branch/)[1];
c$sip_state$pending[c$sip_state$current_request] = c$sip;
}
else # from server
{
if ( c$sip_state$current_response !in c$sip_state$pending )
++c$sip_state$current_response;
set_state(c, is_request);
if ( name == "CONTENT-LENGTH" || name == "L" ) c$sip$response_body_len = value;
else if ( name == "CONTENT-TYPE" || name == "C" ) c$sip$content_type = value;
else if ( name == "WARNING" ) c$sip$warning = value;
c$sip_state$pending[c$sip_state$current_response] = c$sip;
}
}
event sip_message_done(c: connection, is_request: bool) &priority = 5
{
set_state(c, is_request);
}
event sip_message_done(c: connection, is_request: bool) &priority = -5
{
# The reply body is done so we're ready to log.
if ( ! is_request )
{
Log::write(SIP::LOG, c$sip);
delete c$sip_state$pending[c$sip_state$current_response];
}
}
event connection_state_remove(c: connection) &priority=-5
{
# Flush all pending but incomplete request/response pairs.
if ( c?$sip_state )
{
for ( r in c$sip_state$pending )
{
# We don't use pending elements at index 0.
if ( r == 0 ) next;
Log::write(SIP::LOG, c$sip_state$pending[r]);
}
}
}

View file

@ -0,0 +1 @@
Support for Simple Mail Transfer Protocol (SMTP) analysis.

View file

@ -27,8 +27,10 @@ export {
event mime_begin_entity(c: connection) &priority=10
{
c$smtp$entity = Entity();
++c$smtp_state$mime_depth;
if ( c?$smtp )
c$smtp$entity = Entity();
if ( c?$smtp_state )
++c$smtp_state$mime_depth;
}
event file_over_new_connection(f: fa_file, c: connection, is_orig: bool) &priority=5

View file

@ -14,8 +14,8 @@ export {
uid: string &log;
## The connection's 4-tuple of endpoint addresses/ports.
id: conn_id &log;
## A count to represent the depth of this message transaction in a single
## connection where multiple messages were transferred.
## A count to represent the depth of this message transaction in
## a single connection where multiple messages were transferred.
trans_depth: count &log;
## Contents of the Helo header.
helo: string &log &optional;
@ -37,7 +37,7 @@ export {
in_reply_to: string &log &optional;
## Contents of the Subject header.
subject: string &log &optional;
## Contents of the X-Origininating-IP header.
## Contents of the X-Originating-IP header.
x_originating_ip: addr &log &optional;
## Contents of the first Received header.
first_received: string &log &optional;
@ -50,7 +50,8 @@ export {
## Value of the User-Agent header from the client.
user_agent: string &log &optional;
## Indicates if the "Received: from" headers should still be processed.
## Indicates if the "Received: from" headers should still be
## processed.
process_received_from: bool &default=T;
## Indicates if client activity has been seen, but not yet logged.
has_client_activity: bool &default=F;
@ -58,9 +59,9 @@ export {
type State: record {
helo: string &optional;
## Count the number of individual messages transmitted during this
## SMTP session. Note, this is not the number of recipients, but the
## number of message bodies transferred.
## Count the number of individual messages transmitted during
## this SMTP session. Note, this is not the number of
## recipients, but the number of message bodies transferred.
messages_transferred: count &default=0;
pending_messages: set[Info] &optional;
@ -290,7 +291,7 @@ function describe(rec: Info): string
{
if ( |rec$subject| > 20 )
{
abbrev_subject = rec$subject[0:20] + "...";
abbrev_subject = rec$subject[0:21] + "...";
}
}

View file

@ -0,0 +1 @@
Support for Simple Network Management Protocol (SNMP) analysis.

View file

@ -0,0 +1 @@
@load ./main

View file

@ -0,0 +1,15 @@
##! Enables analysis of SNMP datagrams.
module SNMP;
export {
}
const ports = { 161/udp, 162/udp };
redef likely_server_ports += { ports };
event bro_init() &priority=5
{
Analyzer::register_for_ports(Analyzer::ANALYZER_SNMP, ports);
}

View file

@ -0,0 +1 @@
Support for Socket Secure (SOCKS) protocol analysis.

View file

@ -9,17 +9,19 @@ export {
type Info: record {
## Time when the proxy connection was first detected.
ts: time &log;
## Unique ID for the tunnel - may correspond to connection uid or be non-existent.
## Unique ID for the tunnel - may correspond to connection uid
## or be non-existent.
uid: string &log;
## The connection's 4-tuple of endpoint addresses/ports.
id: conn_id &log;
## Protocol version of SOCKS.
version: count &log;
## Username for the proxy if extracted from the network..
## Username for the proxy if extracted from the network.
user: string &log &optional;
## Server status for the attempt at using the proxy.
status: string &log &optional;
## Client requested SOCKS address. Could be an address, a name or both.
## Client requested SOCKS address. Could be an address, a name
## or both.
request: SOCKS::Address &log &optional;
## Client requested port.
request_p: port &log &optional;

View file

@ -0,0 +1 @@
Support for Secure Shell (SSH) protocol analysis.

View file

@ -25,8 +25,8 @@ export {
uid: string &log;
## The connection's 4-tuple of endpoint addresses/ports.
id: conn_id &log;
## Indicates if the login was heuristically guessed to be "success",
## "failure", or "undetermined".
## Indicates if the login was heuristically guessed to be
## "success", "failure", or "undetermined".
status: string &log &default="undetermined";
## Direction of the connection. If the client was a local host
## logging into an external host, this would be OUTBOUND. INBOUND
@ -37,12 +37,6 @@ export {
client: string &log &optional;
## Software string from the server.
server: string &log &optional;
## Amount of data returned from the server. This is currently
## the only measure of the success heuristic and it is logged to
## assist analysts looking at the logs to make their own determination
## about the success on a case-by-case basis.
resp_size: count &log &default=0;
## Indicate if the SSH session is done being watched.
done: bool &default=F;
};
@ -107,10 +101,10 @@ function check_ssh_connection(c: connection, done: bool)
# this matches the conditions for a failed login. Failed
# logins are only detected at connection state removal.
if ( # Require originators to have sent at least 50 bytes.
c$orig$size > 50 &&
if ( # Require originators and responders to have sent at least 50 bytes.
c$orig$size > 50 && c$resp$size > 50 &&
# Responders must be below 4000 bytes.
c$resp$size < 4000 &&
c$resp$size < authentication_data_size &&
# Responder must have sent fewer than 40 packets.
c$resp$num_pkts < 40 &&
# If there was a content gap we can't reliably do this heuristic.
@ -122,7 +116,7 @@ function check_ssh_connection(c: connection, done: bool)
event SSH::heuristic_failed_login(c);
}
if ( c$resp$size > authentication_data_size )
if ( c$resp$size >= authentication_data_size )
{
c$ssh$status = "success";
event SSH::heuristic_successful_login(c);
@ -132,7 +126,7 @@ function check_ssh_connection(c: connection, done: bool)
{
# If this connection is still being tracked, then it's possible
# to watch for it to be a successful connection.
if ( c$resp$size > authentication_data_size )
if ( c$resp$size >= authentication_data_size )
{
c$ssh$status = "success";
event SSH::heuristic_successful_login(c);
@ -150,8 +144,6 @@ function check_ssh_connection(c: connection, done: bool)
# after detection is done.
c$ssh$done=T;
Log::write(SSH::LOG, c$ssh);
if ( skip_processing_after_detection )
{
# Stop watching this connection, we don't care about it anymore.
@ -161,10 +153,24 @@ function check_ssh_connection(c: connection, done: bool)
}
event heuristic_successful_login(c: connection) &priority=-5
{
Log::write(SSH::LOG, c$ssh);
}
event heuristic_failed_login(c: connection) &priority=-5
{
Log::write(SSH::LOG, c$ssh);
}
event connection_state_remove(c: connection) &priority=-5
{
if ( c?$ssh )
{
check_ssh_connection(c, T);
if ( c$ssh$status == "undetermined" )
Log::write(SSH::LOG, c$ssh);
}
}
event ssh_watcher(c: connection)

View file

@ -0,0 +1 @@
Support for Secure Sockets Layer (SSL) protocol analysis.

View file

@ -1,5 +1,6 @@
@load ./consts
@load ./main
@load ./mozilla-ca-list
@load ./files
@load-sigs ./dpd.sig
@load-sigs ./dpd.sig

View file

@ -23,7 +23,7 @@ export {
} &default=function(i: count):string { return fmt("unknown-%d", i); };
## Mapping between numeric codes and human readable strings for alert
## descriptions..
## descriptions.
const alert_descriptions: table[count] of string = {
[0] = "close_notify",
[10] = "unexpected_message",
@ -47,6 +47,7 @@ export {
[70] = "protocol_version",
[71] = "insufficient_security",
[80] = "internal_error",
[86] = "inappropriate_fallback",
[90] = "user_canceled",
[100] = "no_renegotiation",
[110] = "unsupported_extension",
@ -55,6 +56,7 @@ export {
[113] = "bad_certificate_status_response",
[114] = "bad_certificate_hash_value",
[115] = "unknown_psk_identity",
[120] = "no_application_protocol",
} &default=function(i: count):string { return fmt("unknown-%d", i); };
## Mapping between numeric codes and human readable strings for SSL/TLS
@ -78,11 +80,17 @@ export {
[13] = "signature_algorithms",
[14] = "use_srtp",
[15] = "heartbeat",
[16] = "application_layer_protocol_negotiation",
[17] = "status_request_v2",
[18] = "signed_certificate_timestamp",
[35] = "SessionTicket TLS",
[40] = "extended_random",
[13172] = "next_protocol_negotiation",
[13175] = "origin_bound_certificates",
[13180] = "encrypted_client_certificates",
[30031] = "channel_id",
[30032] = "channel_id_new",
[35655] = "padding",
[65281] = "renegotiation_info"
} &default=function(i: count):string { return fmt("unknown-%d", i); };
@ -178,6 +186,21 @@ export {
const TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = 0x006B;
const TLS_DH_ANON_WITH_AES_128_CBC_SHA256 = 0x006C;
const TLS_DH_ANON_WITH_AES_256_CBC_SHA256 = 0x006D;
# draft-ietf-tls-openpgp-keys-06
const TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD = 0x0072;
const TLS_DHE_DSS_WITH_AES_128_CBC_RMD = 0x0073;
const TLS_DHE_DSS_WITH_AES_256_CBC_RMD = 0x0074;
const TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD = 0x0077;
const TLS_DHE_RSA_WITH_AES_128_CBC_RMD = 0x0078;
const TLS_DHE_RSA_WITH_AES_256_CBC_RMD = 0x0079;
const TLS_RSA_WITH_3DES_EDE_CBC_RMD = 0x007C;
const TLS_RSA_WITH_AES_128_CBC_RMD = 0x007D;
const TLS_RSA_WITH_AES_256_CBC_RMD = 0x007E;
# draft-chudov-cryptopro-cptls-04
const TLS_GOSTR341094_WITH_28147_CNT_IMIT = 0x0080;
const TLS_GOSTR341001_WITH_28147_CNT_IMIT = 0x0081;
const TLS_GOSTR341094_WITH_NULL_GOSTR3411 = 0x0082;
const TLS_GOSTR341001_WITH_NULL_GOSTR3411 = 0x0083;
const TLS_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0084;
const TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA = 0x0085;
const TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0086;
@ -244,6 +267,9 @@ export {
const TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C3;
const TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C4;
const TLS_DH_ANON_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C5;
# draft-bmoeller-tls-downgrade-scsv-01
const TLS_FALLBACK_SCSV = 0x5600;
# RFC 4492
const TLS_ECDH_ECDSA_WITH_NULL_SHA = 0xC001;
const TLS_ECDH_ECDSA_WITH_RC4_128_SHA = 0xC002;
const TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA = 0xC003;
@ -303,6 +329,126 @@ export {
const TLS_ECDHE_PSK_WITH_NULL_SHA = 0xC039;
const TLS_ECDHE_PSK_WITH_NULL_SHA256 = 0xC03A;
const TLS_ECDHE_PSK_WITH_NULL_SHA384 = 0xC03B;
# RFC 6209
const TLS_RSA_WITH_ARIA_128_CBC_SHA256 = 0xC03C;
const TLS_RSA_WITH_ARIA_256_CBC_SHA384 = 0xC03D;
const TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256 = 0xC03E;
const TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384 = 0xC03F;
const TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256 = 0xC040;
const TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384 = 0xC041;
const TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256 = 0xC042;
const TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384 = 0xC043;
const TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256 = 0xC044;
const TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384 = 0xC045;
const TLS_DH_ANON_WITH_ARIA_128_CBC_SHA256 = 0xC046;
const TLS_DH_ANON_WITH_ARIA_256_CBC_SHA384 = 0xC047;
const TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256 = 0xC048;
const TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384 = 0xC049;
const TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256 = 0xC04A;
const TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384 = 0xC04B;
const TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256 = 0xC04C;
const TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384 = 0xC04D;
const TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256 = 0xC04E;
const TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384 = 0xC04F;
const TLS_RSA_WITH_ARIA_128_GCM_SHA256 = 0xC050;
const TLS_RSA_WITH_ARIA_256_GCM_SHA384 = 0xC051;
const TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256 = 0xC052;
const TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384 = 0xC053;
const TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256 = 0xC054;
const TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384 = 0xC055;
const TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256 = 0xC056;
const TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384 = 0xC057;
const TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256 = 0xC058;
const TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384 = 0xC059;
const TLS_DH_ANON_WITH_ARIA_128_GCM_SHA256 = 0xC05A;
const TLS_DH_ANON_WITH_ARIA_256_GCM_SHA384 = 0xC05B;
const TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256 = 0xC05C;
const TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384 = 0xC05D;
const TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256 = 0xC05E;
const TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384 = 0xC05F;
const TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256 = 0xC060;
const TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384 = 0xC061;
const TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256 = 0xC062;
const TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384 = 0xC063;
const TLS_PSK_WITH_ARIA_128_CBC_SHA256 = 0xC064;
const TLS_PSK_WITH_ARIA_256_CBC_SHA384 = 0xC065;
const TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256 = 0xC066;
const TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384 = 0xC067;
const TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256 = 0xC068;
const TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384 = 0xC069;
const TLS_PSK_WITH_ARIA_128_GCM_SHA256 = 0xC06A;
const TLS_PSK_WITH_ARIA_256_GCM_SHA384 = 0xC06B;
const TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256 = 0xC06C;
const TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384 = 0xC06D;
const TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256 = 0xC06E;
const TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384 = 0xC06F;
const TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256 = 0xC070;
const TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 = 0xC071;
# RFC 6367
const TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 = 0xC072;
const TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 = 0xC073;
const TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 = 0xC074;
const TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 = 0xC075;
const TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0xC076;
const TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 = 0xC077;
const TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0xC078;
const TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 = 0xC079;
const TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC07A;
const TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC07B;
const TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC07C;
const TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC07D;
const TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC07E;
const TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC07F;
const TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256 = 0xC080;
const TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384 = 0xC081;
const TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256 = 0xC082;
const TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384 = 0xC083;
const TLS_DH_ANON_WITH_CAMELLIA_128_GCM_SHA256 = 0xC084;
const TLS_DH_ANON_WITH_CAMELLIA_256_GCM_SHA384 = 0xC085;
const TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC086;
const TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC087;
const TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC088;
const TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC089;
const TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC08A;
const TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC08B;
const TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC08C;
const TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC08D;
const TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 = 0xC08E;
const TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 = 0xC08F;
const TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 = 0xC090;
const TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 = 0xC091;
const TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 = 0xC092;
const TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 = 0xC093;
const TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 = 0xC094;
const TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 = 0xC095;
const TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 = 0xC096;
const TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 = 0xC097;
const TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 = 0xC098;
const TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 = 0xC099;
const TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 = 0xC09A;
const TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 = 0xC09B;
# RFC 6655
const TLS_RSA_WITH_AES_128_CCM = 0xC09C;
const TLS_RSA_WITH_AES_256_CCM = 0xC09D;
const TLS_DHE_RSA_WITH_AES_128_CCM = 0xC09E;
const TLS_DHE_RSA_WITH_AES_256_CCM = 0xC09F;
const TLS_RSA_WITH_AES_128_CCM_8 = 0xC0A0;
const TLS_RSA_WITH_AES_256_CCM_8 = 0xC0A1;
const TLS_DHE_RSA_WITH_AES_128_CCM_8 = 0xC0A2;
const TLS_DHE_RSA_WITH_AES_256_CCM_8 = 0xC0A3;
const TLS_PSK_WITH_AES_128_CCM = 0xC0A4;
const TLS_PSK_WITH_AES_256_CCM = 0xC0A5;
const TLS_DHE_PSK_WITH_AES_128_CCM = 0xC0A6;
const TLS_DHE_PSK_WITH_AES_256_CCM = 0xC0A7;
const TLS_PSK_WITH_AES_128_CCM_8 = 0xC0A8;
const TLS_PSK_WITH_AES_256_CCM_8 = 0xC0A9;
const TLS_PSK_DHE_WITH_AES_128_CCM_8 = 0xC0AA;
const TLS_PSK_DHE_WITH_AES_256_CCM_8 = 0xC0AB;
# draft-agl-tls-chacha20poly1305-02
const TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCC13;
const TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCC14;
const TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCC15;
const SSL_RSA_FIPS_WITH_DES_CBC_SHA = 0xFEFE;
const SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA = 0xFEFF;
const SSL_RSA_FIPS_WITH_DES_CBC_SHA_2 = 0xFFE1;
@ -314,8 +460,8 @@ export {
const TLS_EMPTY_RENEGOTIATION_INFO_SCSV = 0x00FF;
## This is a table of all known cipher specs. It can be used for
## detecting unknown ciphers and for converting the cipher spec constants
## into a human readable format.
## detecting unknown ciphers and for converting the cipher spec
## constants into a human readable format.
const cipher_desc: table[count] of string = {
[SSLv20_CK_RC4_128_EXPORT40_WITH_MD5] =
"SSLv20_CK_RC4_128_EXPORT40_WITH_MD5",
@ -410,6 +556,19 @@ export {
[TLS_DHE_RSA_WITH_AES_256_CBC_SHA256] = "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",
[TLS_DH_ANON_WITH_AES_128_CBC_SHA256] = "TLS_DH_ANON_WITH_AES_128_CBC_SHA256",
[TLS_DH_ANON_WITH_AES_256_CBC_SHA256] = "TLS_DH_ANON_WITH_AES_256_CBC_SHA256",
[TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD] = "TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD",
[TLS_DHE_DSS_WITH_AES_128_CBC_RMD] = "TLS_DHE_DSS_WITH_AES_128_CBC_RMD",
[TLS_DHE_DSS_WITH_AES_256_CBC_RMD] = "TLS_DHE_DSS_WITH_AES_256_CBC_RMD",
[TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD] = "TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD",
[TLS_DHE_RSA_WITH_AES_128_CBC_RMD] = "TLS_DHE_RSA_WITH_AES_128_CBC_RMD",
[TLS_DHE_RSA_WITH_AES_256_CBC_RMD] = "TLS_DHE_RSA_WITH_AES_256_CBC_RMD",
[TLS_RSA_WITH_3DES_EDE_CBC_RMD] = "TLS_RSA_WITH_3DES_EDE_CBC_RMD",
[TLS_RSA_WITH_AES_128_CBC_RMD] = "TLS_RSA_WITH_AES_128_CBC_RMD",
[TLS_RSA_WITH_AES_256_CBC_RMD] = "TLS_RSA_WITH_AES_256_CBC_RMD",
[TLS_GOSTR341094_WITH_28147_CNT_IMIT] = "TLS_GOSTR341094_WITH_28147_CNT_IMIT",
[TLS_GOSTR341001_WITH_28147_CNT_IMIT] = "TLS_GOSTR341001_WITH_28147_CNT_IMIT",
[TLS_GOSTR341094_WITH_NULL_GOSTR3411] = "TLS_GOSTR341094_WITH_NULL_GOSTR3411",
[TLS_GOSTR341001_WITH_NULL_GOSTR3411] = "TLS_GOSTR341001_WITH_NULL_GOSTR3411",
[TLS_RSA_WITH_CAMELLIA_256_CBC_SHA] = "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA",
[TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA] = "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA",
[TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA] = "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA",
@ -476,6 +635,7 @@ export {
[TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256] = "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256",
[TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256] = "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256",
[TLS_DH_ANON_WITH_CAMELLIA_256_CBC_SHA256] = "TLS_DH_ANON_WITH_CAMELLIA_256_CBC_SHA256",
[TLS_FALLBACK_SCSV] = "TLS_FALLBACK_SCSV",
[TLS_ECDH_ECDSA_WITH_NULL_SHA] = "TLS_ECDH_ECDSA_WITH_NULL_SHA",
[TLS_ECDH_ECDSA_WITH_RC4_128_SHA] = "TLS_ECDH_ECDSA_WITH_RC4_128_SHA",
[TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA] = "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA",
@ -535,10 +695,130 @@ export {
[TLS_ECDHE_PSK_WITH_NULL_SHA] = "TLS_ECDHE_PSK_WITH_NULL_SHA",
[TLS_ECDHE_PSK_WITH_NULL_SHA256] = "TLS_ECDHE_PSK_WITH_NULL_SHA256",
[TLS_ECDHE_PSK_WITH_NULL_SHA384] = "TLS_ECDHE_PSK_WITH_NULL_SHA384",
[TLS_RSA_WITH_ARIA_128_CBC_SHA256] = "TLS_RSA_WITH_ARIA_128_CBC_SHA256",
[TLS_RSA_WITH_ARIA_256_CBC_SHA384] = "TLS_RSA_WITH_ARIA_256_CBC_SHA384",
[TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256] = "TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256",
[TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384] = "TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384",
[TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256] = "TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256",
[TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384] = "TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384",
[TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256] = "TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256",
[TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384] = "TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384",
[TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256] = "TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256",
[TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384] = "TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384",
[TLS_DH_ANON_WITH_ARIA_128_CBC_SHA256] = "TLS_DH_ANON_WITH_ARIA_128_CBC_SHA256",
[TLS_DH_ANON_WITH_ARIA_256_CBC_SHA384] = "TLS_DH_ANON_WITH_ARIA_256_CBC_SHA384",
[TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256] = "TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256",
[TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384] = "TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384",
[TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256] = "TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256",
[TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384] = "TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384",
[TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256] = "TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256",
[TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384] = "TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384",
[TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256] = "TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256",
[TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384] = "TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384",
[TLS_RSA_WITH_ARIA_128_GCM_SHA256] = "TLS_RSA_WITH_ARIA_128_GCM_SHA256",
[TLS_RSA_WITH_ARIA_256_GCM_SHA384] = "TLS_RSA_WITH_ARIA_256_GCM_SHA384",
[TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256] = "TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256",
[TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384] = "TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384",
[TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256] = "TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256",
[TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384] = "TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384",
[TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256] = "TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256",
[TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384] = "TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384",
[TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256] = "TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256",
[TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384] = "TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384",
[TLS_DH_ANON_WITH_ARIA_128_GCM_SHA256] = "TLS_DH_ANON_WITH_ARIA_128_GCM_SHA256",
[TLS_DH_ANON_WITH_ARIA_256_GCM_SHA384] = "TLS_DH_ANON_WITH_ARIA_256_GCM_SHA384",
[TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256] = "TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256",
[TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384] = "TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384",
[TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256] = "TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256",
[TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384] = "TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384",
[TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256] = "TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256",
[TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384] = "TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384",
[TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256] = "TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256",
[TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384] = "TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384",
[TLS_PSK_WITH_ARIA_128_CBC_SHA256] = "TLS_PSK_WITH_ARIA_128_CBC_SHA256",
[TLS_PSK_WITH_ARIA_256_CBC_SHA384] = "TLS_PSK_WITH_ARIA_256_CBC_SHA384",
[TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256] = "TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256",
[TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384] = "TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384",
[TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256] = "TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256",
[TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384] = "TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384",
[TLS_PSK_WITH_ARIA_128_GCM_SHA256] = "TLS_PSK_WITH_ARIA_128_GCM_SHA256",
[TLS_PSK_WITH_ARIA_256_GCM_SHA384] = "TLS_PSK_WITH_ARIA_256_GCM_SHA384",
[TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256] = "TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256",
[TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384] = "TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384",
[TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256] = "TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256",
[TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384] = "TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384",
[TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256] = "TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256",
[TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384] = "TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384",
[TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256] = "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256",
[TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384] = "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384",
[TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256] = "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256",
[TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384] = "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384",
[TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256] = "TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256",
[TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384] = "TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384",
[TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256] = "TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256",
[TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384] = "TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384",
[TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256] = "TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256",
[TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384] = "TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384",
[TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256] = "TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256",
[TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384] = "TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384",
[TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256] = "TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256",
[TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384] = "TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384",
[TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256] = "TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256",
[TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384] = "TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384",
[TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256] = "TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256",
[TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384] = "TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384",
[TLS_DH_ANON_WITH_CAMELLIA_128_GCM_SHA256] = "TLS_DH_ANON_WITH_CAMELLIA_128_GCM_SHA256",
[TLS_DH_ANON_WITH_CAMELLIA_256_GCM_SHA384] = "TLS_DH_ANON_WITH_CAMELLIA_256_GCM_SHA384",
[TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256] = "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256",
[TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384] = "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384",
[TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256] = "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256",
[TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384] = "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384",
[TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256] = "TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256",
[TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384] = "TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384",
[TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256] = "TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256",
[TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384] = "TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384",
[TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256] = "TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256",
[TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384] = "TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384",
[TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256] = "TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256",
[TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384] = "TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384",
[TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256] = "TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256",
[TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384] = "TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384",
[TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256] = "TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256",
[TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384] = "TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384",
[TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256] = "TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256",
[TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384] = "TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384",
[TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256] = "TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256",
[TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384] = "TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384",
[TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256] = "TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256",
[TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384] = "TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384",
[TLS_RSA_WITH_AES_128_CCM] = "TLS_RSA_WITH_AES_128_CCM",
[TLS_RSA_WITH_AES_256_CCM] = "TLS_RSA_WITH_AES_256_CCM",
[TLS_DHE_RSA_WITH_AES_128_CCM] = "TLS_DHE_RSA_WITH_AES_128_CCM",
[TLS_DHE_RSA_WITH_AES_256_CCM] = "TLS_DHE_RSA_WITH_AES_256_CCM",
[TLS_RSA_WITH_AES_128_CCM_8] = "TLS_RSA_WITH_AES_128_CCM_8",
[TLS_RSA_WITH_AES_256_CCM_8] = "TLS_RSA_WITH_AES_256_CCM_8",
[TLS_DHE_RSA_WITH_AES_128_CCM_8] = "TLS_DHE_RSA_WITH_AES_128_CCM_8",
[TLS_DHE_RSA_WITH_AES_256_CCM_8] = "TLS_DHE_RSA_WITH_AES_256_CCM_8",
[TLS_PSK_WITH_AES_128_CCM] = "TLS_PSK_WITH_AES_128_CCM",
[TLS_PSK_WITH_AES_256_CCM] = "TLS_PSK_WITH_AES_256_CCM",
[TLS_DHE_PSK_WITH_AES_128_CCM] = "TLS_DHE_PSK_WITH_AES_128_CCM",
[TLS_DHE_PSK_WITH_AES_256_CCM] = "TLS_DHE_PSK_WITH_AES_256_CCM",
[TLS_PSK_WITH_AES_128_CCM_8] = "TLS_PSK_WITH_AES_128_CCM_8",
[TLS_PSK_WITH_AES_256_CCM_8] = "TLS_PSK_WITH_AES_256_CCM_8",
[TLS_PSK_DHE_WITH_AES_128_CCM_8] = "TLS_PSK_DHE_WITH_AES_128_CCM_8",
[TLS_PSK_DHE_WITH_AES_256_CCM_8] = "TLS_PSK_DHE_WITH_AES_256_CCM_8",
[TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256] = "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
[TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256] = "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
[TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256] = "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
[SSL_RSA_FIPS_WITH_DES_CBC_SHA] = "SSL_RSA_FIPS_WITH_DES_CBC_SHA",
[SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA] = "SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA",
[SSL_RSA_FIPS_WITH_DES_CBC_SHA_2] = "SSL_RSA_FIPS_WITH_DES_CBC_SHA_2",
[SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA_2] = "SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA_2",
[SSL_RSA_WITH_RC2_CBC_MD5] = "SSL_RSA_WITH_RC2_CBC_MD5",
[SSL_RSA_WITH_IDEA_CBC_MD5] = "SSL_RSA_WITH_IDEA_CBC_MD5",
[SSL_RSA_WITH_DES_CBC_MD5] = "SSL_RSA_WITH_DES_CBC_MD5",
[SSL_RSA_WITH_3DES_EDE_CBC_MD5] = "SSL_RSA_WITH_3DES_EDE_CBC_MD5",
[TLS_EMPTY_RENEGOTIATION_INFO_SCSV] = "TLS_EMPTY_RENEGOTIATION_INFO_SCSV",
} &default=function(i: count):string { return fmt("unknown-%d", i); };
## Mapping between the constants and string values for SSL/TLS errors.

View file

@ -1,7 +1,7 @@
signature dpd_ssl_server {
ip-proto == tcp
# Server hello.
payload /^(\x16\x03[\x00\x01\x02]..\x02...\x03[\x00\x01\x02]|...?\x04..\x00\x02).*/
payload /^(\x16\x03[\x00\x01\x02\x03]..\x02...\x03[\x00\x01\x02\x03]|...?\x04..\x00\x02).*/
requires-reverse-signature dpd_ssl_client
enable "ssl"
tcp-state responder
@ -10,6 +10,6 @@ signature dpd_ssl_server {
signature dpd_ssl_client {
ip-proto == tcp
# Client hello.
payload /^(\x16\x03[\x00\x01\x02]..\x01...\x03[\x00\x01\x02]|...?\x01[\x00\x01\x02][\x02\x03]).*/
payload /^(\x16\x03[\x00\x01\x02\x03]..\x01...\x03[\x00\x01\x02\x03]|...?\x01[\x00\x03][\x00\x01\x02\x03]).*/
tcp-state originator
}

View file

@ -0,0 +1,149 @@
@load ./main
@load base/utils/conn-ids
@load base/frameworks/files
@load base/files/x509
module SSL;
export {
redef record Info += {
## Chain of certificates offered by the server to validate its
## complete signing chain.
cert_chain: vector of Files::Info &optional;
## An ordered vector of all certicate file unique IDs for the
## certificates offered by the server.
cert_chain_fuids: vector of string &optional &log;
## Chain of certificates offered by the client to validate its
## complete signing chain.
client_cert_chain: vector of Files::Info &optional;
## An ordered vector of all certicate file unique IDs for the
## certificates offered by the client.
client_cert_chain_fuids: vector of string &optional &log;
## Subject of the X.509 certificate offered by the server.
subject: string &log &optional;
## Subject of the signer of the X.509 certificate offered by the
## server.
issuer: string &log &optional;
## Subject of the X.509 certificate offered by the client.
client_subject: string &log &optional;
## Subject of the signer of the X.509 certificate offered by the
## client.
client_issuer: string &log &optional;
## Current number of certificates seen from either side. Used
## to create file handles.
server_depth: count &default=0;
client_depth: count &default=0;
};
## Default file handle provider for SSL.
global get_file_handle: function(c: connection, is_orig: bool): string;
## Default file describer for SSL.
global describe_file: function(f: fa_file): string;
}
function get_file_handle(c: connection, is_orig: bool): string
{
set_session(c);
local depth: count;
if ( is_orig )
{
depth = c$ssl$client_depth;
++c$ssl$client_depth;
}
else
{
depth = c$ssl$server_depth;
++c$ssl$server_depth;
}
return cat(Analyzer::ANALYZER_SSL, c$start_time, is_orig, id_string(c$id), depth);
}
function describe_file(f: fa_file): string
{
if ( f$source != "SSL" || ! f?$info || ! f$info?$x509 || ! f$info$x509?$certificate )
return "";
# It is difficult to reliably describe a certificate - especially since
# we do not know when this function is called (hence, if the data structures
# are already populated).
#
# Just return a bit of our connection information and hope that that is good enough.
for ( cid in f$conns )
{
if ( f$conns[cid]?$ssl )
{
local c = f$conns[cid];
return cat(c$id$resp_h, ":", c$id$resp_p);
}
}
return cat("Serial: ", f$info$x509$certificate$serial, " Subject: ",
f$info$x509$certificate$subject, " Issuer: ",
f$info$x509$certificate$issuer);
}
event bro_init() &priority=5
{
Files::register_protocol(Analyzer::ANALYZER_SSL,
[$get_file_handle = SSL::get_file_handle,
$describe = SSL::describe_file]);
}
event file_over_new_connection(f: fa_file, c: connection, is_orig: bool) &priority=5
{
if ( ! c?$ssl )
return;
if ( ! c$ssl?$cert_chain )
{
c$ssl$cert_chain = vector();
c$ssl$client_cert_chain = vector();
c$ssl$cert_chain_fuids = string_vec();
c$ssl$client_cert_chain_fuids = string_vec();
}
if ( is_orig )
{
c$ssl$client_cert_chain[|c$ssl$client_cert_chain|] = f$info;
c$ssl$client_cert_chain_fuids[|c$ssl$client_cert_chain_fuids|] = f$id;
}
else
{
c$ssl$cert_chain[|c$ssl$cert_chain|] = f$info;
c$ssl$cert_chain_fuids[|c$ssl$cert_chain_fuids|] = f$id;
}
Files::add_analyzer(f, Files::ANALYZER_X509);
# always calculate hashes. They are not necessary for base scripts
# but very useful for identification, and required for policy scripts
Files::add_analyzer(f, Files::ANALYZER_MD5);
Files::add_analyzer(f, Files::ANALYZER_SHA1);
}
event ssl_established(c: connection) &priority=6
{
# update subject and issuer information
if ( c$ssl?$cert_chain && |c$ssl$cert_chain| > 0 )
{
c$ssl$subject = c$ssl$cert_chain[0]$x509$certificate$subject;
c$ssl$issuer = c$ssl$cert_chain[0]$x509$certificate$issuer;
}
if ( c$ssl?$client_cert_chain && |c$ssl$client_cert_chain| > 0 )
{
c$ssl$client_subject = c$ssl$client_cert_chain[0]$x509$certificate$subject;
c$ssl$client_issuer = c$ssl$client_cert_chain[0]$x509$certificate$issuer;
}
}

View file

@ -24,42 +24,25 @@ export {
server_name: string &log &optional;
## Session ID offered by the client for session resumption.
session_id: string &log &optional;
## Subject of the X.509 certificate offered by the server.
subject: string &log &optional;
## Subject of the signer of the X.509 certificate offered by the server.
issuer_subject: string &log &optional;
## NotValidBefore field value from the server certificate.
not_valid_before: time &log &optional;
## NotValidAfter field value from the server certificate.
not_valid_after: time &log &optional;
## Last alert that was seen during the connection.
last_alert: string &log &optional;
## Subject of the X.509 certificate offered by the client.
client_subject: string &log &optional;
## Subject of the signer of the X.509 certificate offered by the client.
client_issuer_subject: string &log &optional;
## Full binary server certificate stored in DER format.
cert: string &optional;
## Chain of certificates offered by the server to validate its
## complete signing chain.
cert_chain: vector of string &optional;
## Full binary client certificate stored in DER format.
client_cert: string &optional;
## Chain of certificates offered by the client to validate its
## complete signing chain.
client_cert_chain: vector of string &optional;
## The analyzer ID used for the analyzer instance attached
## to each connection. It is not used for logging since it's a
## meaningless arbitrary number.
analyzer_id: count &optional;
## Flag to indicate if this ssl session has been established
## succesfully, or if it was aborted during the handshake.
established: bool &log &default=F;
## Flag to indicate if this record already has been logged, to
## prevent duplicates.
logged: bool &default=F;
};
## The default root CA bundle. By loading the
## mozilla-ca-list.bro script it will be set to Mozilla's root CA list.
## The default root CA bundle. By default, the mozilla-ca-list.bro
## script sets this to Mozilla's root CA list.
const root_certs: table[string] of string = {} &redef;
## If true, detach the SSL analyzer from the connection to prevent
@ -67,11 +50,8 @@ export {
## (especially with large file transfers).
const disable_analyzer_after_detection = T &redef;
## The maximum amount of time a script can delay records from being logged.
const max_log_delay = 15secs &redef;
## Delays an SSL record for a specific token: the record will not be logged
## as longs the token exists or until :bro:id:`SSL::max_log_delay` elapses.
## Delays an SSL record for a specific token: the record will not be
## logged as long as the token exists or until 15 seconds elapses.
global delay_log: function(info: Info, token: string);
## Undelays an SSL record for a previously inserted token, allowing the
@ -90,7 +70,7 @@ redef record connection += {
redef record Info += {
# Adding a string "token" to this set will cause the SSL script
# to delay logging the record until either the token has been removed or
# the record has been delayed for :bro:id:`SSL::max_log_delay`.
# the record has been delayed.
delay_tokens: set[string] &optional;
};
@ -109,8 +89,7 @@ event bro_init() &priority=5
function set_session(c: connection)
{
if ( ! c?$ssl )
c$ssl = [$ts=network_time(), $uid=c$uid, $id=c$id, $cert_chain=vector(),
$client_cert_chain=vector()];
c$ssl = [$ts=network_time(), $uid=c$uid, $id=c$id];
}
function delay_log(info: Info, token: string)
@ -128,9 +107,13 @@ function undelay_log(info: Info, token: string)
function log_record(info: Info)
{
if ( info$logged )
return;
if ( ! info?$delay_tokens || |info$delay_tokens| == 0 )
{
Log::write(SSL::LOG, info);
info$logged = T;
}
else
{
@ -138,22 +121,28 @@ function log_record(info: Info)
{
log_record(info);
}
timeout SSL::max_log_delay
timeout 15secs
{
Reporter::info(fmt("SSL delay tokens not released in time (%s tokens remaining)",
|info$delay_tokens|));
# We are just going to log the record anyway.
delete info$delay_tokens;
log_record(info);
}
}
}
function finish(c: connection)
# remove_analyzer flag is used to prevent disabling analyzer for finished
# connections.
function finish(c: connection, remove_analyzer: bool)
{
log_record(c$ssl);
if ( disable_analyzer_after_detection && c?$ssl && c$ssl?$analyzer_id )
if ( remove_analyzer && disable_analyzer_after_detection && c?$ssl && c$ssl?$analyzer_id )
{
disable_analyzer(c$id, c$ssl$analyzer_id);
delete c$ssl$analyzer_id;
}
}
event ssl_client_hello(c: connection, version: count, possible_ts: time, session_id: string, ciphers: count_set) &priority=5
event ssl_client_hello(c: connection, version: count, possible_ts: time, client_random: string, session_id: string, ciphers: index_vec) &priority=5
{
set_session(c);
@ -162,7 +151,7 @@ event ssl_client_hello(c: connection, version: count, possible_ts: time, session
c$ssl$session_id = bytestring_to_hexstr(session_id);
}
event ssl_server_hello(c: connection, version: count, possible_ts: time, session_id: string, cipher: count, comp_method: count) &priority=5
event ssl_server_hello(c: connection, version: count, possible_ts: time, server_random: string, session_id: string, cipher: count, comp_method: count) &priority=5
{
set_session(c);
@ -170,49 +159,6 @@ event ssl_server_hello(c: connection, version: count, possible_ts: time, session
c$ssl$cipher = cipher_desc[cipher];
}
event x509_certificate(c: connection, is_orig: bool, cert: X509, chain_idx: count, chain_len: count, der_cert: string) &priority=5
{
set_session(c);
# We aren't doing anything with client certificates yet.
if ( is_orig )
{
if ( chain_idx == 0 )
{
# Save the primary cert.
c$ssl$client_cert = der_cert;
# Also save other certificate information about the primary cert.
c$ssl$client_subject = cert$subject;
c$ssl$client_issuer_subject = cert$issuer;
}
else
{
# Otherwise, add it to the cert validation chain.
c$ssl$client_cert_chain[|c$ssl$client_cert_chain|] = der_cert;
}
}
else
{
if ( chain_idx == 0 )
{
# Save the primary cert.
c$ssl$cert = der_cert;
# Also save other certificate information about the primary cert.
c$ssl$subject = cert$subject;
c$ssl$issuer_subject = cert$issuer;
c$ssl$not_valid_before = cert$not_valid_before;
c$ssl$not_valid_after = cert$not_valid_after;
}
else
{
# Otherwise, add it to the cert validation chain.
c$ssl$cert_chain[|c$ssl$cert_chain|] = der_cert;
}
}
}
event ssl_extension(c: connection, is_orig: bool, code: count, val: string) &priority=5
{
set_session(c);
@ -228,26 +174,36 @@ event ssl_alert(c: connection, is_orig: bool, level: count, desc: count) &priori
c$ssl$last_alert = alert_descriptions[desc];
}
event ssl_established(c: connection) &priority=5
event ssl_established(c: connection) &priority=7
{
set_session(c);
c$ssl$established = T;
}
event ssl_established(c: connection) &priority=-5
{
finish(c);
finish(c, T);
}
event connection_state_remove(c: connection) &priority=-5
{
if ( c?$ssl )
# called in case a SSL connection that has not been established terminates
finish(c, F);
}
event protocol_confirmation(c: connection, atype: Analyzer::Tag, aid: count) &priority=5
{
# Check by checking for existence of c$ssl record.
if ( c?$ssl && atype == Analyzer::ANALYZER_SSL )
if ( atype == Analyzer::ANALYZER_SSL )
{
set_session(c);
c$ssl$analyzer_id = aid;
}
}
event protocol_violation(c: connection, atype: Analyzer::Tag, aid: count,
reason: string) &priority=5
{
if ( c?$ssl )
finish(c);
finish(c, T);
}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
Support for Syslog protocol analysis.