Merge branch 'master' into topic/gregor/smb-nfs

Conflicts:
	policy/bro.init
	policy/nfs.bro
	policy/portmapper.bro
	src/Analyzer.cc
	src/AnalyzerTags.h
	src/Gnutella.cc
	src/NFS.cc
	src/NFS.h
	src/Portmap.cc
	src/Portmap.h
	src/RPC.cc
	src/RPC.h
	src/SSLProxy.h
	src/TCP_Reassembler.cc
	src/XDR.cc
	src/bro.bif
	src/const.bif
	src/event.bif
	src/scan.l
	src/types.bif
This commit is contained in:
Gregor Maier 2011-06-24 16:01:28 -07:00
commit 9f7d4980ea
200 changed files with 3527 additions and 10279 deletions

View file

@ -5,15 +5,12 @@
# to offer. For more, execute that one directly.
#
BUILD=build
BROCCOLI=aux/broccoli
BROCTL=aux/broctl
# CMake/CPack versions before 2.8.2 have bugs that can create bad packages
CMAKE_PACK_REQ=2.8.2
CMAKE_VER=`cmake -version`
OSX_VER_CMD=sw_vers | sed -n 's/ProductVersion://p' | cut -d . -f 2
SOURCE=$(PWD)
BUILD=$(SOURCE)/build
TMP=/tmp/bro-dist.$(UID)
BRO_V=`cat $(SOURCE)/VERSION`
BROCCOLI_V=`cat $(SOURCE)/aux/broccoli/VERSION`
BROCTL_V=`cat $(SOURCE)/aux/broctl/VERSION`
all: configured
( cd $(BUILD) && make )
@ -31,39 +28,25 @@ doc: configured
docclean: configured
( cd $(BUILD) && make docclean && make restclean )
dist: cmake_version
# Minimum Bro source package
( \
./configure --ignore-dirs='aux/broctl;aux/broccoli' --pkg-name-prefix=Bro && \
cd $(BUILD) && \
make package_source \
)
# Full Bro source package
( \
./configure --pkg-name-prefix=Bro-all && \
cd $(BUILD) && \
make package_source \
)
# Broccoli source package
( \
cd $(BROCCOLI) && \
./configure && \
cd $(BUILD) && \
make package_source && \
mv Broccoli*.tar.gz ../../../$(BUILD)/ && \
cd .. && \
rm -r $(BUILD) \
)
# Broctl source package
( \
cd $(BROCTL) && \
./configure && \
cd $(BUILD) && \
make package_source && \
mv Broctl*.tar.gz ../../../$(BUILD)/ && \
cd .. && \
rm -r $(BUILD) \
)
dist:
@( mkdir -p $(BUILD) && rm -rf $(TMP) && mkdir $(TMP) )
@cp -R $(SOURCE) $(TMP)/Bro-$(BRO_V)
@( cd $(TMP) && find . -name .git\* | xargs rm -rf )
@( cd $(TMP) && find . -name \*.swp | xargs rm -rf )
@( cd $(TMP) && find . -type d -name build | xargs rm -rf )
@( cd $(TMP) && tar -czf $(BUILD)/Bro-all-$(BRO_V).tar.gz Bro-$(BRO_V) )
@( cd $(TMP)/Bro-$(BRO_V)/aux && mv broccoli Broccoli-$(BROCCOLI_V) && \
tar -czf $(BUILD)/Broccoli-$(BROCCOLI_V).tar.gz Broccoli-$(BROCCOLI_V) )
@( cd $(TMP)/Bro-$(BRO_V)/aux && mv broctl Broctl-$(BROCTL_V) && \
tar -czf $(BUILD)/Broctl-$(BROCTL_V).tar.gz Broctl-$(BROCTL_V) )
@( cd $(TMP)/Bro-$(BRO_V)/aux && rm -rf Broctl* Broccoli* )
@( cd $(TMP) && tar -czf $(BUILD)/Bro-$(BRO_V).tar.gz Bro-$(BRO_V) )
@rm -rf $(TMP)
@echo "Distribution source tarballs have been compiled in $(BUILD)"
bindist:
@( cd pkg && ( ./make-deb-packages || ./make-mac-packages || \
./make-rpm-packages ) )
distclean:
rm -rf $(BUILD)
@ -72,7 +55,4 @@ configured:
@test -d $(BUILD) || ( echo "Error: No build/ directory found. Did you run configure?" && exit 1 )
@test -e $(BUILD)/Makefile || ( echo "Error: No build/Makefile found. Did you run configure?" && exit 1 )
cmake_version:
@test "$(CMAKE_VER)" \> "cmake version $(CMAKE_PACK_REQ)" || ( echo "Error: please use a CMake version greater than $(CMAKE_PACK_REQ)" && exit 1 )
.PHONY : all install clean distclean configured cmake_version
.PHONY : all install clean doc docclean dist bindist distclean configured

@ -1 +1 @@
Subproject commit 14a7cfe4ea2ff6c7f5301dcb81a869adcd6e9834
Subproject commit 1a610bced1c83644a5bfaeb6e98cf75380fe61a1

@ -1 +1 @@
Subproject commit 7c20b1a41016471eb03ee7a0fbfe1fb34bdc084a
Subproject commit 8843da57dc8aee433550727dcbd1199824ca9da4

@ -1 +1 @@
Subproject commit c4eaf7c7471ab04ae8af0f2913cb8350d9ae0b3a
Subproject commit ad9528f6795f104db8ec2f1425fc0b69d77ab92d

@ -1 +1 @@
Subproject commit d0154a7e88cd1b6bccc11c042e451fcb9b5459bf
Subproject commit a9aeb2e1a8434c583c75f5941b58dc69a7517444

View file

@ -63,10 +63,7 @@ endmacro(SetPackageVersion)
#
# Darwin - PackageMaker
# Linux - RPM if the platform has rpmbuild installed
# DEB is ommitted because CPack does not give enough
# control over how the package is created and lacks support
# for automatic dependency detection.
#
# DEB if the platform has dpkg-shlibdeps installed
#
# CPACK_GENERATOR is set by this macro
# CPACK_SOURCE_GENERATOR is set by this macro
@ -77,9 +74,14 @@ macro(SetPackageGenerators)
list(APPEND CPACK_GENERATOR PackageMaker)
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
find_program(RPMBUILD_EXE rpmbuild)
find_program(DPKGSHLIB_EXE dpkg-shlibdeps)
if (RPMBUILD_EXE)
set(CPACK_GENERATOR ${CPACK_GENERATOR} RPM)
endif ()
if (DPKGSHLIB_EXE)
set(CPACK_GENERATOR ${CPACK_GENERATOR} DEB)
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS true)
endif ()
endif ()
endmacro(SetPackageGenerators)
@ -159,11 +161,27 @@ macro(SetPackageInstallScripts VERSION)
endif ()
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
# DEB packages can automatically handle configuration files
# if provided in a "conffiles" file in the packaging
set(conffiles_file ${CMAKE_CURRENT_BINARY_DIR}/conffiles)
if (INSTALLED_CONFIG_FILES)
string(REPLACE " " ";" conffiles ${INSTALLED_CONFIG_FILES})
endif ()
file(WRITE ${conffiles_file} "")
foreach (_file ${conffiles})
file(APPEND ${conffiles_file} "${_file}\n")
endforeach ()
list(APPEND CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA
${CMAKE_CURRENT_BINARY_DIR}/conffiles)
# RPMs don't need any explicit direction regarding config files.
# Leaving the set of installed config files empty will just
# bypass the logic in the pre/post install scripts and let
# the RPM do their own thing (regarding backups, etc.)
# bypass the logic in the default pre/post install scripts and let
# the RPMs/DEBs do their own thing (regarding backups, etc.)
# when upgrading packages.
set (INSTALLED_CONFIG_FILES "")
set(INSTALLED_CONFIG_FILES "")
endif ()
if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/cmake/package_preinstall.sh.in)
@ -171,10 +189,16 @@ macro(SetPackageInstallScripts VERSION)
${CMAKE_CURRENT_SOURCE_DIR}/cmake/package_preinstall.sh.in
${CMAKE_CURRENT_BINARY_DIR}/package_preinstall.sh
@ONLY)
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/cmake/package_preinstall.sh.in
${CMAKE_CURRENT_BINARY_DIR}/preinst
@ONLY)
set(CPACK_PREFLIGHT_SCRIPT
${CMAKE_CURRENT_BINARY_DIR}/package_preinstall.sh)
set(CPACK_RPM_PRE_INSTALL_SCRIPT_FILE
${CMAKE_CURRENT_BINARY_DIR}/package_preinstall.sh)
list(APPEND CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA
${CMAKE_CURRENT_BINARY_DIR}/preinst)
endif ()
if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/cmake/package_postupgrade.sh.in)
@ -182,10 +206,16 @@ macro(SetPackageInstallScripts VERSION)
${CMAKE_CURRENT_SOURCE_DIR}/cmake/package_postupgrade.sh.in
${CMAKE_CURRENT_BINARY_DIR}/package_postupgrade.sh
@ONLY)
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/cmake/package_postupgrade.sh.in
${CMAKE_CURRENT_BINARY_DIR}/postinst
@ONLY)
set(CPACK_POSTUPGRADE_SCRIPT
${CMAKE_CURRENT_BINARY_DIR}/package_postupgrade.sh)
set(CPACK_RPM_POST_INSTALL_SCRIPT_FILE
${CMAKE_CURRENT_BINARY_DIR}/package_postupgrade.sh)
list(APPEND CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA
${CMAKE_CURRENT_BINARY_DIR}/postinst)
endif ()
endmacro(SetPackageInstallScripts)

View file

@ -48,21 +48,13 @@ if [ -n "${sampleFiles}" ]; then
EOF
fi
# make sure that world-writeable dirs have the sticky bit set
# so that unprivileged can't rename/remove files within
if [ -d /var/opt/bro/spool ]; then
chmod +t /var/opt/bro/spool
fi
if [ -d /var/opt/bro/spool/tmp ]; then
chmod +t /var/opt/bro/spool/tmp
fi
if [ -d /var/opt/bro/spool/policy ]; then
chmod +t /var/opt/bro/spool/policy
fi
if [ -d /var/opt/bro/logs ]; then
chmod +t /var/opt/bro/logs
# Set up world writeable spool and logs directory for broctl, making sure
# to set the sticky bit so that unprivileged users can't rename/remove files.
# (CMake/CPack is supposed to install them, but has problems with empty dirs)
if [ -n "@EMPTY_WORLD_DIRS@" ]; then
for dir in "@EMPTY_WORLD_DIRS@"; do
mkdir -p ${dir}
chmod 777 ${dir}
chmod +t ${dir}
done
fi

14
pkg/check-cmake Executable file
View file

@ -0,0 +1,14 @@
#!/bin/sh
# CMake/CPack versions before 2.8.3 have bugs that can create bad packages
# Since packages will be built on several different systems, a single
# version of CMake is required to obtain consistency, but can be increased
# as new versions of CMake come out that also produce working packages.
CMAKE_PACK_REQ="cmake version 2.8.4"
CMAKE_VER=`cmake -version`
if [ "${CMAKE_VER}" != "${CMAKE_PACK_REQ}" ]; then
echo "Package creation requires ${CMAKE_PACK_REQ}" >&2
exit 1
fi

47
pkg/make-deb-packages Executable file
View file

@ -0,0 +1,47 @@
#!/bin/sh
# This script generates binary DEB packages.
# They can be found in ../build/ after running.
./check-cmake || { exit 1; }
# The DEB CPack generator depends on `dpkg-shlibdeps` to automatically
# determine what dependencies to set for the packages
type dpkg-shlibdeps > /dev/null 2>&1 || {
echo "\
Creating DEB packages requires the "dpkg-shlibs" command, usually provided by
the 'dpkg-dev' package, please install it first.
" >&2;
exit 1;
}
prefix=/opt/bro
# During the packaging process, `dpkg-shlibs` will fail if used on a library
# that links to other internal/project libraries unless an RPATH is used or
# we set LD_LIBRARY_PATH such that it can find the internal/project library
# in the temporary packaging tree.
export LD_LIBRARY_PATH=./${prefix}/lib
cd ..
# Minimum Bro
./configure --prefix=${prefix} --disable-broccoli --disable-broctl \
--pkg-name-prefix=Bro --binary-package
( cd build && make package )
# Full Bro package
./configure --prefix=${prefix} --pkg-name-prefix=Bro-all --binary-package
( cd build && make package )
# Broccoli
cd aux/broccoli
./configure --prefix=${prefix} --binary-package
( cd build && make package && mv Broccoli*.deb ../../../build/ )
cd ../..
# Broctl
cd aux/broctl
./configure --prefix=${prefix} --binary-package
( cd build && make package && mv Broctl*.deb ../../../build/ )
cd ../..

View file

@ -1,18 +1,9 @@
#!/bin/sh
# This script creates binary packages for Mac OS X.
# They can be found in build/ after running.
# They can be found in ../build/ after running.
prefix=/opt/bro
# CMake/CPack versions before 2.8.2 have bugs that can create bad packages
CMAKE_PACK_REQ=2.8.3
CMAKE_VER=`cmake -version`
if [ "${CMAKE_VER}" \< "${CMAKE_PACK_REQ}" ]; then
echo "Package creation requires CMake > 2.8.2" >&2
exit 1
fi
./check-cmake || { exit 1; }
type sw_vers > /dev/null 2>&1 || {
echo "Unable to get Mac OS X version" >&2;
@ -38,6 +29,10 @@ else
arch=x86_64
fi
prefix=/opt/bro
cd ..
# Minimum Bro
CMAKE_OSX_ARCHITECTURES=${arch} ./configure --prefix=${prefix} \
--disable-broccoli --disable-broctl --pkg-name-prefix=Bro \

View file

@ -1,18 +1,22 @@
#!/bin/sh
# This script generates binary RPM packages.
# They can be found in build/ after running.
# They can be found in ../build/ after running.
./check-cmake || { exit 1; }
# The RPM CPack generator depends on `rpmbuild` to create packages
type rpmbuild > /dev/null 2>&1 || {
echo "\
Creating RPM packages requires the "rpmbuild" command, usually provided by
the 'rpm-build' package, please install it first.
" >&2;
exit 1;
}
prefix=/opt/bro
# CMake/CPack versions before 2.8.2 have bugs that can create bad packages
CMAKE_PACK_REQ=2.8.2
CMAKE_VER=`cmake -version`
if [ "${CMAKE_VER}" \< "${CMAKE_PACK_REQ}" ]; then
echo "Package creation requires CMake > 2.8.2" >&2
exit 1
fi
cd ..
# Minimum Bro
./configure --prefix=${prefix} --disable-broccoli --disable-broctl \

View file

@ -11,9 +11,12 @@ global no_handler: event(name: string, val: any);
# Type declarations
type string_array: table[count] of string;
type string_set: set[string];
type count_set: set[count];
type index_vec: vector of count;
type string_vec: vector of string;
type table_string_of_string: table[string] of string;
type transport_proto: enum { unknown_transport, tcp, udp, icmp };
type conn_id: record {
@ -718,47 +721,43 @@ const RPC_status = {
};
module NFS3;
export {
# Should the read and write events return the file data that
# has been read/written?
# Should the read and write events return the file data that has been
# read/written?
const return_data = F &redef;
# If nfs_return_data==T: how much data should be returned at most
# If nfs_return_data is true, how much data should be returned at most.
const return_data_max = 512 &redef;
# If nfs_return_data==T: whether to *only* return data if the read or
# write offset is 0, i.e., only return data for the beginning of the
# file
const return_data_first_only = T &redef;
# This record summarizes the general results and status
# of NFSv3 request/reply pairs. It's part of every NFSv3
# event
# If nfs_return_data is true, whether to *only* return data if the read or write
# offset is 0, i.e., only return data for the beginning of the file.
const return_data_first_only = T &redef;
# This record summarizes the general results and status of NFSv3 request/reply
# pairs. It's part of every NFSv3 event.
type info_t: record {
rpc_stat: rpc_status; # if this indicates not successful, the reply record in the
# events will be a empty and contain uninitialized fields, so
# don't use it!
rpc_stat: rpc_status; # If this indicates not successful, the reply record in the
# events will be empty and contain uninitialized fields, so
# don't use it.
nfs_stat: status_t;
# the start time, duration, and length in bytes of the
# request (call).
# NOTE that the start and end time might not be accurate. For TCP we
# record the time when a chunk of data is delivered to the analyzer. Depending
# on the Reassembler, this might be well after the first packet of the request
# The start time, duration, and length in bytes of the request (call). Note that
# the start and end time might not be accurate. For TCP, we record the
# time when a chunk of data is delivered to the analyzer. Depending on the
# Reassembler, this might be well after the first packet of the request
# was received.
req_start: time;
req_dur: interval;
req_len: count;
# Same for the reply
# Same for the reply.
rep_start: time;
rep_dur: interval;
rep_len: count;
};
# NFSv3 types
# type names are based on RFC 1813
# NFSv3 types. Type names are based on RFC 1813.
type fattr_t: record {
ftype: file_type_t;
mode: count;
@ -777,15 +776,15 @@ export {
};
type diropargs_t : record {
dirfh: string; # the file handle of the directory
fname: string; # the name of the file we are interested in
dirfh: string; # the file handle of the directory
fname: string; # the name of the file we are interested in
};
# Note, we don't need a post_op_attr type. We can always use
# an fattr_t &optional
# Note, we don't need a "post_op_attr" type. We use an "fattr_t &optional"
# instead.
type lookup_reply_t: record {
# If the lookup failed, dir_attr may be set.
# If the lookup failed, dir_attr may be set.
# If the lookup succeeded, fh is always set and obj_attr and dir_attr may be set.
fh: string &optional; # file handle of object looked up
obj_attr: fattr_t &optional; # optional attributes associated w/ file
@ -793,33 +792,33 @@ export {
};
type readargs_t: record {
fh: string; # file handle to read from
offset: count; # Offset in file. Should really go to 64 bit int here
size: count; # number of bytes to read
fh: string; # file handle to read from
offset: count; # offset in file
size: count; # number of bytes to read
};
type read_reply_t: record {
# if the lookup fails attr may be set.
# if the lookup succeeds, attr may be set and all other fields are set
attr: fattr_t &optional; # attributes
size: count &optional; # number of bytes read
eof: bool &optional; # did the read end at EOF
data: string &optional; # the actual data. NOT IMPLEMENTED YET.
# If the lookup fails, attr may be set. If the lookup succeeds, attr may be set
# and all other fields are set.
attr: fattr_t &optional; # attributes
size: count &optional; # number of bytes read
eof: bool &optional; # did the read end at EOF
data: string &optional; # the actual data; not yet implemented.
};
type readlink_reply_t: record {
# if the request fails attr may be set.
# if the request succeeds, attr may be set and all other fields are set
attr: fattr_t &optional; # attributes
nfspath: string &optional; # the contents of the symlink. In general a pathname as text
# If the request fails, attr may be set. If the request succeeds, attr may be
# set and all other fields are set.
attr: fattr_t &optional; # attributes
nfspath: string &optional; # the contents of the symlink; in general a pathname as text
};
type writeargs_t: record {
fh: string; # file handle to write to
offset: count; # Offset in file. Should really go to 64 bit int here
size: count; # number of bytes to write
stable: stable_how_t; # how and when data is commited
data: string &optional; # the actual data. NOT IMPLEMENTED YET.
fh: string; # file handle to write to
offset: count; # offset in file
size: count; # number of bytes to write
stable: stable_how_t; # how and when data is commited
data: string &optional; # the actual data; not implemented yet
};
type wcc_attr_t: record {
@ -829,65 +828,64 @@ export {
};
type write_reply_t: record {
# if the request fails pre|post attr may be set.
# if the request succeeds, pre|post attr may be set and all other fields are set
preattr: wcc_attr_t &optional; # pre operation attributes
postattr: fattr_t &optional; # post operation attributes
# If the request fails, pre|post attr may be set. If the request succeeds,
# pre|post attr may be set and all other fields are set.
preattr: wcc_attr_t &optional; # pre operation attributes
postattr: fattr_t &optional; # post operation attributes
size: count &optional;
commited: stable_how_t &optional;
commited: stable_how_t &optional;
verf: count &optional; # write verifier cookue
};
# reply for create, mkdir, symlink
type newobj_reply_t: record {
# If the proc failed, dir_*_attr may be set.
# If the proc succeeded, fh and the attr's may be set.
# Note no guarantee that fh is set after success
fh: string &optional; # file handle of object created.
obj_attr: fattr_t &optional; # optional attributes associated w/ new object
dir_pre_attr: wcc_attr_t &optional; # optional attributes associated w/ dir.
dir_post_attr: fattr_t &optional; # optional attributes associated w/ dir.
# If the proc failed, dir_*_attr may be set. If the proc succeeded, fh and
# the attr's may be set. Note: no guarantee that fh is set after
# success.
fh: string &optional; # file handle of object created
obj_attr: fattr_t &optional; # optional attributes associated w/ new object
dir_pre_attr: wcc_attr_t &optional; # optional attributes associated w/ dir
dir_post_attr: fattr_t &optional; # optional attributes associated w/ dir
};
# reply for remove, rmdir
# == wcc_data
# Corresponds to "wcc_data" in the spec.
type delobj_reply_t: record {
dir_pre_attr: wcc_attr_t &optional; # optional attributes associated w/ dir.
dir_post_attr: fattr_t &optional; # optional attributes associated w/ dir.
dir_pre_attr: wcc_attr_t &optional; # optional attributes associated w/ dir
dir_post_attr: fattr_t &optional; # optional attributes associated w/ dir
};
# This record is used for both readdir and readdirplus
# This record is used for both readdir and readdirplus.
type readdirargs_t: record {
isplus: bool; # is this a readdirplus request?
dirfh: string; # the directory filehandle
cookie: count; # cookie / pos in dir. 0 for first call
cookieverf: count; # the cookie verifier
dircount: count; # "count" field for readdir, maxcount otherwise. in bytes
maxcount: count &optional; # only used for readdirplus. in bytes
isplus: bool; # is this a readdirplus request?
dirfh: string; # the directory filehandle
cookie: count; # cookie / pos in dir; 0 for first call
cookieverf: count; # the cookie verifier
dircount: count; # "count" field for readdir; maxcount otherwise (in bytes)
maxcount: count &optional; # only used for readdirplus. in bytes
};
type direntry_t: record {
# fh and attr are used for readdirplus. However, even for readdirplus they need not
# be filled out.
fileid: count; # e.g., inode number
fname: string; # filename
cookie: count;
attr: fattr_t &optional; # readdirplus: the FH attributes for the entry
fh: string &optional; # readdirplus: the FH for the entry
# fh and attr are used for readdirplus. However, even for readdirplus they may
# not be filled out.
fileid: count; # e.g., inode number
fname: string; # filename
cookie: count;
attr: fattr_t &optional; # readdirplus: the FH attributes for the entry
fh: string &optional; # readdirplus: the FH for the entry
};
type direntry_vec_t: vector of direntry_t;
# used for readdir and readdirplus
# Used for readdir and readdirplus.
type readdir_reply_t: record {
isplus: bool; # is the reply for a readdirplus request
# if error: dir_attr might be set
# if success: dir_attr may be set, all others must be set
dir_attr: fattr_t &optional;
# If error: dir_attr might be set. If success: dir_attr may be set, all others
# must be set.
isplus: bool; # is the reply for a readdirplus request
dir_attr: fattr_t &optional;
cookieverf: count &optional;
entries: direntry_vec_t &optional;
eof: bool; # if T: no more entries in dir.
eof: bool; # if true, no more entries in dir.
};
type fsstat_t: record {
@ -903,6 +901,7 @@ export {
} # end export
module GLOBAL;
type ntp_msg: record {
id: count;
code: count;
@ -1069,16 +1068,20 @@ global dns_max_queries = 5;
# has bigger cipherspecs, we won't do a comparisons of cipherspecs.
const ssl_max_cipherspec_size = 68 &redef;
# SSL and X.509 types.
type cipher_suites_list: set[count];
type SSL_sessionID: table[count] of count;
type X509_extension: table[count] of string;
type X509_extensions: table[count] of string;
type X509: record {
issuer: string;
version: count;
serial: string;
subject: string;
orig_addr: addr;
issuer: string;
not_valid_before: time;
not_valid_after: time;
};
# This is indexed with the CA's name and yields a DER (binary) encoded certificate.
const root_ca_certs: table[string] of string = {} &redef;
type http_stats_rec: record {
num_requests: count;
num_replies: count;
@ -1383,7 +1386,7 @@ const gap_report_freq = 1.0 sec &redef;
# Whether we want content_gap and drop reports for partial connections
# (a connection is partial if it is missing a full handshake). Note that
# gap reports for partial connections might not be reliable.
# gap reports for partial connections might not be reliable.
const report_gaps_for_partial = F &redef;
# Globals associated with entire-run statistics on gaps (useful

View file

@ -18,6 +18,10 @@ global have_SMTP = F; # if true, we've loaded smtp.bro
# TODO: Do we have a nicer way of defining this prototype?
export { global FTP::is_ftp_data_conn: function(c: connection): bool; }
# Whether to include connection state history in the logs generated
# by record_connection.
const record_state_history = F &redef;
# Whether to add 4 more columns to conn.log with
# orig_packet orig_ip_bytes resp_packets resp_ip_bytes
# Requires use_conn_size_analyzer=T
@ -311,6 +315,10 @@ function record_connection(f: file, c: connection)
conn_size(c$orig, trans), conn_size(c$resp, trans),
conn_state(c, trans), flags);
if ( record_state_history )
log_msg = fmt("%s %s", log_msg,
c$history == "" ? "X" : c$history);
if ( use_conn_size_analyzer && report_conn_size_analyzer )
log_msg = fmt("%s %s %s", log_msg,
conn_size_from_analyzer(c$orig), conn_size_from_analyzer(c$resp));

View file

@ -10,17 +10,16 @@ export {
global names_log_file = open_log_file("nfs-files") &redef;
global readdir_log = open_log_file("nfs-readdir") &redef;
# we want to estiamte how long it takes to lookup a chain of FH
# (directories) until we reach a FH that is used in a read or write
# operation. Whenever we get a new FH, we check how long ago we
# got the FH's parent. If this is less than fh_chain_maxtime, we
# assume that they belong to a lookup chain and set the dt value for
# the FH accordingly.
# We want to estimate how long it takes to lookup a chain of FH (directories)
# until we reach a FH that is used in a read or write operation. Whenever we
# get a new FH, we check how long ago we got the FH's parent. If this is less
# than fh_chain_maxtime, we assume that they belong to a lookup chain and set
# the dt value for the FH accordingly.
global fh_chain_maxtime = 100 msec;
}
redef capture_filters += {
redef capture_filters += {
["nfs"] = "port 2049",
# NFS UDP packets are often fragmented.
["nfs-frag"] = "(ip[6:2] & 0x3fff != 0) and udp",
@ -30,13 +29,13 @@ global nfs_ports = { 2049/tcp, 2049/udp } &redef;
redef dpd_config += { [ANALYZER_NFS] = [$ports = nfs_ports] };
# Information about a filehandle
type fh_info : record {
type fh_info : record {
id: count; # A unique ID (counter) for more readable representation of the FH
pathname: string &default="@"; # the path leading to this FH
basename: string &default=""; # the name of this FHs file or directory
mimetype: string &default="";
t0: time &default=double_to_time(0); # time when we first saw this FH
dt: interval &default=0 sec; # time it took to get this FH (assuming a chain of
dt: interval &default=0 sec; # time it took to get this FH (assuming a chain of
# procedures that ultimately yield the FH for the file
# a client is interested in
chainlen: count &default=0;
@ -66,7 +65,7 @@ function get_fh_info(c: connection, fh: string): fh_info
return fh_map[c$id$resp_h, fh];
}
function log_filename(proc: string, info: fh_info)
function log_filename(proc: string, info: fh_info)
{
print names_log_file, fmt("%.6f %s path FH%d %s/%s", network_time(), proc,
info$id, info$pathname, info$basename);
@ -75,7 +74,7 @@ function log_filename(proc: string, info: fh_info)
function fmt_attr(a: fattr_t): string
{
local s = fmt("%s %s %d %d %d %d %d %d %d %d %d %.2f %.2f %.2f",
local s = fmt("%s %s %d %d %d %d %d %d %d %d %d %.2f %.2f %.2f",
a$ftype, mode2string(a$mode), a$nlink, a$uid, a$gid, a$size, a$used, a$rdev1, a$rdev2,
a$fsid, a$fileid, a$atime, a$mtime, a$ctime);
return s;
@ -85,11 +84,11 @@ function log_attributes(c: connection, proc: string, fh: string, attr: fattr_t)
{
local info = get_fh_info(c,fh);
local did_change = F;
# check whether the attributes have changes
if (info?$attr)
# check whether the attributes have changes
if (info?$attr)
{
# We can't compare records for equality :-(. So we use a hack.
# We add the two instance we want to compare to a set. If there
# We can't compare records for equality :-(. So we use a hack.
# We add the two instance we want to compare to a set. If there
# are two elements in the set, the records are not equal...
local dummy: set[fattr_t];
add dummy[info$attr];
@ -102,13 +101,13 @@ function log_attributes(c: connection, proc: string, fh: string, attr: fattr_t)
if (did_change)
{
info$attr = attr;
print names_log_file, fmt("%.6f %s attr FH%d %s", network_time(), proc,
print names_log_file, fmt("%.6f %s attr FH%d %s", network_time(), proc,
info$id, fmt_attr(attr));
}
}
# Update (or add) a filehandle mapping.
# parentfh ... parent (directory)
# parentfh ... parent (directory)
# name ....... the name for this FH
# fh ......... the new FH
function add_update_fh(c: connection, proc: string, parentfh: string, name: string, fh: string)
@ -120,11 +119,11 @@ function add_update_fh(c: connection, proc: string, parentfh: string, name: stri
if (name == ".")
return;
info$basename = name;
if (parentfh != "")
if (parentfh != "")
{
local parentinfo = get_fh_info(c, parentfh);
info$pathname = cat(parentinfo$pathname, "/", parentinfo$basename);
if ( (network_time() - parentinfo$t0) < fh_chain_maxtime
if ( (network_time() - parentinfo$t0) < fh_chain_maxtime
&& info$dt < 0 sec )
{
# The FH is part of lookup chain and it doesn't yet have a dt value
@ -151,15 +150,15 @@ function set_fh_mimetype(c: connection, fh: string, proc:string, data: string)
}
}
# Get the total time of the lookup chain for this FH to the
# current network time. Returns a negative interal if no
# Get the total time of the lookup chain for this FH to the
# current network time. Returns a negative interal if no
# lookup chain was found
function get_fh_chaintime_str(c:connection, fh:string): string
{
local info = get_fh_info(c, fh);
if ((network_time() - info$t0) < fh_chain_maxtime)
return fmt("%d %.6f", info$chainlen, info$dt + (network_time() - info$t0));
else
else
return fmt("%d %.6f", 0, 0.0);
}
@ -187,7 +186,7 @@ function print_attr(attr: fattr_t): string
return fmt("%s", attr);
}
function map_conn(cid: conn_id): count
function map_conn(cid: conn_id): count
{
if (cid !in nfs_conns)
nfs_conns[cid] = ++num_nfs_conns;
@ -208,16 +207,16 @@ function is_rpc_success(info: info_t): bool
function nfs_get_log_prefix(c: connection, info: info_t, proc: string): string
{
local nfs_stat_str = (info$rpc_stat == RPC_SUCCESS) ? fmt("%s", info$nfs_stat) : "X";
return fmt("%.06f %.06f %d %.06f %.06f %d %s %s %d %s %s %s",
return fmt("%.06f %.06f %d %.06f %.06f %d %s %s %d %s %s %s",
info$req_start, info$req_dur, info$req_len,
info$rep_start, info$rep_dur, info$rep_len,
id_string(c$id), get_port_transport_proto(c$id$orig_p),
map_conn(c$id),
map_conn(c$id),
proc, info$rpc_stat, nfs_stat_str);
}
event nfs_proc_not_implemented(c: connection, info: info_t, proc: proc_t)
event nfs_proc_not_implemented(c: connection, info: info_t, proc: proc_t)
{
local prefix = nfs_get_log_prefix(c, info, fmt("%s", proc));
@ -231,13 +230,13 @@ event nfs_proc_null(c: connection, info: info_t)
print log_file, prefix;
}
event nfs_proc_getattr (c: connection, info: info_t, fh: string, attrs: fattr_t)
event nfs_proc_getattr (c: connection, info: info_t, fh: string, attrs: fattr_t)
{
local prefix = nfs_get_log_prefix(c, info, "getattr");
if (is_success(info))
log_attributes(c, "getattr", fh, attrs);
print log_file, fmt("%s %s", prefix, get_fh_id(c,fh));
}
@ -257,7 +256,7 @@ event nfs_proc_lookup(c: connection, info: info_t, req: diropargs_t, rep: lookup
log_attributes(c, "lookup", rep$fh, rep$obj_attr);
add_update_fh(c, "lookup", req$dirfh, req$fname, rep$fh);
print log_file, fmt("%s %s + %s => %s", prefix, get_fh_id(c, req$dirfh), req$fname, get_fh_id(c, rep$fh));
}
event nfs_proc_read(c: connection, info: info_t, req: readargs_t, rep: read_reply_t)
@ -267,7 +266,7 @@ event nfs_proc_read(c: connection, info: info_t, req: readargs_t, rep: read_repl
msg = fmt("%s %s @%d: %d", msg, get_fh_id(c, req$fh), req$offset, req$size);
if (is_success(info))
{
msg = fmt("%s got %d bytes %s %s", msg, rep$size, (rep$eof) ? "<eof>" : "x",
msg = fmt("%s got %d bytes %s %s", msg, rep$size, (rep$eof) ? "<eof>" : "x",
get_fh_chaintime_str(c, req$fh));
if (rep?$data && req$offset==0 && rep$size>0)
set_fh_mimetype(c, req$fh, "read", rep$data);
@ -278,7 +277,7 @@ event nfs_proc_read(c: connection, info: info_t, req: readargs_t, rep: read_repl
print log_file, msg;
}
event nfs_proc_readlink(c: connection, info: info_t, fh: string, rep: readlink_reply_t)
event nfs_proc_readlink(c: connection, info: info_t, fh: string, rep: readlink_reply_t)
{
local msg = nfs_get_log_prefix(c, info, "readlink");
@ -300,7 +299,7 @@ event nfs_proc_write(c: connection, info: info_t, req: writeargs_t, rep: write_r
msg = fmt("%s %s @%d: %d %s", msg, get_fh_id(c, req$fh), req$offset, req$size, req$stable);
if (is_success(info))
{
msg = fmt("%s wrote %d bytes %s %s", msg, rep$size, rep$commited,
msg = fmt("%s wrote %d bytes %s %s", msg, rep$size, rep$commited,
get_fh_chaintime_str(c, req$fh));
if (req?$data && req$offset==0 && rep$size>0)
set_fh_mimetype(c, req$fh, "write", req$data);
@ -370,7 +369,7 @@ function fmt_direntry(c: connection, e: direntry_t): string
if (e?$fh)
rv = fmt("%s %s", rv, get_fh_id(c, e$fh));
return rv;
}
event nfs_proc_readdir(c: connection, info: info_t, req: readdirargs_t, rep: readdir_reply_t)

View file

@ -58,8 +58,13 @@ function build_default_pcap_filter(): string
return cmd_line_bpf_filter;
if ( all_packets )
{
# Return an "always true" filter.
return "ip or not ip";
if ( bro_has_ipv6() )
return "ip or not ip";
else
return "not ip6";
}
## Build filter dynamically.
@ -76,6 +81,10 @@ function build_default_pcap_filter(): string
# Finally, join them.
local filter = join_filters(cfilter, rfilter);
# Exclude IPv6 if we don't support it.
if ( ! bro_has_ipv6() )
filter = fmt("(not ip6) and (%s)", filter);
return filter;
}

View file

@ -118,6 +118,8 @@ export {
# Indexed by the portmapper request and a boolean that's T if
# the request was answered, F it was attempted but not answered.
# If there's an entry in the set, then the access won't lead to a
# NOTICE (unless the connection is hot for some other reason).
# If there's an entry in the set, then the access won't lead to a
# NOTICE (unless the connection is hot for some other reason).
const RPC_do_not_complain: set[string, bool] = {
@ -140,7 +142,7 @@ export {
# Logs all portmapper mappings that we observe (i.e., getport and
# dump replies. Format:
# timestamp orig_h orig_p resp_h resp_p proto localInit PortmapProcedure RPCprogram version port proto
# the mapping is then: <resp_h> accepts <RPCprogram> with <version>
# the mapping is then: <resp_h> accepts <RPCprogram> with <version>
# calls on <port> <proto>. We learned this mapping via <PortmapProcedure>
const mapping_log_file = open_log_file("portmapper-maps") &redef;
}
@ -151,7 +153,7 @@ const portmapper_ports = { 111/tcp, 111/udp } &redef;
redef dpd_config += { [ANALYZER_PORTMAPPER] = [$ports = portmapper_ports] };
# Indexed by source and destination addresses, plus the portmapper service.
# If the tuple is in the set, then we already created a NOTICE for it and
# If the tuple is in the set, then we already created a NOTICE for it and
# shouldn't do so again.
global did_pm_notice: set[addr, addr, string];
@ -185,7 +187,7 @@ function rpc_prog(p: count): string
function pm_get_conn_string(cid: conn_id) : string
{
return fmt("%s %d %s %d %s %s",
return fmt("%s %d %s %d %s %s",
cid$orig_h, cid$orig_p,
cid$resp_h, cid$resp_p,
get_port_transport_proto(cid$resp_p),
@ -194,9 +196,9 @@ function pm_get_conn_string(cid: conn_id) : string
}
# Log a pm_request or pm_attempt to the log file
function pm_log(r: connection, proc: string, msg: string, success: bool)
function pm_log(r: connection, proc: string, msg: string, success: bool)
{
print log_file, fmt("%f %s %s %s %s", network_time(),
print log_file, fmt("%f %s %s %s %s", network_time(),
pm_get_conn_string(r$id),
proc, success, msg);
}
@ -218,9 +220,9 @@ function pm_log_mapping_dump(r: connection, m: pm_mappings)
}
# Log portmapper mappings received from a getport procedure
# Unfortunately, pm_request_getport doesn't return pm_mapping,
# Unfortunately, pm_request_getport doesn't return pm_mapping,
# but returns the parameters separately ....
function pm_log_mapping_getport(r: connection, pr: pm_port_request, p: port)
function pm_log_mapping_getport(r: connection, pr: pm_port_request, p: port)
{
local prog = rpc_prog(pr$program);
local ver = pr$version;
@ -229,7 +231,7 @@ function pm_log_mapping_getport(r: connection, pr: pm_port_request, p: port)
pm_get_conn_string(r$id),
prog, ver, p, get_port_transport_proto(p));
}
function pm_check_getport(r: connection, prog: string): bool
@ -377,7 +379,7 @@ event pm_request_dump(r: connection, m: pm_mappings)
{
local do_notice = [r$id$orig_h, r$id$resp_h] !in RPC_dump_okay;
# pm_mapping_to_text has the side-effect of updating RPC_server_map
pm_request(r, "pm_dump",
pm_request(r, "pm_dump",
length(m) == 0 ? "(nil)" : pm_mapping_to_text(r$id$resp_h, m),
do_notice);
pm_log_mapping_dump(r, m);

131
policy/ssl-mozilla-CAs.bro Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,7 @@
// $Id: Analyzer.cc,v 1.1.4.28 2006/06/01 17:18:10 sommer Exp $
#include <algorithm>
#include "Analyzer.h"
#include "PIA.h"
#include "Event.h"
@ -34,8 +36,8 @@
#include "Portmap.h"
#include "POP3.h"
#include "SSH.h"
#include "SSLProxy.h"
#include "SSL-binpac.h"
#include "Syslog-binpac.h"
#include "ConnSizeAnalyzer.h"
#include <algorithm>
@ -60,6 +62,9 @@ const Analyzer::Config Analyzer::analyzer_configs[] = {
{ AnalyzerTag::ICMP_Echo, "ICMP_ECHO",
ICMP_Echo_Analyzer::InstantiateAnalyzer,
ICMP_Echo_Analyzer::Available, 0, false },
{ AnalyzerTag::ICMP_Redir, "ICMP_REDIR",
ICMP_Redir_Analyzer::InstantiateAnalyzer,
ICMP_Redir_Analyzer::Available, 0, false },
{ AnalyzerTag::TCP, "TCP", TCP_Analyzer::InstantiateAnalyzer,
TCP_Analyzer::Available, 0, false },
@ -116,8 +121,6 @@ const Analyzer::Config Analyzer::analyzer_configs[] = {
SMTP_Analyzer::Available, 0, false },
{ AnalyzerTag::SSH, "SSH", SSH_Analyzer::InstantiateAnalyzer,
SSH_Analyzer::Available, 0, false },
{ AnalyzerTag::SSL, "SSL", SSLProxy_Analyzer::InstantiateAnalyzer,
SSLProxy_Analyzer::Available, 0, false },
{ AnalyzerTag::Telnet, "TELNET", Telnet_Analyzer::InstantiateAnalyzer,
Telnet_Analyzer::Available, 0, false },
@ -133,9 +136,12 @@ const Analyzer::Config Analyzer::analyzer_configs[] = {
{ AnalyzerTag::HTTP_BINPAC, "HTTP_BINPAC",
HTTP_Analyzer_binpac::InstantiateAnalyzer,
HTTP_Analyzer_binpac::Available, 0, false },
{ AnalyzerTag::SSL_BINPAC, "SSL_BINPAC",
{ AnalyzerTag::SSL, "SSL",
SSL_Analyzer_binpac::InstantiateAnalyzer,
SSL_Analyzer_binpac::Available, 0, false },
{ AnalyzerTag::SYSLOG_BINPAC, "SYSLOG_BINPAC",
Syslog_Analyzer_binpac::InstantiateAnalyzer,
Syslog_Analyzer_binpac::Available, 0, false },
{ AnalyzerTag::File, "FILE", File_Analyzer::InstantiateAnalyzer,
File_Analyzer::Available, 0, false },
@ -168,7 +174,6 @@ const Analyzer::Config Analyzer::analyzer_configs[] = {
{ AnalyzerTag::Contents_SMB, "CONTENTS_SMB", 0, 0, 0, false },
{ AnalyzerTag::Contents_RPC, "CONTENTS_RPC", 0, 0, 0, false },
{ AnalyzerTag::Contents_NFS, "CONTENTS_NFS", 0, 0, 0, false },
{ AnalyzerTag::Contents_SSL, "CONTENTS_SSL", 0, 0, 0, false },
};
AnalyzerTimer::~AnalyzerTimer()

View file

@ -22,19 +22,20 @@ namespace AnalyzerTag {
PIA_TCP, PIA_UDP,
// Transport-layer analyzers.
ICMP, ICMP_TimeExceeded, ICMP_Unreachable, ICMP_Echo, TCP, UDP,
ICMP,
ICMP_TimeExceeded, ICMP_Unreachable, ICMP_Echo, ICMP_Redir,
TCP, UDP,
// Application-layer analyzers (hand-written).
BitTorrent, BitTorrentTracker,
DCE_RPC, DNS, Finger, FTP, Gnutella, HTTP, Ident, IRC,
Login, NCP, NetbiosSSN, NFS, NTP, POP3, Portmapper, Rlogin,
RPC, Rsh, SMB, SMTP, SSH,
SSL,
Telnet,
// Application-layer analyzers, binpac-generated.
DHCP_BINPAC, DNS_TCP_BINPAC, DNS_UDP_BINPAC,
HTTP_BINPAC, SSL_BINPAC,
HTTP_BINPAC, SSL, SYSLOG_BINPAC,
// Other
File, Backdoor, InterConn, SteppingStone, TCPStats,
@ -45,7 +46,6 @@ namespace AnalyzerTag {
Contents, ContentLine, NVT, Zip, Contents_DNS, Contents_NCP,
Contents_NetbiosSSN, Contents_Rlogin, Contents_Rsh,
Contents_DCE_RPC, Contents_SMB, Contents_RPC, Contents_NFS,
Contents_SSL,
// End-marker.
LastAnalyzer
};

View file

@ -7,6 +7,8 @@
#include <algorithm>
#include <ctype.h>
#include <algorithm>
#include "BroString.h"
#include "Var.h"

View file

@ -197,8 +197,8 @@ binpac_target(smb.pac
smb-protocol.pac smb-pipe.pac smb-mailslot.pac)
binpac_target(ssl.pac
ssl-defs.pac ssl-protocol.pac ssl-analyzer.pac)
binpac_target(ssl-record-layer.pac
ssl-defs.pac ssl.pac)
binpac_target(syslog.pac
syslog-protocol.pac syslog-analyzer.pac)
########################################################################
## bro target
@ -239,16 +239,6 @@ set(dns_SRCS nb_dns.c)
set_source_files_properties(nb_dns.c PROPERTIES COMPILE_FLAGS
-fno-strict-aliasing)
set(openssl_SRCS
X509.cc
SSLCiphers.cc
SSLInterpreter.cc
SSLProxy.cc
SSLv2.cc
SSLv3.cc
SSLv3Automaton.cc
)
if (USE_NMALLOC)
set(malloc_SRCS malloc.c)
endif ()
@ -389,6 +379,7 @@ set(bro_SRCS
Stats.cc
SteppingStone.cc
Stmt.cc
Syslog-binpac.cc
TCP.cc
TCP_Endpoint.cc
TCP_Reassembler.cc

View file

@ -216,56 +216,6 @@ Connection::~Connection()
--external_connections;
}
uint64 Connection::uid_counter = 0;
uint64 Connection::uid_instance = 0;
uint64 Connection::CalculateNextUID()
{
if ( uid_instance == 0 )
{
// This is the first time we need a UID.
if ( ! have_random_seed() )
{
// If we don't need deterministic output (as
// indicated by a set seed), we calculate the
// instance ID by hashing something likely to be
// globally unique.
struct {
char hostname[128];
struct timeval time;
pid_t pid;
int rnd;
} unique;
gethostname(unique.hostname, 128);
unique.hostname[sizeof(unique.hostname)-1] = '\0';
gettimeofday(&unique.time, 0);
unique.pid = getpid();
unique.rnd = bro_random();
uid_instance = HashKey::HashBytes(&unique, sizeof(unique));
++uid_instance; // Now it's larger than zero.
}
else
// Generate determistic UIDs.
uid_instance = 1;
}
// Now calculate the unique ID for this connection.
struct {
uint64 counter;
hash_t instance;
} key;
key.counter = ++uid_counter;
key.instance = uid_instance;
uint64_t h = HashKey::HashBytes(&key, sizeof(key));
return h;
}
void Connection::Done()
{
finished = 1;
@ -417,7 +367,7 @@ RecordVal* Connection::BuildConnVal()
conn_val->Assign(8, new StringVal("")); // history
if ( ! uid )
uid = CalculateNextUID();
uid = calculate_unique_id();
char tmp[20];
conn_val->Assign(9, new StringVal(uitoa_n(uid, tmp, sizeof(tmp), 62)));

View file

@ -303,8 +303,6 @@ public:
void SetUID(uint64 arg_uid) { uid = arg_uid; }
static uint64 CalculateNextUID();
protected:
Connection() { persistent = 0; }
@ -363,9 +361,6 @@ protected:
PIA* primary_PIA;
uint64 uid; // Globally unique connection ID.
static uint64 uid_counter; // Counter for uids.
static uint64 uid_instance; // Instance ID, computed once.
};
class ConnectionTimer : public Timer {

View file

@ -620,7 +620,7 @@ void ConnCompressor::PktHdrToPendingConn(double time, const HashKey* key,
c->FIN = (tp->th_flags & TH_FIN) != 0;
c->RST = (tp->th_flags & TH_RST) != 0;
c->ACK = (tp->th_flags & TH_ACK) != 0;
c->uid = Connection::CalculateNextUID();
c->uid = calculate_unique_id();
c->num_bytes_ip = ip->TotalLen();
c->num_pkts = 1;
c->invalid = 0;

View file

@ -1,5 +1,7 @@
// $Id: ContentLine.cc,v 1.1.2.8 2006/06/01 01:55:42 sommer Exp $
#include <algorithm>
#include "ContentLine.h"
#include "TCP.h"

View file

@ -29,6 +29,8 @@
#endif
#include <stdlib.h>
#include <algorithm>
#include "DNS_Mgr.h"
#include "Event.h"
#include "Net.h"

View file

@ -229,6 +229,14 @@ bool DPM::BuildInitialAnalyzerTree(TransportProto proto, Connection* conn,
}
break;
case ICMP_REDIRECT:
if ( ICMP_Redir_Analyzer::Available() )
{
root = new ICMP_Redir_Analyzer(conn);
DBG_DPD(conn, "activated ICMP Redir analyzer");
}
break;
case ICMP_UNREACH:
if ( ICMP_Unreachable_Analyzer::Available() )
{

View file

@ -343,7 +343,7 @@ vector<ParseLocationRec> parse_location_string(const string& s)
plr.type = plrUnknown;
FILE* throwaway = search_for_file(filename.c_str(), "bro",
&full_filename);
&full_filename, true);
if ( ! throwaway )
{
debug_msg("No such policy file: %s.\n", filename.c_str());

View file

@ -207,41 +207,71 @@ void ODesc::Indent()
}
}
static const char hex_chars[] = "0123456789ABCDEF";
static const char hex_chars[] = "0123456789abcdef";
static const char* find_first_unprintable(ODesc* d, const char* bytes, unsigned int n)
{
if ( d->IsBinary() )
return 0;
while ( n-- )
{
if ( ! isprint(*bytes) )
return bytes;
++bytes;
}
return 0;
}
void ODesc::AddBytes(const void* bytes, unsigned int n)
{
if ( ! escape )
return AddBytesRaw(bytes, n);
const char* s = (const char*) bytes;
const char* e = (const char*) bytes + n;
while ( s < e )
{
const char* t = (const char*) memchr(s, escape[0], e - s);
const char* t1 = escape ? (const char*) memchr(s, escape[0], e - s) : e;
const char* t2 = find_first_unprintable(this, s, t1 ? e - t1 : e - s);
if ( ! t )
if ( t2 && (t2 < t1 || ! t1) )
{
AddBytesRaw(s, t2 - s);
char hex[6] = "\\x00";
hex[2] = hex_chars[((*t2) & 0xf0) >> 4];
hex[3] = hex_chars[(*t2) & 0x0f];
AddBytesRaw(hex, sizeof(hex));
s = t2 + 1;
continue;
}
if ( ! escape )
break;
if ( memcmp(t, escape, escape_len) != 0 )
if ( ! t1 )
break;
AddBytesRaw(s, t - s);
if ( memcmp(t1, escape, escape_len) != 0 )
break;
AddBytesRaw(s, t1 - s);
for ( int i = 0; i < escape_len; ++i )
{
char hex[5] = "\\x00";
hex[2] = hex_chars[(*t) >> 4];
hex[3] = hex_chars[(*t) & 0x0f];
hex[2] = hex_chars[((*t1) & 0xf0) >> 4];
hex[3] = hex_chars[(*t1) & 0x0f];
AddBytesRaw(hex, sizeof(hex));
++t;
++t1;
}
s = t;
s = t1;
}
AddBytesRaw(s, e - s);
if ( s < e )
AddBytesRaw(s, e - s);
}
void ODesc::AddBytesRaw(const void* bytes, unsigned int n)

View file

@ -2,6 +2,8 @@
//
// See the file "COPYING" in the main distribution directory for copyright.
#include <algorithm>
#include "config.h"
#include "Net.h"

View file

@ -20,6 +20,8 @@
#include <errno.h>
#include <unistd.h>
#include <algorithm>
#include "File.h"
#include "Type.h"
#include "Timer.h"

View file

@ -1,5 +1,7 @@
// $Id: FileAnalyzer.cc,v 1.1.4.2 2006/06/01 17:18:10 sommer Exp $
#include <algorithm>
#include "FileAnalyzer.h"
#include <algorithm>

View file

@ -6,14 +6,14 @@
#include <ctype.h>
#include <algorithm>
#include "NetVar.h"
#include "HTTP.h"
#include "Gnutella.h"
#include "Event.h"
#include "PIA.h"
#include <algorithm>
GnutellaMsgState::GnutellaMsgState()
{
buffer = "";

View file

@ -2,6 +2,8 @@
//
// See the file "COPYING" in the main distribution directory for copyright.
#include <algorithm>
#include "config.h"
#include "Net.h"
@ -323,6 +325,24 @@ void ICMP_Echo_Analyzer::NextICMP(double t, const struct icmp* icmpp, int len,
ConnectionEvent(f, vl);
}
ICMP_Redir_Analyzer::ICMP_Redir_Analyzer(Connection* c)
: ICMP_Analyzer(AnalyzerTag::ICMP_Redir, c)
{
}
void ICMP_Redir_Analyzer::NextICMP(double t, const struct icmp* icmpp, int len,
int caplen, const u_char*& data)
{
uint32 addr = ntohl(icmpp->icmp_hun.ih_void);
val_list* vl = new val_list;
vl->append(BuildConnVal());
vl->append(BuildICMPVal());
vl->append(new AddrVal(htonl(addr)));
ConnectionEvent(icmp_redirect, vl);
}
void ICMP_Context_Analyzer::NextICMP(double t, const struct icmp* icmpp,
int len, int caplen, const u_char*& data)

View file

@ -74,6 +74,22 @@ protected:
int len, int caplen, const u_char*& data);
};
class ICMP_Redir_Analyzer : public ICMP_Analyzer {
public:
ICMP_Redir_Analyzer(Connection* conn);
static Analyzer* InstantiateAnalyzer(Connection* conn)
{ return new ICMP_Redir_Analyzer(conn); }
static bool Available() { return icmp_redirect; }
protected:
ICMP_Redir_Analyzer() { }
virtual void NextICMP(double t, const struct icmp* icmpp,
int len, int caplen, const u_char*& data);
};
class ICMP_Context_Analyzer : public ICMP_Analyzer {
public:
ICMP_Context_Analyzer(AnalyzerTag::Tag tag, Connection* conn)

View file

@ -5,6 +5,8 @@
#include <unistd.h>
#include <assert.h>
#include <algorithm>
#include "util.h"
#include "IOSource.h"

View file

@ -1089,7 +1089,7 @@ LogVal** LogMgr::RecordToFilterVals(Stream* stream, Filter* filter,
if ( ! val )
{
// Value, or any of its parents, is not set.
vals[i] = new LogVal(type, false);
vals[i] = new LogVal(filter->fields[i]->type, false);
break;
}
}

View file

@ -223,7 +223,7 @@ bool LogWriterAscii::DoWrite(int num_fields, const LogField* const * fields,
return false;
}
desc.Add("\n");
desc.AddRaw("\n", 1);
if ( fwrite(desc.Bytes(), desc.Len(), 1, file) != 1 )
{

View file

@ -2,6 +2,8 @@
//
// See the file "COPYING" in the main distribution directory for copyright.
#include <algorithm>
#include "config.h"
#include "NetVar.h"
@ -9,16 +11,13 @@
#include "NFS.h"
#include "Event.h"
#include <algorithm>
int NFS_Interp::RPC_BuildCall(RPC_CallInfo* c, const u_char*& buf, int& n)
{
if ( c->Program() != 100003 )
Weird(fmt("bad_RPC_program (%d)", c->Program()));
uint32 proc = c->Proc();
// the call arguments, depends on the call type obviously...
// The call arguments, depends on the call type obviously ...
Val *callarg = 0;
switch ( proc ) {
@ -47,15 +46,15 @@ int NFS_Interp::RPC_BuildCall(RPC_CallInfo* c, const u_char*& buf, int& n)
case BifEnum::NFS3::PROC_CREATE:
callarg = nfs3_diropargs(buf, n);
// TODO: implement create attributes.
// For now we just skip over them
// TODO: implement create attributes. For now we just skip
// over them.
n = 0;
break;
case BifEnum::NFS3::PROC_MKDIR:
callarg = nfs3_diropargs(buf, n);
// TODO: implement mkdir attributes.
// For now we just skip over them
// TODO: implement mkdir attributes. For now we just skip
// over them.
n = 0;
break;
@ -78,43 +77,47 @@ int NFS_Interp::RPC_BuildCall(RPC_CallInfo* c, const u_char*& buf, int& n)
default:
callarg = 0;
if ( proc < BifEnum::NFS3::PROC_END_OF_PROCS )
{ // We know the procedure but haven't implemented it
n = 0; // otherwise DeliverRPC complains about excess_RPC
{
// We know the procedure but haven't implemented it.
// Otherwise DeliverRPC would complain about
// excess_RPC.
n = 0;
}
else
else
Weird(fmt("unknown_NFS_request(%u)", proc));
// Return 1 so that replies to unprocessed calls will still
// be processed, and the return status extracted
// be processed, and the return status extracted.
return 1;
}
if ( !buf )
if ( ! buf )
{
// There was a parse error while trying to extract the call
// arguments. However, we don't know where exactly it happened
// and whether Vals where already allocated (e.g., a RecordVal
// was allocated but we failed to fill it).
// So we Unref() the call arguments, and we are fine.
// There was a parse error while trying to extract the call
// arguments. However, we don't know where exactly it
// happened and whether Vals where already allocated (e.g., a
// RecordVal was allocated but we failed to fill it). So we
// Unref() the call arguments, and we are fine.
Unref(callarg);
callarg = 0;
return 0;
}
c->AddVal(callarg); // it's save to AddVal(0).
c->AddVal(callarg); // It's save to AddVal(0).
return 1;
}
int NFS_Interp::RPC_BuildReply(RPC_CallInfo* c, BifEnum::rpc_status rpc_status,
const u_char*& buf, int& n, double start_time, double last_time,
int reply_len)
const u_char*& buf, int& n, double start_time,
double last_time, int reply_len)
{
EventHandlerPtr event = 0;
Val *reply = 0;
BifEnum::NFS3::status_t nfs_status = BifEnum::NFS3::NFS3ERR_OK;
bool rpc_success = ( rpc_status == BifEnum::RPC_SUCCESS );
// reply always starts with the NFS status
// Reply always starts with the NFS status.
if ( rpc_success )
{
if ( n >= 4 )
@ -126,17 +129,19 @@ int NFS_Interp::RPC_BuildReply(RPC_CallInfo* c, BifEnum::rpc_status rpc_status,
if ( nfs_reply_status )
{
val_list* vl = event_common_vl(c, rpc_status, nfs_status,
start_time, last_time, reply_len);
start_time, last_time, reply_len);
analyzer->ConnectionEvent(nfs_reply_status, vl);
}
if (!rpc_success)
if ( ! rpc_success )
{
// We set the buffer to NULL, the function that extract the reply
// from the data stream will then return empty records.
// We set the buffer to NULL, the function that extract the
// reply from the data stream will then return empty records.
//
buf = NULL;
n = 0;
}
switch ( c->Proc() ) {
case BifEnum::NFS3::PROC_NULL:
event = nfs_proc_null;
@ -153,11 +158,9 @@ int NFS_Interp::RPC_BuildReply(RPC_CallInfo* c, BifEnum::rpc_status rpc_status,
break;
case BifEnum::NFS3::PROC_READ:
{
bro_uint_t offset;
offset = c->RequestVal()->AsRecordVal()->Lookup(1)->AsCount();
reply = nfs3_read_reply(buf, n, nfs_status, offset);
}
event = nfs_proc_read;
break;
@ -205,8 +208,11 @@ int NFS_Interp::RPC_BuildReply(RPC_CallInfo* c, BifEnum::rpc_status rpc_status,
default:
if ( c->Proc() < BifEnum::NFS3::PROC_END_OF_PROCS )
{ // We know the procedure but haven't implemented it
n = 0; // otherwise DeliverRPC complains about excess_RPC
{
// We know the procedure but haven't implemented it.
// Otherwise DeliverRPC would complain about
// excess_RPC.
n = 0;
reply = new EnumVal(c->Proc(), BifType::Enum::NFS3::proc_t);
event = nfs_proc_not_implemented;
}
@ -214,31 +220,37 @@ int NFS_Interp::RPC_BuildReply(RPC_CallInfo* c, BifEnum::rpc_status rpc_status,
return 0;
}
if (rpc_success && !buf)
if ( rpc_success && ! buf )
{
// There was a parse error. We have to unref the reply.
// (see also comments in RPC_BuildCall
// There was a parse error. We have to unref the reply. (see
// also comments in RPC_BuildCall.
Unref(reply);
reply = 0;
return 0;
}
// Note: if reply == 0, it won't be added to the val_list for the event.
// While we can check for that on the policy layer it's kinda ugly, because
// it's contrary to the event prototype. But having this optional argument to
// the event is really helpful.... Otherwise I have to let reply
// point to a RecordVal where all fields are optional and all are set
// to 0...
if (event)
// Note: if reply == 0, it won't be added to the val_list for the
// event. While we can check for that on the policy layer it's kinda
// ugly, because it's contrary to the event prototype. But having
// this optional argument to the event is really helpful. Otherwise I
// have to let reply point to a RecordVal where all fields are
// optional and all are set to 0 ...
if ( event )
{
val_list* vl = event_common_vl(c, rpc_status, nfs_status,
start_time, last_time, reply_len);
Val *request = c->TakeRequestVal();
if ( request )
vl->append(request);
if ( reply )
vl->append(reply);
analyzer->ConnectionEvent(event, vl);
}
return 1;
}
@ -247,33 +259,38 @@ StringVal* NFS_Interp::nfs3_file_data(const u_char*& buf, int& n, uint64_t offse
int data_n;
// extract the data, move buf and n
const u_char *data = extract_XDR_opaque(buf, n, data_n, 1<<30, true);
const u_char *data = extract_XDR_opaque(buf, n, data_n, 1 << 30, true);
// check whether we have to deliver data to the event
if (!BifConst::NFS3::return_data)
// check whether we have to deliver data to the event
if ( ! BifConst::NFS3::return_data )
return 0;
if (BifConst::NFS3::return_data_first_only && offset!=0)
if ( BifConst::NFS3::return_data_first_only && offset != 0 )
return 0;
// Ok, so we want to return some data
data_n = min(data_n, size);
data_n = min(data_n, int(BifConst::NFS3::return_data_max));
if (data_n>0)
if ( data_n > 0 )
return new StringVal(new BroString(data, data_n, 0));
return 0;
}
val_list* NFS_Interp::event_common_vl(RPC_CallInfo *c, BifEnum::rpc_status rpc_status,
BifEnum::NFS3::status_t nfs_status, double rep_start_time, double rep_last_time,
int reply_len)
val_list* NFS_Interp::event_common_vl(RPC_CallInfo *c, BifEnum::rpc_status rpc_status,
BifEnum::NFS3::status_t nfs_status,
double rep_start_time,
double rep_last_time, int reply_len)
{
// returns a new val_list that already has a conn_val, and nfs3_info
// These are the first parameters for each nfs_* event...
// Returns a new val_list that already has a conn_val, and nfs3_info.
// These are the first parameters for each nfs_* event ...
val_list *vl = new val_list;
vl->append(analyzer->BuildConnVal());
RecordVal *info = new RecordVal(BifType::Record::NFS3::info_t);
info->Assign(0, new EnumVal(rpc_status, BifType::Enum::rpc_status));
info->Assign(1, new EnumVal(nfs_status, BifType::Enum::NFS3::status_t));
info->Assign(0, new EnumVal(rpc_status, BifType::Enum::rpc_status));
info->Assign(1, new EnumVal(nfs_status, BifType::Enum::NFS3::status_t));
info->Assign(2, new Val(c->StartTime(), TYPE_TIME));
info->Assign(3, new Val(c->LastTime()-c->StartTime(), TYPE_INTERVAL));
info->Assign(4, new Val(c->RPCLen(), TYPE_COUNT));
@ -299,6 +316,7 @@ StringVal* NFS_Interp::nfs3_fh(const u_char*& buf, int& n)
RecordVal* NFS_Interp::nfs3_fattr(const u_char*& buf, int& n)
{
RecordVal* attrs = new RecordVal(BifType::Record::NFS3::fattr_t);
attrs->Assign(0, nfs3_ftype(buf, n)); // file type
attrs->Assign(1, ExtractUint32(buf, n)); // mode
attrs->Assign(2, ExtractUint32(buf, n)); // nlink
@ -317,7 +335,7 @@ RecordVal* NFS_Interp::nfs3_fattr(const u_char*& buf, int& n)
return attrs;
}
EnumVal* NFS_Interp::nfs3_ftype(const u_char*& buf, int& n)
EnumVal* NFS_Interp::nfs3_ftype(const u_char*& buf, int& n)
{
BifEnum::NFS3::file_type_t t = (BifEnum::NFS3::file_type_t)extract_XDR_uint32(buf, n);
return new EnumVal(t, BifType::Enum::NFS3::file_type_t);
@ -326,6 +344,7 @@ EnumVal* NFS_Interp::nfs3_ftype(const u_char*& buf, int& n)
RecordVal* NFS_Interp::nfs3_wcc_attr(const u_char*& buf, int& n)
{
RecordVal* attrs = new RecordVal(BifType::Record::NFS3::wcc_attr_t);
attrs->Assign(0, ExtractUint64(buf, n)); // size
attrs->Assign(1, ExtractTime(buf, n)); // mtime
attrs->Assign(2, ExtractTime(buf, n)); // ctime
@ -333,18 +352,21 @@ RecordVal* NFS_Interp::nfs3_wcc_attr(const u_char*& buf, int& n)
return attrs;
}
StringVal *NFS_Interp::nfs3_filename(const u_char*& buf, int& n)
StringVal *NFS_Interp::nfs3_filename(const u_char*& buf, int& n)
{
int name_len;
const u_char* name = extract_XDR_opaque(buf, n, name_len);
if ( !name )
if ( ! name )
return 0;
return new StringVal(new BroString(name, name_len, 0));
}
RecordVal *NFS_Interp::nfs3_diropargs(const u_char*& buf, int& n)
{
RecordVal *diropargs = new RecordVal(BifType::Record::NFS3::diropargs_t);
diropargs->Assign(0, nfs3_fh(buf, n));
diropargs->Assign(1, nfs3_filename(buf, n));
@ -358,6 +380,7 @@ RecordVal* NFS_Interp::nfs3_post_op_attr(const u_char*& buf, int& n)
if ( have_attrs )
return nfs3_fattr(buf, n);
return 0;
}
@ -367,6 +390,7 @@ StringVal* NFS_Interp::nfs3_post_op_fh(const u_char*& buf, int& n)
if ( have_fh )
return nfs3_fh(buf, n);
return 0;
}
@ -379,7 +403,7 @@ RecordVal* NFS_Interp::nfs3_pre_op_attr(const u_char*& buf, int& n)
return 0;
}
EnumVal *NFS_Interp::nfs3_stable_how(const u_char*& buf, int& n)
EnumVal *NFS_Interp::nfs3_stable_how(const u_char*& buf, int& n)
{
BifEnum::NFS3::stable_how_t stable = (BifEnum::NFS3::stable_how_t)extract_XDR_uint32(buf, n);
return new EnumVal(stable, BifType::Enum::NFS3::stable_how_t);
@ -388,7 +412,8 @@ EnumVal *NFS_Interp::nfs3_stable_how(const u_char*& buf, int& n)
RecordVal* NFS_Interp::nfs3_lookup_reply(const u_char*& buf, int& n, BifEnum::NFS3::status_t status)
{
RecordVal *rep = new RecordVal(BifType::Record::NFS3::lookup_reply_t);
if (status == BifEnum::NFS3::NFS3ERR_OK)
if ( status == BifEnum::NFS3::NFS3ERR_OK )
{
rep->Assign(0, nfs3_fh(buf,n));
rep->Assign(1, nfs3_post_op_attr(buf, n));
@ -406,16 +431,19 @@ RecordVal* NFS_Interp::nfs3_lookup_reply(const u_char*& buf, int& n, BifEnum::NF
RecordVal *NFS_Interp::nfs3_readargs(const u_char*& buf, int& n)
{
RecordVal *readargs = new RecordVal(BifType::Record::NFS3::readargs_t);
readargs->Assign(0, nfs3_fh(buf, n));
readargs->Assign(1, ExtractUint64(buf, n)); // offset
readargs->Assign(2, ExtractUint32(buf,n)); // size
readargs->Assign(2, ExtractUint32(buf,n)); // size
return readargs;
}
RecordVal* NFS_Interp::nfs3_read_reply(const u_char*& buf, int& n, BifEnum::NFS3::status_t status,
RecordVal* NFS_Interp::nfs3_read_reply(const u_char*& buf, int& n, BifEnum::NFS3::status_t status,
bro_uint_t offset)
{
RecordVal *rep = new RecordVal(BifType::Record::NFS3::read_reply_t);
if (status == BifEnum::NFS3::NFS3ERR_OK)
{
uint32_t bytes_read;
@ -430,12 +458,14 @@ RecordVal* NFS_Interp::nfs3_read_reply(const u_char*& buf, int& n, BifEnum::NFS3
{
rep->Assign(0, nfs3_post_op_attr(buf, n));
}
return rep;
}
RecordVal* NFS_Interp::nfs3_readlink_reply(const u_char*& buf, int& n, BifEnum::NFS3::status_t status)
{
RecordVal *rep = new RecordVal(BifType::Record::NFS3::readlink_reply_t);
if (status == BifEnum::NFS3::NFS3ERR_OK)
{
rep->Assign(0, nfs3_post_op_attr(buf, n));
@ -445,6 +475,7 @@ RecordVal* NFS_Interp::nfs3_readlink_reply(const u_char*& buf, int& n, BifEnum::
{
rep->Assign(0, nfs3_post_op_attr(buf, n));
}
return rep;
}
@ -453,40 +484,48 @@ RecordVal *NFS_Interp::nfs3_writeargs(const u_char*& buf, int& n)
uint32_t bytes;
uint64_t offset;
RecordVal *writeargs = new RecordVal(BifType::Record::NFS3::writeargs_t);
writeargs->Assign(0, nfs3_fh(buf, n));
offset = extract_XDR_uint64(buf, n);
bytes = extract_XDR_uint32(buf, n);
writeargs->Assign(0, nfs3_fh(buf, n));
writeargs->Assign(1, new Val(offset, TYPE_COUNT));
writeargs->Assign(2, new Val(bytes, TYPE_COUNT));
writeargs->Assign(3, nfs3_stable_how(buf, n));
writeargs->Assign(4, nfs3_file_data(buf, n, offset, bytes));
return writeargs;
}
RecordVal *NFS_Interp::nfs3_write_reply(const u_char*& buf, int& n, BifEnum::NFS3::status_t status)
{
RecordVal *rep = new RecordVal(BifType::Record::NFS3::write_reply_t);
if (status == BifEnum::NFS3::NFS3ERR_OK)
if ( status == BifEnum::NFS3::NFS3ERR_OK )
{
rep->Assign(0, nfs3_pre_op_attr(buf, n));
rep->Assign(1, nfs3_post_op_attr(buf, n));
rep->Assign(2, ExtractUint32(buf, n));
rep->Assign(3, nfs3_stable_how(buf, n));
rep->Assign(4, ExtractUint64(buf, n)); // Writeverf. While the RFC says that this
// should be a fixed length opaque, it specifies the lenght as 8 bytes, so we can
// also just as easily extract a uint64
// Writeverf. While the RFC says that this should be a fixed
// length opaque, it specifies the lenght as 8 bytes, so we
// can also just as easily extract a uint64.
rep->Assign(4, ExtractUint64(buf, n));
}
else
{
rep->Assign(0, nfs3_post_op_attr(buf, n));
rep->Assign(1, nfs3_pre_op_attr(buf, n));
}
return rep;
}
RecordVal* NFS_Interp::nfs3_newobj_reply(const u_char*& buf, int& n, BifEnum::NFS3::status_t status)
{
RecordVal *rep = new RecordVal(BifType::Record::NFS3::newobj_reply_t);
if (status == BifEnum::NFS3::NFS3ERR_OK)
{
int i = 0;
@ -503,28 +542,34 @@ RecordVal* NFS_Interp::nfs3_newobj_reply(const u_char*& buf, int& n, BifEnum::NF
rep->Assign(2, nfs3_pre_op_attr(buf, n));
rep->Assign(3, nfs3_post_op_attr(buf, n));
}
return rep;
}
RecordVal* NFS_Interp::nfs3_delobj_reply(const u_char*& buf, int& n)
{
RecordVal *rep = new RecordVal(BifType::Record::NFS3::delobj_reply_t);
// wcc_data
rep->Assign(0, nfs3_pre_op_attr(buf, n));
rep->Assign(1, nfs3_post_op_attr(buf, n));
return rep;
}
RecordVal* NFS_Interp::nfs3_readdirargs(bool isplus, const u_char*& buf, int&n)
RecordVal* NFS_Interp::nfs3_readdirargs(bool isplus, const u_char*& buf, int&n)
{
RecordVal *args = new RecordVal(BifType::Record::NFS3::readdirargs_t);
args->Assign(0, new Val(isplus, TYPE_BOOL));
args->Assign(1, nfs3_fh(buf, n));
args->Assign(2, ExtractUint64(buf,n)); // cookie
args->Assign(3, ExtractUint64(buf,n)); // cookieverf
args->Assign(4, ExtractUint32(buf,n)); // dircount
if (isplus)
args->Assign(2, ExtractUint64(buf,n)); // cookie
args->Assign(3, ExtractUint64(buf,n)); // cookieverf
args->Assign(4, ExtractUint32(buf,n)); // dircount
if ( isplus )
args->Assign(5, ExtractUint32(buf,n));
return args;
}
@ -534,29 +579,36 @@ RecordVal* NFS_Interp::nfs3_readdir_reply(bool isplus, const u_char*& buf,
RecordVal *rep = new RecordVal(BifType::Record::NFS3::readdir_reply_t);
rep->Assign(0, new Val(isplus, TYPE_BOOL));
if (status == BifEnum::NFS3::NFS3ERR_OK)
if ( status == BifEnum::NFS3::NFS3ERR_OK )
{
VectorVal *entries = new VectorVal(BifType::Vector::NFS3::direntry_vec_t);
unsigned pos;
VectorVal *entries = new VectorVal(BifType::Vector::NFS3::direntry_vec_t);
rep->Assign(1, nfs3_post_op_attr(buf,n)); // dir_attr
rep->Assign(2, ExtractUint64(buf,n)); // cookieverf
pos = 1;
while ( extract_XDR_uint32(buf,n) )
while ( extract_XDR_uint32(buf,n) )
{
RecordVal *entry = new RecordVal(BifType::Record::NFS3::direntry_t);
entry->Assign(0, ExtractUint64(buf,n)); // fileid
entry->Assign(0, ExtractUint64(buf,n)); // fileid
entry->Assign(1, nfs3_filename(buf,n)); // fname
entry->Assign(2, ExtractUint64(buf,n)); // cookie
if (isplus)
entry->Assign(2, ExtractUint64(buf,n)); // cookie
if ( isplus )
{
entry->Assign(3, nfs3_post_op_attr(buf,n));
entry->Assign(4, nfs3_post_op_fh(buf,n));
}
entries->Assign(pos, entry, 0);
pos++;
}
rep->Assign(3, entries);
rep->Assign(4, ExtractBool(buf,n)); // eof
rep->Assign(4, ExtractBool(buf,n)); // eof
}
else
{
@ -565,6 +617,9 @@ RecordVal* NFS_Interp::nfs3_readdir_reply(bool isplus, const u_char*& buf,
return rep;
}
return rep;
}
Val* NFS_Interp::ExtractUint32(const u_char*& buf, int& n)
{
return new Val(extract_XDR_uint32(buf, n), TYPE_COUNT);
@ -592,7 +647,7 @@ Val* NFS_Interp::ExtractBool(const u_char*& buf, int& n)
NFS_Analyzer::NFS_Analyzer(Connection* conn)
: RPC_Analyzer(AnalyzerTag::NFS, conn, new NFS_Interp(this))
: RPC_Analyzer(AnalyzerTag::NFS, conn, new NFS_Interp(this))
{
orig_rpc = resp_rpc = 0;
}

View file

@ -16,31 +16,35 @@ public:
protected:
int RPC_BuildCall(RPC_CallInfo* c, const u_char*& buf, int& n);
int RPC_BuildReply(RPC_CallInfo* c, BifEnum::rpc_status rpc_status,
const u_char*& buf, int& n, double start_time, double last_time,
const u_char*& buf, int& n, double start_time,
double last_time, int reply_len);
// Returns a new val_list that already has a conn_val, rpc_status and
// nfs_status. These are the first parameters for each nfs_* event
// ...
val_list* event_common_vl(RPC_CallInfo *c, BifEnum::rpc_status rpc_status,
BifEnum::NFS3::status_t nfs_status,
double rep_start_time, double rep_last_time,
int reply_len);
// returns a new val_list that already has a conn_val, rpc_status and nfs_status.
// These are the first parameters for each nfs_* event...
val_list* event_common_vl(RPC_CallInfo *c, BifEnum::rpc_status rpc_status,
BifEnum::NFS3::status_t nfs_status, double rep_start_time, double rep_last_time,
int reply_len);
// These methods parse the appropriate NFSv3 "type" out of buf. If
// there are any errors (i.e., buffer to short, etc), buf will be
// set to 0. However, the methods might still return an allocated
// Val * !
// So, you might want to Unref() the Val if buf is 0.
// Method names are based on the type names of RFC 1813
// These methods parse the appropriate NFSv3 "type" out of buf. If
// there are any errors (i.e., buffer to short, etc), buf will be set
// to 0. However, the methods might still return an allocated Val * !
// So, you might want to Unref() the Val if buf is 0. Method names
// are based on the type names of RFC 1813.
StringVal* nfs3_fh(const u_char*& buf, int& n);
RecordVal* nfs3_fattr(const u_char*& buf, int& n);
EnumVal* nfs3_ftype(const u_char*& buf, int& n);
RecordVal* nfs3_wcc_attr(const u_char*& buf, int& n);
RecordVal* nfs3_diropargs(const u_char*&buf, int &n);
StringVal* nfs3_filename(const u_char*& buf, int& n);
StringVal* nfs3_nfspath(const u_char*& buf, int& n) { return nfs3_filename(buf,n); }
RecordVal* nfs3_post_op_attr(const u_char*&buf, int &n); // Return 0 or an fattr
RecordVal* nfs3_pre_op_attr(const u_char*&buf, int &n); // Return 0 or an wcc_attr
StringVal* nfs3_nfspath(const u_char*& buf, int& n)
{
return nfs3_filename(buf,n);
}
RecordVal* nfs3_post_op_attr(const u_char*&buf, int &n); // Return 0 or an fattr
RecordVal* nfs3_pre_op_attr(const u_char*&buf, int &n); // Return 0 or an wcc_attr
RecordVal* nfs3_lookup_reply(const u_char*& buf, int& n, BifEnum::NFS3::status_t status);
RecordVal* nfs3_readargs(const u_char*& buf, int& n);
RecordVal* nfs3_read_reply(const u_char*& buf, int& n, BifEnum::NFS3::status_t status, bro_uint_t offset);
@ -53,14 +57,13 @@ protected:
StringVal* nfs3_post_op_fh(const u_char*& buf, int& n);
RecordVal* nfs3_readdirargs(bool isplus, const u_char*& buf, int&n);
RecordVal* nfs3_readdir_reply(bool isplus, const u_char*& buf, int&n, BifEnum::NFS3::status_t status);
// consumes the file data in the RPC message. Depending on NFS::return_data* consts
// in bro.init returns NULL or the data as string val
// Consumes the file data in the RPC message. Depending on NFS::return_data* consts
// in bro.init returns NULL or the data as string val:
// * offset is the offset of the read/write call
// * size is the amount of bytes read (or requested to be written),
StringVal* nfs3_file_data(const u_char*& buf, int& n, uint64_t offset, int size);
RecordVal* ExtractOptAttrs(const u_char*& buf, int& n);
Val* ExtractUint32(const u_char*& buf, int& n);
Val* ExtractUint64(const u_char*& buf, int& n);
@ -77,50 +80,18 @@ public:
static Analyzer* InstantiateAnalyzer(Connection* conn)
{ return new NFS_Analyzer(conn); }
//static bool Available() { return nfs_request_getattr || rpc_call; }
static bool Available() { return true; }
};
#if 0
namespace nfs3_types {
#define NFS3_MAX_FHSIZE 64
class nfs3_type {
public:
//nfs3_type(const u_char*&buf, int& len) = 0;
virtual ~nfs3_type()
{
}
virtual Val *GetVal() = 0;
bool IsValid() { return valid; };
bool valid;
};
// A file handle
class nfs3_fh : public nfs3_type {
public:
nfs3_fh(const u_char*&buf, int& len) {
const u_char *fh_tmp;
int fh_len;
valid = false;
fh_tmp = extract_XDR_opaque(buf,len,fh_len,NFS3_MAX_FHSIZE);
if (fh_tmp) {
fh = new StringVal(new BroString(fh, fh_len, 0));
valid = true;
}
else
fh = 0;
static bool Available()
{
return ( nfs_proc_null || nfs_proc_not_implemented || nfs_proc_getattr ||
nfs_proc_lookup || nfs_proc_read || nfs_proc_readlink ||
nfs_proc_write || nfs_proc_create || nfs_proc_mkdir ||
nfs_proc_remove || nfs_proc_rmdir || nfs_proc_readdir ||
nfs_reply_status ||
rpc_dialogue || rpc_call || rpc_reply );
}
~nfs3_fh() { printf("~nfs3_fh\n"); }
Val *GetVal() { return fh; }
// Data
StringVal *fh;
}; // nfs3_fh
};
#endif
#endif

View file

@ -18,6 +18,7 @@ RecordType* pcap_packet;
RecordType* signature_state;
EnumType* transport_proto;
TableType* string_set;
TableType* count_set;
RecordType* net_stats;
@ -195,8 +196,6 @@ StringVal* ssl_private_key;
StringVal* ssl_passphrase;
StringVal* x509_crl_file;
TableType* x509_extension;
TableType* SSL_sessionID;
Val* profiling_file;
double profiling_interval;
@ -367,10 +366,7 @@ void init_net_var()
x509_trusted_cert_path = opt_internal_string("X509_trusted_cert_path");
ssl_store_cert_path = opt_internal_string("ssl_store_cert_path");
x509_type = internal_type("X509")->AsRecordType();
cipher_suites_list = internal_type("cipher_suites_list")->AsTableType();
x509_crl_file = opt_internal_string("X509_crl_file");
x509_extension = internal_type("X509_extension")->AsTableType();
SSL_sessionID = internal_type("SSL_sessionID")->AsTableType();
non_analyzed_lifetime = opt_internal_double("non_analyzed_lifetime");
tcp_inactivity_timeout = opt_internal_double("tcp_inactivity_timeout");

View file

@ -21,6 +21,7 @@ extern RecordType* SYN_packet;
extern RecordType* pcap_packet;
extern EnumType* transport_proto;
extern TableType* string_set;
extern TableType* count_set;
extern RecordType* net_stats;
@ -61,11 +62,8 @@ extern int ssl_store_key_material;
extern int ssl_max_cipherspec_size;
extern StringVal* ssl_store_cert_path;
extern StringVal* x509_trusted_cert_path;
extern TableType* cipher_suites_list;
extern RecordType* x509_type;
extern StringVal* x509_crl_file;
extern TableType* x509_extension;
extern TableType* SSL_sessionID;
extern double non_analyzed_lifetime;
extern double tcp_inactivity_timeout;

View file

@ -295,7 +295,7 @@ void OSFingerprint::load_config(const char* file)
uint32 ln=0;
char buf[MAXLINE];
char* p;
FILE* c = search_for_file( file, "osf", 0);
FILE* c = search_for_file( file, "osf", 0, false);
if (!c)
{

View file

@ -576,9 +576,11 @@ void POP3_Analyzer::ProcessReply(int length, const char* line)
if ( multiLine == true )
{
bool terminator =
length > 1 && line[0] == '.' &&
(line[1] == '\n' ||
(length > 2 && line[1] == '\r' && line[2] == '\n'));
line[0] == '.' &&
(length == 1 ||
(length > 1 &&
(line[1] == '\n' ||
(length > 2 && line[1] == '\r' && line[2] == '\n'))));
if ( terminator )
{

View file

@ -72,12 +72,13 @@ int PortmapperInterp::RPC_BuildCall(RPC_CallInfo* c, const u_char*& buf, int& n)
}
int PortmapperInterp::RPC_BuildReply(RPC_CallInfo* c, BifEnum::rpc_status status,
const u_char*& buf, int& n, double start_time, double last_time,
int reply_len)
const u_char*& buf, int& n,
double start_time, double last_time,
int reply_len)
{
EventHandlerPtr event;
Val *reply = 0;
int success = status == BifEnum::RPC_SUCCESS;
int success = (status == BifEnum::RPC_SUCCESS);
switch ( c->Proc() ) {
@ -283,6 +284,7 @@ void PortmapperInterp::Event(EventHandlerPtr f, Val* request, BifEnum::rpc_statu
val_list* vl = new val_list;
vl->append(analyzer->BuildConnVal());
if ( status == BifEnum::RPC_SUCCESS )
{
if ( request )

View file

@ -14,8 +14,8 @@ public:
protected:
int RPC_BuildCall(RPC_CallInfo* c, const u_char*& buf, int& n);
int RPC_BuildReply(RPC_CallInfo* c, BifEnum::rpc_status success,
const u_char*& buf, int& n, double start_time, double last_time,
int reply_len);
const u_char*& buf, int& n, double start_time,
double last_time, int reply_len);
uint32 CheckPort(uint32 port);
void Event(EventHandlerPtr f, Val* request, BifEnum::rpc_status status, Val* reply);

View file

@ -2,10 +2,12 @@
//
// See the file "COPYING" in the main distribution directory for copyright.
#include "config.h"
#include <stdlib.h>
#include <algorithm>
#include "config.h"
#include "NetVar.h"
#include "XDR.h"
#include "RPC.h"
@ -83,11 +85,12 @@ RPC_Interpreter::~RPC_Interpreter()
{
}
int RPC_Interpreter::DeliverRPC(const u_char* buf, int n, int rpclen, int is_orig, double start_time, double last_time)
int RPC_Interpreter::DeliverRPC(const u_char* buf, int n, int rpclen,
int is_orig, double start_time, double last_time)
{
uint32 xid = extract_XDR_uint32(buf, n);
uint32 msg_type = extract_XDR_uint32(buf, n);
int rpc_len = n;
int rpc_len = n;
if ( ! buf )
return 0;
@ -107,9 +110,14 @@ int RPC_Interpreter::DeliverRPC(const u_char* buf, int n, int rpclen, int is_ori
call->SetStartTime(start_time);
call->SetLastTime(last_time);
// TODO: Should we update start_time and last_time or
// not??
call->SetStartTime(start_time);
call->SetLastTime(last_time);
// TODO: Not sure whether the handling if rexmit
// inconsistencies are correct. Maybe we should use the info in the new
// call for further processing.
// inconsistencies are correct. Maybe we should use
// the info in the new call for further processing.
if ( call->HeaderLen() > n )
{
Weird("RPC_underflow");
@ -137,6 +145,11 @@ int RPC_Interpreter::DeliverRPC(const u_char* buf, int n, int rpclen, int is_ori
// TODO: What to do in case of a rexmit_inconistency??
Event_RPC_Call(call);
// We now have a valid RPC_CallInfo (either the previous one
// in case of a rexmit or the current one).
// TODO: What to do in case of a rexmit_inconistency??
Event_RPC_Call(call);
if ( RPC_BuildCall(call, buf, n) )
call->SetValidCall();
else
@ -217,10 +230,9 @@ int RPC_Interpreter::DeliverRPC(const u_char* buf, int n, int rpclen, int is_ori
else
Weird("bad_RPC");
// We now have extracted the status we want to use.
// We now have extracted the status we want to use.
Event_RPC_Reply(xid, status, n);
if ( call )
{
if ( ! call->IsValidCall() )
@ -277,10 +289,12 @@ void RPC_Interpreter::Timeout()
while ( (c = calls.NextEntry(cookie)) )
{
Event_RPC_Dialogue(c, BifEnum::RPC_TIMEOUT, 0);
if ( c->IsValidCall() )
{
const u_char* buf;
int n = 0;
if ( ! RPC_BuildReply(c, BifEnum::RPC_TIMEOUT, buf, n, network_time, network_time, 0) )
Weird("bad_RPC");
}
@ -339,7 +353,7 @@ void RPC_Interpreter::Weird(const char* msg)
void RPC_Reasm_Buffer::Init(int64_t arg_maxsize, int64_t arg_expected) {
if (buf)
if ( buf )
delete [] buf;
expected = arg_expected;
maxsize = arg_maxsize;
@ -347,23 +361,25 @@ void RPC_Reasm_Buffer::Init(int64_t arg_maxsize, int64_t arg_expected) {
buf = new u_char[maxsize];
};
bool RPC_Reasm_Buffer::ConsumeChunk(const u_char*& data, int& len)
bool RPC_Reasm_Buffer::ConsumeChunk(const u_char*& data, int& len)
{
// How many bytes to we want to process with this call?
// Either the all of the bytes available or the number of bytes
// that we are still missing
int64_t to_process = min( int64_t(len), (expected-processed) );
// How many bytes do we want to process with this call? Either the
// all of the bytes available or the number of bytes that we are
// still missing.
int64_t to_process = min(int64_t(len), (expected-processed));
if (fill < maxsize)
if ( fill < maxsize )
{
// We haven't yet filled the buffer.
// How many bytes to copy into the buff. Either all of the bytes
// we want to process or the number of bytes until we reach maxsize
int64_t to_copy = min( to_process, (maxsize-fill) );
if (to_copy)
// We haven't yet filled the buffer. How many bytes to copy
// into the buff. Either all of the bytes we want to process
// or the number of bytes until we reach maxsize.
int64_t to_copy = min( to_process, (maxsize-fill) );
if ( to_copy )
memcpy(buf+fill, data, to_copy);
fill += to_copy;
}
processed += to_process;
len -= to_process;
data += to_process;
@ -372,7 +388,7 @@ bool RPC_Reasm_Buffer::ConsumeChunk(const u_char*& data, int& len)
Contents_RPC::Contents_RPC(Connection* conn, bool orig,
RPC_Interpreter* arg_interp)
: TCP_SupportAnalyzer(AnalyzerTag::Contents_RPC, conn, orig)
: TCP_SupportAnalyzer(AnalyzerTag::Contents_RPC, conn, orig)
{
interp = arg_interp;
state = WAIT_FOR_MESSAGE;
@ -387,7 +403,6 @@ void Contents_RPC::Init()
TCP_SupportAnalyzer::Init();
}
Contents_RPC::~Contents_RPC()
{
}
@ -407,7 +422,7 @@ bool Contents_RPC::CheckResync(int& len, const u_char*& data, bool orig)
bool discard_this_chunk = false;
if (resync_state == RESYNC_INIT)
if ( resync_state == RESYNC_INIT )
{
// First time CheckResync is called. If the TCP endpoint
// is fully established we are in sync (since it's the first chunk
@ -417,8 +432,8 @@ bool Contents_RPC::CheckResync(int& len, const u_char*& data, bool orig)
static_cast<TCP_ApplicationAnalyzer*>(Parent())->TCP();
assert(tcp);
if ((IsOrig() ? tcp->OrigState() : tcp->RespState()) !=
TCP_ENDPOINT_ESTABLISHED)
if ( (IsOrig() ? tcp->OrigState() : tcp->RespState()) !=
TCP_ENDPOINT_ESTABLISHED )
{
NeedResync();
}
@ -426,41 +441,41 @@ bool Contents_RPC::CheckResync(int& len, const u_char*& data, bool orig)
resync_state = INSYNC;
}
if (resync_state == INSYNC)
if ( resync_state == INSYNC )
return true;
// This is an attempt to re-synchronize the stream with RPC
// frames after a content gap.
// Returns true if we are in sync.
// Returns false otherwise (we are in resync mode)
// This is an attempt to re-synchronize the stream with RPC frames
// after a content gap. Returns true if we are in sync. Returns
// false otherwise (we are in resync mode)
//
// We try to look for the beginning of a RPC frame, assuming
// RPC frames begin at packet boundaries (though they may span
// over multiple packets) (note that the data* of DeliverStream()
// usually starts at a packet boundrary).
// We try to look for the beginning of a RPC frame, assuming RPC
// frames begin at packet boundaries (though they may span over
// multiple packets) (note that the data* of DeliverStream() usually
// starts at a packet boundrary).
//
// If we see a frame start that makes sense (direction and
// frame lenght seem ok), we try to read (skip over) the next RPC
// message. If this is successfull and we the place we are seems
// like a valid start of a RPC msg (direction and frame length
// seem ok). We assume that we have successfully resync'ed.
// If we see a frame start that makes sense (direction and frame
// lenght seem ok), we try to read (skip over) the next RPC message.
// If this is successfull and we the place we are seems like a valid
// start of a RPC msg (direction and frame length seem ok). We assume
// that we have successfully resync'ed.
// Assuming RPC frames align with packet boundaries ...
while (len > 0)
{
if (resync_toskip)
if ( resync_toskip )
{
if ( DEBUG_rpc_resync )
DEBUG_MSG("RPC resync: skipping %d bytes.\n", len);
// We have some bytes to skip over.
if (resync_toskip < len)
// We have some bytes to skip over.
if ( resync_toskip < len )
{
len -= resync_toskip;
data += resync_toskip;
resync_toskip = 0;
}
else
else
{
resync_toskip -= len;
data += len;
@ -469,22 +484,18 @@ bool Contents_RPC::CheckResync(int& len, const u_char*& data, bool orig)
}
}
if (resync_toskip != 0)
{
// Should never happen
if ( resync_toskip != 0 )
// Should never happen.
internal_error("RPC resync: skipping over data failed");
NeedResync();
return false;
}
// Now lets see whether data points to the beginning of a
// RPC frame. If the resync processs is successful, we should
// be at the beginning of a frame.
// Now lets see whether data points to the beginning of a RPC
// frame. If the resync processs is successful, we should be
// at the beginning of a frame.
if ( len < 12 )
{
// Ignore small chunks.
// Ignore small chunks.
if ( len != 1 && DEBUG_rpc_resync )
{
// One-byte fragments are likely caused by
@ -496,6 +507,7 @@ bool Contents_RPC::CheckResync(int& len, const u_char*& data, bool orig)
fmt("RPC resync: discard %d bytes\n",
len));
}
NeedResync();
return false;
}
@ -517,22 +529,23 @@ bool Contents_RPC::CheckResync(int& len, const u_char*& data, bool orig)
discard_this_chunk = true;
// Make sure the frame isn't too long.
// TODO: Could possible even reduce this number even further.
if (frame_len > MAX_RPC_LEN)
// Make sure the frame isn't too long.
// TODO: Could possible even reduce this number even further.
if ( frame_len > MAX_RPC_LEN )
discard_this_chunk = true;
if (discard_this_chunk)
if ( discard_this_chunk )
{
// Skip this chunk
if ( DEBUG_rpc_resync )
DEBUG_MSG("RPC resync: Need to resync. dicarding %d bytes.\n", len);
NeedResync(); // let's try the resync again from the beginning
return false;
}
// Looks like we are at the start of a frame and have successfully
// extracted the frame length (marker).
// Looks like we are at the start of a frame and have successfully
// extracted the frame length (marker).
switch (resync_state) {
case NEED_RESYNC:
@ -540,30 +553,33 @@ bool Contents_RPC::CheckResync(int& len, const u_char*& data, bool orig)
// Initial phase of resyncing. Skip frames until we get a frame
// with the last_fragment bit set.
resync_toskip = frame_len + 4;
if (last_frag)
if ( last_frag )
resync_state = RESYNC_WAIT_FOR_FULL_MSG;
else
else
resync_state = RESYNC_WAIT_FOR_MSG_START;
break;
case RESYNC_WAIT_FOR_FULL_MSG:
// If the resync was successful so far, we should now be the start
// If the resync was successful so far, we should now be the start
// of a new RPC message. Try to skip over it.
resync_toskip = frame_len + 4;
if (last_frag)
if ( last_frag )
resync_state = RESYNC_HAD_FULL_MSG;
break;
case RESYNC_HAD_FULL_MSG:
// We have now successfully skipped over a full RPC message.
// If we got that far, we are in sync.
// We have now successfully skipped over a full RPC message.
// If we got that far, we are in sync.
resync_state = INSYNC;
if ( DEBUG_rpc_resync )
DEBUG_MSG("RPC resync: success.\n");
return true;
default:
// Shoult never happen
// Should never happen.
NeedResync();
return false;
} // end switch
@ -571,7 +587,7 @@ bool Contents_RPC::CheckResync(int& len, const u_char*& data, bool orig)
return false;
}
@ -581,41 +597,45 @@ void Contents_RPC::DeliverStream(int len, const u_char* data, bool orig)
uint32 marker;
bool last_frag;
if (!CheckResync(len, data, orig))
return; // Not in sync yet. Still resyncing
if ( ! CheckResync(len, data, orig) )
return; // Not in sync yet. Still resyncing.
// Should be in sync now.
// Should be in sync now
while (len > 0)
while (len > 0)
{
last_time = network_time;
switch (state) {
case WAIT_FOR_MESSAGE:
// A new RPC message is starting. Initialize state
// We expect and want 4 bytes of the frame markers
switch (state) {
case WAIT_FOR_MESSAGE:
// A new RPC message is starting. Initialize state.
// We expect and want 4 bytes of the frame markers.
marker_buf.Init(4,4);
// We want at most 64KB of message data and we don't know
// yet how much we expect, so we set expected to 0
// We want at most 64KB of message data and we don't
// know yet how much we expect, so we set expected to
// 0.
msg_buf.Init(MAX_RPC_LEN, 0);
last_frag = 0;
state = WAIT_FOR_MARKER;
start_time = network_time;
// no break. fall through
case WAIT_FOR_MARKER:
{
bool got_marker = marker_buf.ConsumeChunk(data,len);
if (got_marker)
if ( got_marker )
{
const u_char *dummy_p = marker_buf.GetBuf();
int dummy_len = (int) marker_buf.GetFill();
// have full marker
marker = extract_XDR_uint32(dummy_p, dummy_len);
marker_buf.Init(4,4);
if ( ! dummy_p )
if ( ! dummy_p )
{
internal_error("inconsistent RPC record marker extraction");
}
@ -624,41 +644,49 @@ void Contents_RPC::DeliverStream(int len, const u_char* data, bool orig)
marker &= 0x7fffffff;
//printf("%.6f %d marker= %u <> last_frag= %d <> expected=%llu <> processed= %llu <> len = %d\n",
// network_time, IsOrig(), marker, last_frag, msg_buf.GetExpected(), msg_buf.GetProcessed(), len);
if (!msg_buf.AddToExpected(marker))
if ( ! msg_buf.AddToExpected(marker) )
Conn()->Weird(fmt("RPC_message_too_long (%" PRId64 ")" , msg_buf.GetExpected()));
if (last_frag)
if ( last_frag )
state = WAIT_FOR_LAST_DATA;
else
state = WAIT_FOR_DATA;
}
}
// else remain in state. Haven't got the full 4 bytes for the marker yet
// Else remain in state. Haven't got the full 4 bytes
// for the marker yet.
break;
case WAIT_FOR_DATA:
case WAIT_FOR_LAST_DATA:
{
bool got_all_data = msg_buf.ConsumeChunk(data, len);
if (got_all_data)
if ( got_all_data )
{
// got all the data we expected. Now let's see whether there is
// another fragment coming or whether we just finished the last
// fragment.
if (state == WAIT_FOR_LAST_DATA)
// Got all the data we expected. Now let's
// see whether there is another fragment
// coming or whether we just finished the
// last fragment.
if ( state == WAIT_FOR_LAST_DATA )
{
const u_char *dummy_p = msg_buf.GetBuf();
int dummy_len = (int) msg_buf.GetFill();
if ( ! interp->DeliverRPC(dummy_p, dummy_len, (int)msg_buf.GetExpected(), IsOrig(), start_time, last_time) )
Conn()->Weird("partial_RPC");
state = WAIT_FOR_MESSAGE;
}
else
state = WAIT_FOR_MARKER;
}
// else remain in state. Haven't read all the data yet.
// Else remain in state. Haven't read all the data
// yet.
}
break;
} // end switch
} // end switch
} // end while
}
@ -701,29 +729,6 @@ void RPC_Analyzer::Done()
TCP_ApplicationAnalyzer::Done();
interp->Timeout();
#if 0
TODO: maybe put this check back in. But there are so many other
things the RPC analyzer might miss....
// This code was replicated in NFS.cc and Portmap.cc, so we factor
// it into here. The semantics have slightly changed - it used
// to be we'd always execute interp->Timeout(), but now we only
// do for UDP.
if ( Conn()->ConnTransport() == TRANSPORT_TCP && TCP() )
{
if ( orig_rpc->State() != RPC_COMPLETE &&
(TCP()->OrigState() == TCP_ENDPOINT_CLOSED ||
TCP()->OrigPrevState() == TCP_ENDPOINT_CLOSED) &&
// Sometimes things like tcpwrappers will immediately
// close the connection, without any data having been
// transferred. Don't bother flagging these.
TCP()->Orig()->Size() > 0 )
Weird("partial_RPC_request");
}
else
interp->Timeout();
#endif
}
void RPC_Analyzer::ExpireTimer(double /* t */)
@ -731,4 +736,3 @@ void RPC_Analyzer::ExpireTimer(double /* t */)
Event(connection_timeout);
sessions->Remove(Conn());
}

View file

@ -49,7 +49,8 @@ enum {
class RPC_CallInfo {
public:
RPC_CallInfo(uint32 xid, const u_char*& buf, int& n, double start_time, double last_time, int rpc_len);
RPC_CallInfo(uint32 xid, const u_char*& buf, int& n, double start_time,
double last_time, int rpc_len);
~RPC_CallInfo();
void AddVal(Val* arg_v) { Unref(v); v = arg_v; }
@ -63,11 +64,11 @@ public:
uint32 Proc() const { return proc; }
double StartTime() const { return start_time; }
void SetStartTime(double t) { start_time = t; }
void SetStartTime(double t) { start_time = t; }
double LastTime() const { return last_time; }
void SetLastTime(double t) { last_time = t; }
void SetLastTime(double t) { last_time = t; }
int CallLen() const { return call_n; }
int RPCLen() const { return rpc_len; }
int RPCLen() const { return rpc_len; }
int HeaderLen() const { return header_len; }
uint32 XID() const { return xid; }
@ -81,7 +82,7 @@ protected:
u_char* call_buf; // copy of original call buffer
double start_time;
double last_time;
int rpc_len; // size of the full RPC call, incl. xid and msg_type
int rpc_len; // size of the full RPC call, incl. xid and msg_type
int call_n; // size of call buf
int header_len; // size of data before the arguments
bool valid_call; // whether call was well-formed
@ -106,8 +107,8 @@ public:
protected:
virtual int RPC_BuildCall(RPC_CallInfo* c, const u_char*& buf, int& n) = 0;
virtual int RPC_BuildReply(RPC_CallInfo* c, BifEnum::rpc_status success,
const u_char*& buf, int& n, double start_time, double last_time,
int reply_len) = 0;
const u_char*& buf, int& n, double start_time, double last_time,
int reply_len) = 0;
void Event_RPC_Dialogue(RPC_CallInfo* c, BifEnum::rpc_status status, int reply_len);
void Event_RPC_Call(RPC_CallInfo* c);
@ -121,22 +122,22 @@ protected:
/* A simple buffer for reassembling the fragments that RPC-over-TCP
* uses. Only needed by RPC_Contents
* uses. Only needed by RPC_Contents.
* However, RPC messages can be quite large. As a first step, we only
* extract and analyzer the first part of an RPC message and skip
* extract and analyzer the first part of an RPC message and skip
* over the rest.
*
* We specify:
* maxsize ... the number of bytes we want to copy into the buffer
* to analyze.
* expected .. the total number of bytes in the RPC message. Can be
* quite large. We will be "skipping over" expected-maxsize bytes.
* maxsize: the number of bytes we want to copy into the buffer to analyze.
* expected: the total number of bytes in the RPC message. Can be
* quite large. We will be "skipping over" expected-maxsize bytes.
*
* We can extend "expected" (by calling AddToExpected()), but maxsize is
* fixed.
* fixed.
*
* TODO: grow buffer dynamically
*/
*/
class RPC_Reasm_Buffer {
public:
RPC_Reasm_Buffer() {
@ -149,33 +150,34 @@ public:
void Init(int64_t arg_maxsize, int64_t arg_expected);
const u_char *GetBuf() { return buf; } // Pointer to the buffer
int64_t GetFill() { return fill; } // Number of bytes in buf
int64_t GetSkipped() { return processed-fill; } // How many bytes did we skipped?
int64_t GetExpected() { return expected; } // How many bytes are we expecting?
int64_t GetProcessed() { return processed; } // How many bytes are we expecting?
const u_char *GetBuf() { return buf; } // Pointer to the buffer
int64_t GetFill() { return fill; } // Number of bytes in buf
int64_t GetSkipped() { return processed-fill; } // How many bytes did we skipped?
int64_t GetExpected() { return expected; } // How many bytes are we expecting?
int64_t GetProcessed() { return processed; } // How many bytes are we expecting?
// Expand expected by delta bytes.
// Returns false if the number of expected bytes exceeds maxsize
// (which means that we will truncate the message).
bool AddToExpected(int64_t delta) { expected += delta; return !(expected>maxsize); }
// Expand expected by delta bytes. Returns false if the number of
// expected bytes exceeds maxsize (which means that we will truncate
// the message).
bool AddToExpected(int64_t delta)
{ expected += delta; return ! (expected > maxsize); }
// Consume a chunk of input data (pointed to by data, up len in size).
// data and len will be adjustes accordingly.
// Returns true if "exptected" bytes have been processed, i.e., returns
// true when we don't expect any more data.
// Consume a chunk of input data (pointed to by data, up len in
// size). data and len will be adjusted accordingly. Returns true if
// "expected" bytes have been processed, i.e., returns true when we
// don't expect any more data.
bool ConsumeChunk(const u_char*& data, int& len);
protected:
int64_t fill; // how many bytes we currently have in the buffer
int64_t maxsize; // maximum buffer size we want to allocate
int64_t processed; // number of bytes we have processed so far
int64_t expected; // number of input bytes we expect
int64_t fill; // how many bytes we currently have in the buffer
int64_t maxsize; // maximum buffer size we want to allocate
int64_t processed; // number of bytes we have processed so far
int64_t expected; // number of input bytes we expect
u_char *buf;
};
/* Support Analyzer for reassembling RPC-over-TCP messages */
/* Support Analyzer for reassembling RPC-over-TCP messages */
class Contents_RPC : public TCP_SupportAnalyzer {
public:
Contents_RPC(Connection* conn, bool orig, RPC_Interpreter* interp);
@ -188,6 +190,7 @@ protected:
WAIT_FOR_DATA,
WAIT_FOR_LAST_DATA,
} state_t;
typedef enum {
NEED_RESYNC,
RESYNC_WAIT_FOR_MSG_START,
@ -196,6 +199,7 @@ protected:
INSYNC,
RESYNC_INIT,
} resync_state_t;
virtual void Init();
virtual bool CheckResync(int& len, const u_char*& data, bool orig);
virtual void DeliverStream(int len, const u_char* data, bool orig);
@ -209,8 +213,8 @@ protected:
RPC_Interpreter* interp;
RPC_Reasm_Buffer marker_buf; // Reassembles the 32bit RPC-over-TCP marker
RPC_Reasm_Buffer msg_buf; // Reassembles RPC messages
RPC_Reasm_Buffer marker_buf; // reassembles the 32bit RPC-over-TCP marker
RPC_Reasm_Buffer msg_buf; // reassembles RPC messages
state_t state;
double start_time;
@ -240,5 +244,4 @@ protected:
Contents_RPC* resp_rpc;
};
#endif

View file

@ -2,6 +2,8 @@
//
// See the file "COPYING" in the main distribution directory for copyright.
#include <algorithm>
#include "config.h"
#include "Reassem.h"

View file

@ -1,5 +1,7 @@
// $Id: RuleMatcher.cc 6724 2009-06-07 09:23:03Z vern $
#include <algorithm>
#include "config.h"
#include "Analyzer.h"
@ -197,7 +199,7 @@ bool RuleMatcher::ReadFiles(const name_list& files)
for ( int i = 0; i < files.length(); ++i )
{
rules_in = search_for_file( files[i], "sig", 0);
rules_in = search_for_file( files[i], "sig", 0, false);
if ( ! rules_in )
{
error("Can't open signature file", files[i]);

View file

@ -1,5 +1,3 @@
// $Id:$
#include "SSL-binpac.h"
#include "TCP_Reassembler.h"
#include "util.h"
@ -8,13 +6,10 @@
bool SSL_Analyzer_binpac::warnings_generated = false;
SSL_Analyzer_binpac::SSL_Analyzer_binpac(Connection* c)
: TCP_ApplicationAnalyzer(AnalyzerTag::SSL_BINPAC, c)
: TCP_ApplicationAnalyzer(AnalyzerTag::SSL, c)
{
ssl = new binpac::SSL::SSLAnalyzer;
ssl->set_bro_analyzer(this);
records = new binpac::SSLRecordLayer::SSLRecordLayerAnalyzer;
records->set_ssl_analyzer(ssl);
interp = new binpac::SSL::SSLAnalyzer;
interp->set_bro_analyzer(this);
if ( ! warnings_generated )
generate_warnings();
@ -22,23 +17,21 @@ SSL_Analyzer_binpac::SSL_Analyzer_binpac(Connection* c)
SSL_Analyzer_binpac::~SSL_Analyzer_binpac()
{
delete records;
delete ssl;
delete interp;
}
void SSL_Analyzer_binpac::Done()
{
TCP_ApplicationAnalyzer::Done();
records->FlowEOF(true);
records->FlowEOF(false);
interp->FlowEOF(true);
interp->FlowEOF(false);
}
void SSL_Analyzer_binpac::EndpointEOF(TCP_Reassembler* endp)
{
TCP_ApplicationAnalyzer::EndpointEOF(endp);
records->FlowEOF(endp->IsOrig());
ssl->FlowEOF(endp->IsOrig());
interp->FlowEOF(endp->IsOrig());
}
void SSL_Analyzer_binpac::DeliverStream(int len, const u_char* data, bool orig)
@ -50,13 +43,13 @@ void SSL_Analyzer_binpac::DeliverStream(int len, const u_char* data, bool orig)
if ( TCP()->IsPartial() )
return;
records->NewData(orig, data, data + len);
interp->NewData(orig, data, data + len);
}
void SSL_Analyzer_binpac::Undelivered(int seq, int len, bool orig)
{
TCP_ApplicationAnalyzer::Undelivered(seq, len, orig);
records->NewGap(orig, len);
interp->NewGap(orig, len);
}
void SSL_Analyzer_binpac::warn_(const char* msg)

View file

@ -1,12 +1,9 @@
// $Id:$
#ifndef ssl_binpac_h
#define ssl_binpac_h
#include "TCP.h"
#include "ssl_pac.h"
#include "ssl-record-layer_pac.h"
class SSL_Analyzer_binpac : public TCP_ApplicationAnalyzer {
public:
@ -23,11 +20,9 @@ public:
static bool Available()
{
return FLAGS_use_binpac &&
(ssl_certificate_seen || ssl_certificate ||
ssl_conn_attempt || ssl_conn_server_reply ||
ssl_conn_established || ssl_conn_reused ||
ssl_conn_alert);
return ( ssl_client_hello || ssl_server_hello ||
ssl_established || ssl_extension || ssl_alert ||
x509_certificate || x509_extension || x509_error );
}
static bool warnings_generated;
@ -35,8 +30,7 @@ public:
static void generate_warnings();
protected:
binpac::SSLRecordLayer::SSLRecordLayerAnalyzer* records;
binpac::SSL::SSLAnalyzer* ssl;
binpac::SSL::SSLAnalyzer* interp;
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,367 +0,0 @@
// $Id: SSLCiphers.h 1678 2005-11-08 19:16:37Z vern $
#ifndef SSL_CIPHERS_H
#define SSL_CIPHERS_H
#include "Dict.h"
// --- definitions for sslv3x cipher handling ---------------------------------
/*!
* In SSLv2, a cipher spec consists of three bytes.
*/
enum SSLv2_CipherSpec {
// --- standard SSLv2 ciphers
SSL_CK_RC4_128_WITH_MD5 = 0x010080,
SSL_CK_RC4_128_EXPORT40_WITH_MD5 = 0x020080,
SSL_CK_RC2_128_CBC_WITH_MD5 = 0x030080,
SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5 = 0x040080,
SSL_CK_IDEA_128_CBC_WITH_MD5 = 0x050080,
SSL_CK_DES_64_CBC_WITH_MD5 = 0x060040,
SSL_CK_DES_192_EDE3_CBC_WITH_MD5 = 0x0700C0,
SSL_CK_RC4_64_WITH_MD5 = 0x080080
};
/*!
* In SSLv3x, a cipher spec consists of two bytes.
*/
enum SSL3_1_CipherSpec {
// --- standard SSLv3x ciphers
TLS_NULL_WITH_NULL_NULL = 0x0000,
TLS_RSA_WITH_NULL_MD5 = 0x0001,
TLS_RSA_WITH_NULL_SHA = 0x0002,
TLS_RSA_EXPORT_WITH_RC4_40_MD5 = 0x0003,
TLS_RSA_WITH_RC4_128_MD5 = 0x0004,
TLS_RSA_WITH_RC4_128_SHA = 0x0005,
TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 = 0x0006,
TLS_RSA_WITH_IDEA_CBC_SHA = 0x0007,
TLS_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x0008,
TLS_RSA_WITH_DES_CBC_SHA = 0x0009,
TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0x000A,
TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x000B,
TLS_DH_DSS_WITH_DES_CBC_SHA = 0x000C,
TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = 0x000D,
TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x000E,
TLS_DH_RSA_WITH_DES_CBC_SHA = 0x000F,
TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = 0x0010,
TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x0011,
TLS_DHE_DSS_WITH_DES_CBC_SHA = 0x0012,
TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = 0x0013,
TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x0014,
TLS_DHE_RSA_WITH_DES_CBC_SHA = 0x0015,
TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = 0x0016,
TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 = 0x0017,
TLS_DH_anon_WITH_RC4_128_MD5 = 0x0018,
TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA = 0x0019,
TLS_DH_anon_WITH_DES_CBC_SHA = 0x001A,
TLS_DH_anon_WITH_3DES_EDE_CBC_SHA = 0x001B,
// --- special SSLv3 ciphers
SSL_FORTEZZA_KEA_WITH_NULL_SHA = 0x001C,
SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA = 0x001D,
//SSL_FORTEZZA_KEA_WITH_RC4_128_SHA = 0x001E,
// -- RFC 2712 (ciphers not fully described in SSLCiphers.cc)
TLS_KRB5_WITH_DES_CBC_SHA = 0x001E,
TLS_KRB5_WITH_3DES_EDE_CBC_SHA = 0x001F,
TLS_KRB5_WITH_RC4_128_SHA = 0x0020,
TLS_KRB5_WITH_IDEA_CBC_SHA = 0x0021,
TLS_KRB5_WITH_DES_CBC_MD5 = 0x0022,
TLS_KRB5_WITH_3DES_EDE_CBC_MD5 = 0x0023,
TLS_KRB5_WITH_RC4_128_MD5 = 0x0024,
TLS_KRB5_WITH_IDEA_CBC_MD5 = 0x0025,
TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA = 0x0026,
TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA = 0x0027,
TLS_KRB5_EXPORT_WITH_RC4_40_SHA = 0x0028,
TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5 = 0x0029,
TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5 = 0x002A,
TLS_KRB5_EXPORT_WITH_RC4_40_MD5 = 0x002B,
// --- new AES ciphers
TLS_RSA_WITH_AES_128_CBC_SHA = 0x002F,
TLS_DH_DSS_WITH_AES_128_CBC_SHA = 0x0030,
TLS_DH_RSA_WITH_AES_128_CBC_SHA = 0x0031,
TLS_DHE_DSS_WITH_AES_128_CBC_SHA = 0x0032,
TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x0033,
TLS_DH_anon_WITH_AES_128_CBC_SHA = 0x0034,
TLS_RSA_WITH_AES_256_CBC_SHA = 0x0035,
TLS_DH_DSS_WITH_AES_256_CBC_SHA = 0x0036,
TLS_DH_RSA_WITH_AES_256_CBC_SHA = 0x0037,
TLS_DHE_DSS_WITH_AES_256_CBC_SHA = 0x0038,
TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x0039,
TLS_DH_anon_WITH_AES_256_CBC_SHA = 0x003A,
TLS_RSA_WITH_NULL_SHA256 = 0x003B,
TLS_RSA_WITH_AES_128_CBC_SHA256 = 0x003C,
TLS_RSA_WITH_AES_256_CBC_SHA256 = 0x003D,
TLS_DH_DSS_WITH_AES_128_CBC_SHA256 = 0x003E,
TLS_DH_RSA_WITH_AES_128_CBC_SHA256 = 0x003F,
TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 = 0x0040,
// -- RFC 4132
TLS_RSA_WITH_CAMELLIA_128_CBC_SHA = 0x0041,
TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA = 0x0042,
TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA = 0x0043,
TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA = 0x0044,
TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA = 0x0045,
TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA = 0x0046,
// -- Non-RFC. Widely deployed implementation (ciphers not fully described in SSLCiphers.cc)
TLS_RSA_EXPORT1024_WITH_RC4_56_MD5 = 0x0060,
TLS_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5 = 0x0061,
TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA = 0x0062,
TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA = 0x0063,
TLS_RSA_EXPORT1024_WITH_RC4_56_SHA = 0x0064,
TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA = 0x0065,
TLS_DHE_DSS_WITH_RC4_128_SHA = 0x0066,
// -- RFC 5246 (ciphers not fully described in SSLCiphers.cc)
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = 0x0067,
TLS_DH_DSS_WITH_AES_256_CBC_SHA256 = 0x0068,
TLS_DH_RSA_WITH_AES_256_CBC_SHA256 = 0x0069,
TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 = 0x006A,
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = 0x006B,
TLS_DH_anon_WITH_AES_128_CBC_SHA256 = 0x006C,
TLS_DH_anon_WITH_AES_256_CBC_SHA256 = 0x006D,
// -- RFC 5932
TLS_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0084,
TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA = 0x0085,
TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0086,
TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA = 0x0087,
TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0088,
TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA = 0x0089,
// -- RFC 4279 (ciphers not fully described in SSLCiphers.cc)
TLS_PSK_WITH_RC4_128_SHA = 0x008A,
TLS_PSK_WITH_3DES_EDE_CBC_SHA = 0x008B,
TLS_PSK_WITH_AES_128_CBC_SHA = 0x008C,
TLS_PSK_WITH_AES_256_CBC_SHA = 0x008D,
TLS_DHE_PSK_WITH_RC4_128_SHA = 0x008E,
TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA = 0x008F,
TLS_DHE_PSK_WITH_AES_128_CBC_SHA = 0x0090,
TLS_DHE_PSK_WITH_AES_256_CBC_SHA = 0x0091,
TLS_RSA_PSK_WITH_RC4_128_SHA = 0x0092,
TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA = 0x0093,
TLS_RSA_PSK_WITH_AES_128_CBC_SHA = 0x0094,
TLS_RSA_PSK_WITH_AES_256_CBC_SHA = 0x0095,
// -- RFC 4162
TLS_RSA_WITH_SEED_CBC_SHA = 0x0096,
TLS_DH_DSS_WITH_SEED_CBC_SHA = 0x0097,
TLS_DH_RSA_WITH_SEED_CBC_SHA = 0x0098,
TLS_DHE_DSS_WITH_SEED_CBC_SHA = 0x0099,
TLS_DHE_RSA_WITH_SEED_CBC_SHA = 0x009A,
TLS_DH_anon_WITH_SEED_CBC_SHA = 0x009B,
// -- RFC 5288 (ciphers not fully described in SSLCiphers.cc)
TLS_RSA_WITH_AES_128_GCM_SHA256 = 0x009C,
TLS_RSA_WITH_AES_256_GCM_SHA384 = 0x009D,
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = 0x009E,
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 = 0x009F,
TLS_DH_RSA_WITH_AES_128_GCM_SHA256 = 0x00A0,
TLS_DH_RSA_WITH_AES_256_GCM_SHA384 = 0x00A1,
TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 = 0x00A2,
TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 = 0x00A3,
TLS_DH_DSS_WITH_AES_128_GCM_SHA256 = 0x00A4,
TLS_DH_DSS_WITH_AES_256_GCM_SHA384 = 0x00A5,
TLS_DH_anon_WITH_AES_128_GCM_SHA256 = 0x00A6,
TLS_DH_anon_WITH_AES_256_GCM_SHA384 = 0x00A7,
// -- RFC 5487 (ciphers not fully described in SSLCiphers.cc)
TLS_PSK_WITH_AES_128_GCM_SHA256 = 0x00A8,
TLS_PSK_WITH_AES_256_GCM_SHA384 = 0x00A9,
TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 = 0x00AA,
TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 = 0x00AB,
TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 = 0x00AC,
TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 = 0x00AD,
TLS_PSK_WITH_AES_128_CBC_SHA256 = 0x00AE,
TLS_PSK_WITH_AES_256_CBC_SHA384 = 0x00AF,
TLS_PSK_WITH_NULL_SHA256 = 0x00B0,
TLS_PSK_WITH_NULL_SHA384 = 0x00B1,
TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 = 0x00B2,
TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 = 0x00B3,
TLS_DHE_PSK_WITH_NULL_SHA256 = 0x00B4,
TLS_DHE_PSK_WITH_NULL_SHA384 = 0x00B5,
TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 = 0x00B6,
TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 = 0x00B7,
TLS_RSA_PSK_WITH_NULL_SHA256 = 0x00B8,
TLS_RSA_PSK_WITH_NULL_SHA384 = 0x00B9,
// -- RFC 5932 (ciphers not fully described in SSLCiphers.cc)
TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BA,
TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BB,
TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BC,
TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BD,
TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BE,
TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BF,
TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C0,
TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C1,
TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C2,
TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C3,
TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C4,
TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C5,
// -- RFC 4492
TLS_ECDH_ECDSA_WITH_NULL_SHA = 0xC001,
TLS_ECDH_ECDSA_WITH_RC4_128_SHA = 0xC002,
TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA = 0xC003,
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA = 0xC004,
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA = 0xC005,
TLS_ECDHE_ECDSA_WITH_NULL_SHA = 0xC006,
TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = 0xC007,
TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA = 0xC008,
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = 0xC009,
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = 0xC00A,
TLS_ECDH_RSA_WITH_NULL_SHA = 0xC00B,
TLS_ECDH_RSA_WITH_RC4_128_SHA = 0xC00C,
TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA = 0xC00D,
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA = 0xC00E,
TLS_ECDH_RSA_WITH_AES_256_CBC_SHA = 0xC00F,
TLS_ECDHE_RSA_WITH_NULL_SHA = 0xC010,
TLS_ECDHE_RSA_WITH_RC4_128_SHA = 0xC011,
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = 0xC012,
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = 0xC013,
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0xC014,
TLS_ECDH_anon_WITH_NULL_SHA = 0xC015,
TLS_ECDH_anon_WITH_RC4_128_SHA = 0xC016,
TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA = 0xC017,
TLS_ECDH_anon_WITH_AES_128_CBC_SHA = 0xC018,
TLS_ECDH_anon_WITH_AES_256_CBC_SHA = 0xC019,
// -- RFC 5054 (ciphers not fully described in SSLCiphers.cc)
TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA = 0xC01A,
TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA = 0xC01B,
TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA = 0xC01C,
TLS_SRP_SHA_WITH_AES_128_CBC_SHA = 0xC01D,
TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA = 0xC01E,
TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA = 0xC01F,
TLS_SRP_SHA_WITH_AES_256_CBC_SHA = 0xC020,
TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA = 0xC021,
TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA = 0xC022,
// -- RFC 5289 (ciphers not fully described in SSLCiphers.cc)
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC023,
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = 0xC024,
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC025,
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 = 0xC026,
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 0xC027,
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = 0xC028,
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 = 0xC029,
TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 = 0xC02A,
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02B,
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = 0xC02C,
TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02D,
TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 = 0xC02E,
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0xC02F,
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = 0xC030,
TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 = 0xC031,
TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 = 0xC032,
// -- RFC 5489 (ciphers not fully described in SSLCiphers.cc)
TLS_ECDHE_PSK_WITH_RC4_128_SHA = 0xC033,
TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA = 0xC034,
TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA = 0xC035,
TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA = 0xC036,
TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 = 0xC037,
TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 = 0xC038,
TLS_ECDHE_PSK_WITH_NULL_SHA = 0xC039,
TLS_ECDHE_PSK_WITH_NULL_SHA256 = 0xC03A,
TLS_ECDHE_PSK_WITH_NULL_SHA384 = 0xC03B,
// --- special SSLv3 FIPS ciphers
SSL_RSA_FIPS_WITH_DES_CBC_SHA = 0xFEFE,
SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA = 0xFEFF,
SSL_RSA_FIPS_WITH_DES_CBC_SHA_2 = 0xFFE1,
SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA_2 = 0xFFE0,
// Tags for SSL 2 cipher kinds which are not specified for SSL 3.
SSL_RSA_WITH_RC2_CBC_MD5 = 0xFF80,
SSL_RSA_WITH_IDEA_CBC_MD5 = 0xFF81,
SSL_RSA_WITH_DES_CBC_MD5 = 0xFF82,
SSL_RSA_WITH_3DES_EDE_CBC_MD5 = 0xFF83,
TLS_EMPTY_RENEGOTIATION_INFO_SCSV = 0x00FF,
};
enum SSL_CipherType {
SSL_CIPHER_TYPE_STREAM,
SSL_CIPHER_TYPE_BLOCK,
SSL_CIPHER_TYPE_NULL
};
enum SSL_BulkCipherAlgorithm {
SSL_CIPHER_NULL,
SSL_CIPHER_RC4,
SSL_CIPHER_RC2,
SSL_CIPHER_DES,
SSL_CIPHER_3DES,
SSL_CIPHER_DES40,
SSL_CIPHER_FORTEZZA,
SSL_CIPHER_IDEA,
SSL_CIPHER_AES,
SSL_CIPHER_CAMELLIA,
SSL_CIPHER_SEED,
};
enum SSL_MACAlgorithm {
SSL_MAC_NULL,
SSL_MAC_MD5,
SSL_MAC_SHA
};
enum SSL_KeyExchangeAlgorithm {
SSL_KEY_EXCHANGE_NULL,
SSL_KEY_EXCHANGE_RSA,
SSL_KEY_EXCHANGE_RSA_EXPORT,
SSL_KEY_EXCHANGE_DH,
SSL_KEY_EXCHANGE_DH_DSS,
SSL_KEY_EXCHANGE_DH_DSS_EXPORT,
SSL_KEY_EXCHANGE_DH_RSA,
SSL_KEY_EXCHANGE_DH_RSA_EXPORT,
SSL_KEY_EXCHANGE_DHE_DSS,
SSL_KEY_EXCHANGE_DHE_DSS_EXPORT,
SSL_KEY_EXCHANGE_DHE_RSA,
SSL_KEY_EXCHANGE_DHE_RSA_EXPORT,
SSL_KEY_EXCHANGE_DH_anon,
SSL_KEY_EXCHANGE_DH_anon_EXPORT,
SSL_KEY_EXCHANGE_FORTEZZA_KEA,
// --- new 56 bit export ciphers
SSL_KEY_EXCHANGE_RSA_EXPORT1024,
SSL_KEY_EXCHANGE_DHE_DSS_EXPORT1024,
// -- Elliptic Curve key change algorithms (rfc4492)
SSL_KEY_EXCHANGE_ECDH_ECDSA,
SSL_KEY_EXCHANGE_ECDHE_ECDSA,
SSL_KEY_EXCHANGE_ECDH_RSA,
SSL_KEY_EXCHANGE_ECDHE_RSA,
SSL_KEY_EXCHANGE_ECDH_anon,
};
#if 0
struct SSL_CipherSpecImprove {
uint32 identifier;
// SSL_CipherType cipherType;
SSL_BulkCipherAlgorithm encryptionAlgorithm;
SSL_BulkCipherAlgorithm authenticationAlgorithm;
SSL_BulkCipherAlgorithm keyAlgorithm;
SSL_MACAlgorithm macAlgorithm;
int clearkeySize;
int encryptedkeySize;
uint32 flags; // IsExportable IsSSLv2 IsSSLv30 IsSSLv31
const char* fullName = "TLS_WITH_NULL_NULL";
};
#endif
struct SSL_CipherSpec {
uint32 identifier; ///< type code of the CIPHER-SPEC (2 or 3 Bytes)
SSL_CipherType cipherType;
uint32 flags;
SSL_BulkCipherAlgorithm bulkCipherAlgorithm;
SSL_MACAlgorithm macAlgorithm;
SSL_KeyExchangeAlgorithm keyExchangeAlgorithm;
int clearKeySize; ///< size in bits of plaintext part of master key
int encryptedKeySize; ///< size in bits of encrypted part of master key
int hashSize;
};
const uint32 SSL_FLAG_EXPORT = 0x0001; ///< set if exportable cipher
const uint32 SSL_FLAG_SSLv20 = 0x0002; ///< set if cipher defined for SSLv20
const uint32 SSL_FLAG_SSLv30 = 0x0004; ///< set if cipher defined for SSLv30
const uint32 SSL_FLAG_SSLv31 = 0x0008; ///< set if cipher defined for SSLv31
declare(PDict, SSL_CipherSpec);
extern PDict(SSL_CipherSpec) SSL_CipherSpecDict;
extern SSL_CipherSpec SSL_CipherSpecs[];
extern const uint SSL_CipherSpecs_Count;
#endif

View file

@ -1,48 +0,0 @@
// $Id: SSLDefines.h 80 2004-07-14 20:15:50Z jason $
// Defines the states and transitions in the ssl-protocol-machine.
#ifndef SSL_DEFINES_H
#define SSL_DEFINES_H
const int SSL3_1_NUM_STATES = 20;
enum SSL3_1_States {
SSL3_1_STATE_ERROR = 0,
SSL3_1_STATE_INIT = 1,
SSL3_1_STATE_SERVER_HELLO_REQ_SENT = 2,
SSL3_1_STATE_CLIENT_HELLO_SENT = 3,
SSL3_1_STATE_SERVER_HELLO_SENT = 4,
SSL3_1_STATE_SERVER_CERT_SENT = 5,
SSL3_1_STATE_SERVER_KEY_EXCHANGE_SENT = 6,
SSL3_1_STATE_SERVER_CERT_REQ_SENT = 7,
SSL3_1_STATE_SERVER_HELLO_DONE_SENT_A = 8,
SSL3_1_STATE_SERVER_HELLO_DONE_SENT_B = 9,
SSL3_1_STATE_CLIENT_KEY_EXCHANGE_SENT_A = 10,
SSL3_1_STATE_CLIENT_KEY_EXCHANGE_SENT_B = 11,
SSL3_1_STATE_CLIENT_CERT_SENT = 12,
SSL3_1_STATE_CLIENT_CERT_VERIFY_SENT = 13,
SSL3_1_STATE_CLIENT_FIN_SENT_A = 14,
SSL3_1_STATE_SERVER_FIN_SENT_A = 15,
SSL3_1_STATE_CLIENT_FIN_SENT_B = 16,
SSL3_1_STATE_SERVER_FIN_SENT_B = 17,
SSL3_1_STATE_HS_FIN_A = 18,
SSL3_1_STATE_HS_FIN_B = 19
};
const int SSL3_1_NUM_TRANS = 11;
enum SSL_3_1_Transitions {
SSL3_1_TRANS_SERVER_HELLO_REQ = 0,
SSL3_1_TRANS_CLIENT_HELLO = 1,
SSL3_1_TRANS_SERVER_HELLO = 2,
SSL3_1_TRANS_SERVER_CERT = 3,
SSL3_1_TRANS_SERVER_KEY_EXCHANGE = 4,
SSL3_1_TRANS_SERVER_CERT_REQ = 5,
SSL3_1_TRANS_SERVER_HELLO_DONE = 6,
SSL3_1_TRANS_CLIENT_CERT = 3,
SSL3_1_TRANS_CLIENT_KEY_EXCHANGE = 7,
SSL3_1_TRANS_CLIENT_CERT_VERIFY = 8,
SSL3_1_TRANS_CLIENT_FIN = 9,
SSL3_1_TRANS_SERVER_FIN = 10
};
#endif

View file

@ -1,553 +0,0 @@
// $Id: SSLInterpreter.cc 5988 2008-07-19 07:02:12Z vern $
#include "SSLInterpreter.h"
#include "SSLv2.h"
#include "X509.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
declare(PDict, CertStore);
PDict(CertStore) cert_states;
// --- Initalization of static variables --------------------------------------
uint32 SSL_Interpreter::analyzedCertificates = 0;
uint32 SSL_Interpreter::verifiedCertificates = 0;
uint32 SSL_Interpreter::failedCertificates = 0;
uint32 SSL_Interpreter::certificateChains = 0;
// --- SSL_Interpreter --------------------------------------------------------
/*!
* The constructor.
*
* \param proxy Pointer to the SSLProxy_Analyzer which created this instance.
*/
SSL_Interpreter::SSL_Interpreter(SSLProxy_Analyzer* proxy)
{
this->proxy = proxy;
}
/*!
* The destructor.
*/
SSL_Interpreter::~SSL_Interpreter()
{
delete orig;
delete resp;
}
/*!
* Analogous to TCP_Connection::Init(), this method calls
* BuildInterpreterEndpoints() to create the corresponding endpoints.
*/
void SSL_Interpreter::Init()
{
BuildInterpreterEndpoints();
orig->SetPeer(resp);
resp->SetPeer(orig);
}
/*!
* This method analyzes a given certificate (chain), using the OpenSSL library.
*
* \param s Pointer to the SSL_InterpreterEndpoint which received the
* cerificate (chain).
* \param data Pointer to the data block which contains the certificate (chain).
* \param length Size of the data block.
* \param type the certificate type
* \param isChain false if data is pointing to a single certificate,
* true if data is pointing to a certificate chain
* mod by scott in:
* uint32 ip_address = *(s->proxyEndpoint->Endpoint()->dst_addr);
* uint16 port = (uint16) s->proxyEndpoint->Endpoint()->conn->RespPort();
* inserting endpoint
*/
void SSL_Interpreter::analyzeCertificate(SSL_InterpreterEndpoint* s,
const u_char* data, int length, uint8 type, bool isChain)
{
// See if we should continue with this certificate.
if ( ssl_certificate_seen )
{
val_list* vl = new val_list;
vl->append(proxy->BuildConnVal());
vl->append(new Val(! s->IsOrig(), TYPE_BOOL));
proxy->ConnectionEvent(ssl_certificate_seen, vl);
}
++analyzedCertificates;
const u_char* pCert = data;
uint32 certLength = length;
uint certCount = 0;
if ( isChain )
{
++certificateChains;
// Sum of all cert sizes has to match certListLength.
int tempLength = 0;
while ( tempLength < length )
{
++certCount;
uint32 certLength =
uint32((data[tempLength + 0] << 16) |
data[tempLength + 1] << 8) |
data[tempLength + 2];
tempLength += certLength + 3;
}
if ( tempLength > length )
{
Weird( "SSLv3x: sum of size of certificates doesn't match size of certificate chain" );
return;
}
// Get the first certificate.
pCert = data + 3;
certLength = uint32((data[0] << 16) | data[1] << 8) | data[2];
}
// Create a hashsum of the current certificate.
hash_t hashsum = HashKey::HashBytes(pCert, certLength);
if ( ! proxy->TCP() )
return;
TCP_Endpoint* endp = s->IsOrig() ? proxy->TCP()->Orig() : proxy->TCP()->Resp();
// Check if we've seen a certificate from this addr/port before.
uint8 key[6];
// ### Won't work for IPv6.
uint32 ip_address = *(endp->dst_addr);
uint16 port = uint16(proxy->Conn()->RespPort());
memcpy(key, &ip_address, 4);
memcpy(&key[4], &port, 2);
HashKey h(key, sizeof(key));
CertStore* pCertState = 0;
pCertState = (CertStore*) cert_states.Lookup(&h);
if ( ! pCertState )
{ // new address
pCertState = new CertStore(ip_address, port, hashsum, certLength);
cert_states.Insert(&h, pCertState);
}
else
{
// We've seen this address/certificate before. Check if
// certificate changed.
if ( ! pCertState->isSameCert(hashsum, certLength) )
{
// This shouldn't happen; ### make a stronger error.
Weird("SSL: Certificate changed for this ip+port !!!");
// Update status.
++pCertState->changes;
pCertState->certHash = hashsum;
pCertState->certSize = certLength;
pCertState->isValid = -1;
}
else
{ // cert didn't change
if ( pCertState->isValid == 0 )
{
// This is an invalid cert, but we
// warned before.
}
// Save time - don't analyze it any further.
return;
}
}
// Certificate verification.
if ( ssl_verify_certificates != 0 )
{
++verifiedCertificates;
int invalid = 0;
switch ( type ) {
case SSLv2_CT_X509_CERTIFICATE:
if ( ! isChain )
invalid = X509_Cert::verify(s->GetProxyEndpoint(),
pCert, certLength);
else
invalid = X509_Cert::verifyChain(s->GetProxyEndpoint(),
data, length);
break;
default:
Weird("SSL: Unknown CERTIFICATE-TYPE!");
invalid = 1; // quick 'n dirty :)
break;
}
if ( invalid )
{
proxy->Weak("SSL: Certificate check FAILED!");
pCertState->isValid = 0;
++failedCertificates;
}
else
pCertState->isValid = 1;
}
// Store the certificate.
if ( ssl_store_certificates != 0 )
{
// Let's hope the address is currently in network byte order!
in_addr addr;
addr.s_addr = ip_address;
char* pDummy = inet_ntoa(addr);
char sFileName[PATH_MAX];
if ( ssl_store_cert_path &&
ssl_store_cert_path->AsString()->Len() > 0 )
{
const BroString* pString = ssl_store_cert_path->AsString();
safe_snprintf(sFileName, PATH_MAX, "%s/cert.%s-server-c%i.der",
pString->Bytes(), pDummy, pCertState->changes);
}
else
safe_snprintf(sFileName, PATH_MAX, "cert.%s-server-c%i.der",
pDummy, pCertState->changes);
FILE* certFile = fopen(sFileName, "wb");
if ( ! certFile )
{
Weird(fmt("SSL_Interpreter::analyzeCertificate(): Error opening '%s'!\n", sFileName));
return;
}
fwrite(pCert, 1, certLength, certFile);
fclose(certFile);
}
// TODO: test if cert is valid for the address we got it from.
}
/*!
* \return the originating SSL_InterpreterEndpoint
*/
SSL_InterpreterEndpoint* SSL_Interpreter::Orig() const
{
return orig;
}
/*!
* \return the responding SSL_InterpreterEndpoint
*/
SSL_InterpreterEndpoint* SSL_Interpreter::Resp() const
{
return resp;
}
/*!
* \param p Pointer to an SSL_InterpreterEndpoint to test
*
* \return true if p is the originating SSL_InterpreterEndpoint,
* false otherwise
*/
int SSL_Interpreter::Is_Orig(SSL_InterpreterEndpoint* p) const
{
return p == orig;
}
/*!
* \return the responding SSL_InterpreterEndpoint
*/
SSLProxy_Analyzer* SSL_Interpreter::Proxy() const
{
return proxy;
}
/*!
* This methods prints a string into the "weird" log file.
*
* \param name String to log into the "weird" file.
*/
void SSL_Interpreter::Weird(const char* name) const
{
proxy->Weird(name);
}
/*!
* Prints some counters.
*/
void SSL_Interpreter::printStats()
{
printf("SSL_Interpreter:\n");
printf("analyzedCertificates = %u\n", analyzedCertificates);
printf("verifiedCertificates = %u\n", verifiedCertificates);
printf("failedCertificates = %u\n", failedCertificates);
printf("certificateChains = %u\n", certificateChains);
}
/*!
* Wrapper function for the event ssl_conn_attempt.
*
* \param sslVersion the SSL version for which the event occured
*
* \see SSLProxy_Analyzer::SSL_Versions
*/
void SSL_Interpreter::fire_ssl_conn_attempt(uint16 sslVersion,
TableVal* currentCipherSuites)
{
EventHandlerPtr event = ssl_conn_attempt;
if ( event )
{
val_list* vl = new val_list;
vl->append(proxy->BuildConnVal());
vl->append(new Val(sslVersion, TYPE_INT));
vl->append(currentCipherSuites);
proxy->ConnectionEvent(event, vl);
}
}
/*!
* Wrapper function for the event ssl_conn_server_reply.
*
* \param sslVersion the SSL version for which the event occured
*
* \see SSLProxy_Analyzer::SSL_Versions
*/
void SSL_Interpreter::fire_ssl_conn_server_reply(uint16 sslVersion,
TableVal* currentCipherSuites)
{
EventHandlerPtr event = ssl_conn_server_reply;
if ( event )
{
val_list* vl = new val_list;
vl->append(proxy->BuildConnVal());
vl->append(new Val(sslVersion, TYPE_INT));
vl->append(currentCipherSuites);
proxy->ConnectionEvent(event, vl);
}
}
/*!
* Wrapper function for the event ssl_conn_established.
*
* \param sslVersion the SSL version for which the event occured
* \param cipherSuite constant indicating the used SSL cipher suite
*
* \see SSLProxy_Analyzer::SSL_Versions, SSLv2_CipherSpecs and SSL3_1_CipherSpec.
*/
void SSL_Interpreter::fire_ssl_conn_established(uint16 sslVersion,
uint32 cipherSuite)
{
EventHandlerPtr event = ssl_conn_established;
if ( event )
{
val_list* vl = new val_list;
vl->append(proxy->BuildConnVal());
vl->append(new Val(sslVersion, TYPE_INT));
vl->append(new Val(cipherSuite, TYPE_COUNT));
proxy->ConnectionEvent(event, vl);
}
}
/*!
* Wrapper function for the event ssl_conn_reused
*
* \param pData Pointer to a SSL_DataBlock which contains the SSL session ID
* of the originating ssl session.
*/
void SSL_Interpreter::fire_ssl_conn_reused(const SSL_DataBlock* pData)
{
EventHandlerPtr event = ssl_conn_reused;
if ( event )
{
val_list* vl = new val_list;
vl->append(proxy->BuildConnVal());
vl->append(MakeSessionID(pData->data, pData->len));
proxy->ConnectionEvent(event, vl);
}
}
/*!
* Wrapper function for the event ssl_conn_alert
*
* \param sslVersion the SSL version for which the event occured
* \param level constant indicating the level of severity
* \param description constant indicating the type of alert/error
*
* \see SSLProxy_Analyzer::SSL_Versions, SSL3x_AlertLevel, SSL3_1_AlertDescription
* and SSLv2_ErrorCodes.
*/
void SSL_Interpreter::fire_ssl_conn_alert(uint16 sslVersion, uint16 level,
uint16 description)
{
if ( ssl_conn_alert )
{
EventHandlerPtr event = ssl_conn_alert;
if ( event )
{
val_list* vl = new val_list;
vl->append(proxy->BuildConnVal());
vl->append(new Val(sslVersion, TYPE_INT));
vl->append(new Val(level, TYPE_COUNT));
vl->append(new Val(description, TYPE_COUNT));
proxy->ConnectionEvent(event, vl);
}
}
}
// Generate a session ID table. Returns an empty table
// if len is zero.
TableVal* SSL_Interpreter::MakeSessionID(const u_char* data, int len)
{
TableVal* sessionIDTable = new TableVal(SSL_sessionID);
if ( ! len )
return sessionIDTable;
for ( int i = 0; i < len; i += 4 )
{
uint32 temp = (data[i] << 24) | (data[i + 1] << 16) |
(data[i + 2] << 8) | data[i + 3];
Val* index = new Val(i / 4, TYPE_COUNT);
sessionIDTable->Assign(index, new Val(temp, TYPE_COUNT));
Unref(index);
}
return sessionIDTable;
}
//--- SSL_InterpreterEndpoint -------------------------------------------------
/*!
* The constructor.
*
* \param interpreter Pointer to the instance of an SSL_Interpreter to which
* this endpoint belongs to.
* \param is_orig true if this endpoint is the originator of the connection,
* false otherwise
* SC: an adjustment was made here since the endpoints are now assosciated with
* TCP_Contents base objects rather than TCP_Endpoint.
*/
SSL_InterpreterEndpoint::SSL_InterpreterEndpoint(SSL_Interpreter* arg_interpreter,
bool arg_is_orig )
{
interpreter = arg_interpreter;
is_orig = arg_is_orig;
proxyEndpoint = new Contents_SSL(interpreter->Proxy()->Conn(), is_orig);
ourProxyEndpoint = true;
}
/*!
* The destructor.
*/
SSL_InterpreterEndpoint::~SSL_InterpreterEndpoint()
{
SetProxyEndpoint(0);
}
/*!
* \return true if there's currently data pending for this endpoint,
* false otherwise
*/
bool SSL_InterpreterEndpoint::isDataPending()
{
return proxyEndpoint->isDataPending();
}
/*!
* Sets the peer of this endpoint.
*
* \param p Pointer to an interpreter endpoint which will be set as the peer
* of this endpoint.
*/
void SSL_InterpreterEndpoint::SetPeer(SSL_InterpreterEndpoint* p)
{
peer = p;
}
/*!
* Sets the proxy endpoint of this endpoint.
*
* \param p Pointer to a Contents_SSL analyzer which will be set as the proxy endpoint
* of this endpoint.
*/
void SSL_InterpreterEndpoint::SetProxyEndpoint(Contents_SSL* p)
{
if ( ourProxyEndpoint )
{
proxyEndpoint->Done();
delete proxyEndpoint;
ourProxyEndpoint = false;
}
proxyEndpoint = p;
}
/*!
* \return is_orig true if this endpoint is the originator of the connection,
* false otherwise
*/
int SSL_InterpreterEndpoint::IsOrig() const
{
return is_orig;
}
/*!
* \return the peer of this endpoint
*/
SSL_InterpreterEndpoint* SSL_InterpreterEndpoint::Peer() const
{
return peer;
}
/*!
* \return the interpreter of this endpoint
*/
SSL_Interpreter* SSL_InterpreterEndpoint::Interpreter() const
{
return interpreter;
}
// --- CertStore --------------------------------------------------------------
/*
* The constructor.
*
* \param ip ip adress where this certificate came from
* \param port port number where this certificate came from
* \param hash hahssum for this certificate
* \param size of this certificate in bytes
*/
CertStore::CertStore(uint32 ip, uint32 arg_port, hash_t hash, int size)
{
ip_addr = ip;
certHash = hash;
certSize = size;
isValid = -1;
changes = 0;
port = arg_port;
}
/*
* This method can be used to compare certificates by certain criterias.
*
* \param hash hashsum of the certificate to compare
* \param size size of the certificate to compare
*
* \return true if the criterias match, false otherwise
*/
bool CertStore::isSameCert(hash_t hash, int length)
{
return hash == certHash && length == certSize;
}

View file

@ -1,142 +0,0 @@
// $Id: SSLInterpreter.h 5988 2008-07-19 07:02:12Z vern $
#ifndef sslinterpreter_h
#define sslinterpreter_h
#include "util.h"
#include "SSLProxy.h"
// --- forward declarations ----------------------------------------------------
class SSLProxy_Analyzer;
class Contents_SSL;
class SSL_InterpreterEndpoint;
class SSL_DataBlock;
// --- SSL_Interpreter --------------------------------------------------------
/*!
* \brief This class is the abstract base-class for the different ssl
* interpreters used for the different ssl versions.
*
* Since there is currently no support in Bro for a change of the connection
* type (IMAP -> TLS, for example), we decided not to inherit from the class
* Connection. This way, we can easily switch to SSLv3x after we've seen (and
* analyzed) a SSLv2 client hello record with a version number > SSLv2.
*
* There currently two (non-abstract) interpreters: SSLv2_Interpreter and
* SSLv3_Interpreter. The first one supports SSL 2.0, the second one supports
* both SSL 3.0 and SSL 3.1/TLS 1.0.
*
* See SSLProxy_Analyzer for additional information.
*/
class SSL_Interpreter {
public:
SSL_Interpreter(SSLProxy_Analyzer* proxy);
virtual ~SSL_Interpreter();
static uint32 analyzedCertificates; ///< how often analyzeCertificate() has been called
static uint32 verifiedCertificates; ///< how many certificates have actually been verified
static uint32 failedCertificates; ///< how many certificates have failed verification
static uint32 certificateChains; ///< counter for certificate chains
// In order to initialize the correct SSL_InterpreterEndpoints,
// override it in the corresponding subclass.
virtual void BuildInterpreterEndpoints() = 0;
virtual void Init();
SSL_InterpreterEndpoint* Orig() const;
SSL_InterpreterEndpoint* Resp() const;
SSLProxy_Analyzer* Proxy() const;
int Is_Orig(SSL_InterpreterEndpoint* p) const;
virtual void analyzeCertificate(SSL_InterpreterEndpoint* s,
const u_char* data, int length,
uint8 type, bool isChain);
void Weird(const char* name) const;
static void printStats();
void fire_ssl_conn_attempt(uint16 sslVersion,
TableVal* currentCipherSuites);
void fire_ssl_conn_server_reply(uint16 sslVersion,
TableVal* currentCipherSuites);
void fire_ssl_conn_established(uint16 sslVersion, uint32 cipherSuite);
void fire_ssl_conn_reused(const SSL_DataBlock* pData);
void fire_ssl_conn_alert(uint16 sslVersion, uint16 level,
uint16 description);
protected:
TableVal* MakeSessionID(const u_char* data, int len);
SSLProxy_Analyzer* proxy;
SSL_InterpreterEndpoint* orig;
SSL_InterpreterEndpoint* resp;
};
// --- SSL_InterpreterEndpoint ------------------------------------------------
/*!
* \brief This abstract class represents the SSL_InterpreterEndpoints for the
* SSL_Interpreter.
*
* The key-method is Deliver() which receives the ssl records
* from the SSLProxy_Analyzer. So overwrite the Deliver()-method and do
* whatever analysis on the record content (and/or pass it to the corresponding
* SSL_Interpreter).
*/
class SSL_InterpreterEndpoint {
public:
SSL_InterpreterEndpoint(SSL_Interpreter* interpreter, bool is_orig);
virtual ~SSL_InterpreterEndpoint();
/**This method is called by corresponding SSLProxy_Analyzer and
* delivers the data.
* @param t time, when the segment was received by bro (?)
* @param len length of TCP-Segment
* @param data content of TCP-Segment
*/
virtual void Deliver(int len, const u_char* data) = 0;
bool isDataPending();
void SetPeer(SSL_InterpreterEndpoint* p);
int IsOrig() const;
SSL_InterpreterEndpoint* Peer() const;
SSL_Interpreter* Interpreter() const;
Contents_SSL* GetProxyEndpoint() { return proxyEndpoint; }
void SetProxyEndpoint(Contents_SSL* proxyEndpoint);
protected:
SSL_Interpreter* interpreter; ///< Pointer to the SSL_Interpreter to which this endpoint belongs to
SSL_InterpreterEndpoint* peer; ///< Pointer to the peer of this endpoint
Contents_SSL* proxyEndpoint; ///< Pointer to the corresponding Contents_SSL
bool ourProxyEndpoint; // true if we need to delete the proxyEndpoint
int is_orig; ///< true if this endpoint is the originator of the connection, false otherwise
};
// --- class CertStore --------------------------------------------------------
/*!
* \brief This class is used to store some information about a X509 certificate.
*
* To save memory, we only store some characteristic criterias about a
* certificate, that's currently it's size and a hashsum.
*
* \note This class is currently <b>experimental</b>.
*/
class CertStore {
public:
uint32 ip_addr; ///< ip address where this certificate is from
uint32 port; ///< port number where this certificate is from
int certSize; ///< size of the certificate in bytes
hash_t certHash; ///< hashsum obver the entire certificate
int isValid; ///< boolean value indicating if the certificate is valid
int changes; ///< counter for how often this certificate has changed for the above ip + port number
CertStore(uint32 ip, uint32 port, hash_t hash, int size);
bool isSameCert(hash_t hash, int length);
};
#endif

View file

@ -1,830 +0,0 @@
// $Id: SSLProxy.cc 6008 2008-07-23 00:24:22Z vern $
#include "SSLProxy.h"
#include "SSLv3.h"
#include "SSLv2.h"
// --- Initalization of static variables --------------------------------------
uint SSLProxy_Analyzer::totalPackets = 0;
uint SSLProxy_Analyzer::totalRecords = 0;
uint SSLProxy_Analyzer::nonSSLConnections = 0;
// --- SSL_DataBlock --------------------------------------------------------
/*!
* This constructor will allocate a block of data on the heap. If min_len is
* given, it will determine the minimum size of the new block. The data block
* referenced by data will be then be copied into the new block.
*
* \param data Pointer to the data which will be copied into the newly
* allocated heap block.
* \param len Length of the data block to copy.
* \param min_len The minimum size of data to allocate on the heap, can be omitted.
*/
SSL_DataBlock::SSL_DataBlock(const u_char* arg_data, int len, int min_len)
{
// For performance reasons, we allocate at least min_len.
if ( len < min_len )
{
data = new u_char[min_len];
size = min_len;
}
else
{
data = new u_char[len];
this->size = len;
}
memcpy(data, arg_data, len);
this->len = len;
next = 0;
}
/*!
* This is an experimental function which will print the contents of the
* internal data block in a human-readable fashion to a stream.
*
* \param stream The stream for printing the data block to.
*/
void SSL_DataBlock::toStream(FILE* stream) const
{
if ( len <= 0 )
return;
int idx;
for ( idx = 0; idx < len-1; ++idx )
fprintf(stream, "%02X:", data[idx]);
fprintf(stream, "%02X", data[idx]);
}
/*!
* This is an experimental function which will print the contents of the
* internal data block in a human-readable fashion to a string.
*
* \return A string which has to be freed by the caller.
*/
char* SSL_DataBlock::toString() const
{
if ( len <= 0 )
{
// Currently, we return an empty string if data block is empty.
char* pDummy = new char[1];
pDummy[0] = '\0';
return pDummy;
}
char* pString = new char[len*3];
char* pItx = pString;
int idx;
for ( idx = 0; idx < len-1; ++idx )
{
sprintf(pItx, "%02X:", data[idx]);
pItx += 3;
}
sprintf(pItx, "%02X", data[idx]);
return pString;
}
// --- SSL_RecordBuilder ------------------------------------------------------
uint SSL_RecordBuilder::maxAllocCount = 0;
uint SSL_RecordBuilder::maxFragmentCount = 0;
uint SSL_RecordBuilder::fragmentedHeaders = 0;
/*!
* The constructor takes an Contents_SSL as parameter. Whenever a SSL
* record has been reassembled, the DoDeliver() function of this
* Contents_SSL will be called.
*
* \param sslEndpoint The Contents_SSL to which this instance of
* SSL_RecordBuilder is bound.
*/
SSL_RecordBuilder::SSL_RecordBuilder(Contents_SSL* arg_sslEndpoint)
{
head = tail = 0;
currentSize = 0;
expectedSize = -1; // -1 means we don't know yet
hasPendingData = false;
fragmentCounter = 0;
neededSize = 5; // we need at least 5 bytes to determine version
sslEndpoint = arg_sslEndpoint;
}
/*!
* The destructor frees the chain of SSL_DataBlocks.
*/
SSL_RecordBuilder::~SSL_RecordBuilder()
{
// Free the data chain.
SSL_DataBlock* idx = head;
SSL_DataBlock* rm;
while ( idx )
{
rm = idx;
idx = idx->next;
delete rm;
}
}
/*!
* This function is the main entry point of the class. Call it with a segment
* of data to process.
*
* \param data pointer to a data segment that will be reassembled
* \param length length of the data segment to be reassembled
*
* \return true if succesfull, false otherwise
*/
bool SSL_RecordBuilder::addSegment(const u_char* data, int length)
{
while ( length > 0 )
{
if ( ! head )
{
// This is the first fragment of a SSLv2 record,
// so we analyze the header.
// Special case: SSL header has been fragmented.
if ( length < neededSize )
{
// We can't determine the record size yet,
// so we just add this stuff.
++fragmentedHeaders;
head = tail = new SSL_DataBlock(data, length,
MIN_ALLOC_SIZE);
currentSize += length;
expectedSize = -1; // special meaning
break;
}
// Get the expected length of this record.
if ( ! computeExpectedSize(data, length) )
return false;
if ( neededSize > expectedSize )
{
sslEndpoint->Weird("SSL_RecordBuilder::addSegment neededSize > expectedSize");
return false;
}
if ( tail != 0 )
{
sslEndpoint->Parent()->Weird("SSL_RecordBuilder::addSegment tail != 0");
return false;
}
if ( length > expectedSize )
{
// No fragmentation -> no memory-reallocation.
// We have additional data pending.
hasPendingData = true;
sslEndpoint->DoDeliver(expectedSize, data);
length -= expectedSize;
data += expectedSize;
expectedSize = -1;
}
else if ( length == expectedSize )
{
// No fragmentation -> no memory-reallocation.
// No additional data pending.
hasPendingData = false;
sslEndpoint->DoDeliver(expectedSize, data);
length -= expectedSize;
data += expectedSize;
expectedSize = -1;
break;
}
else
{
// First fragment of a record.
head = tail = new SSL_DataBlock(data, length,
MIN_ALLOC_SIZE);
currentSize += length;
break;
}
continue;
}
// ! head.
// We already have some data, so add the current
// segment special case.
if ( expectedSize < 0 )
{
// We don't know the expected size of
// this record yet.
if ( currentSize + length < neededSize )
{
// We still can't determine the expected size,
// so we just add the current fragment.
addData(data, length);
break;
}
// Now we can determine the expected size the
// header has been fragmented, so we have to
// reassemble it.
uint8 Header[neededSize];
memcpy(Header, head->data, head->len);
memcpy(Header + head->len, data, neededSize - head->len);
if ( ! computeExpectedSize(Header, neededSize) )
{
// Since neededSize <= MIN_ALLOC_SIZE,
// we free only head.
delete head;
head = tail = 0;
return false;
}
if ( neededSize > expectedSize )
{
sslEndpoint->Parent()->Weird("SSL_RecordBuilder::addSegment neededSize > expectedSize");
return false;
}
// No break, go on with this packet.
}
if ( currentSize + length == expectedSize )
{ // this is exactly the last segment of the record
hasPendingData = false;
// Create a continuous data structure and call
// DoDeliver().
u_char* pBlock = assembleBlocks(data, length);
sslEndpoint->DoDeliver(expectedSize, pBlock);
delete [] pBlock;
expectedSize = -1;
break;
}
else if ( currentSize + length < expectedSize )
{ // another (middle) segment
if ( length <= MIN_FRAGMENT_SIZE )
sslEndpoint->Parent()->Weird("SSLProxy: Excessive small TCP Segment!");
addData(data, length);
break;
}
else
{
// This is the last fragment of the current record,
// but there's more data in this segment.
int deltaSize = expectedSize - currentSize;
hasPendingData = true;
// Create a continuous data structure and call
// DoDeliver().
u_char* pBlock = assembleBlocks(data, deltaSize);
sslEndpoint->DoDeliver(expectedSize, pBlock);
delete [] pBlock;
expectedSize = -1;
// Process the rest.
length -= deltaSize;
data += deltaSize;
}
} // while
return true;
}
/*!
* This function is called internally by addSegment(), and add's a new SSL
* record fragment to the internally used list of SSL_DataBlocks. Note that
* the data will be copied!
*
* \param data pointer to the data that will be added
* \param length length of the data that will be added
*/
inline void SSL_RecordBuilder::addData(const u_char* data, int length)
{
++fragmentCounter;
// Check if there's some space left in the last datablock.
int bytesLeft = tail->size - tail->len;
if ( bytesLeft > 0 )
{
// There's some space left in the last data block.
if ( bytesLeft >= length )
{
// We can store all bytes in the last data block.
memcpy(tail->data + tail->len, data, length);
tail->len += length;
currentSize += length;
}
else
{
// We cannot store all bytes in the last data block,
// so we also need to add a new one.
memcpy(tail->data + tail->len, data, bytesLeft);
tail->len = tail->size;
currentSize += length;
data += bytesLeft;
length -= bytesLeft;
tail->next = new SSL_DataBlock(data, length, MIN_ALLOC_SIZE);
tail = tail->next;
}
}
else
{
// Last data block is full.
tail->next = new SSL_DataBlock(data, length, MIN_ALLOC_SIZE);
tail = tail->next;
currentSize += length;
}
}
/*!
* This function is called internally by addSegment(), whenever a SSL record
* has been fully received. It creates a single data block from the list of
* SSL record fragments while freeing them.
*
* \param data pointer to the last SSL record fragment
* \param length size of the last SSL record fragment
*
* \return pointer to a data block which contains the reassembled SSL record
*/
u_char* SSL_RecordBuilder::assembleBlocks(const u_char* data, int length)
{
// We don't store the last SSL record fragment in a DataBlock,
// instead we get it directly as parameter.
u_char* dataptr = new u_char[currentSize + length];
u_char* nextseg = dataptr;
SSL_DataBlock* idx = head;
SSL_DataBlock* rm;
uint allocCounter = 0;
while ( idx )
{
++allocCounter;
memcpy(nextseg, idx->data, idx->len);
nextseg += idx->len;
rm = idx;
idx = idx->next;
delete rm;
}
// The last fragment isn't stored in a datablock.
memcpy(nextseg, data, length);
// The first and last fragments aren't counted.
fragmentCounter += 2;
// Update statistics.
if ( allocCounter > maxAllocCount )
maxAllocCount = allocCounter;
if ( fragmentCounter > maxFragmentCount )
maxFragmentCount = fragmentCounter;
fragmentCounter = 0;
currentSize = 0;
head = tail = 0;
return dataptr;
}
/*!
* This method is called internally by computeExpectedSize(), when the SSL
* record format has not been determined yet. It tries to do so by using
* heuristics, since there's no definitive way to distinguish SSLv2 vs. SSLv3
* record headers.
*
* \param data pointer to a data block containing the SSL record to analyze
* \param length length of the SSL record to analyze, has to be >= neededSize!
*
* \return
* - 2 for SSLv2 record format
* - 3 for SSLv3 record format
* - -1 if an error occurred
*/
int SSL_RecordBuilder::analyzeSSLRecordFormat(const u_char* data, int length)
{
// We have to use heuristics for this one.
if ( length < neededSize )
{
sslEndpoint->Parent()->Weird("SSLProxy: analyzeSSLRecordFormat length < neededSize");
return -1;
}
bool found_ssl3x = 0;
bool found_ssl2x = 0;
// SSLv3x-check.
SSL3_1_ContentType ct = SSL3_1_ContentType(uint8(*data));
switch ( ct ) {
case SSL3_1_TYPE_CHANGE_CIPHER_SPEC:
case SSL3_1_TYPE_ALERT:
case SSL3_1_TYPE_HANDSHAKE:
case SSL3_1_TYPE_APPLICATION_DATA:
{
sslEndpoint->sslVersion = ((data[1]) << 8) | data[2];
uint16 v = sslEndpoint->sslVersion;
if ( v == uint16(SSLProxy_Analyzer::SSLv30) ||
v == uint16(SSLProxy_Analyzer::SSLv31) )
found_ssl3x = true;
break;
}
}
// SSLv2 check.
// We look for CLIENT-HELLOs, SERVER-HELLOs and ERRORs.
const u_char* pContents = data;
uint offset = 0;
uint16 size = 0;
if ( (data[0] & 0x80) > 0 )
{ // we have a two-byte record header
offset = 2;
size = (((data[0] & 0x7f) << 8) | data[1]) + 2;
}
else
{ // we have a three-byte record header
offset = 3;
size = (((data[0] & 0x3f) << 8) | data[1]) + 3;
}
pContents += offset;
switch ( SSLv2_MessageTypes(pContents[0]) ) {
case SSLv2_MT_ERROR:
if ( size == SSLv2_ERROR_RECORD_SIZE + offset)
{
found_ssl2x = true;
sslEndpoint->sslVersion =
uint16(SSLProxy_Analyzer::SSLv20);
}
break;
case SSLv2_MT_CLIENT_HELLO:
{
sslEndpoint->sslVersion =
uint16(pContents[1] << 8) | pContents[2];
uint16 v = sslEndpoint->sslVersion;
if ( v == SSLProxy_Analyzer::SSLv20 ||
v == SSLProxy_Analyzer::SSLv30 ||
v == SSLProxy_Analyzer::SSLv31 )
found_ssl2x = true;
break;
}
case SSLv2_MT_SERVER_HELLO:
{
sslEndpoint->sslVersion =
uint16(pContents[3] << 8) | pContents[4];
uint16 v = sslEndpoint->sslVersion;
if ( v == SSLProxy_Analyzer::SSLv20 ||
v == SSLProxy_Analyzer::SSLv30 ||
v == SSLProxy_Analyzer::SSLv31 )
found_ssl2x = true;
break;
}
default:
break;
}
// Consistency checks.
if ( (found_ssl3x || found_ssl2x) == false )
{
sslEndpoint->Parent()->Weird("SSLProxy: Could not determine SSL version!");
return -1;
}
if ( (found_ssl3x && found_ssl2x) == true )
{
sslEndpoint->Parent()->Weird("SSLProxy: Found ambigous SSL version!");
return -1;
}
if ( found_ssl2x )
return 2;
else
return 3;
}
/*!
* This method is called internally by addSegment() to determine the expected
* size of a SSL record.
*
* \param data pointer to the SSL record to analyze
* \param length length of the SSL record to analyze
*
* \return true if succesfull, false otherwise
*/
bool SSL_RecordBuilder::computeExpectedSize(const u_char* data, int length)
{
if ( sslEndpoint->sslRecordVersion < 0 )
{
// We don't know the ssl record format yet, so we try
// to find out.
sslEndpoint->sslRecordVersion =
analyzeSSLRecordFormat(data, length);
if ( sslEndpoint->sslRecordVersion != 2 &&
sslEndpoint->sslRecordVersion != 3 )
// We could not determine the ssl record version.
return false;
}
// Get the expected length of this record.
if ( sslEndpoint->sslRecordVersion == 2 )
{
if ( (data[0] & 0x80) > 0 )
// We have a two-byte record header.
expectedSize = (((data[0] & 0x7f) << 8) | data[1]) + 2;
else
// We have a three-byte record header.
expectedSize = (((data[0] & 0x3f) << 8) | data[1]) + 3;
}
else if ( sslEndpoint->sslRecordVersion == 3 )
expectedSize = ((data[3] << 8) | data[4]) + 5;
if ( expectedSize < neededSize )
{
// This should never happen (otherwise: UNTESTED).
sslEndpoint->Parent()->Weird( "SSLProxy: expectedSize < neededSize in RecordBuilder!" );
return false;
}
return true;
}
// --- SSL_Connection_Proxy ---------------------------------------------------
bool SSLProxy_Analyzer::bInited = false;
SSLProxy_Analyzer::SSLProxy_Analyzer(Connection* conn)
: TCP_ApplicationAnalyzer(AnalyzerTag::SSL, conn)
{
sSLv2Interpreter = new SSLv2_Interpreter(this);
sSLv3xInterpreter = new SSLv3_Interpreter(this);
sSLInterpreter = 0;
bPassThrough = false;
if ( ! bInited )
{
BuildCipherDict();
bInited = true;
}
AddSupportAnalyzer(sslpeo = new Contents_SSL(conn, true));
AddSupportAnalyzer(sslper = new Contents_SSL(conn, false));
}
SSLProxy_Analyzer::~SSLProxy_Analyzer()
{
delete sSLv2Interpreter;
delete sSLv3xInterpreter;
}
void SSLProxy_Analyzer::Init()
{
TCP_ApplicationAnalyzer::Init();
sSLv2Interpreter->Init();
sSLv3xInterpreter->Init();
sSLv2Interpreter->Orig()
->SetProxyEndpoint(sSLv3xInterpreter->Orig()->GetProxyEndpoint());
sSLv2Interpreter->Resp()
->SetProxyEndpoint(sSLv3xInterpreter->Resp()->GetProxyEndpoint());
}
void SSLProxy_Analyzer::BuildCipherDict()
{
for ( uint idx = 0; idx < SSL_CipherSpecs_Count; ++idx )
{
HashKey h(static_cast<bro_uint_t>(SSL_CipherSpecs[idx].identifier));
SSL_CipherSpecDict.Insert(&h, &SSL_CipherSpecs[idx]);
}
}
void SSLProxy_Analyzer::NewSSLRecord(Contents_SSL* endp,
int len, const u_char* data)
{
// This is to extract only SSLv2 traffic.
if ( recordSSLv2Traffic )
{
uint16 sslVersion = 0;
if ( (data[0] & 0x80) > 0 )
// We have a two-byte record header.
sslVersion = (data[3] << 8) | data[4];
else
// We have a three-byte record header.
sslVersion = (data[4] << 8) | data[5];
if ( ! endp->IsSSLv2Record() ||
sslVersion != SSLProxy_Analyzer::SSLv20 )
{
SetSkip(1);
Conn()->SetRecordPackets(0);
Conn()->SetRecordContents(0);
// FIXME: Could do memory cleanup here.
}
else
// No analysis - only recording.
SetSkip(1);
return;
}
if ( bPassThrough )
{
DoDeliver(len, data, endp->IsOrig());
return;
}
if ( ! endp->IsSSLv2Record() )
{
// It's TLS or SSLv3, so we are done ...
sSLInterpreter = sSLv3xInterpreter;
bPassThrough = true;
// Tell the other record builder we have SSLv3x.
endp->sslRecordVersion = 3;
DoDeliver(len, data, endp->IsOrig());
}
else
{ // we have a SSLv2 record ...
sSLInterpreter = sSLv2Interpreter;
// Check whether it's the first or second we've seen ...
if ( sslpeo->VersionRecognized() &&
sslper->VersionRecognized() )
{
// Second record we've seen.
// O.K. Both endpoints recognized the version.
// So this needs to be an SSLv2-Connection ...
bPassThrough = true;
DoDeliver(len, data, endp->IsOrig());
}
// First record we see.
// The next one may be SSLv2 or SSLv3x,
// we don't know yet ...
else if ( endp->sslVersion == SSLv20 )
{
// The client supports only SSLv2, so we're done.
bPassThrough = true;
endp->sslRecordVersion = 2;
endp->sslVersion = SSLv20;
DoDeliver(len, data, endp->IsOrig());
}
else
{
bPassThrough = false;
DoDeliver(len, data, endp->IsOrig());
// Transfer the state of the SSLv2-Interpreter
// to the state of the SSLv3x-Interpreter ...
if ( ((SSLv2_Interpreter*) sSLInterpreter)->ConnState() == CLIENT_HELLO_SEEN )
((SSLv3_Interpreter*) sSLv3xInterpreter)->SetState(SSL3_1_STATE_CLIENT_HELLO_SENT);
}
}
}
void SSLProxy_Analyzer::DoDeliver(int len, const u_char* data, bool orig)
{
if ( orig )
sSLInterpreter->Orig()->Deliver(len, data);
else
sSLInterpreter->Resp()->Deliver(len, data);
}
void SSLProxy_Analyzer::printStats()
{
printf("SSLProxy_Analyzer::totalPackets = %u\n", totalPackets);
printf("SSLProxy_Analyzer::totalRecords = %u\n", totalRecords);
printf("SSLProxy_Analyzer::nonSSLConnections = %u\n", nonSSLConnections);
}
void SSLProxy_Analyzer::Weak(const char* name)
{
if ( ssl_conn_weak )
Event(ssl_conn_weak, name);
}
// --- Contents_SSL ------------------------------------------------------
/*!
* mod Contents_SSL::Contents_SSL( TCP_Endpoint* arg_endpt, int stop_on_gap )
* : TCP_Contents( arg_conn, stop_on_gap, punt_on_partial )
*/
Contents_SSL::Contents_SSL(Connection* conn, bool orig)
: TCP_SupportAnalyzer(AnalyzerTag::Contents_SSL, conn, orig)
{
sslRecordBuilder = new SSL_RecordBuilder(this);
bVersionRecognized = false;
bIsSSLv2Record = false;
sslRecordVersion = -1; // -1 means we don't know yet
sslVersion = 0; // 0 means we don't know yet
}
Contents_SSL::~Contents_SSL()
{
delete sslRecordBuilder;
}
bool Contents_SSL::isDataPending()
{
return sslRecordBuilder->isDataPending();
}
void Contents_SSL::DeliverStream(int len, const u_char* data, bool orig)
{
TCP_SupportAnalyzer::DeliverStream(len, data, orig);
TCP_Analyzer* tcp = static_cast<TCP_ApplicationAnalyzer *>(Parent())->TCP();
assert(tcp);
if ( tcp->HadGap(orig) || tcp->IsPartial() )
return;
++SSLProxy_Analyzer::totalPackets;
TCP_Endpoint* endp = orig ? tcp->Orig() : tcp->Resp();
#if 0
// FIXME: What's this???
int ack = endp->AckSeq() - endp->StartSeq();
int top_seq = seq + len;
if ( top_seq <= ack )
// There is no new data in this packet.
return;
#endif
if ( len <= 0 )
return;
// No further processing if we have a partial connection.
if ( endp->state == TCP_ENDPOINT_PARTIAL ||
endp->peer->state == TCP_ENDPOINT_PARTIAL )
{
Parent()->SetSkip(1);
Conn()->SetRecordPackets(0);
return;
}
if ( ! sslRecordBuilder->addSegment(data, len) )
{
// The RecordBuilder failed to determine the SSL record version,
// so we can't analyze this connection any further.
++SSLProxy_Analyzer::nonSSLConnections;
Parent()->Weird("SSL: Skipping connection (not an SSL connection?!)!");
Parent()->SetSkip(1);
Conn()->SetRecordPackets(0);
}
}
// Called by the RecordBuilder with a complete SSL record.
void Contents_SSL::DoDeliver(int len, const u_char* data)
{
++SSLProxy_Analyzer::totalRecords;
bIsSSLv2Record = sslRecordVersion == 2;
bVersionRecognized = true;
((SSLProxy_Analyzer*) Parent())->NewSSLRecord(this, len, data);
}
bool Contents_SSL::IsSSLv2Record()
{
return bIsSSLv2Record;
}
bool Contents_SSL::VersionRecognized()
{
return bVersionRecognized;
}

View file

@ -1,289 +0,0 @@
// $Id: SSLProxy.h 5952 2008-07-13 19:45:15Z vern $
#ifndef SSLPROXY_H
#define SSLPROXY_H
#include "TCP.h"
#include "SSLInterpreter.h"
#include "binpac_bro.h"
#include <algorithm>
// --- forward declarations ---------------------------------------------------
class SSL_Interpreter;
class SSL_RecordBuilder;
class Contents_SSL;
// --- class SSL_DataBlock ----------------------------------------------------
/*!
* \brief This class is used to store a block of data on the heap, which is
* allocated and copied by the constructor, and freed by the destructor.
*
* It is mainly used by the SSL_RecordBuilder to store the received data. To
* reduce heap operations (HeapOps), which can be quite expensive, it is
* possible to let the constructor allocate a minimum heap block size. The
* class members keep track of how much data has been allocated and how much of
* it has been used. Plus, there's a pointer to the next SSL_DataBlock, for
* easy creation of a single-linked list.
*/
class SSL_DataBlock {
public:
SSL_DataBlock(const u_char* data, int len, int min_len = 0);
int len; ///< The <b>used</b> size of the reserved heap block.
int size; ///< The <b>allocated</b> size of the reserved heap block.
u_char* data; ///< Pointer to the allocated heap block.
SSL_DataBlock* next; ///< Pointer to the next SSL_Datablock in the chain.
/*!
* The destructor will free the allocated data block.
*/
~SSL_DataBlock() { delete [] data; }
void toStream(FILE* stream) const;
char* toString() const;
};
// --- class SSL_RecordBuilder ------------------------------------------------
/*!
* \brief This class is used to reassemble SSL records from a stream of data.
*
* It supports both SSLv2 and SSLv3 record formats at the same time. The record
* builder has been designed to be robust, efficient and hard to attack. To add
* a segments of data, call addSegment(). Whenever a SSL record has been
* reassembled, the DoDeliver() function of the corresponding Contents_SSL
* will be called.
*
* Two forms of attack have been taken into consideration:
* -# The "fake size" attack, where the actual size of the SSL record is much
* smaller then the size given in the record header. This way, an attacker
* could force Bro to allocate a huge amount of memory and make it crash.
* -# The "small fragment" attack, where an attacker sends huge SSL records
* in very small (1 byte or so) TCP segments. This could lead to a huge
* amount of very small memory blocks allocated by Bro. After the last byte
* of an SSL record has been received, all allocated blocks have to be
* freed. Freeing something like 32K blocks of memory can be quite expensive,
* so packet drops may occur, which could prevent Bro from detecting an
* attacker.
*
* The current implementation always allocates a minimum size of data on the
* heap, which is MIN_ALLOC_SIZE. The processed SSL record fragments are stored
* in a single-linked list of type SSL_DataBlock.
*
* The following assumptions are made:
* - neededSize <= min( expectedSize )
* - neededSize <= MIN_ALLOC_SIZE, so the data needed to determine the SSL
* record version fits in one SSL_DataBlock
*/
class SSL_RecordBuilder {
public:
SSL_RecordBuilder(Contents_SSL* sslEndpoint);
~SSL_RecordBuilder();
static const uint MIN_ALLOC_SIZE = 16; ///< min. size of memory to alloc
static const int MIN_FRAGMENT_SIZE = 100; ///< min. size of a middle TCP Segment
static uint maxAllocCount; ///< max. number of allocated data blocks for an instance of a reassembler
static uint maxFragmentCount; ///< max. number of fragments for a ssl record
static uint fragmentedHeaders; ///< counter for the number of fragmented headers (header=neededSize)
bool addSegment(const u_char* data, int length);
/*!
* Calls this method to see if there's currently data in the
* record builder pending.
* \return true if there's data pending, false otherwise
*/
bool isDataPending() { return hasPendingData; };
protected:
u_char* assembleBlocks(const u_char* data, int length);
int analyzeSSLRecordFormat(const u_char* data, int length);
bool computeExpectedSize (const u_char* data, int length);
void addData(const u_char* data, int length);
SSL_DataBlock* head; ///< pointer to the first element in the linked list of SSL_DataBlocks
SSL_DataBlock* tail; ///< pointer to the last element in the linked list of SSL_DataBlocks
Contents_SSL* sslEndpoint; ///< pointer to the containing Contents_SSL
int expectedSize; ///< expected size of SSLv2 record including header
int currentSize; ///< current bytes stored in data blocks (that is, processed size of actual record)
int neededSize; ///< min. size in bytes so that the length of the current record can be determinded
bool hasPendingData; ///< true if there's data following in the current tcp segment
uint fragmentCounter; ///< counter for the number of tcp segments for the current record
};
// --- class SSLProxy_Analyzer ----------------------------------------------
/** This class represents an SSL_Connection with two SSL_ConnectionEndpoints.
* Note, that this class acts as a proxy, because there are different versions
* of the SSL protocol in use and you don't know in advance which SSL version
* really will be used. This depends on the first two messages of the SSL handshake
* process. Because Bro offers no possibility for switching connections we
* decided only to inherit this proxy from TCP_Connection.
* The different SSL versions are implemented in classed derived from
* SSL_Interpreter/SSL_InterpreterEndpoint and so, we can easily switch the flow
* of data to the appropriate SSL Interpreter.
* Currently, we support SSL Version 2.0 and 3.0/3.1(TLS)(@see SSLv2_Interpreter and @see
* SSLv3_Interpreter).
* This class holds an instance of both SSLv2- and SSLv3_Interpreter. The version
* of the SSL that is used for a connection is negotiated within the first
* two records (SSL messages): client hello and server hello.
* So after scanning this two records (which is mainly done in @see SSL_RecordBuilder and
* @see Contents_SSL) and determing the versions, it is clear which
* SSL version will be used for the succeding SSL records. From now
* on, they can be directly passed through to the appropriate SSL_Interpreter.
*
* FIXME: Now we have a dynamic analyzer framework so this could be restructured.
*/
class SSLProxy_Analyzer: public TCP_ApplicationAnalyzer {
public:
SSLProxy_Analyzer(Connection* conn);
virtual ~SSLProxy_Analyzer();
static uint totalPackets; ///< counter for total ssl packets seen
static uint totalRecords; ///< counter for total ssl records seen
static uint nonSSLConnections; ///< counter for connections where we couldn't reassemble a ssl record
static const bool recordSSLv2Traffic = false; ///< if true, only recording of SSLv2 connections is done (no analysis)
static bool bInited;
enum SSL_Versions {
SSLv20 = 0x0002,
SSLv30 = 0x0300,
SSLv31 = 0x0301 // = TLS 1.0
};
/* This method is called from the corresponding Contents_SSL to
* deliver the data to the SSL_ProxyConnection. It decides which
* SSL_Interpreter (Version 2 or Version 3x) gets the record or
* directly passes it through, if it's already clear which version
* this SSL connection uses.
* @param endp the sending endpoint
* @param len length of SSL record
* @param data the SSL record
*
* SC mod - pass a TCP_Contents rather than endpoint in terms of an actual
* Contents_SSL. There is much less overall work to do since we
* have already done the assosciation.
*/
void NewSSLRecord(Contents_SSL* endp, int len, const u_char* data);
// Initialises the SSLv2- and SSLv3_Interpreters.
virtual void Init();
// This method is used for passing messages to Bro that contain
// information about weaknesses in the choosen SSL encryption
// (short keys, unverifyable certificates, ...)
// @param name the name of the weakness.
void Weak(const char* name);
static Analyzer* InstantiateAnalyzer(Connection* conn)
{ return new SSLProxy_Analyzer(conn); }
static bool Available()
{
return (ssl_certificate_seen || ssl_certificate ||
ssl_conn_attempt || ssl_conn_server_reply ||
ssl_conn_established || ssl_conn_reused ||
ssl_conn_alert)
&& ! FLAGS_use_binpac;
}
static void printStats();
protected:
bool bPassThrough; ///< whether it is clear which SSL version the connection will use
SSL_Interpreter* sSLv2Interpreter; ///< Interpreter for SSL version 2
SSL_Interpreter* sSLv3xInterpreter; ///< Interpreter for SSL version 3.0 and 3.1
SSL_Interpreter* sSLInterpreter; ///< Pointer to the interpreter currently in use
Contents_SSL* sslpeo;
Contents_SSL* sslper;
/** Internally called from this class Deliver()-method.
* It delivers the data to the correct corresponding
* SSL_InterpreterEndpoint.
* @param endp the sending endpoint
* @param t time, when the segment was received by bro (not used)
* @param seq relative sequenze number (from Endpoint::start_seq) (not used)
* @param len length of SSL record
* @param data the SSL record
*/
void DoDeliver(int len, const u_char* data, bool orig);
// Initialises the dictionary where the SSL cipher specs are stored.
// It needs only to be called once for a whole bro. @see SSLDefines.h
void BuildCipherDict();
};
// --- class Contents_SSL ------------------------------------------------
/** This class represents an endpoint of a SSLProxy_Analyzer.
* It receives the new data (TCP segments) within the Deliver()-method, does
* some basic checks on the segment and passes it on to the SSL_RecordBuilder,
* which reassembles the segments into SSL records and determines the
* versions of the records. If the SSL_RecordBuilder was able to determine
* the versions of the records it delivers the reassembled records back tho this
* Contents_SSL by calling the DoDeliver()-method.
* The Contents_SSL then hands the record over to the corresponding
* SSLProxy_Analyzer by invoking it's NewSSLRecord()-method.
*
* SC mod: change class Contents_SSL: public TCP_EndpointContents
* to class Contents_SSL: public TCP_Contents
* this is done since the class uses the Deliver() method to take care of data.
*
*/
class Contents_SSL: public TCP_SupportAnalyzer {
public:
/* The constructor builds up and initialises the Contents_SSL.
* @param conn the corresponding Connection
* @param whether this is the originator
*/
Contents_SSL(Connection* conn, bool orig);
~Contents_SSL();
int sslRecordVersion; ///< record version of the first SSL record seen (set by SSLProxy_Analyzer and SSL_RecordBuilder)
uint16 sslVersion; ///< SSL version of the SSL record seen (set by SSL_RecordBuilder)
/** Via this method, this Contents_SSL receives the
* TCP segments.
* @param len length of TCP-Segment
* @param data content of TCP-Segment
* @param orig whether sending endpoint is originator
*/
virtual void DeliverStream(int len, const u_char* data, bool orig);
/** This method is called by the corresponding SSL_RecordBuilder
* upon delivering a new reassembled SSL record.
* @param len the length of the record
* @param data the record
*/
void DoDeliver(int len, const u_char* data);
/* @return whether we have already seen the first record of the connection of this endpoint yet
*/
bool VersionRecognized();
/* @return whether the first record was of SSL version 2.0
*/
bool IsSSLv2Record();
/* @return whether the corresponding SSL_RecordBuilder has pending data
*/
bool isDataPending(); // should be inline
SSL_RecordBuilder* sslRecordBuilder;
protected:
bool bVersionRecognized; ///< False, if we haven't seen the first record of the connection of this endpoint yet
bool bIsSSLv2Record; ///< Was the first record of SSL version 2.0
};
#endif

View file

@ -1,946 +0,0 @@
// $Id: SSLv2.cc 5988 2008-07-19 07:02:12Z vern $
#include "SSLv2.h"
#include "SSLv3.h"
// --- Initalization of static variables --------------------------------------
uint SSLv2_Interpreter::totalConnections = 0;
uint SSLv2_Interpreter::analyzedConnections = 0;
uint SSLv2_Interpreter::openedConnections = 0;
uint SSLv2_Interpreter::failedConnections = 0;
uint SSLv2_Interpreter::weirdConnections = 0;
uint SSLv2_Interpreter::totalRecords = 0;
uint SSLv2_Interpreter::clientHelloRecords = 0;
uint SSLv2_Interpreter::serverHelloRecords = 0;
uint SSLv2_Interpreter::clientMasterKeyRecords = 0;
uint SSLv2_Interpreter::errorRecords = 0;
// --- SSLv2_Interpreter -------------------------------------------------------
/*!
* The Constructor.
*
* \param proxy Pointer to the SSLProxy_Analyzer who created this instance.
*/
SSLv2_Interpreter::SSLv2_Interpreter(SSLProxy_Analyzer* proxy)
: SSL_Interpreter(proxy)
{
++totalConnections;
records = 0;
bAnalyzedCounted = false;
connState = START;
pServerCipherSpecs = 0;
pClientCipherSpecs = 0;
bClientWantsCachedSession = false;
usedCipherSpec = (SSLv2_CipherSpec) 0;
pConnectionId = 0;
pChallenge = 0;
pSessionId = 0;
pMasterClearKey = 0;
pMasterEncryptedKey = 0;
pClientReadKey = 0;
pServerReadKey = 0;
}
/*!
* The Destructor.
*/
SSLv2_Interpreter::~SSLv2_Interpreter()
{
if ( connState != CLIENT_MASTERKEY_SEEN &&
connState != CACHED_SESSION &&
connState != START && // we only complain if we saw some data
connState != ERROR_SEEN )
++failedConnections;
if ( connState != CLIENT_MASTERKEY_SEEN && connState != CACHED_SESSION )
++weirdConnections;
delete pServerCipherSpecs;
delete pClientCipherSpecs;
delete pConnectionId;
delete pChallenge;
delete pSessionId;
delete pMasterClearKey;
delete pMasterEncryptedKey;
delete pClientReadKey;
delete pServerReadKey;
}
/*!
* This method implements SSL_Interpreter::BuildInterpreterEndpoints()
*/
void SSLv2_Interpreter::BuildInterpreterEndpoints()
{
orig = new SSLv2_Endpoint(this, 1);
resp = new SSLv2_Endpoint(this, 0);
}
/*!
* This method prints some counters.
*/
void SSLv2_Interpreter::printStats()
{
printf("SSLv2:\n");
printf("totalConnections = %u\n", totalConnections);
printf("analyzedConnections = %u\n", analyzedConnections);
printf("openedConnections = %u\n", openedConnections);
printf("failedConnections = %u\n", failedConnections);
printf("weirdConnections = %u\n", weirdConnections);
printf("totalRecords = %u\n", totalRecords);
printf("clientHelloRecords = %u\n", clientHelloRecords);
printf("serverHelloRecords = %u\n", serverHelloRecords);
printf("clientMasterKeyRecords = %u\n", clientMasterKeyRecords);
printf("errorRecords = %u\n", errorRecords);
printf("SSL_RecordBuilder::maxAllocCount = %u\n", SSL_RecordBuilder::maxAllocCount);
printf("SSL_RecordBuilder::maxFragmentCount = %u\n", SSL_RecordBuilder::maxFragmentCount);
printf("SSL_RecordBuilder::fragmentedHeaders = %u\n", SSL_RecordBuilder::fragmentedHeaders);
}
/*!
* \return the current state of the ssl connection
*/
SSLv2_States SSLv2_Interpreter::ConnState()
{
return connState;
}
/*!
* This method is called by SSLv2_Endpoint::Deliver(). It is the main entry
* point of this class. The header of the given SSLV2 record is analyzed and
* its contents are then passed to the corresponding analyzer method. After
* the record has been analyzed, the ssl connection state is updated.
*
* \param s Pointer to the endpoint which sent the record
* \param length length of SSLv2 record
* \param data pointer to SSLv2 record to analyze
*/
void SSLv2_Interpreter::NewSSLRecord(SSL_InterpreterEndpoint* s,
int length, const u_char* data)
{
++records;
++totalRecords;
if ( ! bAnalyzedCounted )
{
++analyzedConnections;
bAnalyzedCounted = true;
}
// We should see a maximum of 4 cleartext records.
if ( records == 5 )
{ // so this should never happen
Weird("SSLv2: Saw more than 4 records, skipping connection...");
proxy->SetSkip(1);
return;
}
// SSLv2 record header analysis
uint32 recordLength = 0; // data length of SSLv2 record
bool isEscape = false;
uint8 padding = 0;
const u_char* contents;
if ( (data[0] & 0x80) > 0 )
{ // we have a two-byte record header
recordLength = ((data[0] & 0x7f) << 8) | data[1];
contents = data + 2;
if ( recordLength + 2 != uint32(length) )
{
// This should never happen, otherwise
// we have a bug in the SSL_RecordBuilder.
Weird("SSLv2: FATAL: recordLength doesn't match data block length!");
connState = ERROR_REQUIRED;
proxy->SetSkip(1);
return;
}
}
else
{ // We have a three-byte record header.
recordLength = ((data[0] & 0x3f) << 8) | data[1];
isEscape = (data[0] & 0x40) != 0;
padding = data[2];
contents = data + 3;
if ( recordLength + 3 != uint32(length) )
{
// This should never happen, otherwise
// we have a bug in the SSL_RecordBuilder.
Weird("SSLv2: FATAL: recordLength doesn't match data block length!");
connState = ERROR_REQUIRED;
proxy->SetSkip(1);
return;
}
if ( padding == 0 && ! isEscape )
Weird("SSLv2: 3 Byte record header, but no escape, no padding!");
}
if ( recordLength == 0 )
{
Weird("SSLv2: Record length is zero (no record data)!");
return;
}
if ( isEscape )
Weird("SSLv2: Record has escape bit set (security escape)!");
if ( padding > 0 && connState != CACHED_SESSION &&
connState != CLIENT_MASTERKEY_SEEN )
Weird("SSLv2 record with padding > 0 in cleartext!");
// MISSING:
// A final consistency check is done when a block cipher is used
// and the protocol is using encryption. The amount of data present
// in a record (RECORD-LENGTH))must be a multiple of the cipher's
// block size. If the received record is not a multiple of the
// cipher's block size then the record is considered damaged, and it
// is to be treated as if an "I/O Error" had occurred (i.e. an
// unrecoverable error is asserted and the connection is closed).
switch ( connState ) {
case START:
// Only CLIENT-HELLLOs allowed here.
if ( contents[0] != SSLv2_MT_CLIENT_HELLO )
{
Weird("SSLv2: First packet is not a CLIENT-HELLO!");
analyzeRecord(s, recordLength, contents);
connState = ERROR_REQUIRED;
}
else
connState = ClientHelloRecord(s, recordLength, contents);
break;
case CLIENT_HELLO_SEEN:
// Only SERVER-HELLOs or ERRORs allowed here.
if ( contents[0] == SSLv2_MT_SERVER_HELLO )
connState = ServerHelloRecord(s, recordLength, contents);
else if ( contents[0] == SSLv2_MT_ERROR )
connState = ErrorRecord(s, recordLength, contents);
else
{
Weird("SSLv2: State violation in CLIENT_HELLO_SEEN!");
analyzeRecord(s, recordLength, contents);
connState = ERROR_REQUIRED;
}
break;
case NEW_SESSION:
// We expect a client master key.
if ( contents[0] == SSLv2_MT_CLIENT_MASTER_KEY )
connState = ClientMasterKeyRecord(s, recordLength, contents);
else if ( contents[0] == SSLv2_MT_ERROR )
connState = ErrorRecord(s, recordLength, contents);
else
{
Weird("SSLv2: State violation in NEW_SESSION or encrypted record!");
analyzeRecord(s, recordLength, contents);
connState = ERROR_REQUIRED;
}
delete pServerCipherSpecs;
pServerCipherSpecs = 0;
break;
case CACHED_SESSION:
delete pServerCipherSpecs;
pServerCipherSpecs = 0;
// No break here.
case CLIENT_MASTERKEY_SEEN:
// If no error record, no further analysis.
if ( contents[0] == SSLv2_MT_ERROR &&
recordLength == SSLv2_ERROR_RECORD_SIZE )
connState = ErrorRecord(s, recordLength, contents);
else
{
// So we finished the cleartext handshake.
// Skip all further data.
proxy->SetSkip(1);
++openedConnections;
}
break;
case ERROR_REQUIRED:
if ( contents[0] == SSLv2_MT_ERROR )
connState = ErrorRecord(s, recordLength, contents);
else
{
// We lost tracking: this should not happen.
Weird("SSLv2: State inconsistency in ERROR_REQUIRED (lost tracking!)!");
analyzeRecord(s, recordLength, contents);
connState = ERROR_REQUIRED;
}
break;
case ERROR_SEEN:
// We don't have recoverable errors in cleartext phase,
// so we shouldn't see anymore packets.
Weird("SSLv2: Traffic after error record!");
analyzeRecord(s, recordLength, contents);
break;
default:
internal_error("SSLv2: unknown state");
break;
}
}
/*!
* This method is called whenever the connection tracking failed. It calls
* the corresponding analyzer method for the given SSLv2 record, but does not
* update the ssl connection state.
*
* \param s Pointer to the endpoint which sent the record
* \param length length of SSLv2 record
* \param data pointer to SSLv2 record to analyze
*/
void SSLv2_Interpreter::analyzeRecord(SSL_InterpreterEndpoint* s,
int length, const u_char* data)
{
switch ( data[0] ) {
case SSLv2_MT_ERROR:
ErrorRecord(s, length, data);
break;
case SSLv2_MT_CLIENT_HELLO:
ClientHelloRecord(s, length, data);
break;
case SSLv2_MT_CLIENT_MASTER_KEY:
ClientMasterKeyRecord(s, length, data);
break;
case SSLv2_MT_SERVER_HELLO:
ServerHelloRecord(s, length, data);
break;
case SSLv2_MT_CLIENT_FINISHED:
case SSLv2_MT_SERVER_VERIFY:
case SSLv2_MT_SERVER_FINISHED:
case SSLv2_MT_REQUEST_CERTIFICATE:
case SSLv2_MT_CLIENT_CERTIFICATE:
Weird("SSLv2: Encrypted record type seems to be in cleartext");
break;
default:
// Unknown record type.
Weird("SSLv2: Unknown record type or encrypted record");
break;
}
}
/*!
* This method analyses a SSLv2 CLIENT-HELLO record.
*
* \param s Pointer to the endpoint which sent the record
* \param length length of SSLv2 CLIENT-HELLO record
* \param data pointer to SSLv2 CLIENT-HELLO record to analyze
*
* \return the updated state of the current ssl connection
*/
SSLv2_States SSLv2_Interpreter::ClientHelloRecord(SSL_InterpreterEndpoint* s,
int recordLength, const u_char* recordData)
{
// This method gets the record's data (without the header).
++clientHelloRecords;
if ( s != orig )
Weird("SSLv2: CLIENT-HELLO record from server!");
// There should not be any pending data in the SSLv2 reassembler,
// because the client should wait for a server response.
if ( ((SSLv2_Endpoint*) s)->isDataPending() )
Weird("SSLv2: Pending data in SSL_RecordBuilder after CLIENT-HELLO!");
// Client hello minimum header size check.
if ( recordLength < SSLv2_CLIENT_HELLO_HEADER_SIZE )
{
Weird("SSLv2: CLIENT-HELLO is too small!");
return ERROR_REQUIRED;
}
// Extract the data of the client hello header.
SSLv2_ClientHelloHeader ch;
ch.clientVersion = uint16(recordData[1] << 8) | recordData[2];
ch.cipherSpecLength = uint16(recordData[3] << 8) | recordData[4];
ch.sessionIdLength = uint16(recordData[5] << 8) | recordData[6];
ch.challengeLength = uint16(recordData[7] << 8) | recordData[8];
if ( ch.clientVersion != SSLProxy_Analyzer::SSLv20 &&
ch.clientVersion != SSLProxy_Analyzer::SSLv30 &&
ch.clientVersion != SSLProxy_Analyzer::SSLv31 )
{
Weird("SSLv2: Unsupported SSL-Version in CLIENT-HELLO");
return ERROR_REQUIRED;
}
if ( ch.challengeLength + ch.cipherSpecLength + ch.sessionIdLength +
SSLv2_CLIENT_HELLO_HEADER_SIZE != recordLength )
{
Weird("SSLv2: Size inconsistency in CLIENT-HELLO");
return ERROR_REQUIRED;
}
// The CIPHER-SPECS-LENGTH must be > 0 and a multiple of 3.
if ( ch.cipherSpecLength == 0 || ch.cipherSpecLength % 3 != 0 )
{
Weird("SSLv2: Nonconform CIPHER-SPECS-LENGTH in CLIENT-HELLO.");
return ERROR_REQUIRED;
}
// The SESSION-ID-LENGTH must either be zero or 16.
if ( ch.sessionIdLength != 0 && ch.sessionIdLength != 16 )
Weird("SSLv2: Nonconform SESSION-ID-LENGTH in CLIENT-HELLO.");
if ( (ch.challengeLength < 16) || (ch.challengeLength > 32))
Weird("SSLv2: Nonconform CHALLENGE-LENGTH in CLIENT-HELLO.");
const u_char* ptr = recordData;
ptr += SSLv2_CLIENT_HELLO_HEADER_SIZE + ch.cipherSpecLength;
pSessionId = new SSL_DataBlock(ptr, ch.sessionIdLength);
// If decrypting, store the challenge.
if ( ssl_store_key_material && ch.challengeLength <= 32 )
pChallenge = new SSL_DataBlock(ptr, ch.challengeLength);
bClientWantsCachedSession = ch.sessionIdLength != 0;
TableVal* currentCipherSuites =
analyzeCiphers(s, ch.cipherSpecLength,
recordData + SSLv2_CLIENT_HELLO_HEADER_SIZE);
fire_ssl_conn_attempt(ch.clientVersion, currentCipherSuites);
return CLIENT_HELLO_SEEN;
}
/*!
* This method analyses a SSLv2 SERVER-HELLO record.
*
* \param s Pointer to the endpoint which sent the record
* \param length length of SSLv2 SERVER-HELLO record
* \param data pointer to SSLv2 SERVER-HELLO record to analyze
*
* \return the updated state of the current ssl connection
*/
SSLv2_States SSLv2_Interpreter::ServerHelloRecord(SSL_InterpreterEndpoint* s,
int recordLength, const u_char* recordData)
{
++serverHelloRecords;
TableVal* currentCipherSuites = NULL;
if ( s != resp )
Weird("SSLv2: SERVER-HELLO from client!");
if ( recordLength < SSLv2_SERVER_HELLO_HEADER_SIZE )
{
Weird("SSLv2: SERVER-HELLO is too small!");
return ERROR_REQUIRED;
}
// Extract the data of the client hello header.
SSLv2_ServerHelloHeader sh;
sh.sessionIdHit = recordData[1];
sh.certificateType = recordData[2];
sh.serverVersion = uint16(recordData[3] << 8) | recordData[4];
sh.certificateLength = uint16(recordData[5] << 8) | recordData[6];
sh.cipherSpecLength = uint16(recordData[7] << 8) | recordData[8];
sh.connectionIdLength = uint16(recordData[9] << 8) | recordData[10];
if ( sh.serverVersion != SSLProxy_Analyzer::SSLv20 )
{
Weird("SSLv2: Unsupported SSL-Version in SERVER-HELLO");
return ERROR_REQUIRED;
}
if ( sh.certificateLength + sh.cipherSpecLength +
sh.connectionIdLength +
SSLv2_SERVER_HELLO_HEADER_SIZE != recordLength )
{
Weird("SSLv2: Size inconsistency in SERVER-HELLO");
return ERROR_REQUIRED;
}
// The length of the CONNECTION-ID must be between 16 and 32 bytes.
if ( sh.connectionIdLength < 16 || sh.connectionIdLength > 32 )
Weird("SSLv2: Nonconform CONNECTION-ID-LENGTH in SERVER-HELLO");
// If decrypting, store the connection ID.
if ( ssl_store_key_material && sh.connectionIdLength <= 32 )
{
const u_char* ptr = recordData;
ptr += SSLv2_SERVER_HELLO_HEADER_SIZE + sh.cipherSpecLength +
sh.certificateLength;
pConnectionId = new SSL_DataBlock(ptr, sh.connectionIdLength);
}
if ( sh.sessionIdHit == 0 )
{
// Generating reusing-connection event.
EventHandlerPtr event = ssl_session_insertion;
if ( event )
{
TableVal* sessionIDTable =
MakeSessionID(
recordData +
SSLv2_SERVER_HELLO_HEADER_SIZE +
sh.certificateLength +
sh.cipherSpecLength,
sh.connectionIdLength);
val_list* vl = new val_list;
vl->append(proxy->BuildConnVal());
vl->append(sessionIDTable);
proxy->ConnectionEvent(ssl_session_insertion, vl);
}
}
SSLv2_States nextState;
if ( sh.sessionIdHit != 0 )
{ // we're using a cached session
// There should not be any pending data in the SSLv2
// reassembler, because the server should wait for a
// client response.
if ( ((SSLv2_Endpoint*) s)->isDataPending() )
{
// But turns out some SSL Implementations do this
// when using a cached session.
}
// Consistency check for SESSION-ID-HIT.
if ( ! bClientWantsCachedSession )
Weird("SSLv2: SESSION-ID hit in SERVER-HELLO, but no SESSION-ID in CLIENT-HELLO!");
// If the SESSION-ID-HIT flag is non-zero then the
// CERTIFICATE-TYPE, CERTIFICATE-LENGTH and
// CIPHER-SPECS-LENGTH fields will be zero.
if ( sh.certificateType != 0 || sh.certificateLength != 0 ||
sh.cipherSpecLength != 0 )
Weird("SSLv2: SESSION-ID-HIT, but session data in SERVER-HELLO");
// Generate reusing-connection event.
if ( pSessionId )
{
fire_ssl_conn_reused(pSessionId);
delete pSessionId;
pSessionId = 0;
}
nextState = CACHED_SESSION;
}
else
{ // we're starting a new session
// There should not be any pending data in the SSLv2
// reassembler, because the server should wait for
// a client response.
if ( ((SSLv2_Endpoint*) s)->isDataPending() )
Weird("SSLv2: Pending data in SSL_RecordBuilder after SERVER-HELLO (new session)!");
// TODO: check certificate length ???
if ( sh.certificateLength == 0 )
Weird("SSLv2: No certificate in SERVER-HELLO!");
// The CIPHER-SPECS-LENGTH must be > zero and a multiple of 3.
if ( sh.cipherSpecLength == 0 )
Weird("SSLv2: No CIPHER-SPECS in SERVER-HELLO!");
if ( sh.cipherSpecLength % 3 != 0 )
{
Weird("SSLv2: Nonconform CIPHER-SPECS-LENGTH in SERVER-HELLO");
return ERROR_REQUIRED;
}
const u_char* ptr = recordData;
ptr += sh.certificateLength + SSLv2_SERVER_HELLO_HEADER_SIZE;
currentCipherSuites = analyzeCiphers(s, sh.cipherSpecLength, ptr);
nextState = NEW_SESSION;
}
// Check if at least one cipher is supported by the client.
if ( pClientCipherSpecs && pServerCipherSpecs )
{
bool bFound = false;
for ( int i = 0; i < pClientCipherSpecs->len; i += 3 )
{
for ( int j = 0; j < pServerCipherSpecs->len; j += 3 )
{
if ( memcmp(pClientCipherSpecs + i,
pServerCipherSpecs + j, 3) == 0 )
{
bFound = true;
i = pClientCipherSpecs->len;
break;
}
}
}
if ( ! bFound )
{
Weird("SSLv2: Client's and server's CIPHER-SPECS don't match!");
nextState = ERROR_REQUIRED;
}
delete pClientCipherSpecs;
pClientCipherSpecs = 0;
}
// Certificate analysis.
if ( sh.certificateLength > 0 && ssl_analyze_certificates != 0 )
{
analyzeCertificate(s, recordData + SSLv2_SERVER_HELLO_HEADER_SIZE,
sh.certificateLength, sh.certificateType, false);
}
if ( nextState == NEW_SESSION )
// generate server-reply event
fire_ssl_conn_server_reply(sh.serverVersion, currentCipherSuites);
else if ( nextState == CACHED_SESSION )
{ // generate server-reply event
fire_ssl_conn_server_reply(sh.serverVersion, currentCipherSuites);
// Generate a connection-established event with a dummy
// cipher suite, since we can't remember session information
// (yet).
// Note: A new session identifier is sent encrypted in SSLv2!
fire_ssl_conn_established(sh.serverVersion, 0xABCD);
}
else
// Unref, since the table is not delivered to any event.
Unref(currentCipherSuites);
return nextState;
}
/*!
* This method analyses a SSLv2 CLIENT-MASTER-KEY record.
*
* \param s Pointer to the endpoint which sent the record
* \param length length of SSLv2 CLIENT-MASTER-KEY record
* \param data pointer to SSLv2 CLIENT-MASTER-KEY record to analyze
*
* \return the updated state of the current ssl connection
*/
SSLv2_States SSLv2_Interpreter::
ClientMasterKeyRecord(SSL_InterpreterEndpoint* s, int recordLength,
const u_char* recordData)
{
++clientMasterKeyRecords;
SSLv2_States nextState = CLIENT_MASTERKEY_SEEN;
if ( s != orig )
Weird("SSLv2: CLIENT-MASTER-KEY from server!");
if ( recordLength < SSLv2_CLIENT_MASTER_KEY_HEADER_SIZE )
{
Weird("SSLv2: CLIENT-MASTER-KEY is too small!");
return ERROR_REQUIRED;
}
// Extract the data of the client master key header.
SSLv2_ClientMasterKeyHeader cmk;
cmk.cipherKind =
((recordData[1] << 16) | recordData[2] << 8) | recordData[3];
cmk.clearKeyLength = uint16(recordData[4] << 8) | recordData[5];
cmk.encryptedKeyLength = uint16(recordData[6] << 8) | recordData[7];
cmk.keyArgLength = uint16(recordData[8] << 8) | recordData[9];
if ( cmk.clearKeyLength + cmk.encryptedKeyLength + cmk.keyArgLength +
SSLv2_CLIENT_MASTER_KEY_HEADER_SIZE != recordLength )
{
Weird("SSLv2: Size inconsistency in CLIENT-MASTER-KEY");
return ERROR_REQUIRED;
}
// Check if cipher is supported by the server.
if ( pServerCipherSpecs )
{
bool bFound = false;
for ( int i = 0; i < pServerCipherSpecs->len; i += 3 )
{
uint32 cipherSpec =
((pServerCipherSpecs->data[i] << 16) |
pServerCipherSpecs->data[i+1] << 8) |
pServerCipherSpecs->data[i+2];
if ( cmk.cipherKind == cipherSpec )
{
bFound = true;
break;
}
}
if ( ! bFound )
{
Weird("SSLv2: Client chooses unadvertised cipher in CLIENT-MASTER-KEY!");
nextState = ERROR_REQUIRED;
}
else
nextState = CLIENT_MASTERKEY_SEEN;
delete pServerCipherSpecs;
pServerCipherSpecs = 0;
}
// TODO: check if cipher has been advertised before.
SSL_CipherSpec* pCipherSpecTemp = 0;
HashKey h(static_cast<bro_uint_t>(cmk.cipherKind));
pCipherSpecTemp = (SSL_CipherSpec*) SSL_CipherSpecDict.Lookup(&h);
if ( ! pCipherSpecTemp || ! (pCipherSpecTemp->flags & SSL_FLAG_SSLv20) )
Weird("SSLv2: Unknown CIPHER-SPEC in CLIENT-MASTER-KEY!");
else
{ // check for conistency of clearKeyLength
if ( cmk.clearKeyLength * 8 != pCipherSpecTemp->clearKeySize )
{
Weird("SSLv2: Inconsistency of clearKeyLength in CLIENT-MASTER-KEY!");
// nextState = ERROR_REQUIRED;
}
// TODO: check for consistency of encryptedKeyLength.
// TODO: check for consistency of keyArgLength.
// switch ( cmk.cipherKind )
// {
// case SSL_CK_RC4_128_WITH_MD5:
// case SSL_CK_RC4_128_EXPORT40_WITH_MD5:
// if ( cmk.keyArgLength != 0 )
// {
// Weird("SSLv2: Inconsistency of keyArgLength in CLIENT-MASTER-KEY!");
// //nextState = ERROR_REQUIRED;
// }
// break;
// case SSL_CK_DES_64_CBC_WITH_MD5:
// case SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5:
// case SSL_CK_RC2_128_CBC_WITH_MD5:
// case SSL_CK_IDEA_128_CBC_WITH_MD5:
// case SSL_CK_DES_192_EDE3_CBC_WITH_MD5:
// if ( cmk.keyArgLength != 8 )
// {
// Weird("SSLv2: Inconsistency of keyArgLength in CLIENT-MASTER-KEY!");
// }
// break;
// }
}
// Remember the used cipher spec.
usedCipherSpec = SSLv2_CipherSpec(cmk.cipherKind);
// If decrypting, store the clear key part of the master key.
if ( ssl_store_key_material /* && cmk.clearKeyLength == 11 */ )
{
pMasterClearKey =
new SSL_DataBlock((recordData + SSLv2_CLIENT_MASTER_KEY_HEADER_SIZE), cmk.clearKeyLength);
pMasterEncryptedKey =
new SSL_DataBlock((recordData + SSLv2_CLIENT_MASTER_KEY_HEADER_SIZE + cmk.clearKeyLength ), cmk.encryptedKeyLength);
}
if ( nextState == CLIENT_MASTERKEY_SEEN )
fire_ssl_conn_established(SSLProxy_Analyzer::SSLv20,
cmk.cipherKind);
return nextState;
}
/*!
* This method analyses a SSLv2 ERROR record.
*
* \param s Pointer to the endpoint which sent the record
* \param length length of SSLv2 ERROR record
* \param data pointer to SSLv2 ERROR record to analyze
*
* \return the updated state of the current ssl connection
*/
SSLv2_States SSLv2_Interpreter::ErrorRecord(SSL_InterpreterEndpoint* s,
int recordLength, const u_char* recordData)
{
++errorRecords;
if ( unsigned(recordLength) != SSLv2_ERROR_RECORD_SIZE )
{
Weird("SSLv2: Size mismatch in Error Record!");
return ERROR_REQUIRED;
}
SSLv2_ErrorRecord er;
er.errorCode = (recordData[1] << 8) | recordData[2];
SSL3x_AlertLevel al = SSL3x_AlertLevel(255);
switch ( er.errorCode ) {
case SSLv2_PE_NO_CIPHER:
// The client doesn't support a cipher which the server
// supports. Only from client to server and not recoverable!
al = SSL3x_ALERT_LEVEL_FATAL;
break;
case SSLv2_PE_NO_CERTIFICATE:
if ( s == orig )
// from client to server: not recoverable
al = SSL3x_ALERT_LEVEL_FATAL;
else
// from server to client: recoverable
al = SSL3x_ALERT_LEVEL_WARNING;
break;
case SSLv2_PE_BAD_CERTIFICATE:
if ( s == orig )
// from client to server: not recoverable
al = SSL3x_ALERT_LEVEL_FATAL;
else
// from server to client: recoverable
al = SSL3x_ALERT_LEVEL_WARNING;
break;
case SSLv2_PE_UNSUPPORTED_CERTIFICATE_TYPE:
if ( s == orig )
// from client to server: not recoverable
al = SSL3x_ALERT_LEVEL_FATAL;
else
// from server to client: recoverable
al = SSL3x_ALERT_LEVEL_WARNING;
break;
default:
al = SSL3x_ALERT_LEVEL_FATAL;
break;
}
fire_ssl_conn_alert(SSLProxy_Analyzer::SSLv20, al, er.errorCode);
return ERROR_SEEN;
}
/*!
* This method analyses a set of SSLv2 cipher suites.
*
* \param s Pointer to the endpoint which sent the cipher suites
* \param length length of cipher suites
* \param data pointer to cipher suites to analyze
*
* \return a pointer to a Bro TableVal (of type cipher_suites_list) which contains
* the cipher suites list of the current analyzed record
*/
TableVal* SSLv2_Interpreter::analyzeCiphers(SSL_InterpreterEndpoint* s,
int length, const u_char* data)
{
if ( length > MAX_CIPHERSPEC_SIZE )
{
if ( s == orig )
Weird("SSLv2: Client has CipherSpecs > MAX_CIPHERSPEC_SIZE");
else
Weird("SSLv2: Server has CipherSpecs > MAX_CIPHERSPEC_SIZE");
}
else
{ // cipher specs are not too big
if ( ssl_compare_cipherspecs )
{ // store cipher specs for state analysis
if ( s == resp )
pServerCipherSpecs =
new SSL_DataBlock(data, length);
else
pClientCipherSpecs =
new SSL_DataBlock(data, length);
}
}
const u_char* pCipher = data;
bool bExtractCipherSuite = false;
TableVal* pCipherTable = 0;
// We only extract the cipher suite when the corresponding
// ssl events are defined (otherwise we do work for nothing
// and suffer a memory leak).
// FIXME: This check needs to be done only once!
if ( (s == orig && ssl_conn_attempt) ||
(s == resp && ssl_conn_server_reply) )
{
pCipherTable = new TableVal(cipher_suites_list);
bExtractCipherSuite = true;
}
for ( int i = 0; i < length; i += 3 )
{
SSL_CipherSpec* pCurrentCipherSpec;
uint32 cipherSpecID =
((pCipher[0] << 16) | pCipher[1] << 8) | pCipher[2];
// Check for unknown cipher specs.
HashKey h(static_cast<bro_uint_t>(cipherSpecID));
pCurrentCipherSpec =
(SSL_CipherSpec*) SSL_CipherSpecDict.Lookup(&h);
if ( ! pCurrentCipherSpec )
{
if ( s == orig )
Weird("SSLv2: Unknown CIPHER-SPEC in CLIENT-HELLO!");
else
Weird("SSLv2: Unknown CIPHER-SPEC in SERVER-HELLO!");
}
if ( bExtractCipherSuite )
{
Val* index = new Val(cipherSpecID, TYPE_COUNT);
pCipherTable->Assign(index, 0);
Unref(index);
}
pCipher += 3;
}
return pCipherTable;
}
// --- SSLv2_EndPoint ---------------------------------------------------------
/*!
* The constructor.
*
* \param interpreter Pointer to the SSLv2 interpreter to whom this endpoint belongs to
* \param is_orig true if this is the originating endpoint of the ssl connection,
* false otherwise
*/
SSLv2_Endpoint::SSLv2_Endpoint(SSLv2_Interpreter* interpreter, int is_orig)
: SSL_InterpreterEndpoint(interpreter, is_orig)
{
sentRecords = 0;
}
/*!
* The destructor.
*/
SSLv2_Endpoint::~SSLv2_Endpoint()
{
}
/*!
* This method is called by the SSLProxy_Analyzer with a complete reassembled
* SSLv2 record. It passes the record to SSLv2_Interpreter::NewSSLRecord().
*
* \param t <b>reserved</b> (always zero)
* \param seq <b>reserved</b> (always zero)
* \param len length of the data block containing the ssl record
* \param data pointer to the data block containing the ssl record
*/
void SSLv2_Endpoint::Deliver(int len, const u_char* data)
{
++((SSLv2_Endpoint*)peer)->sentRecords;
((SSLv2_Interpreter*)interpreter)->NewSSLRecord(this, len, data);
}

View file

@ -1,239 +0,0 @@
// $Id: SSLv2.h 3526 2006-09-12 07:32:21Z vern $
#ifndef SSLV2_H
#define SSLV2_H
#include "SSLInterpreter.h"
#include "SSLCiphers.h"
// --- constants for SSLv2 ---------------------------------------------------
/*!
* In SSLv2, each record is of a special message type. Note that the message
* type is encrypted if the record has been encrypted, so we can determine
* the message type only if we have a cleartext record.
*/
enum SSLv2_MessageTypes {
SSLv2_MT_ERROR = 0, ///< can be in cleartext or encrypted
SSLv2_MT_CLIENT_HELLO = 1, ///< always in cleartext
SSLv2_MT_CLIENT_MASTER_KEY = 2, ///< always in cleartext
SSLv2_MT_CLIENT_FINISHED = 3, ///< always encrypted
SSLv2_MT_SERVER_HELLO = 4, ///< always in cleartext
SSLv2_MT_SERVER_VERIFY = 5, ///< always encrypted
SSLv2_MT_SERVER_FINISHED = 6, ///< always encrypted
SSLv2_MT_REQUEST_CERTIFICATE = 7, ///< always encrypted
SSLv2_MT_CLIENT_CERTIFICATE = 8, ///< always encrypted
};
// Certificate Type Codes.
//
// Authentication Type Codes
// #define SSL_AT_MD5_WITH_RSA_ENCRYPTION 0x01
// Upper/Lower Bounds
// #define SSL_MAX_MASTER_KEY_LENGTH_IN_BITS 256
// #define SSL_MAX_SESSION_ID_LENGTH_IN_BYTES 16
// #define SSL_MIN_RSA_MODULUS_LENGTH_IN_BYTES 64
// #define SSL_MAX_RECORD_LENGTH_2_BYTE_HEADER 32767
// #define SSL_MAX_RECORD_LENGTH_3_BYTE_HEADER 16383
const uint8 SSLv2_CT_X509_CERTIFICATE = 0x01;
/*!
* Error codes used in the error record.
*/
enum SSLv2_ErrorCodes {
SSLv2_PE_NO_CIPHER = 0x0001,
SSLv2_PE_NO_CERTIFICATE = 0x0002,
SSLv2_PE_BAD_CERTIFICATE = 0x0004,
SSLv2_PE_UNSUPPORTED_CERTIFICATE_TYPE = 0x0006
};
// --- structs ----------------------------------------------------------------
const int SSLv2_CLIENT_HELLO_HEADER_SIZE = 9;
struct SSLv2_ClientHelloHeader {
uint8 messageType;
uint16 clientVersion;
uint16 cipherSpecLength;
uint16 sessionIdLength;
uint16 challengeLength;
};
const int SSLv2_SERVER_HELLO_HEADER_SIZE = 11;
struct SSLv2_ServerHelloHeader {
uint8 messageType;
uint8 sessionIdHit;
uint8 certificateType;
uint16 serverVersion;
uint16 certificateLength;
uint16 cipherSpecLength;
uint16 connectionIdLength;
};
const int SSLv2_CLIENT_MASTER_KEY_HEADER_SIZE = 10;
struct SSLv2_ClientMasterKeyHeader {
uint8 messageType;
uint32 cipherKind; // caution: is an uint24
uint16 clearKeyLength;
uint16 encryptedKeyLength;
uint16 keyArgLength;
};
const unsigned int SSLv2_ERROR_RECORD_SIZE = 3;
struct SSLv2_ErrorRecord {
uint8 messageType;
uint16 errorCode;
};
const unsigned int SSLv2_CLIENT_FINISHED_HEADER_SIZE = 1;
struct SSLv2_ClientFinished {
uint8 messageType;
//char CONNECTION-ID[N-1]
};
struct SSLv2_ServerVerify {
uint8 messageType;
//char CHALLENGE-DATA[N-1]
};
struct SSLv2_ServerFinished {
uint8 messageType;
//char SESSION-ID-DATA[N-1]
};
// MISSING:
// CLIENT-CERTIFICATE
// REQUEST-CERTIFICATE
/*!
* States used by the internal SSLv2 automaton.
*/
enum SSLv2_States {
START, ///< start state, no data seen yet
CLIENT_HELLO_SEEN, ///< client hello flew by
NEW_SESSION, ///< server hello with sessionIdHit == 0 seen
CACHED_SESSION, ///< server hello with sessionIdHit != 0 seen
CLIENT_MASTERKEY_SEEN, ///< we saw a client master key record
ERROR_SEEN, ///< we saw an error record
ERROR_REQUIRED ///< one of our critical checks failed, so we think we should see an error record
};
// --- forward declarations ---------------------------------------------------
class SSLv2_Interpreter;
class SSLv2_Endpoint;
class SSLv2_Record;
class SSL_DataBlock;
class SSL_RecordBuilder;
// --- class SSLv2_Interpreter ------------------------------------------------
/*!
* \brief This class is used to analyze SSLv2 connections.
*
* Since there's currently no support for decrypting ssl connections, analysis
* stops when a connection switches to encrypted communication.
* The interpreter does several checks, both record- and connection-orientated.
*
* The record checks mainly consist of consistency checks, where the correct
* use of the SSL 2.0 specification is checked. Furthermore, the CIPHER-SPECS
* of the client and the server can be compared to detect non-intersecting sets.
*
* The connection check monitors the handshaking process for invalid transitions,
* until the end of the cleartext phase.
*
* Several events are thrown for BroScript, including client connection attempt,
* server reply, ssl connection establishment/reuse of former connection, proposed
* cipher suites and certificates seen.
*
* \see SSLv2_Endpoint
*/
class SSLv2_Interpreter : public SSL_Interpreter {
public:
SSLv2_Interpreter(SSLProxy_Analyzer* proxy);
~SSLv2_Interpreter();
void NewSSLRecord(SSL_InterpreterEndpoint* s, int length, const u_char* data);
void analyzeRecord(SSL_InterpreterEndpoint* s, int length, const u_char* data);
SSLv2_States ClientHelloRecord(SSL_InterpreterEndpoint* s,
int recordLength,
const u_char* recordData);
SSLv2_States ServerHelloRecord(SSL_InterpreterEndpoint* s,
int recordLength, const u_char* recordData);
SSLv2_States ClientMasterKeyRecord(SSL_InterpreterEndpoint* s,
int recordLength,
const u_char* recordData);
SSLv2_States ErrorRecord(SSL_InterpreterEndpoint* s,
int recordLength,
const u_char* recordData);
TableVal* analyzeCiphers(SSL_InterpreterEndpoint* s,
int length, const u_char* data);
SSLv2_States ConnState();
static void printStats();
#define MAX_CIPHERSPEC_SIZE ssl_max_cipherspec_size
// Global connection counters.
static uint totalConnections; ///< counter for total sslv2 connections
static uint analyzedConnections; ///< counter for analyzed (=not partial) connections
static uint openedConnections; ///< counter for SSLv2 connections with complete handshake
static uint failedConnections; ///< counter for SSLv2 connections with failed but correct handshake
static uint weirdConnections; ///< counter for SSLv2 connections with failed and weird handshake
// Global record counters.
static uint totalRecords; ///< counter for total SSLv2 records seen
static uint clientHelloRecords; ///< counter for SSLv2 CLIENT-HELLOs seen
static uint serverHelloRecords; ///< counter for SSLv2 SERVER-HELLOs seen
static uint clientMasterKeyRecords; ///< counter for SSLv2 CLIENT-MASTER-KEYSs seen
static uint errorRecords; ///< counter for SSLv2 ERRORs seen
// Counters for this instance.
uint32 records; ///< counter for SSLv2 records of this connection
SSLv2_States connState; ///< state of connection
bool bAnalyzedCounted; ///< flag for counting analyzedConnections
// FIXME: this should be states.
bool bClientWantsCachedSession; ///< true if the client wants a cached session, false otherwise
protected:
void BuildInterpreterEndpoints();
SSL_DataBlock* pClientCipherSpecs; ///< the CIPHER-SPECs from the client
SSL_DataBlock* pServerCipherSpecs; ///< the CIPHER-SPECs from the server
SSLv2_CipherSpec usedCipherSpec; ///< the used CIPHER-SPEC for this connection
// Currently experimental:
SSL_DataBlock* pConnectionId; // 16 <= ConnectionId <= 32
SSL_DataBlock* pChallenge; // 16 <= Challenge <= 32
SSL_DataBlock* pSessionId; // has to be 16 Bytes
SSL_DataBlock* pMasterClearKey;
SSL_DataBlock* pMasterEncryptedKey;
SSL_DataBlock* pClientReadKey;
SSL_DataBlock* pServerReadKey;
};
// --- class SSLv2_Endpoint ---------------------------------------------------
/*!
* \brief This class represents an endpoint of an SSLv2 connection.
*
* Fully reassembled SSLv2 records are passed to its Deliver() function.
* There, some counters are updated and the record is then passed to
* SSLv2_Interpreter::NewSSLRecord().
*/
class SSLv2_Endpoint: public SSL_InterpreterEndpoint {
public:
SSLv2_Endpoint(SSLv2_Interpreter* interpreter, int is_orig);
virtual ~SSLv2_Endpoint();
void Deliver(int len, const u_char* data);
uint32 sentRecords; ///< counter for sent records of this endpoint
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,590 +0,0 @@
// $Id: SSLv3.h 3526 2006-09-12 07:32:21Z vern $
#ifndef sslv3_h
#define sslv3_h
#include "SSLInterpreter.h"
#include "SSLProxy.h"
#include "SSLv3Automaton.h"
#include "SSLDefines.h"
// Offsets in SSL record layer header.
const int SSL3_1_CONTENTTYPEOFFSET = 0;
const int SSL3_1_VERSIONTYPEOFFSET = 1;
const int SSL3_1_LENGTHOFFSET = 3;
const int SSL3_1_HEADERLENGTH = 5;
// --- forward declarations ---------------------------------------------------
class SSL_Interpreter;
class SSL_InterpreterEndpoint;
class SSLProxy_Analyzer;
class SSLv3_Endpoint;
class SSLv3_Record;
class SSLv3_HandshakeRecord;
class SSLv3_AlertRecord;
class SSLv3_ApplicationRecord;
class SSLv3_ChangeCipherRecord;
class CertStore;
struct SSL_CipherSpec;
// --- enums for SSLv3.0/3.1 message handling ---------------------------------
enum SSL3_1_ContentType {
SSL3_1_TYPE_CHANGE_CIPHER_SPEC = 20,
SSL3_1_TYPE_ALERT = 21,
SSL3_1_TYPE_HANDSHAKE = 22,
SSL3_1_TYPE_APPLICATION_DATA = 23
};
enum SSL3_1_HandshakeType {
SSL3_1_HELLO_REQUEST = 0,
SSL3_1_CLIENT_HELLO = 1,
SSL3_1_SERVER_HELLO = 2,
SSL3_1_CERTIFICATE = 11,
SSL3_1_SERVER_KEY_EXCHANGE = 12,
SSL3_1_CERTIFICATE_REQUEST = 13,
SSL3_1_SERVER_HELLO_DONE = 14,
SSL3_1_CERTIFICATE_VERIFY = 15,
SSL3_1_CLIENT_KEY_EXCHANGE = 16,
SSL3_1_FINISHED = 20
};
enum SSL3_1_AlertDescription {
SSL3_1_CLOSE_NOTIFY = 0,
SSL3_1_UNEXPECTED_MESSAGE = 10,
SSL3_1_BAD_RECORD_MAC = 20,
SSL3_1_DECRYPTION_FAILED = 21,
SSL3_1_RECORD_OVERFLOW = 22,
SSL3_1_DECOMPRESSION_FAILURE = 30,
SSL3_1_HANDSHAKE_FAILURE = 40,
SSL3_0_NO_CERTIFICATE = 41,
SSL3_1_BAD_CERTIFICATE = 42,
SSL3_1_UNSUPPORTED_CERTIFICATE = 43,
SSL3_1_CERTIFICATE_REVOKED = 44,
SSL3_1_CERTIFICATE_EXPIRED = 45,
SSL3_1_CERTIFICATE_UNKNOWN = 46,
SSL3_1_ILLEGAL_PARAMETER = 47,
SSL3_1_UNKNOWN_CA = 48,
SSL3_1_ACCESS_DENIED = 49,
SSL3_1_DECODE_ERROR = 50,
SSL3_1_DECRYPT_ERROR = 51,
SSL3_1_EXPORT_RESTRICTION = 60,
SSL3_1_PROTOCOL_VERSION = 70,
SSL3_1_INSUFFICIENT_SECURITY = 71,
SSL3_1_INTERNAL_ERROR = 80,
SSL3_1_USER_CANCELED = 90,
SSL3_1_NO_RENEGOTIATION = 100
};
enum SSL3x_AlertLevel {
SSL3x_ALERT_LEVEL_WARNING = 1,
SSL3x_ALERT_LEVEL_FATAL = 2
};
// --- structs ----------------------------------------------------------------
struct SSLv3x_Random {
uint32 gmt_unix_time;
SSL_DataBlock* random_bytes; // 28-bytes
};
struct SSLv3x_ServerRSAParams {
SSL_DataBlock* rsa_modulus; // <1..2^16-1>
SSL_DataBlock* rsa_exponent; // <1..2^16-1>
};
struct SSLv3x_ServerDHParams{
SSL_DataBlock* dh_p; // <1..2^16-1>
SSL_DataBlock* dh_g; // <1..2^16-1>
SSL_DataBlock* dh_Ys; // <1..2^16-1>
};
struct SSLv3x_EncryptedPremasterSecret{
SSL_DataBlock* encryptedSecret;
};
struct SSLv3x_ClientDHPublic{
SSL_DataBlock* dh_Yc; // <1..2^16-1>
};
// ----------------------------------------------------------------------------
/**
* Class SSLv3_Interpreter is the implementation for a SSLv3.0/SSLv3.1 connection
* interpreter (derived from the abstract class SSL_Interpreter).
*
* The corresponding SSLProxy_Analyzer creates an instance of this class and
* properly initialises the corresponding SSLv3_Endpoints by calling the
* SSL_Interpreter's Init() method which then invokes the BuildInterpreterEndpoints() method
* (of the SSLv3_Interpreter) which causes the SSLv3_Endpoints to be created properly.
*
* The SSLv3_Interpreter receives the four various SSLv3_Records:
* - SSLv3_HandshakeRecord
* - SSLv3_AlertRecord
* - SSLv3_ChangeCipherRecord
* - SSLv3_ApplicationRecord
* via the DeliverSSLv3_Record() methods from the two corresponding SSLv3_Endpoints
* (which get fed by the SSLProxy_Analyzer).
*
* There is one global static SSLv3_Automaton which describes the possible transitions
* in the SSLv3.0/SSLv3.1 state machine for the handshaking phase. This automaton
* is initialised once, when Bro sees the first SSL connection. By the attribute
* currentState every instance of SSLv3_Interpreter holds the automaton state it
* is currently in and so is able
* to track the correctness of the SSL handshaking process. It weird-checks and verifies
* all arriving SSL records up to the point where handshaking is finished or an
* error occures caused by weird SSL records or not allowed transitions in the
* state machine. Information that was negotiated between the client and server
* during the handshaking phase is/may also be stored. That is:
* - used SSL version
* - negotiated cipher suite
* - session ID
* - client/server random
* - key exchange algorithms
* - cryptographic parameters
* - encrypted pre-master secret
*
* The certificates are verified using the analyzeCertificate() method of the
* SSL_Interpreter class.
* Events for Bro scripting are thrown for client connection attempt, server reply,
* ssl connection establishment/reuse of former connection, proposed cipher suites and
* seen certificates.
*
* @see SSLv3_Endpoint
*/
class SSLv3_Interpreter : public SSL_Interpreter {
public:
/** The constructor takes the SSLProxy_Analyzer as argument,
* that created this SSLv3_Interpreter.
*
* @param proxy the creating SSL_ConectionProxy
*/
SSLv3_Interpreter(SSLProxy_Analyzer* proxy);
~SSLv3_Interpreter();
/** Delivers an SSLv3_HandshakeRecord to the SSLv3_Interpreter.
* The record gets verified and it is checked whether it is allowed
* in the current phase of the handshaking process.
*
* @param rec the SSLv3_HandshakeRecord
*/
void DeliverSSLv3_Record(SSLv3_HandshakeRecord* rec);
/** Delivers an SSLv3_AlertRecord to the SSLv3_Interpreter.
* The record gets verified and weird checked.
*
* @param rec the SSLv3_AlertRecord
*/
void DeliverSSLv3_Record(SSLv3_AlertRecord* rec);
/** Delivers an SSLv3_ChangeCipherRecord to the SSLv3_Interpreter.
* The record gets verified and weird checked. If a change cipher
* record is received the next record from this endpoint needs
* to be a finished message.
*
* @param rec the SSLv3_ChangeCipherRecord
*/
void DeliverSSLv3_Record(SSLv3_ChangeCipherRecord* rec);
/** Delivers a SSLv3_ApplicationRecord to the SSLv3_Interpreter.
* It is checked, whether handshaking phase is already finished
* and sending application data is valid (the normal case is,
* that after finishing the handshaking phase, all further data
* is skipped).
*
* @param rec the SSLv3_AlertRecord
*/
void DeliverSSLv3_Record(SSLv3_ApplicationRecord* rec);
/** This method sets the currentState variable of this SSLv3_Interpreter
* and so sets the SSLv3.0/SSLv3.1 state machine to the state passed
* as parameter.It is invoked in the SSLProxy_Analyzer to enable
* this SSLv3_Interpreter to start work without having seen the first
* handshake record. This happens, when the client hello is sent in
* SSLv2 format and processed by the SSLv2_Interpreter but the further
* SSL connection taking place as a SSLv3.0/SSLv3.1 session.
*
* @param i the new state of the sslAutomaton
*/
void SetState(int i);
static void printStats();
// Total SSLv3x connections.
static uint totalConnections;
// Total SSLv3x connections with <b>complete</b> handshake.
static uint openedConnections;
static uint totalRecords; ///< counter for total SSLv3x records seen
static uint handshakeRecords; ///< counter for SSLv3x handshake records seen
static uint clientHelloRecords; ///< counter for SSLv3x client hellos seen
static uint serverHelloRecords; ///< counter for SSLv3x server hellos seen
static uint alertRecords; ///< counter for SSLv3x alert records seen
static uint changeCipherRecords; ///< counter for SSLv3x change cipher records seen
/**Flags for handling the change-cipher-messages and fin-handshake-
* messages
*/
bool change_cipher_client_seen; ///< whether a client change cipher record was seen
bool change_cipher_server_seen; ///< whether a server change cipher record was seen
bool fin_client_seen; ///< whether a client finished handshake message was seen (must immediately follow the client change cipher)
bool fin_server_seen; ///< whether a server finished handshake message was seen (must immediately follow the server change cipher)
protected:
static SSLv3_Automaton sslAutomaton; ///< represents the SSLv3.0/SSLv3.1 automaton
static bool bInited; ///< whether the automaton is already initialised (has to be only done once)
int currentState; ///< the current state of the SSL automaton in this SSLv3_Interpreter instance
// uint16 cipherSuite; ///< the cipher spec client and server agreed upon
SSL_DataBlock* pClientCipherSpecs; ///< the CIPHER-SPECs from the client
SSL_CipherSpec* pCipherSuite; ///< pointer to the cipher spec definition client and server agreed upon
uint32 cipherSuiteIdentifier; ///< only used for unknown cipher-specs
SSL_DataBlock* clientSessionID; ///< the session ID of the client hello record
SSL_DataBlock* serverSessionID; ///< the session ID for this SSL session
/**Attributes for cryptographic computations*/
SSLv3x_Random* clientRandom;
SSLv3x_Random* serverRandom;
//SSL_KeyExchangeAlgorithm keyXAlgorithm;
SSLv3x_ServerRSAParams* serverRSApars;
SSLv3x_ServerDHParams* serverDHPars;
SSLv3x_EncryptedPremasterSecret* encryptedPreSecret;
SSLv3x_ClientDHPublic* clientDHpublic;
bool helloRequestValid; ///< Whether sending a hello request is valid (normally after handshaking phase)
/** This method builds the corresponding SSLv3_Endpoints for this SSLv3_Interpreter.
* It is called in the SSL_Interpreter's Init() method.
*/
void BuildInterpreterEndpoints();
/** This method initialises the SSL state automaton; sets the states and transitions.
* It needs only to be called once for a whole bro. @see SSLDefines.h
*/
void BuildAutomaton();
/** This helper method translates the handshake types included in the SSL handshake
* records to the corresponding transition of the SSL automaton. It is invoked within
* the DeliverSSLv3_Record(SSLv3_HandshakeRecord*) method.
*
* @param type the handshake type of the handshake record
*/
int HandshakeType2Trans(int type);
/** This method is used for event generation during the handshaking phase and
* generates the connection-attempt, server-reply, connection-established, connection-reused
* events dependant on the currentState of the SSL Automaton.
* It calls the appropriate fire_* methods of the SSL_Interpreter for this.
* The method is called within the the DeliverSSLv3_Record() methods.
*
* @param rec the SSLv3_Record which is currently processed
*/
void GenerateEvents(SSLv3_Record* rec, TableVal* curCipherSuites);
/** This method analyzes the cipher suites the client and server offer
* each other during handshaking phase. It checks, whether it's a 'common'
* cipher suite and sets the pCipherSuite attribute according to the
* cipher suite client and server agreed on.
*
* @param s the SSLv3_Endpoint which sent the SSL record with the cipher suite(s) to be analyzed
* @param length length of data
* @param data pointer to where the cipher suites can be found
* @param version SSL version of the SSL record that contained the cipher suite(s)
* @return a pointer to a Bro TableVal (of type cipher_suites_list) which contains
* the cipher suites list of the current analyzed record
*/
TableVal* analyzeCiphers(const SSLv3_Endpoint* s, int length, const u_char* data, uint16 version);
};
// ----------------------------------------------------------------------------
/** Class SSLv3_Endpoint is the implementation for SSLv3.0/SSLv3.1 connection
* endpoints (derived from the abstract class SSL_InterpreterEndpoint).
*
* A SSLv3_Endpoint gets completely reassembled ssl records via the method
* Deliver(), which is invoked in this Endpoint's corresponding SSLProxy_Analyzer.
* The defragmentation and reassembling already took place in the
* SSLProxy_Analyzer's SSL_RecordBuilder.
* The Deliver()-method does some basic weird checks and then calls
* ProcessMessage() which determines the content type of the ssl record
* and, dependant on that, creates an instance of the appropriate SSLv3_Record.
* This is passed on to this endpoint's corresponding SSLv3_Interpreter via
* the DeliverSSLv3_Record()-method.
*/
class SSLv3_Endpoint : public SSL_InterpreterEndpoint {
public:
/** The constructor takes the corresponding SSL_Interpreter as argument.
* is_orig sets this endpoint as originator of the connection (1), and
* responder otherwise (0).
*
* @param interpreter the SSL_Interpreter this endpoint is bound to.
* @param is_orig whether this endpoint is the originator (1) of the
* connection or not (0).
*/
SSLv3_Endpoint(SSL_Interpreter* interpreter, int is_orig);
virtual ~SSLv3_Endpoint();
/** This method is invoked by this endpoint's corresponding
* SSLProxy_Analyzer and receives completely reassembled SSL
* records (by the data argument).
*
* @param t time is always 0 (former: when the segment was received
* by bro (?))
* @param len length of SSL record
* @param data content of SSL record
*/
void Deliver(int len, const u_char* data);
protected:
uint16 sslVersion; ///< holds the version of the just delivered SSL record
uint16 currentMessage_length; ///< the length of the just delivered SSL record
/** This method extracts the content type of the SSL record passed
* in the first parameter.
*
* @param data the SSL record
* @param len length of the record
* @return SSL3_1_ContentType of SSL record
*/
SSL3_1_ContentType ExtractContentType(const u_char* data, int len);
/** This method determines the version of the SSL record passed to it.
* It sets the field sslVersion of this endpoint an is called within
* the method ProcessMessage().
*
* @param data the SSL record
* @param len length of the record
* @return 0 if version is NOT 3.0/3.1, 1 otherwise
*/
int ExtractVersion(const u_char* data, int len);
/** This method processes a complete SSL record. It
* determines the content type of the SSL record
* (handshake, alert, change-cipher-spec, application),
* cuts away the SSL record layer header and generates
* the appropriate SSLv3_Record. Then it calls the SSLv3_Record's
* Deliver() method, which manages the delivery of the record
* to the corresponding SSLv3_Interpreter
*
* @param data the complete SSL record
* @param len data's (record's) length
*/
void ProcessMessage(const u_char* data, int len);
};
// ----------------------------------------------------------------------------
// Offsets are now relative to the end of the SSL record layer header
#define SSL3_1_CHANGE_CIPHER_TYPE_OFFSET (SSL3_1_HEADERLENGTH - 5)
#define SSL3_1_ALERT_LEVEL_OFFSET (SSL3_1_HEADERLENGTH - 5)
#define SSL3_1_ALERT_DESCRIPTION_OFFSET (SSL3_1_HEADERLENGTH - 4)
#define SSL3_1_SESSION_ID_LENGTH_OFFSET 38
#define SSL3_1_SESSION_ID_OFFSET 39
/** This class is an abstract base class for the four different
* SSLv3.0/SSLv3.1 record types (handshake, alert, change-cipher-spec,
* application).
*
* It contains a pointer to the data of the SSL record <b>without</b>
* the SSL record layer header, it's length and the version information, which
* was present in the now cut away SSL record layer header.
*
* (Note: the version field of the SSL record layer header may differ from
* the version of the record format that was used when sending the record.
* (e.g. a client may send a SSLv2 record including
* a version field containing 3.1 (for SSLv3.1) to show, that he supports
* version 3.1.))
*
* Every subclass of SSLv3_Record implements the Deliver() method, which
* manages the delivery of the record to the corresponding SSLv3_Interpreter.
* Instances of SSLv3_Record (resp. it's subclasses) are created within
* the ProcessMessage() method of a SSLv3_Endpoint.
* */
class SSLv3_Record : public BroObj{
public:
/** The constructor gets a pointer to the SSL record without the
* record layer header, it's length, the version information
* contained in the record layer header and a pointer to the
* SSLv3_Endpoint that created this instance of SSLv3_Record.
*
* @param data pointer to the SSL record without record layer header
* @param data's length
* @param version version information contained in the SSL record layer header
* @param e the SSLv3_Endpoint that created this instance
*/
SSLv3_Record(const u_char* data, int len, uint16 version,
SSLv3_Endpoint const* e);
~SSLv3_Record();
void Describe(ODesc* d) const;
int GetRecordLength() const;
const u_char* GetData() const;
uint16 GetVersion() const;
SSLv3_Endpoint const* GetEndpoint() const;
/** This abstract method is implemented by the various SSLv3_Record
* subclasses for handshake, alert, change cipher spec and application
* records. It manages the delivery of the SSLv3_Record to the
* SSLv3_Interpreter passed as argument.
* SSLv3_Records are created within the ProcessMessage() method of the
* SSLv3_Endpoint which then calls the just created SSLv3_Records
* Deliver() method with it's corresponding SSLv3_Interpreter as
* argument which then receives the (evtl. preprocessed) SSLv3_Record
* (via the method(s) DeliverSSLv3_Record()).
*
* @param conn the SSLv3_Interpreter to which this SSLv3_Record should be deliverd
*/
virtual void Deliver(SSLv3_Interpreter* conn) =0;
/** Helper function that converts from 24-bit big endian integer
* starting at offset to 32 bit integer in little endian format.
*
* @param data the ssl-record
* @param len length of data (record)
* @param offset where the 24 bit big endian starts
* @return 32 bit little endian
*/
int ExtractInt24(const u_char* data, int len, int offset);
int recordLength; ///< total length of the SSL record <b>without</b> the record layer header
const u_char* data; ///< pointer to the SSL record without the record layer header
SSLv3_Endpoint const* endp; ///< pointer to the SSLv3_Endpoint that created this instance of SSLv3_Record
uint16 sslVersion; ///< version information of the SSL record layer header
};
// ----------------------------------------------------------------------------
/* This class represents a handshake record used in SSLv3.0/SSLv3.1.
*
* Handshake records in SSLv3.0/SSLv3.1 need a special treatment,
* because it is possible that multiple handshake messages are coalesced into
* a single SSLv3.0/SSLv3.1 record.
* I think, this only can happen to
* handshake records (even RFC2246 page 16 generally talks about all
* messages of a same content type), because only handshake records
* have got an own length descriptor within and thus make de-coalescing
* possible.
* So when generating a new instance of a SSLv3_HandshakeRecord, it is checked whether there
* are more handshake records within data.
* If so, they are put apart and linked together to a chain by using
* the next-pointer.
* The Deliver() method takes this into account and delivers every single
* handshake record one by one to the SSLv3_Interpreter.
*/
class SSLv3_HandshakeRecord : public SSLv3_Record{
public:
SSLv3_HandshakeRecord(const u_char* data, int len, uint16 version,
SSLv3_Endpoint const* e);
~SSLv3_HandshakeRecord();
int GetType() const;
int GetLength() const;
/** This method delivers the SSLv3_HandshakeRecord(s) to the
* SSLv3_Interpreter passed as argument. The method follows
* the next-pointer and delivers every SSLv3_HandshakeRecord
* contained in this list to the SSLv3_Interpreter.
*
* @param conn the SSLv3_Interpreter to which this SSLv3_HandshakeRecord should be deliverd
*/
void Deliver(SSLv3_Interpreter* conn);
/* This method is invoked within the SSLv3_Interpreter and does lots of
* weird and consistency checks on a client hello SSL handshake record.
*
* @return 0 if further processing of this client hello is not
* possible due to inconsistency and 1 otherwise.
*/
int checkClientHello();
/* This method is invoked within the SSLv3_Interpreter and does lots of
* weird and consistency checks on a server hello SSL handshake record.
*
* @return 0 if further processing of this server hello is not
* possible due to inconsistency and 1 otherwise.
*/
int checkServerHello();
int type; ///< holds the handshake type of the handshake record (first byte)
int length; ///< holds the length of this handshake record (which is needed due to coalesced handshake messages)
private:
SSLv3_HandshakeRecord* next; ///< pointer to the next ssl handshake record if they are coalesced into a single record
SSLv3_HandshakeRecord* GetNext();
};
// ----------------------------------------------------------------------------
/** This class represents an alert record used in SSLv3.0/SSLv3.1.
*
* description holds the SSL alert description and level the alert level.
*/
class SSLv3_AlertRecord : public SSLv3_Record {
public:
SSLv3_AlertRecord(const u_char* data, int len, uint16 version,
SSLv3_Endpoint const* e);
~SSLv3_AlertRecord();
int GetDescription() const;
int GetLevel() const;
/** This method delivers the SSLv3_AlertRecord to the SSLv3_Interpreter passed as
* argument.
*
* @param conn the SSLv3_Interpreter to which this SSLv3_AlertRecord should be deliverd
*/
void Deliver(SSLv3_Interpreter* conn);
int description; ///< holds the alert description
int level; ///< holds the alert level
};
// ----------------------------------------------------------------------------
/** This class represents a change cipher record used in SSLv3.0/SSLv3.1.
*
* type holds the change cipher type used (currently only 1 is valid (rfc 2246))
*/
class SSLv3_ChangeCipherRecord : public SSLv3_Record{
public:
SSLv3_ChangeCipherRecord(const u_char* data, int len, uint16 version,
SSLv3_Endpoint const* e);
~SSLv3_ChangeCipherRecord();
int GetType() const;
/** This method delivers the SSLv3_ChangeCipherRecord to the
* SSLv3_Interpreter passed as argument.
*
* @param conn the SSLv3_Interpreter to which this
* SSLv3_ChangeCipherRecord should be delivered
*/
void Deliver(SSLv3_Interpreter* conn);
int type; ///< holds the change cipher type
};
// ----------------------------------------------------------------------------
/** This class represents an application record used in SSLv3.0/SSLv3.1.
*/
class SSLv3_ApplicationRecord : public SSLv3_Record {
public:
SSLv3_ApplicationRecord(const u_char* data, int len, uint16 version,
SSLv3_Endpoint const* e);
~SSLv3_ApplicationRecord();
/** This method delivers the SSLv3_ApplicationRecord to the
* SSLv3_Interpreter passed as argument.
*
* @param conn the SSLv3_Interpreter to which this
* SSLv3_ApplicationRecord should be deliverd
*/
void Deliver(SSLv3_Interpreter* conn);
};
#endif

View file

@ -1,83 +0,0 @@
// $Id: SSLv3Automaton.cc 80 2004-07-14 20:15:50Z jason $
// ---SSLv3_Automaton----------------------------------------------------------
#include "SSLv3Automaton.h"
SSLv3_Automaton::SSLv3_Automaton(int arg_num_states, int num_trans,
int error_state)
{
num_states = arg_num_states;
states = new SSLv3_State*[num_states];
for ( int i = 0; i < num_states; ++i )
states[i] = new SSLv3_State(num_trans, error_state);
}
SSLv3_Automaton::~SSLv3_Automaton()
{
for ( int i = 0; i < num_states; ++i )
delete states[i];
delete [] states;
}
void SSLv3_Automaton::Describe(ODesc* d) const
{
d->Add("sslAutomaton");
}
void SSLv3_Automaton::setStartState(int state)
{
if ( state < num_states )
startState = state;
}
void SSLv3_Automaton::addTrans(int state1, int trans, int state2)
{
if ( state1 < num_states && state2 < num_states )
states[state1]->addTrans(trans, state2);
}
int SSLv3_Automaton::getNextState(int state, int trans)
{
if ( state < num_states )
return states[state]->getNextState(trans);
else
return 0;
}
int SSLv3_Automaton::getStartState()
{
if (startState >= 0)
return startState;
else
return -1;
}
// ---SSLv3_State--------------------------------------------------------------
SSLv3_State::SSLv3_State(int num_trans, int error_state)
{
this->num_trans = num_trans;
transitions = new int[num_trans];
for ( int i = 0; i < num_trans; ++i )
transitions[i] = error_state;
}
SSLv3_State::~SSLv3_State()
{
delete [] transitions;
}
void SSLv3_State::addTrans(int trans, int state)
{
if ( trans < num_trans )
transitions[trans] = state;
}
int SSLv3_State::getNextState(int trans)
{
if ( trans < num_trans )
return transitions[trans];
else
return 0;
}

View file

@ -1,107 +0,0 @@
// $Id: SSLv3Automaton.h 80 2004-07-14 20:15:50Z jason $
#ifndef ssl_v3_automaton_h
#define ssl_v3_automaton_h
#include "Obj.h"
#include "SSLDefines.h"
class SSLv3_State;
/** Class SSLv3_Automaton is there for holding the transitions of a state machine.
* The States are simply Integer Constants >= 0. Same for the transitions.
* The SSLv3_Automaton holds a pointer to an array of pointers to the
* states of the automaton. The array is indexed by the integer that
* represents the corresponding state.
* By default, the automaton is initialized with every transition leading to
* the error_state.
* By calling addTrans() (done in the SSLv3_Interpreter's BuildAutomaton()-method)
* the proper transitions for the SSL automaton are created.
* When calling getNextState(state, trans), you get the next state of the
* automaton, according to state and trans.
* */
class SSLv3_Automaton : public BroObj {
public:
/* The constructor initialises the states 2-dim. array
* (which's size depends on num_states and num_trans).
* By default, every transition from every state leads to the error_state.
* @param num_states how many states the automaton has
* @param num_trans how many different transitions the automaton has
* @param error_state which Integer the error_state has
*/
SSLv3_Automaton(int num_states, int num_trans, int error_state);
~SSLv3_Automaton();
void Describe(ODesc* d) const;
/* Sets the start state of the automaton.
* @param state the start state
*/
void setStartState(int state);
/* This method is used for building up the automaton and defining
* from which state you get to which state which what transition.
* @param state1 the state from which the transition starts
* @param trans the transition itself
* @param to which state the transition leads
*/
void addTrans(int state1, int trans, int state2);
/* Used for determinig into which state the automaton gets by using the
* given transition in the given state.
* @param state the state from which the transition starts
* @param trans the transition itself
* @return the state to which the transition leads
*/
int getNextState(int state, int trans);
int getStartState();
int OutRef()
{
return RefCnt();
}
protected:
int num_states; ///< how many states the automaton has
SSLv3_State** states; ///< the pointer to the array of pointers that holds the states
int startState; ///< the start state of the automaton
};
// ----------------------------------------------------------------------------
/** This class represents a state of the SSLv3_Automaton.
* It holds a pointer to an array of integers, which corresponds to the
* succeeding states of this state when "taking" a transition.
* The transition array is indexed by the integer-values corresponding to
* the transitions of the automaton.
* */
class SSLv3_State {
public:
/* The constructor initialises the state. By default, every transition
* of the automaton leads to the error_state.
* @param num_trans how many different transitions the automaton has
* @param error_state how many different transitions the automaton has
*/
SSLv3_State(int num_trans, int error_state);
~SSLv3_State();
/* This method is used for building up the automaton and is invoked by
* the SSLv3_Automaton's addTrans()-method. It defines the successing state
* of the automaton by taking the transition trans in this state.
* @param trans the transition,
* @param that leads to the state
*/
void addTrans(int trans, int state);
/* Used for determinig into which state the automaton gets by using the
* given transition in the this state.
* @param trans which transition is to be taken
* @return the resulting state of the automaton
*/
int getNextState(int trans);
protected:
int num_trans; ///< how many transitions the automaton has
int* transitions; ///< the array of successing states of this state by taking the transition that indexes this array
};
#endif

View file

@ -21,6 +21,7 @@ void SerializationFormat::StartRead(char* data, uint32 arg_len)
input = data;
input_len = arg_len;
input_pos = 0;
bytes_read = 0;
}
void SerializationFormat::EndRead()
@ -44,7 +45,6 @@ void SerializationFormat::StartWrite()
output_pos = 0;
bytes_written = 0;
bytes_read = 0;
}
uint32 SerializationFormat::EndWrite(char** data)

90
src/Syslog-binpac.cc Normal file
View file

@ -0,0 +1,90 @@
#include "Syslog-binpac.h"
#include "TCP_Reassembler.h"
Syslog_Analyzer_binpac::Syslog_Analyzer_binpac(Connection* conn)
: Analyzer(AnalyzerTag::SYSLOG_BINPAC, conn)
{
interp = new binpac::Syslog::Syslog_Conn(this);
did_session_done = 0;
//ADD_ANALYZER_TIMER(&Syslog_Analyzer_binpac::ExpireTimer,
// network_time + Syslog_session_timeout, 1, TIMER_Syslog_EXPIRE);
}
Syslog_Analyzer_binpac::~Syslog_Analyzer_binpac()
{
delete interp;
}
void Syslog_Analyzer_binpac::Done()
{
Analyzer::Done();
if ( ! did_session_done )
Event(udp_session_done);
}
void Syslog_Analyzer_binpac::DeliverPacket(int len, const u_char* data, bool orig, int seq, const IP_Hdr* ip, int caplen)
{
Analyzer::DeliverPacket(len, data, orig, seq, ip, caplen);
interp->NewData(orig, data, data + len);
}
//void Syslog_Analyzer_binpac::ExpireTimer(double t)
// {
// // The - 1.0 in the following is to allow 1 second for the
// // common case of a single request followed by a single reply,
// // so we don't needlessly set the timer twice in that case.
// if ( t - Conn()->LastTime() >= Syslog_session_timeout - 1.0 || terminating )
// {
// Event(connection_timeout);
// sessions->Remove(Conn());
// }
// else
// ADD_ANALYZER_TIMER(&Syslog_Analyzer_binpac::ExpireTimer,
// t + Syslog_session_timeout, 1, TIMER_Syslog_EXPIRE);
// }
//Syslog_TCP_Analyzer_binpac::Syslog_TCP_Analyzer_binpac(Connection* conn)
//: TCP_ApplicationAnalyzer(AnalyzerTag::Syslog_TCP_BINPAC, conn)
// {
// interp = new binpac::Syslog_on_TCP::Syslog_TCP_Conn(this);
// }
//Syslog_TCP_Analyzer_binpac::~Syslog_TCP_Analyzer_binpac()
// {
// delete interp;
// }
//void Syslog_TCP_Analyzer_binpac::Done()
// {
// TCP_ApplicationAnalyzer::Done();
//
// interp->FlowEOF(true);
// interp->FlowEOF(false);
// }
//void Syslog_TCP_Analyzer_binpac::EndpointEOF(TCP_Reassembler* endp)
// {
// TCP_ApplicationAnalyzer::EndpointEOF(endp);
// interp->FlowEOF(endp->IsOrig());
// }
//void Syslog_TCP_Analyzer_binpac::DeliverStream(int len, const u_char* data,
// bool orig)
// {
// TCP_ApplicationAnalyzer::DeliverStream(len, data, orig);
//
// assert(TCP());
//
// if ( TCP()->IsPartial() || TCP()->HadGap(orig) )
// // punt-on-partial or stop-on-gap.
// return;
//
// interp->NewData(orig, data, data + len);
// }
//void Syslog_TCP_Analyzer_binpac::Undelivered(int seq, int len, bool orig)
// {
// TCP_ApplicationAnalyzer::Undelivered(seq, len, orig);
// interp->NewGap(orig, len);
// }

55
src/Syslog-binpac.h Normal file
View file

@ -0,0 +1,55 @@
#ifndef Syslog_binpac_h
#define Syslog_binpac_h
#include "UDP.h"
#include "TCP.h"
#include "syslog_pac.h"
class Syslog_Analyzer_binpac : public Analyzer {
public:
Syslog_Analyzer_binpac(Connection* conn);
virtual ~Syslog_Analyzer_binpac();
virtual void Done();
virtual void DeliverPacket(int len, const u_char* data, bool orig,
int seq, const IP_Hdr* ip, int caplen);
static Analyzer* InstantiateAnalyzer(Connection* conn)
{ return new Syslog_Analyzer_binpac(conn); }
static bool Available()
{ return syslog_message; }
protected:
friend class AnalyzerTimer;
void ExpireTimer(double t);
int did_session_done;
binpac::Syslog::Syslog_Conn* interp;
};
// #include "Syslog_tcp_pac.h"
//
//class Syslog_TCP_Analyzer_binpac : public TCP_ApplicationAnalyzer {
//public:
// Syslog_TCP_Analyzer_binpac(Connection* conn);
// virtual ~Syslog_TCP_Analyzer_binpac();
//
// virtual void Done();
// virtual void DeliverStream(int len, const u_char* data, bool orig);
// virtual void Undelivered(int seq, int len, bool orig);
// virtual void EndpointEOF(TCP_Reassembler* endp);
//
// static Analyzer* InstantiateAnalyzer(Connection* conn)
// { return new Syslog_TCP_Analyzer_binpac(conn); }
//
// static bool Available()
// { return (Syslog_request || Syslog_full_request) && FLAGS_use_binpac; }
//
//protected:
// binpac::Syslog_on_TCP::Syslog_TCP_Conn* interp;
//};
//
#endif

View file

@ -2,6 +2,8 @@
//
// See the file "COPYING" in the main distribution directory for copyright.
#include <algorithm>
#include "NetVar.h"
#include "PIA.h"
#include "File.h"

View file

@ -1,5 +1,7 @@
// $Id: TCP_Reassembler.cc,v 1.1.2.8 2006/05/31 01:52:02 sommer Exp $
#include <algorithm>
#include "Analyzer.h"
#include "TCP_Reassembler.h"
#include "TCP.h"
@ -220,11 +222,9 @@ void TCP_Reassembler::Undelivered(int up_to_seq)
// handshakes, but Oh Well.
if ( content_gap &&
(BifConst::report_gaps_for_partial ||
(endpoint->state == TCP_ENDPOINT_ESTABLISHED &&
peer->state == TCP_ENDPOINT_ESTABLISHED )
)
)
(BifConst::report_gaps_for_partial ||
(endpoint->state == TCP_ENDPOINT_ESTABLISHED &&
peer->state == TCP_ENDPOINT_ESTABLISHED ) ) )
{
val_list* vl = new val_list;
vl->append(dst_analyzer->BuildConnVal());
@ -492,11 +492,9 @@ void TCP_Reassembler::AckReceived(int seq)
return;
bool test_active = ! skip_deliveries && ! tcp_analyzer->Skipping() &&
( BifConst::report_gaps_for_partial ||
(endp->state == TCP_ENDPOINT_ESTABLISHED &&
endp->peer->state == TCP_ENDPOINT_ESTABLISHED
)
);
( BifConst::report_gaps_for_partial ||
(endp->state == TCP_ENDPOINT_ESTABLISHED &&
endp->peer->state == TCP_ENDPOINT_ESTABLISHED ) );
int num_missing = TrimToSeq(seq);

View file

@ -848,8 +848,8 @@ void TypeDecl::DescribeReST(ODesc* d) const
}
CommentedTypeDecl::CommentedTypeDecl(BroType* t, const char* i,
attr_list* attrs, std::list<std::string>* cmnt_list)
: TypeDecl(t, i, attrs)
attr_list* attrs, bool in_record, std::list<std::string>* cmnt_list)
: TypeDecl(t, i, attrs, in_record)
{
comments = cmnt_list;
}
@ -1157,6 +1157,7 @@ void RecordType::DescribeFieldsReST(ODesc* d, bool func_args) const
for ( int i = 0; i < num_fields; ++i )
{
if ( i > 0 )
{
if ( func_args )
d->Add(", ");
else
@ -1164,6 +1165,7 @@ void RecordType::DescribeFieldsReST(ODesc* d, bool func_args) const
d->NL();
d->NL();
}
}
FieldDecl(i)->DescribeReST(d);
}

View file

@ -420,7 +420,7 @@ public:
class CommentedTypeDecl : public TypeDecl {
public:
CommentedTypeDecl(BroType* t, const char* i, attr_list* attrs = 0,
std::list<std::string>* cmnt_list = 0);
bool in_record = false, std::list<std::string>* cmnt_list = 0);
virtual ~CommentedTypeDecl();
void DescribeReST(ODesc* d) const;

View file

@ -2,6 +2,8 @@
//
// See the file "COPYING" in the main distribution directory for copyright.
#include <algorithm>
#include "config.h"
#include "Net.h"

View file

@ -2866,7 +2866,7 @@ RecordVal::RecordVal(RecordType* t) : MutableVal(t)
else if ( tag == TYPE_TABLE )
def = new TableVal(type->AsTableType(), a);
else if ( t->Tag() == TYPE_VECTOR )
else if ( tag == TYPE_VECTOR )
def = new VectorVal(type->AsVectorType());
}

View file

@ -242,15 +242,26 @@ void add_type(ID* id, BroType* t, attr_list* attr, int /* is_event */)
// t->GetTypeID() is true.
if ( generate_documentation )
{
if ( t->Tag() == TYPE_RECORD )
{
// Only "shallow" copy record types because we want to be able
// to see additions to the original type's list of fields
switch ( t->Tag() ) {
// Only "shallow" copy types that may contain records because
// we want to be able to see additions to the original record type's
// list of fields
case TYPE_RECORD:
tnew = new RecordType(t->AsRecordType()->Types());
}
else
{
break;
case TYPE_TABLE:
tnew = new TableType(t->AsTableType()->Indices(),
t->AsTableType()->YieldType());
break;
case TYPE_VECTOR:
tnew = new VectorType(t->AsVectorType()->YieldType());
break;
case TYPE_FUNC:
tnew = new FuncType(t->AsFuncType()->Args(),
t->AsFuncType()->YieldType(),
t->AsFuncType()->IsEvent());
break;
default:
SerializationFormat* form = new BinarySerializationFormat();
form->StartWrite();
CloneSerializer ss(form);
@ -267,7 +278,7 @@ void add_type(ID* id, BroType* t, attr_list* attr, int /* is_event */)
tnew = t->Unserialize(&uinfo);
delete [] data;
}
}
tnew->SetTypeID(copy_string(id->Name()));
}

View file

@ -1,265 +0,0 @@
// $Id: X509.cc 6724 2009-06-07 09:23:03Z vern $
#include <openssl/err.h>
#include "X509.h"
#include "config.h"
// ### NOTE: while d2i_X509 does not take a const u_char** pointer,
// here we assume d2i_X509 does not write to <data>, so it is safe to
// convert data to a non-const pointer. Could some X509 guru verify
// this?
X509* d2i_X509_(X509** px, const u_char** in, int len)
{
#ifdef OPENSSL_D2I_X509_USES_CONST_CHAR
return d2i_X509(px, in, len);
#else
return d2i_X509(px, (u_char**)in, len);
#endif
}
X509_STORE* X509_Cert::ctx = 0;
X509_LOOKUP* X509_Cert::lookup = 0;
X509_STORE_CTX X509_Cert::csc;
bool X509_Cert::bInited = false;
// TODO: Check if Key < 768 Bits => Weakness!
// FIXME: Merge verify and verifyChain.
void X509_Cert::sslCertificateEvent(Contents_SSL* e, X509* pCert)
{
EventHandlerPtr event = ssl_certificate;
if ( ! event )
return;
char tmp[256];
RecordVal* pX509Cert = new RecordVal(x509_type);
X509_NAME_oneline(X509_get_issuer_name(pCert), tmp, sizeof tmp);
pX509Cert->Assign(0, new StringVal(tmp));
X509_NAME_oneline(X509_get_subject_name(pCert), tmp, sizeof tmp);
pX509Cert->Assign(1, new StringVal(tmp));
pX509Cert->Assign(2, new AddrVal(e->Conn()->OrigAddr()));
val_list* vl = new val_list;
vl->append(e->BuildConnVal());
vl->append(pX509Cert);
vl->append(new Val(e->IsOrig(), TYPE_BOOL));
e->Conn()->ConnectionEvent(event, e, vl);
}
void X509_Cert::sslCertificateError(Contents_SSL* e, int error_numbe)
{
Val* err_str = new StringVal(X509_verify_cert_error_string(csc.error));
val_list* vl = new val_list;
vl->append(e->BuildConnVal());
vl->append(new Val(csc.error, TYPE_INT));
vl->append(err_str);
e->Conn()->ConnectionEvent(ssl_X509_error, e, vl);
}
int X509_Cert::init()
{
#if 0
OpenSSL_add_all_algorithms();
#endif
ctx = X509_STORE_new();
int flag = 0;
int ret = 0;
if ( x509_trusted_cert_path &&
x509_trusted_cert_path->AsString()->Len() > 0 )
{ // add the path(s) for the local CA's certificates
const BroString* pString = x509_trusted_cert_path->AsString();
lookup = X509_STORE_add_lookup(ctx, X509_LOOKUP_hash_dir());
if ( ! lookup )
{
fprintf(stderr, "X509_Cert::init(): initing lookup failed\n");
flag = 1;
}
int i = X509_LOOKUP_add_dir(lookup,
(const char*) pString->Bytes(),
X509_FILETYPE_PEM);
if ( ! i )
{
fprintf( stderr, "X509_Cert::init(): error adding lookup directory\n" );
ret = 0;
}
}
else
{
printf("X509: Using the default trusted cert path.\n");
X509_STORE_set_default_paths(ctx);
}
// Add crl functionality - will only add if defined and
// X509_STORE_add_lookup was successful.
if ( ! flag && x509_crl_file && x509_crl_file->AsString()->Len() > 0 )
{
const BroString* rString = x509_crl_file->AsString();
if ( X509_load_crl_file(lookup, (const char*) rString->Bytes(),
X509_FILETYPE_PEM) != 1 )
{
fprintf(stderr, "X509_Cert::init(): error reading CRL file\n");
ret = 1;
}
#if 0
// Note, openssl version must be > 0.9.7(a).
X509_STORE_set_flags(ctx,
X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
#endif
}
bInited = true;
return ret;
}
int X509_Cert::verify(Contents_SSL* e, const u_char* data, uint32 len)
{
if ( ! bInited )
init();
X509* pCert = d2i_X509_(NULL, &data, len);
if ( ! pCert )
{
// 5 = X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY
sslCertificateError(e, 5);
return -1;
}
sslCertificateEvent(e, pCert);
X509_STORE_CTX_init(&csc, ctx, pCert, 0);
X509_STORE_CTX_set_time(&csc, 0, (time_t) network_time);
int i = X509_verify_cert(&csc);
X509_STORE_CTX_cleanup(&csc);
int ret = 0;
int ext = X509_get_ext_count(pCert);
if ( ext > 0 )
{
TableVal* x509ex = new TableVal(x509_extension);
val_list* vl = new val_list;
char buf[256];
for ( int k = 0; k < ext; ++k )
{
X509_EXTENSION* ex = X509_get_ext(pCert, k);
ASN1_OBJECT* obj = X509_EXTENSION_get_object(ex);
i2t_ASN1_OBJECT(buf, sizeof(buf), obj);
Val* index = new Val(k+1, TYPE_COUNT);
Val* value = new StringVal(strlen(buf), buf);
x509ex->Assign(index, value);
Unref(index);
// later we can do critical extensions like:
// X509_EXTENSION_get_critical(ex);
}
vl->append(e->BuildConnVal());
vl->append(x509ex);
e->Conn()->ConnectionEvent(process_X509_extensions, e, vl);
}
if ( ! i )
{
sslCertificateError(e, csc.error);
ret = csc.error;
}
else
ret = 0;
delete pCert;
return ret;
}
int X509_Cert::verifyChain(Contents_SSL* e, const u_char* data, uint32 len)
{
if ( ! bInited )
init();
// Gets an ssl3x cert chain (could be one single cert, too,
// but in chain format).
// Init the stack.
STACK_OF(X509)* untrustedCerts = sk_X509_new_null();
if ( ! untrustedCerts )
{
// Internal error allocating stack of untrusted certs.
// 11 = X509_V_ERR_OUT_OF_MEM
sslCertificateError(e, 11);
return -1;
}
// NOT AGAIN!!!
// Extract certificates and put them into an OpenSSL Stack.
uint tempLength = 0;
int certCount = 0;
X509* pCert = 0; // base cert, this one is to be verified
while ( tempLength < len )
{
++certCount;
uint32 certLength =
uint32((data[tempLength + 0] << 16) |
data[tempLength + 1] << 8) |
data[tempLength + 2];
// Points to current cert.
const u_char* pCurrentCert = &data[tempLength+3];
X509* pTemp = d2i_X509_(0, &pCurrentCert, certLength);
if ( ! pTemp )
{ // error is somewhat of a misnomer
// 5 = X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY
sslCertificateError(e, 5);
//FIXME: free ptrs
return -1;
}
if ( certCount == 1 )
// The first certificate goes directly into the ctx.
pCert = pTemp;
else
// The remaining certificates (if any) are put into
// the list of untrusted certificates
sk_X509_push(untrustedCerts, pTemp);
tempLength += certLength + 3;
}
sslCertificateEvent(e, pCert);
X509_STORE_CTX_init(&csc, ctx, pCert, untrustedCerts);
X509_STORE_CTX_set_time(&csc, 0, (time_t) network_time);
int i = X509_verify_cert(&csc);
X509_STORE_CTX_cleanup(&csc);
//X509_STORE_CTX_free(&csc);
int ret = 0;
if ( ! i )
{
sslCertificateError(e, csc.error);
ret = csc.error;
}
else
ret = 0;
delete pCert;
// Free the stack, incuding. contents.
// FIXME: could this break Bro's memory tracking?
sk_X509_pop_free(untrustedCerts, X509_free);
return ret;
}

View file

@ -1,33 +0,0 @@
// $Id: X509.h 3526 2006-09-12 07:32:21Z vern $
#ifndef X509_H
#define X509_H
#include <sys/types.h>
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
#include "SSLProxy.h"
class X509_Cert {
public:
static X509_STORE* ctx;
static X509_LOOKUP* lookup;
static X509_STORE_CTX csc;
static bool bInited;
// Initializes the OpenSSL library, which is used for verify().
static int init();
// Wrapper for X.509 error event.
static void sslCertificateError(Contents_SSL* e, int error_numbe);
// Retrieves a DER-encoded X.509 certificate. Returns 0 on failure.
static int verify(Contents_SSL* e, const u_char* data, uint32 len);
static int verifyChain(Contents_SSL* e, const u_char* data, uint32 len);
// Wrapper for the ssl_certificate event.
static void sslCertificateEvent(Contents_SSL* e, X509* pCert);
};
#endif

View file

@ -2,6 +2,8 @@
//
// See the file "COPYING" in the main distribution directory for copyright.
#include <algorithm>
#include "config.h"
#include "XDR.h"
@ -33,7 +35,7 @@ uint64 extract_XDR_uint64(const u_char*& buf, int& len)
if ( ! buf || len < 8 )
{
buf = 0;
return 0.0;
return 0;
}
uint64 uhi = extract_XDR_uint32(buf, len);
@ -64,6 +66,9 @@ const u_char* extract_XDR_opaque(const u_char*& buf, int& len, int& n, int max_l
if (short_buf_ok)
n = std::min(n, len);
if ( short_buf_ok )
n = std::min(n, len);
if ( n < 0 || n > len || n > max_len )
{ // ### Should really flag this as a different sort of error.
buf = 0;
@ -79,7 +84,6 @@ const u_char* extract_XDR_opaque(const u_char*& buf, int& len, int& n, int max_l
return opaque;
}
const u_char* extract_XDR_opaque_fixed(const u_char*& buf, int& len, int n)
{
if ( ! buf )

View file

@ -486,15 +486,15 @@ function to_count%(str: string%): count
%{
const char* s = str->CheckString();
char* end_s;
uint64 u = (uint64) strtoll(s, &end_s, 10);
if ( s[0] == '\0' || end_s[0] != '\0' )
{
builtin_run_time("bad conversion to count", @ARG@[0]);
u = 0;
}
return new Val(u, TYPE_COUNT);
%}
@ -556,7 +556,7 @@ function to_addr%(ip: string%): addr
delete [] s;
return ret;
%}
function count_to_v4_addr%(ip: count%): addr
%{
if ( ip > 4294967295 )
@ -564,7 +564,7 @@ function count_to_v4_addr%(ip: count%): addr
builtin_run_time("conversion of non-IPv4 count to addr", @ARG@[0]);
return new AddrVal(uint32(0));
}
return new AddrVal(htonl(uint32(ip)));
%}
@ -1348,7 +1348,7 @@ function fmt_ftp_port%(a: addr, p: port%): string
function decode_netbios_name%(name: string%): string
%{
char buf[16];
char result[32];
char result[16];
const u_char* s = name->Bytes();
int i, j;
@ -1370,7 +1370,7 @@ function decode_netbios_name%(name: string%): string
break;
}
return new StringVal(result);
return new StringVal(i, result);
%}
function decode_netbios_name_type%(name: string%): count
@ -3106,7 +3106,13 @@ function lookup_location%(a: addr%) : geo_location
}
#else
builtin_run_time("Bro was not configured for GeoIP support");
static int missing_geoip_reported = 0;
if ( ! missing_geoip_reported )
{
builtin_run_time("Bro was not configured for GeoIP support");
missing_geoip_reported = 1;
}
#endif
// We can get here even if we have GeoIP support if we weren't
@ -3164,7 +3170,13 @@ function lookup_asn%(a: addr%) : count
return new Val(atoi(gir+2), TYPE_COUNT);
}
#else
builtin_run_time("Bro was not configured for GeoIP ASN support");
static int missing_geoip_reported = 0;
if ( ! missing_geoip_reported )
{
builtin_run_time("Bro was not configured for GeoIP ASN support");
missing_geoip_reported = 1;
}
#endif
// We can get here even if we have GeoIP support, if we weren't
@ -3328,21 +3340,146 @@ function entropy_test_finish%(index: any%): entropy_test_result
return ent_result;
%}
function bro_has_ipv6%(%) : bool
%{
#ifdef BROv6
return new Val(1, TYPE_BOOL);
#else
return new Val(0, TYPE_BOOL);
#endif
%}
function unique_id%(prefix: string%) : string
%{
char tmp[20];
uint64 uid = calculate_unique_id();
return new StringVal(uitoa_n(uid, tmp, sizeof(tmp), 62, prefix->CheckString()));
%}
%%{
#include <openssl/x509.h>
#include <openssl/asn1.h>
#include <openssl/x509_vfy.h>
// This is the indexed map of X509 certificate stores.
static map<BroString, X509_STORE*> x509_stores;
// ### NOTE: while d2i_X509 does not take a const u_char** pointer,
// here we assume d2i_X509 does not write to <data>, so it is safe to
// convert data to a non-const pointer. Could some X509 guru verify
// this?
X509* d2i_X509_(X509** px, const u_char** in, int len)
{
#ifdef OPENSSL_D2I_X509_USES_CONST_CHAR
return d2i_X509(px, in, len);
#else
return d2i_X509(px, (u_char**)in, len);
#endif
}
%%}
function x509_verify%(der_cert: string, cert_stack: string_vec, root_certs: table_string_of_string%): count
%{
X509_STORE* ctx = 0;
int i = 0;
// If this certificate store was built previously, just reuse the old one.
BroString* s = convert_index_to_string(root_certs);
if ( x509_stores.count(*s) > 0 )
ctx = x509_stores[*s];
if ( ! ctx ) // lookup to see if we have this one built already!
{
ctx = X509_STORE_new();
TableVal* root_certs2 = root_certs->AsTableVal();
ListVal* idxs = root_certs2->ConvertToPureList();
// Build the validation store
for ( i = 0; i < idxs->Length(); ++i )
{
Val* key = idxs->Index(i);
StringVal *sv = root_certs2->Lookup(key)->AsStringVal();
const uint8* data = sv->Bytes();
X509* x = d2i_X509_(NULL, &data, sv->Len());
if ( ! x )
{
builtin_run_time(fmt("Root CA error: %s", ERR_error_string(ERR_peek_last_error(),NULL)));
return new Val((uint64) ERR_get_error(), TYPE_COUNT);
}
X509_STORE_add_cert(ctx, x);
}
// Save the newly constructed certificate store into the cacheing map.
x509_stores[*s] = ctx;
}
STACK_OF(X509)* untrusted_certs = sk_X509_new_null();
if ( ! untrusted_certs )
{
builtin_run_time(fmt("Untrusted certificate stack initialization error: %s", ERR_error_string(ERR_peek_last_error(),NULL)));
return new Val((uint64) ERR_get_error(), TYPE_COUNT);
}
VectorVal *cert_stack_vec = cert_stack->AsVectorVal();
for ( i = 0; i < (int) cert_stack_vec->Size(); ++i )
{
StringVal *sv = cert_stack_vec->Lookup(i)->AsStringVal();
const uint8 *data = sv->Bytes();
X509* x = d2i_X509_(NULL, &data, sv->Len());
if ( ! x )
{
builtin_run_time(fmt("Untrusted certificate stack creation error: %s", ERR_error_string(ERR_peek_last_error(),NULL)));
return new Val((uint64) ERR_get_error(), TYPE_COUNT);
}
sk_X509_push(untrusted_certs, x);
}
const uint8 *cert_data = der_cert->Bytes();
X509_STORE_CTX csc;
X509* cert = d2i_X509_(NULL, &cert_data, der_cert->Len());
if ( ! cert )
{
builtin_run_time(fmt("Certificate error: %s", ERR_error_string(ERR_peek_last_error(),NULL)));
return new Val((uint64) ERR_get_error(), TYPE_COUNT);
}
X509_STORE_CTX_init(&csc, ctx, cert, untrusted_certs);
X509_STORE_CTX_set_time(&csc, 0, (time_t) network_time);
int result = X509_verify_cert(&csc);
X509_STORE_CTX_cleanup(&csc);
if ( untrusted_certs )
sk_X509_pop_free(untrusted_certs, X509_free);
return new Val((uint64) csc.error, TYPE_COUNT);
%}
function x509_err2str%(err_num: count%): string
%{
return new StringVal(X509_verify_cert_error_string(err_num));
%}
function NFS3::mode2string%(mode: count%): string
%{
char str[12];
char *p = str;
/* usr */
if (mode & S_IRUSR)
*p++ = 'r';
else
*p++ = '-';
if (mode & S_IWUSR)
*p++ = 'w';
else
*p++ = '-';
switch (mode & (S_IXUSR | S_ISUID)) {
case 0:
*p++ = '-';
@ -3357,6 +3494,7 @@ function NFS3::mode2string%(mode: count%): string
*p++ = 's';
break;
}
/* group */
if (mode & S_IRGRP)
*p++ = 'r';
@ -3366,6 +3504,7 @@ function NFS3::mode2string%(mode: count%): string
*p++ = 'w';
else
*p++ = '-';
switch (mode & (S_IXGRP | S_ISGID)) {
case 0:
*p++ = '-';
@ -3380,6 +3519,7 @@ function NFS3::mode2string%(mode: count%): string
*p++ = 's';
break;
}
/* other */
if (mode & S_IROTH)
*p++ = 'r';
@ -3389,6 +3529,7 @@ function NFS3::mode2string%(mode: count%): string
*p++ = 'w';
else
*p++ = '-';
switch (mode & (S_IXOTH | S_ISVTX)) {
case 0:
*p++ = '-';
@ -3403,6 +3544,7 @@ function NFS3::mode2string%(mode: count%): string
*p++ = 't';
break;
}
*p = '\0';
return new StringVal(str);

View file

@ -1,6 +1,6 @@
# $Id: const.bif 3929 2007-01-14 00:37:59Z vern $
# Documentation and default values for these are located in policy/bro.init
# Documentation and default values for these are located in policy/bro.init.
const ignore_keep_alive_rexmit: bool;
const skip_http_data: bool;
@ -8,7 +8,6 @@ const parse_udp_tunnels: bool;
const use_conn_size_analyzer: bool;
const report_gaps_for_partial: bool;
# NFS analyzer settings. See bro.init for documentation
const NFS3::return_data: bool;
const NFS3::return_data_max: count;
const NFS3::return_data_first_only: bool;

View file

@ -52,6 +52,7 @@ event icmp_echo_request%(c: connection, icmp: icmp_conn, id: count, seq: count,
event icmp_echo_reply%(c: connection, icmp: icmp_conn, id: count, seq: count, payload: string%);
event icmp_unreachable%(c: connection, icmp: icmp_conn, code: count, context: icmp_context%);
event icmp_time_exceeded%(c: connection, icmp: icmp_conn, code: count, context: icmp_context%);
event icmp_redirect%(c: connection, icmp: icmp_conn, a: addr%);
event net_stats_update%(t: time, ns: net_stats%);
event conn_stats%(c: connection, os: endpoint_stats, rs: endpoint_stats%);
event conn_weird%(name: string, c: connection%);
@ -156,6 +157,13 @@ event mime_all_data%(c: connection, length: count, data: string%);
event mime_event%(c: connection, event_type: string, detail: string%);
event mime_content_hash%(c: connection, content_len: count, hash_value: string%);
# Generated for each RPC request / reply *pair* (if there is no reply, the event
# will be generated on timeout).
event rpc_dialogue%(c: connection, prog: count, ver: count, proc: count, status: rpc_status, start_time: time, call_len: count, reply_len: count%);
# Generated for each (correctly formed) RPC_CALL message received.
event rpc_call%(c: connection, xid: count, prog: count, ver: count, proc: count, call_len: count%);
# Generated for each (correctly formed) RPC_REPLY message received.
event rpc_reply%(c: connection, xid: count, status: rpc_status, reply_len: count%);
# Generated for each RPC request / reply *pair* (if there is no reply, the event
# will be generated on timeout).
@ -179,12 +187,12 @@ event pm_attempt_dump%(r: connection, status: rpc_status%);
event pm_attempt_callit%(r: connection, status: rpc_status, call: pm_callit_request%);
event pm_bad_port%(r: connection, bad_p: count%);
# Event for the NFS analyzer. An event is generated if we have received a
# Call (request) / Response pair (or in case of a time out).
# info$rpc_stat and info$nfs_stat show whether the request was successful.
# The request record is always filled out, however, the reply record(s) might not be set or
# might only be partially set. See the comments for the record types in
# bro.init to see which reply fields are set when.
# Events for the NFS analyzer. An event is generated if we have received a
# Call (request) / Response pair (or in case of a time out). info$rpc_stat and
# info$nfs_stat show whether the request was successful. The request record is
# always filled out, however, the reply record(s) might not be set or might only
# be partially set. See the comments for the record types in bro.init to see which
# reply fields are set when.
event nfs_proc_null%(c: connection, info: NFS3::info_t%);
event nfs_proc_not_implemented%(c: connection, info: NFS3::info_t, proc: NFS3::proc_t%);
@ -199,7 +207,7 @@ event nfs_proc_remove%(c: connection, info: NFS3::info_t, req: NFS3::diropargs_t
event nfs_proc_rmdir%(c: connection, info: NFS3::info_t, req: NFS3::diropargs_t, rep: NFS3::delobj_reply_t%);
event nfs_proc_readdir%(c: connection, info: NFS3::info_t, req: NFS3::readdirargs_t, rep: NFS3::readdir_reply_t%);
# Generated for each NFS reply message we receive. Just gives the status.
# Generated for each NFS reply message we receive, giving just gives the status.
event nfs_reply_status%(n: connection, info: NFS3::info_t%);
event ntp_message%(u: connection, msg: ntp_msg, excess: string%);
@ -287,19 +295,15 @@ event http_stats%(c: connection, stats: http_stats_rec%);
event ssh_client_version%(c: connection, version: string%);
event ssh_server_version%(c: connection, version: string%);
event ssl_certificate_seen%(c: connection, is_server: bool%);
event ssl_certificate%(c: connection, cert: X509, is_server: bool%);
event ssl_conn_attempt%(c: connection, version: count, ciphers: cipher_suites_list%);
event ssl_conn_server_reply%(c: connection, version: count, ciphers: cipher_suites_list%);
event ssl_conn_established%(c: connection, version: count, cipher_suite: count%);
event ssl_conn_reused%(c: connection, session_id: SSL_sessionID%);
event ssl_conn_alert%(c: connection, version: count, level: count,
description: count%);
event ssl_conn_weak%(name: string, c: connection%);
event ssl_client_hello%(c: connection, version: count, possible_ts: time, session_id: string, ciphers: count_set%);
event ssl_server_hello%(c: connection, version: count, possible_ts: time, session_id: string, cipher: count, comp_method: count%);
event ssl_extension%(c: connection, code: count, val: string%);
event ssl_established%(c: connection%);
event ssl_alert%(c: connection, level: count, desc: count%);
event ssl_session_insertion%(c: connection, id: SSL_sessionID%);
event process_X509_extensions%(c: connection, ex: X509_extension%);
event ssl_X509_error%(c: connection, err: int, err_string: string%);
event x509_certificate%(c: connection, cert: X509, is_server: bool, chain_idx: count, chain_len: count, der_cert: string%);
event x509_extension%(c: connection, data: string%);
event x509_error%(c: connection, err: count%);
event stp_create_endp%(c: connection, e: int, is_orig: bool%);
event stp_resume_endp%(e: int%);
@ -410,6 +414,8 @@ event irc_password_message%(c: connection, password: string%);
event file_transferred%(c: connection, prefix: string, descr: string, mime_type: string%);
event file_virus%(c: connection, virname: string%);
event syslog_message%(c: connection, facility: count, severity: count, msg: string%);
event signature_match%(state: signature_state, msg: string, data: string%);
# Generated if a handler finds an identification of the software

View file

@ -740,6 +740,20 @@ int main(int argc, char** argv)
}
#endif
if ( generate_documentation )
{
std::list<BroDoc*>::iterator it;
for ( it = docs_generated.begin(); it != docs_generated.end(); ++it )
(*it)->WriteDocFile();
for ( it = docs_generated.begin(); it != docs_generated.end(); ++it )
delete *it;
terminate_bro();
return 0;
}
if ( nerr > 0 )
{
delete dns_mgr;
@ -975,20 +989,6 @@ int main(int argc, char** argv)
mgr.Drain();
if ( generate_documentation )
{
std::list<BroDoc*>::iterator it;
for ( it = docs_generated.begin(); it != docs_generated.end(); ++it )
(*it)->WriteDocFile();
for ( it = docs_generated.begin(); it != docs_generated.end(); ++it )
delete *it;
terminate_bro();
return 0;
}
have_pending_timers = ! reading_traces && timer_mgr->Size() > 0;
if ( io_sources.Size() > 0 || have_pending_timers )

View file

@ -936,6 +936,7 @@ type_decl:
if ( generate_documentation )
{
// TypeDecl ctor deletes the attr list, so make a copy
attr_list* a = $5;
attr_list* a_copy = 0;
@ -947,7 +948,7 @@ type_decl:
}
last_fake_type_decl = new CommentedTypeDecl(
$4, $2, a_copy, concat_opt_docs($1, $7));
$4, $2, a_copy, (in_record > 0), concat_opt_docs($1, $7));
}
$$ = new TypeDecl($4, $2, $5, (in_record > 0));
@ -1091,8 +1092,10 @@ decl:
new RecordType(fake_type_decl_list);
ID* fake = create_dummy_id($3, fake_record);
fake_type_decl_list = 0;
current_reST_doc->AddRedef(
new BroDocObj(fake, reST_doc_comments, true));
BroDocObj* o =
new BroDocObj(fake, reST_doc_comments, true);
o->SetRole(true);
current_reST_doc->AddRedef(o);
}
else
{

View file

@ -4,6 +4,11 @@
#include <errno.h>
#include <stack>
#include <list>
#include <string>
#include <algorithm>
#include "input.h"
#include "util.h"
#include "Scope.h"
@ -19,11 +24,6 @@
#include "Analyzer.h"
#include "AnalyzerTags.h"
#include <stack>
#include <list>
#include <string>
#include <algorithm>
extern YYLTYPE yylloc; // holds start line and column of token
extern int print_loaded_scripts;
extern int generate_documentation;
@ -558,7 +558,7 @@ static int load_files_with_prefix(const char* orig_file)
else
strcpy(new_filename, file);
f = search_for_file(new_filename, "bro", &full_filename);
f = search_for_file(new_filename, "bro", &full_filename, true);
delete [] new_filename;
}

View file

@ -1,5 +1,3 @@
# $Id:$
# Analyzer for SSL (Bro-specific part).
%extern{
@ -11,8 +9,7 @@
#include "util.h"
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
#include "X509.h"
#include <openssl/asn1.h>
%}
@ -46,22 +43,20 @@
%}
function to_table_val(data : uint8[]) : TableVal
function to_string_val(data : uint8[]) : StringVal
%{
TableVal* tv = new TableVal(SSL_sessionID);
for ( unsigned int i = 0; i < data->size(); i += 4 )
{
uint32 temp = 0;
for ( unsigned int j = 0; j < 4; ++j )
if ( i + j < data->size() )
temp |= (*data)[i + j] << (24 - 8 * j);
assert(data->size() <= 32);
Val* idx = new Val(i / 4, TYPE_COUNT);
tv->Assign(idx, new Val((*data)[i], TYPE_COUNT));
Unref(idx);
char tmp[32];
memset(tmp, 0, sizeof(tmp));
if ( data )
{
for ( unsigned int i = data->size(); i > 0; --i )
tmp[i-1] = (*data)[i-1];
}
return tv;
return new StringVal(32, tmp);
%}
function version_ok(vers : uint16) : bool
@ -83,7 +78,7 @@ function convert_ciphers_uint24(ciph : uint24[]) : int[]
vector<int>* newciph = new vector<int>();
std::transform(ciph->begin(), ciph->end(),
std::back_inserter(*newciph), to_int());
std::back_inserter(*newciph), to_int());
return newciph;
%}
@ -93,7 +88,7 @@ function convert_ciphers_uint16(ciph : uint16[]) : int[]
vector<int>* newciph = new vector<int>();
std::copy(ciph->begin(), ciph->end(),
std::back_inserter(*newciph));
std::back_inserter(*newciph));
return newciph;
%}
@ -101,23 +96,10 @@ function convert_ciphers_uint16(ciph : uint16[]) : int[]
refine analyzer SSLAnalyzer += {
%member{
Analyzer* bro_analyzer_;
vector<uint8>* client_session_id_;
vector<int>* advertised_ciphers_;
int version_;
int cipher_;
%}
%init{
bro_analyzer_ = 0;
client_session_id_ = 0;
advertised_ciphers_ = new vector<int>;
version_ = -1;
cipher_ = -1;
if ( ! X509_Cert::bInited )
X509_Cert::init();
%}
%eof{
@ -128,11 +110,6 @@ refine analyzer SSLAnalyzer += {
%}
%cleanup{
delete client_session_id_;
client_session_id_ = 0;
delete advertised_ciphers_;
advertised_ciphers_ = 0;
%}
function bro_analyzer() : Analyzer
@ -145,282 +122,203 @@ refine analyzer SSLAnalyzer += {
bro_analyzer_ = a;
%}
function check_cipher(cipher : int) : bool
%{
if ( ! ssl_compare_cipherspecs )
return true;
if ( std::find(advertised_ciphers_->begin(),
advertised_ciphers_->end(), cipher) ==
advertised_ciphers_->end() )
{
bro_analyzer()->ProtocolViolation("chosen cipher not advertised before");
return false;
}
return true;
%}
function certificate_error(err_num : int) : void
%{
StringVal* err_str =
new StringVal(X509_verify_cert_error_string(err_num));
BifEvent::generate_ssl_X509_error(bro_analyzer_, bro_analyzer_->Conn(),
err_num, err_str);
%}
function proc_change_cipher_spec(msg : ChangeCipherSpec) : bool
function proc_change_cipher_spec(rec: SSLRecord) : bool
%{
if ( state_ == STATE_TRACK_LOST )
bro_analyzer()->ProtocolViolation(fmt("unexpected ChangeCipherSpec from %s at state %s",
orig_label(current_record_is_orig_).c_str(),
orig_label(${rec.is_orig}).c_str(),
state_label(old_state_).c_str()));
return true;
%}
function proc_application_data(msg : ApplicationData) : bool
function proc_application_data(rec: SSLRecord) : bool
%{
if ( state_ != STATE_CONN_ESTABLISHED )
bro_analyzer()->ProtocolViolation(fmt("unexpected ApplicationData from %s at state %s",
orig_label(current_record_is_orig_).c_str(),
orig_label(${rec.is_orig}).c_str(),
state_label(old_state_).c_str()));
return true;
%}
function proc_alert(level : int, description : int) : bool
function proc_alert(rec: SSLRecord, level : int, desc : int) : bool
%{
BifEvent::generate_ssl_conn_alert(bro_analyzer_, bro_analyzer_->Conn(),
current_record_version_, level,
description);
BifEvent::generate_ssl_alert(bro_analyzer_, bro_analyzer_->Conn(),
level, desc);
return true;
%}
function proc_client_hello(version : uint16, session_id : uint8[],
csuits : int[]) : bool
function proc_client_hello(rec: SSLRecord,
version : uint16, ts : double,
session_id : uint8[],
cipher_suites : int[]) : bool
%{
if ( state_ == STATE_TRACK_LOST )
bro_analyzer()->ProtocolViolation(fmt("unexpected client hello message from %s in state %s",
orig_label(current_record_is_orig_).c_str(),
orig_label(${rec.is_orig}).c_str(),
state_label(old_state_).c_str()));
if ( ! version_ok(version) )
bro_analyzer()->ProtocolViolation(fmt("unsupported client SSL version 0x%04x", version));
delete client_session_id_;
client_session_id_ = new vector<uint8>(*session_id);
TableVal* cipher_table = new TableVal(cipher_suites_list);
for ( unsigned int i = 0; i < csuits->size(); ++i )
if ( ssl_client_hello )
{
Val* ciph = new Val((*csuits)[i], TYPE_COUNT);
cipher_table->Assign(ciph, 0);
Unref(ciph);
}
BroType* count_t = base_type(TYPE_COUNT);
TypeList* set_index = new TypeList(count_t);
set_index->Append(count_t);
SetType* s = new SetType(set_index, 0);
TableVal* cipher_set = new TableVal(s);
for ( unsigned int i = 0; i < cipher_suites->size(); ++i )
{
Val* ciph = new Val((*cipher_suites)[i], TYPE_COUNT);
cipher_set->Assign(ciph, 0);
Unref(ciph);
}
BifEvent::generate_ssl_conn_attempt(bro_analyzer_, bro_analyzer_->Conn(),
version, cipher_table);
if ( ssl_compare_cipherspecs )
{
delete advertised_ciphers_;
advertised_ciphers_ = csuits;
BifEvent::generate_ssl_client_hello(bro_analyzer_, bro_analyzer_->Conn(),
version, ts,
to_string_val(session_id),
cipher_set);
}
else
delete csuits;
return true;
%}
function proc_server_hello(version : uint16, session_id : uint8[],
ciphers : int[], v2_sess_hit : int) : bool
function proc_server_hello(rec: SSLRecord,
version : uint16, ts : double,
session_id : uint8[],
cipher_suite : uint16,
comp_method : uint8) : bool
%{
if ( state_ == STATE_TRACK_LOST )
bro_analyzer()->ProtocolViolation(fmt("unexpected server hello message from %s in state %s",
orig_label(current_record_is_orig_).c_str(),
orig_label(${rec.is_orig}).c_str(),
state_label(old_state_).c_str()));
if ( ! version_ok(version) )
bro_analyzer()->ProtocolViolation(fmt("unsupported server SSL version 0x%04x", version));
version_ = version;
TableVal* chosen_ciphers = new TableVal(cipher_suites_list);
for ( unsigned int i = 0; i < ciphers->size(); ++i )
if ( ssl_server_hello )
{
Val* ciph = new Val((*ciphers)[i], TYPE_COUNT);
chosen_ciphers->Assign(ciph, 0);
Unref(ciph);
}
BifEvent::generate_ssl_conn_server_reply(bro_analyzer_,
bro_analyzer_->Conn(),
version_, chosen_ciphers);
if ( v2_sess_hit < 0 )
{ // this is SSLv3
cipher_ = (*ciphers)[0];
check_cipher(cipher_);
TableVal* tv = to_table_val(session_id);
if ( client_session_id_ &&
*client_session_id_ == *session_id )
BifEvent::generate_ssl_conn_reused(bro_analyzer_,
bro_analyzer_->Conn(), tv);
else
BifEvent::generate_ssl_session_insertion(bro_analyzer_,
bro_analyzer_->Conn(), tv);
delete ciphers;
}
else if ( v2_sess_hit > 0 )
{ // this is SSLv2 and a session hit
if ( client_session_id_ )
{
TableVal* tv = to_table_val(client_session_id_);
BifEvent::generate_ssl_conn_reused(bro_analyzer_,
bro_analyzer_->Conn(), tv);
}
// We don't know the chosen cipher, as there is
// no session storage.
BifEvent::generate_ssl_conn_established(bro_analyzer_,
BifEvent::generate_ssl_server_hello(bro_analyzer_,
bro_analyzer_->Conn(),
version_, 0xffffffff);
delete ciphers;
}
else
{
// This is SSLv2; we have to set advertised
// ciphers to server ciphers.
if ( ssl_compare_cipherspecs )
{
delete advertised_ciphers_;
advertised_ciphers_ = ciphers;
}
version, ts,
to_string_val(session_id),
cipher_suite, comp_method);
}
bro_analyzer()->ProtocolConfirmation();
return true;
%}
function proc_certificate(certificates : bytestring[]) : bool
function proc_ssl_extension(type: int, data: bytestring) : bool
%{
if ( ssl_extension )
BifEvent::generate_ssl_extension(bro_analyzer_,
bro_analyzer_->Conn(), type,
new StringVal(data.length(), (const char*) data.data()));
return true;
%}
function proc_certificate(rec: SSLRecord, certificates : bytestring[]) : bool
%{
if ( state_ == STATE_TRACK_LOST )
bro_analyzer()->ProtocolViolation(fmt("unexpected certificate message from %s in state %s",
orig_label(current_record_is_orig_).c_str(),
orig_label(${rec.is_orig}).c_str(),
state_label(old_state_).c_str()));
if ( ! ssl_analyze_certificates )
return true;
if ( certificates->size() == 0 )
return true;
BifEvent::generate_ssl_certificate_seen(bro_analyzer_,
bro_analyzer_->Conn(),
! current_record_is_orig_);
STACK_OF(X509)* untrusted_certs = 0;
const bytestring& cert = (*certificates)[0];
const uint8* data = cert.data();
X509* pCert = d2i_X509_binpac(NULL, &data, cert.length());
if ( ! pCert )
if ( x509_certificate )
{
// X509_V_UNABLE_TO_DECRYPT_CERT_SIGNATURE
certificate_error(4);
return false;
}
RecordVal* pX509Cert = new RecordVal(x509_type);
char tmp[256];
X509_NAME_oneline(X509_get_issuer_name(pCert), tmp, sizeof tmp);
pX509Cert->Assign(0, new StringVal(tmp));
X509_NAME_oneline(X509_get_subject_name(pCert), tmp, sizeof tmp);
pX509Cert->Assign(1, new StringVal(tmp));
pX509Cert->Assign(2, new AddrVal(bro_analyzer_->Conn()->OrigAddr()));
BifEvent::generate_ssl_certificate(bro_analyzer_, bro_analyzer_->Conn(),
pX509Cert, current_record_is_orig_);
if ( X509_get_ext_count(pCert) > 0 )
{
TableVal* x509ex = new TableVal(x509_extension);
for ( int k = 0; k < X509_get_ext_count(pCert); ++k )
X509* pCert = 0;
for ( unsigned int i = 0; i < certificates->size(); ++i )
{
X509_EXTENSION* ex = X509_get_ext(pCert, k);
ASN1_OBJECT* obj = X509_EXTENSION_get_object(ex);
char buf[256];
i2t_ASN1_OBJECT(buf, sizeof(buf), obj);
Val* index = new Val(k+1, TYPE_COUNT);
Val* value = new StringVal(strlen(buf), buf);
x509ex->Assign(index, value);
Unref(index);
}
BifEvent::generate_process_X509_extensions(bro_analyzer_,
bro_analyzer_->Conn(), x509ex);
}
if ( ssl_verify_certificates )
{
STACK_OF(X509)* untrusted_certs = 0;
if ( certificates->size() > 1 )
{
untrusted_certs = sk_X509_new_null();
if ( ! untrusted_certs )
const bytestring& cert = (*certificates)[i];
const uint8* data = cert.data();
X509* pTemp = d2i_X509_binpac(NULL, &data, cert.length());
if ( ! pTemp )
{
// X509_V_ERR_OUT_OF_MEM;
certificate_error(17);
BifEvent::generate_x509_error(bro_analyzer_, bro_analyzer_->Conn(),
ERR_get_error());
return false;
}
for ( unsigned int i = 1;
i < certificates->size(); ++i )
{
const bytestring& temp =
(*certificates)[i];
const uint8* tdata = temp.data();
X509* pTemp = d2i_X509_binpac(NULL,
&tdata, temp.length());
if ( ! pTemp )
{
// X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT
certificate_error(2);
return false;
}
RecordVal* pX509Cert = new RecordVal(x509_type);
char tmp[256];
BIO *bio = BIO_new(BIO_s_mem());
sk_X509_push(untrusted_certs, pTemp);
pX509Cert->Assign(0, new Val((uint64) X509_get_version(pTemp), TYPE_COUNT));
i2a_ASN1_INTEGER(bio, X509_get_serialNumber(pTemp));
int len = BIO_read(bio, &(*tmp), sizeof tmp);
pX509Cert->Assign(1, new StringVal(len, tmp));
X509_NAME_print_ex(bio, X509_get_subject_name(pTemp), 0, XN_FLAG_RFC2253);
len = BIO_gets(bio, &(*tmp), sizeof tmp);
pX509Cert->Assign(2, new StringVal(len, tmp));
X509_NAME_print_ex(bio, X509_get_issuer_name(pTemp), 0, XN_FLAG_RFC2253);
len = BIO_gets(bio, &(*tmp), sizeof tmp);
pX509Cert->Assign(3, new StringVal(len, tmp));
BIO_free(bio);
pX509Cert->Assign(4, new Val(get_time_from_asn1(X509_get_notBefore(pTemp)), TYPE_TIME));
pX509Cert->Assign(5, new Val(get_time_from_asn1(X509_get_notAfter(pTemp)), TYPE_TIME));
StringVal* der_cert = new StringVal(cert.length(), (const char*) cert.data());
BifEvent::generate_x509_certificate(bro_analyzer_, bro_analyzer_->Conn(),
pX509Cert,
! ${rec.is_orig},
i, certificates->size(),
der_cert);
// Are there any X509 extensions?
if ( x509_extension && X509_get_ext_count(pTemp) > 0 )
{
BroType* count_t = base_type(TYPE_COUNT);
TypeList* set_index = new TypeList(count_t);
set_index->Append(count_t);
SetType* s = new SetType(set_index, 0);
TableVal* x509ex = new TableVal(s);
int num_ext = X509_get_ext_count(pTemp);
for ( int k = 0; k < num_ext; ++k )
{
char *pBuffer = 0;
int length = 0;
X509_EXTENSION* ex = X509_get_ext(pTemp, k);
if (ex)
{
ASN1_STRING *pString = X509_EXTENSION_get_data(ex);
length = ASN1_STRING_to_UTF8((unsigned char**)&pBuffer, pString);
//i2t_ASN1_OBJECT(&pBuffer, length, obj)
// -1 indicates an error.
if ( length < 0 )
continue;
StringVal* value = new StringVal(length, pBuffer);
BifEvent::generate_x509_extension(bro_analyzer_,
bro_analyzer_->Conn(), value);
OPENSSL_free(pBuffer);
}
}
}
}
X509_STORE_CTX csc;
X509_STORE_CTX_init(&csc, X509_Cert::ctx,
pCert, untrusted_certs);
X509_STORE_CTX_set_time(&csc, 0, time_t(network_time()));
if (! X509_verify_cert(&csc))
certificate_error(csc.error);
X509_STORE_CTX_cleanup(&csc);
sk_X509_pop_free(untrusted_certs, X509_free);
}
X509_free(pCert);
return true;
return true;
%}
function proc_v2_certificate(cert : bytestring) : bool
function proc_v2_certificate(rec: SSLRecord, cert : bytestring) : bool
%{
vector<bytestring>* cert_list = new vector<bytestring>(1,cert);
bool ret = proc_certificate(cert_list);
bool ret = proc_certificate(rec, cert_list);
delete cert_list;
return ret;
%}
function proc_v3_certificate(cl : CertificateList) : bool
function proc_v3_certificate(rec: SSLRecord, cl : CertificateList) : bool
%{
vector<X509Certificate*>* certs = cl->val();
vector<bytestring>* cert_list = new vector<bytestring>();
@ -428,65 +326,61 @@ refine analyzer SSLAnalyzer += {
std::transform(certs->begin(), certs->end(),
std::back_inserter(*cert_list), extract_certs());
bool ret = proc_certificate(cert_list);
bool ret = proc_certificate(rec, cert_list);
delete cert_list;
return ret;
%}
function proc_v2_client_master_key(cipher : int) : bool
function proc_v2_client_master_key(rec: SSLRecord, cipher_kind: int) : bool
%{
if ( state_ == STATE_TRACK_LOST )
bro_analyzer()->ProtocolViolation(fmt("unexpected v2 client master key message from %s in state %s",
orig_label(current_record_is_orig_).c_str(),
orig_label(${rec.is_orig}).c_str(),
state_label(old_state_).c_str()));
check_cipher(cipher);
BifEvent::generate_ssl_conn_established(bro_analyzer_,
bro_analyzer_->Conn(), version_, cipher);
BifEvent::generate_ssl_established(bro_analyzer_,
bro_analyzer_->Conn());
return true;
%}
function proc_unknown_handshake(msg_type : int) : bool
function proc_unknown_handshake(hs: Handshake, is_orig: bool) : bool
%{
bro_analyzer()->ProtocolViolation(fmt("unknown handshake message (%d) from %s",
msg_type, orig_label(current_record_is_orig_).c_str()));
${hs.msg_type}, orig_label(is_orig).c_str()));
return true;
%}
function proc_handshake(msg : Handshake) : bool
function proc_handshake(hs: Handshake, is_orig: bool) : bool
%{
if ( state_ == STATE_TRACK_LOST )
bro_analyzer()->ProtocolViolation(fmt("unexpected Handshake message %s from %s in state %s",
handshake_type_label(msg->msg_type()).c_str(),
orig_label(current_record_is_orig_).c_str(),
handshake_type_label(${hs.msg_type}).c_str(),
orig_label(is_orig).c_str(),
state_label(old_state_).c_str()));
return true;
%}
function proc_unknown_record(msg : UnknownRecord) : bool
function proc_unknown_record(rec: SSLRecord) : bool
%{
bro_analyzer()->ProtocolViolation(fmt("unknown SSL record type (%d) from %s",
current_record_type_,
orig_label(current_record_is_orig_).c_str()));
${rec.content_type},
orig_label(${rec.is_orig}).c_str()));
return true;
%}
function proc_ciphertext_record(msg : CiphertextRecord) : bool
function proc_ciphertext_record(rec : SSLRecord) : bool
%{
if ( state_ == STATE_TRACK_LOST )
bro_analyzer()->ProtocolViolation(fmt("unexpected ciphertext record from %s in state %s",
orig_label(current_record_is_orig_).c_str(),
orig_label(${rec.is_orig}).c_str(),
state_label(old_state_).c_str()));
if ( state_ == STATE_CONN_ESTABLISHED &&
old_state_ == STATE_COMM_ENCRYPTED )
{
BifEvent::generate_ssl_conn_established(bro_analyzer_,
bro_analyzer_->Conn(),
version_, cipher_);
}
else if ( state_ == STATE_CONN_ESTABLISHED &&
old_state_ == STATE_COMM_ENCRYPTED )
BifEvent::generate_ssl_established(bro_analyzer_,
bro_analyzer_->Conn());
return true;
%}
@ -494,72 +388,80 @@ refine analyzer SSLAnalyzer += {
};
refine typeattr ChangeCipherSpec += &let {
proc : bool = $context.analyzer.proc_change_cipher_spec(this)
proc : bool = $context.analyzer.proc_change_cipher_spec(rec)
&requires(state_changed);
};
refine typeattr Alert += &let {
proc : bool = $context.analyzer.proc_alert(level, description);
proc : bool = $context.analyzer.proc_alert(rec, level, description);
};
refine typeattr V2Error += &let {
proc : bool = $context.analyzer.proc_alert(-1, error_code);
proc : bool = $context.analyzer.proc_alert(rec, -1, error_code);
};
refine typeattr ApplicationData += &let {
proc : bool = $context.analyzer.proc_application_data(this);
proc : bool = $context.analyzer.proc_application_data(rec);
};
refine typeattr ClientHello += &let {
proc : bool = $context.analyzer.proc_client_hello(client_version,
proc : bool = $context.analyzer.proc_client_hello(rec, client_version,
gmt_unix_time,
session_id, convert_ciphers_uint16(csuits))
&requires(state_changed);
};
refine typeattr V2ClientHello += &let {
proc : bool = $context.analyzer.proc_client_hello(client_version,
proc : bool = $context.analyzer.proc_client_hello(rec, client_version, 0,
session_id, convert_ciphers_uint24(ciphers))
&requires(state_changed);
};
refine typeattr ServerHello += &let {
proc : bool = $context.analyzer.proc_server_hello(server_version,
session_id, convert_ciphers_uint16(cipher_suite), -1)
proc : bool = $context.analyzer.proc_server_hello(rec, server_version,
gmt_unix_time, session_id, cipher_suite,
compression_method)
&requires(state_changed);
};
refine typeattr V2ServerHello += &let {
proc : bool = $context.analyzer.proc_server_hello(server_version, 0,
convert_ciphers_uint24(ciphers), session_id_hit)
proc : bool = $context.analyzer.proc_server_hello(rec, server_version, 0, 0,
convert_ciphers_uint24(ciphers)[0], 0)
&requires(state_changed);
cert : bool = $context.analyzer.proc_v2_certificate(cert_data)
cert : bool = $context.analyzer.proc_v2_certificate(rec, cert_data)
&requires(proc);
};
refine typeattr Certificate += &let {
proc : bool = $context.analyzer.proc_v3_certificate(certificates)
proc : bool = $context.analyzer.proc_v3_certificate(rec, certificates)
&requires(state_changed);
};
refine typeattr V2ClientMasterKey += &let {
proc : bool = $context.analyzer.proc_v2_client_master_key(to_int()(cipher_kind))
proc : bool = $context.analyzer.proc_v2_client_master_key(rec, to_int()(cipher_kind))
&requires(state_changed);
};
refine typeattr UnknownHandshake += &let {
proc : bool = $context.analyzer.proc_unknown_handshake(msg_type);
proc : bool = $context.analyzer.proc_unknown_handshake(hs, is_orig);
};
refine typeattr Handshake += &let {
proc : bool = $context.analyzer.proc_handshake(this);
proc : bool = $context.analyzer.proc_handshake(this, rec.is_orig);
};
refine typeattr UnknownRecord += &let {
proc : bool = $context.analyzer.proc_unknown_record(this);
proc : bool = $context.analyzer.proc_unknown_record(rec);
};
refine typeattr CiphertextRecord += &let {
proc : bool = $context.analyzer.proc_ciphertext_record(this)
&requires(state_changed);
proc : bool = $context.analyzer.proc_ciphertext_record(rec);
}
refine typeattr SSLExtension += &let {
proc : bool = $context.analyzer.proc_ssl_extension(type, data);
};

View file

@ -1,5 +1,3 @@
# $Id:$
# Analyzer for SSL messages (general part).
# To be used in conjunction with an SSL record-layer analyzer.
# Separation is necessary due to possible fragmentation of SSL records.
@ -26,6 +24,57 @@ type uint24 = record {
extern type to_int;
type SSLRecord(is_orig: bool) = record {
head0 : uint8;
head1 : uint8;
head2 : uint8;
head3 : uint8;
head4 : uint8;
rec : RecordText(this, is_orig) &requires(content_type), &restofdata;
} &length = length+5, &byteorder=bigendian,
&let {
version : int =
$context.analyzer.determine_ssl_version(head0, head1, head2);
content_type : int = case version of {
UNKNOWN_VERSION -> 0;
SSLv20 -> head2+300;
default -> head0;
};
length : int = case version of {
UNKNOWN_VERSION -> 0;
SSLv20 -> (((head0 & 0x7f) << 8) | head1) - 3;
default -> (head3 << 8) | head4;
};
};
type RecordText(rec: SSLRecord, is_orig: bool) = case $context.analyzer.state() of {
STATE_ABBREV_SERVER_ENCRYPTED, STATE_CLIENT_ENCRYPTED,
STATE_COMM_ENCRYPTED, STATE_CONN_ESTABLISHED
-> ciphertext : CiphertextRecord(rec, is_orig);
default
-> plaintext : PlaintextRecord(rec, is_orig);
};
type PlaintextRecord(rec: SSLRecord, is_orig: bool) = case rec.content_type of {
CHANGE_CIPHER_SPEC -> ch_cipher : ChangeCipherSpec(rec);
ALERT -> alert : Alert(rec);
HANDSHAKE -> handshake : Handshake(rec)[];
APPLICATION_DATA -> app_data : ApplicationData(rec);
V2_ERROR -> v2_error : V2Error(rec);
V2_CLIENT_HELLO -> v2_client_hello : V2ClientHello(rec);
V2_CLIENT_MASTER_KEY -> v2_client_master_key : V2ClientMasterKey(rec);
V2_SERVER_HELLO -> v2_server_hello : V2ServerHello(rec);
default -> unknown_record : UnknownRecord(rec);
};
type SSLExtension = record {
type: uint16;
data_len: uint16;
data: bytestring &length=data_len;
};
######################################################################
# state management according to Section 7.3. in spec
######################################################################
@ -99,6 +148,104 @@ enum AnalyzerState {
{
return string(is_orig ? "originator" :"responder");
}
double get_time_from_asn1(const ASN1_TIME * atime)
{
time_t lResult = 0;
char lBuffer[24];
char * pBuffer = lBuffer;
size_t lTimeLength = atime->length;
char * pString = (char *) atime->data;
if ( atime->type == V_ASN1_UTCTIME )
{
if ( lTimeLength < 11 || lTimeLength > 17 )
return 0;
memcpy(pBuffer, pString, 10);
pBuffer += 10;
pString += 10;
}
else
{
if ( lTimeLength < 13 )
return 0;
memcpy(pBuffer, pString, 12);
pBuffer += 12;
pString += 12;
}
if ((*pString == 'Z') || (*pString == '-') || (*pString == '+'))
{
*(pBuffer++) = '0';
*(pBuffer++) = '0';
}
else
{
*(pBuffer++) = *(pString++);
*(pBuffer++) = *(pString++);
// Skip any fractional seconds...
if (*pString == '.')
{
pString++;
while ((*pString >= '0') && (*pString <= '9'))
pString++;
}
}
*(pBuffer++) = 'Z';
*(pBuffer++) = '\0';
time_t lSecondsFromUTC;
if ( *pString == 'Z' )
lSecondsFromUTC = 0;
else
{
if ((*pString != '+') && (pString[5] != '-'))
return 0;
lSecondsFromUTC = ((pString[1]-'0') * 10 + (pString[2]-'0')) * 60;
lSecondsFromUTC += (pString[3]-'0') * 10 + (pString[4]-'0');
if (*pString == '-')
lSecondsFromUTC = -lSecondsFromUTC;
}
tm lTime;
lTime.tm_sec = ((lBuffer[10] - '0') * 10) + (lBuffer[11] - '0');
lTime.tm_min = ((lBuffer[8] - '0') * 10) + (lBuffer[9] - '0');
lTime.tm_hour = ((lBuffer[6] - '0') * 10) + (lBuffer[7] - '0');
lTime.tm_mday = ((lBuffer[4] - '0') * 10) + (lBuffer[5] - '0');
lTime.tm_mon = (((lBuffer[2] - '0') * 10) + (lBuffer[3] - '0')) - 1;
lTime.tm_year = ((lBuffer[0] - '0') * 10) + (lBuffer[1] - '0');
if ( lTime.tm_year < 50 )
lTime.tm_year += 100; // RFC 2459
lTime.tm_wday = 0;
lTime.tm_yday = 0;
lTime.tm_isdst = 0; // No DST adjustment requested
lResult = mktime(&lTime);
if ( lResult )
{
if ( 0 != lTime.tm_isdst )
lResult -= 3600; // mktime may adjust for DST (OS dependent)
lResult += lSecondsFromUTC;
}
else
lResult = 0;
return lResult;
}
%}
######################################################################
@ -115,7 +262,9 @@ enum HandshakeType {
SERVER_HELLO_DONE = 14,
CERTIFICATE_VERIFY = 15,
CLIENT_KEY_EXCHANGE = 16,
FINISHED = 20
FINISHED = 20,
CERTIFICATE_URL = 21, # RFC 3546
CERTIFICATE_STATUS = 22, # RFC 3546
};
%code{
@ -132,6 +281,8 @@ enum HandshakeType {
case CERTIFICATE_VERIFY: return string("CERTIFICATE_VERIFY");
case CLIENT_KEY_EXCHANGE: return string("CLIENT_KEY_EXCHANGE");
case FINISHED: return string("FINISHED");
case CERTIFICATE_URL: return string("CERTIFICATE_URL");
case CERTIFICATE_STATUS: return string("CERTIFICATE_STATUS");
default: return string(fmt("UNKNOWN (%d)", type));
}
}
@ -142,23 +293,25 @@ enum HandshakeType {
# V3 Change Cipher Spec Protocol (7.1.)
######################################################################
type ChangeCipherSpec = record {
type ChangeCipherSpec(rec: SSLRecord) = record {
type : uint8;
} &length = 1, &let {
state_changed : bool =
$context.analyzer.transition(STATE_CLIENT_FINISHED,
STATE_COMM_ENCRYPTED, false) ||
$context.analyzer.transition(STATE_IN_SERVER_HELLO,
STATE_ABBREV_SERVER_ENCRYPTED, false) ||
$context.analyzer.transition(STATE_CLIENT_KEY_NO_CERT,
STATE_CLIENT_ENCRYPTED, true) ||
$context.analyzer.transition(STATE_CLIENT_CERT_VERIFIED,
STATE_CLIENT_ENCRYPTED, true) ||
$context.analyzer.transition(STATE_CLIENT_KEY_WITH_CERT,
STATE_CLIENT_ENCRYPTED, true) ||
$context.analyzer.transition(STATE_ABBREV_SERVER_FINISHED,
STATE_COMM_ENCRYPTED, true) ||
$context.analyzer.lost_track();
$context.analyzer.transition(STATE_CLIENT_FINISHED,
STATE_COMM_ENCRYPTED, rec.is_orig, false) ||
$context.analyzer.transition(STATE_IN_SERVER_HELLO,
STATE_ABBREV_SERVER_ENCRYPTED, rec.is_orig, false) ||
$context.analyzer.transition(STATE_CLIENT_KEY_NO_CERT,
STATE_CLIENT_ENCRYPTED, rec.is_orig, true) ||
$context.analyzer.transition(STATE_CLIENT_CERT_VERIFIED,
STATE_CLIENT_ENCRYPTED, rec.is_orig, true) ||
#$context.analyzer.transition(STATE_CLIENT_CERT,
# STATE_CLIENT_ENCRYPTED, rec.is_orig, true) ||
$context.analyzer.transition(STATE_CLIENT_KEY_WITH_CERT,
STATE_CLIENT_ENCRYPTED, rec.is_orig, true) ||
$context.analyzer.transition(STATE_ABBREV_SERVER_FINISHED,
STATE_COMM_ENCRYPTED, rec.is_orig, true) ||
$context.analyzer.lost_track();
};
@ -166,19 +319,19 @@ type ChangeCipherSpec = record {
# V3 Alert Protocol (7.2.)
######################################################################
type Alert = record {
type Alert(rec: SSLRecord) = record {
level : uint8;
description: uint8;
} &length = 2;
};
######################################################################
# V2 Error Records (SSLv2 2.7.)
######################################################################
type V2Error = record {
type V2Error(rec: SSLRecord) = record {
error_code : uint16;
} &length = 2;
};
######################################################################
@ -187,9 +340,7 @@ type V2Error = record {
# Application data should always be encrypted, so we should not
# reach this point.
type ApplicationData = empty &let {
discard: bool = $context.flow.discard_data();
};
type ApplicationData(rec: SSLRecord) = empty;
######################################################################
# Handshake Protocol (7.4.)
@ -200,7 +351,7 @@ type ApplicationData = empty &let {
######################################################################
# Hello Request is empty
type HelloRequest = empty &let {
type HelloRequest(rec: SSLRecord) = empty &let {
hr: bool = $context.analyzer.set_hello_requested(true);
};
@ -209,7 +360,7 @@ type HelloRequest = empty &let {
# V3 Client Hello (7.4.1.2.)
######################################################################
type ClientHello = record {
type ClientHello(rec: SSLRecord) = record {
client_version : uint16;
gmt_unix_time : uint32;
random_bytes : bytestring &length = 28 &transient;
@ -219,12 +370,16 @@ type ClientHello = record {
csuits : uint16[csuit_len/2];
cmeth_len : uint8 &check(cmeth_len > 0);
cmeths : uint8[cmeth_len];
# This weirdness is to deal with the possible existence or absence
# of the following fields.
ext_len: uint16[] &until($element == 0 || $element != 0);
extensions : SSLExtension[] &until($input.length() == 0);
} &let {
state_changed : bool =
$context.analyzer.transition(STATE_INITIAL,
STATE_CLIENT_HELLO_RCVD, true) ||
STATE_CLIENT_HELLO_RCVD, rec.is_orig, true) ||
($context.analyzer.hello_requested() &&
$context.analyzer.transition(STATE_ANY, STATE_CLIENT_HELLO_RCVD, true)) ||
$context.analyzer.transition(STATE_ANY, STATE_CLIENT_HELLO_RCVD, rec.is_orig, true)) ||
$context.analyzer.lost_track();
};
@ -233,7 +388,7 @@ type ClientHello = record {
# V2 Client Hello (SSLv2 2.5.)
######################################################################
type V2ClientHello = record {
type V2ClientHello(rec: SSLRecord) = record {
client_version : uint16;
csuit_len : uint16;
session_len : uint16;
@ -244,9 +399,9 @@ type V2ClientHello = record {
} &length = 8 + csuit_len + session_len + chal_len, &let {
state_changed : bool =
$context.analyzer.transition(STATE_INITIAL,
STATE_CLIENT_HELLO_RCVD, true) ||
STATE_CLIENT_HELLO_RCVD, rec.is_orig, true) ||
($context.analyzer.hello_requested() &&
$context.analyzer.transition(STATE_ANY, STATE_CLIENT_HELLO_RCVD, true)) ||
$context.analyzer.transition(STATE_ANY, STATE_CLIENT_HELLO_RCVD, rec.is_orig, true)) ||
$context.analyzer.lost_track();
};
@ -255,18 +410,18 @@ type V2ClientHello = record {
# V3 Server Hello (7.4.1.3.)
######################################################################
type ServerHello = record {
type ServerHello(rec: SSLRecord) = record {
server_version : uint16;
gmt_unix_time : uint32;
random_bytes : bytestring &length = 28 &transient;
session_len : uint8;
session_id : uint8[session_len];
cipher_suite : uint16[1];
cipher_suite : uint16;
compression_method : uint8;
} &let {
state_changed : bool =
$context.analyzer.transition(STATE_CLIENT_HELLO_RCVD,
STATE_IN_SERVER_HELLO, false) ||
STATE_IN_SERVER_HELLO, rec.is_orig, false) ||
$context.analyzer.lost_track();
};
@ -275,7 +430,7 @@ type ServerHello = record {
# V2 Server Hello (SSLv2 2.6.)
######################################################################
type V2ServerHello = record {
type V2ServerHello(rec: SSLRecord) = record {
session_id_hit : uint8;
cert_type : uint8;
server_version : uint16;
@ -289,9 +444,9 @@ type V2ServerHello = record {
state_changed : bool =
(session_id_hit > 0 ?
$context.analyzer.transition(STATE_CLIENT_HELLO_RCVD,
STATE_CONN_ESTABLISHED, false) :
STATE_CONN_ESTABLISHED, rec.is_orig, false) :
$context.analyzer.transition(STATE_CLIENT_HELLO_RCVD,
STATE_V2_CL_MASTER_KEY_EXPECTED, false)) ||
STATE_V2_CL_MASTER_KEY_EXPECTED, rec.is_orig, false)) ||
$context.analyzer.lost_track();
};
@ -307,15 +462,15 @@ type X509Certificate = record {
type CertificateList = X509Certificate[] &until($input.length() == 0);
type Certificate = record {
type Certificate(rec: SSLRecord) = record {
length : uint24;
certificates : CertificateList &length = to_int()(length);
} &let {
state_changed : bool =
$context.analyzer.transition(STATE_IN_SERVER_HELLO,
STATE_IN_SERVER_HELLO, false) ||
STATE_IN_SERVER_HELLO, rec.is_orig, false) ||
$context.analyzer.transition(STATE_SERVER_HELLO_DONE,
STATE_CLIENT_CERT, true) ||
STATE_CLIENT_CERT, rec.is_orig, true) ||
$context.analyzer.lost_track();
};
@ -325,12 +480,12 @@ type Certificate = record {
######################################################################
# For now ignore details; just eat up complete message
type ServerKeyExchange = record {
cont : bytestring &restofdata &transient;
type ServerKeyExchange(rec: SSLRecord) = record {
key : bytestring &restofdata;
} &let {
state_changed : bool =
$context.analyzer.transition(STATE_IN_SERVER_HELLO,
STATE_IN_SERVER_HELLO, false) ||
STATE_IN_SERVER_HELLO, rec.is_orig, false) ||
$context.analyzer.lost_track();
};
@ -340,12 +495,12 @@ type ServerKeyExchange = record {
######################################################################
# For now, ignore Certificate Request Details; just eat up message.
type CertificateRequest = record {
type CertificateRequest(rec: SSLRecord) = record {
cont : bytestring &restofdata &transient;
} &let {
state_changed : bool =
$context.analyzer.transition(STATE_IN_SERVER_HELLO,
STATE_IN_SERVER_HELLO, false) ||
STATE_IN_SERVER_HELLO, rec.is_orig, false) ||
$context.analyzer.lost_track();
};
@ -355,10 +510,10 @@ type CertificateRequest = record {
######################################################################
# Server Hello Done is empty
type ServerHelloDone = empty &let {
type ServerHelloDone(rec: SSLRecord) = empty &let {
state_changed : bool =
$context.analyzer.transition(STATE_IN_SERVER_HELLO,
STATE_SERVER_HELLO_DONE, false) ||
STATE_SERVER_HELLO_DONE, rec.is_orig, false) ||
$context.analyzer.lost_track();
};
@ -377,14 +532,16 @@ type ServerHelloDone = empty &let {
# For now ignore details of ClientKeyExchange (most of it is
# encrypted anyway); just eat up message.
type ClientKeyExchange = record {
type ClientKeyExchange(rec: SSLRecord) = record {
cont : bytestring &restofdata &transient;
} &let {
state_changed : bool =
$context.analyzer.transition(STATE_SERVER_HELLO_DONE,
STATE_CLIENT_KEY_NO_CERT, true) ||
STATE_CLIENT_KEY_NO_CERT, rec.is_orig, true) ||
$context.analyzer.transition(STATE_CLIENT_CERT,
STATE_CLIENT_KEY_WITH_CERT, true) ||
STATE_CLIENT_KEY_WITH_CERT, rec.is_orig, true) ||
$context.analyzer.transition(STATE_CLIENT_CERT,
STATE_CLIENT_KEY_WITH_CERT, rec.is_orig, true) ||
$context.analyzer.lost_track();
};
@ -392,7 +549,7 @@ type ClientKeyExchange = record {
# V2 Client Master Key (SSLv2 2.5.)
######################################################################
type V2ClientMasterKey = record {
type V2ClientMasterKey(rec: SSLRecord) = record {
cipher_kind : uint24;
cl_key_len : uint16;
en_key_len : uint16;
@ -403,7 +560,7 @@ type V2ClientMasterKey = record {
} &length = 9 + cl_key_len + en_key_len + key_arg_len, &let {
state_changed : bool =
$context.analyzer.transition(STATE_V2_CL_MASTER_KEY_EXPECTED,
STATE_CONN_ESTABLISHED, true) ||
STATE_CONN_ESTABLISHED, rec.is_orig, true) ||
$context.analyzer.lost_track();
};
@ -413,12 +570,12 @@ type V2ClientMasterKey = record {
######################################################################
# For now, ignore Certificate Verify; just eat up the message.
type CertificateVerify = record {
type CertificateVerify(rec: SSLRecord) = record {
cont : bytestring &restofdata &transient;
} &let {
state_changed : bool =
$context.analyzer.transition(STATE_CLIENT_KEY_WITH_CERT,
STATE_CLIENT_CERT_VERIFIED, true) ||
STATE_CLIENT_CERT_VERIFIED, rec.is_orig, true) ||
$context.analyzer.lost_track();
};
@ -427,35 +584,40 @@ type CertificateVerify = record {
# V3 Finished (7.4.9.)
######################################################################
# The Finished messages are always sent after encryption is in effect,
# so we will not be able to read those message
# The finished messages are always sent after encryption is in effect,
# so we will not be able to read those message.
######################################################################
# V3 Handshake Protocol (7.)
######################################################################
type UnknownHandshake(msg_type : uint8) = record {
type UnknownHandshake(hs: Handshake, is_orig: bool) = record {
cont : bytestring &restofdata &transient;
} &let {
state_changed : bool = $context.analyzer.lost_track();
# TODO: an unknown handshake could just be an encrypted handshake
# before a server sends the change cipher spec message.
# I have no clue why this happens, but it does seem to happen.
# This should be solved in a different way eventually.
#state_changed : bool = $context.analyzer.lost_track();
};
type Handshake = record {
type Handshake(rec: SSLRecord) = record {
msg_type : uint8;
length : uint24;
body : case msg_type of {
HELLO_REQUEST -> hello_request : HelloRequest;
CLIENT_HELLO -> client_hello : ClientHello;
SERVER_HELLO -> server_hello : ServerHello;
CERTIFICATE -> certificate : Certificate;
SERVER_KEY_EXCHANGE -> server_key_exchange : ServerKeyExchange;
CERTIFICATE_REQUEST -> certificate_request : CertificateRequest;
SERVER_HELLO_DONE -> server_hello_done : ServerHelloDone;
CERTIFICATE_VERIFY -> certificate_verify : CertificateVerify;
CLIENT_KEY_EXCHANGE -> client_key_exchange : ClientKeyExchange;
default -> unknown_handshake : UnknownHandshake(msg_type);
HELLO_REQUEST -> hello_request : HelloRequest(rec);
CLIENT_HELLO -> client_hello : ClientHello(rec);
SERVER_HELLO -> server_hello : ServerHello(rec);
CERTIFICATE -> certificate : Certificate(rec);
SERVER_KEY_EXCHANGE -> server_key_exchange : ServerKeyExchange(rec);
CERTIFICATE_REQUEST -> certificate_request : CertificateRequest(rec);
SERVER_HELLO_DONE -> server_hello_done : ServerHelloDone(rec);
CERTIFICATE_VERIFY -> certificate_verify : CertificateVerify(rec);
CLIENT_KEY_EXCHANGE -> client_key_exchange : ClientKeyExchange(rec);
default -> unknown_handshake : UnknownHandshake(this, rec.is_orig);
};
} &length = 4 + to_int()(length);
@ -464,40 +626,26 @@ type Handshake = record {
# Fragmentation (6.2.1.)
######################################################################
type UnknownRecord = record {
cont : empty;
type UnknownRecord(rec: SSLRecord) = record {
cont : bytestring &restofdata &transient;
} &let {
discard : bool = $context.flow.discard_data();
state_changed : bool = $context.analyzer.lost_track();
};
type PlaintextRecord = case $context.analyzer.current_record_type() of {
CHANGE_CIPHER_SPEC -> ch_cipher : ChangeCipherSpec;
ALERT -> alert : Alert;
HANDSHAKE -> handshakes : Handshake;
APPLICATION_DATA -> app_data : ApplicationData;
V2_ERROR -> v2_error : V2Error;
V2_CLIENT_HELLO -> v2_client_hello : V2ClientHello;
V2_CLIENT_MASTER_KEY -> v2_client_master_key : V2ClientMasterKey;
V2_SERVER_HELLO -> v2_server_hello : V2ServerHello;
UNKNOWN_OR_V2_ENCRYPTED -> unknown_record : UnknownRecord;
};
type CiphertextRecord = empty &let {
discard : bool = $context.flow.discard_data();
type CiphertextRecord(rec: SSLRecord, is_orig: bool) = empty &let {
state_changed : bool =
$context.analyzer.transition(STATE_ABBREV_SERVER_ENCRYPTED,
STATE_ABBREV_SERVER_FINISHED, false) ||
STATE_ABBREV_SERVER_FINISHED, rec.is_orig, false) ||
$context.analyzer.transition(STATE_CLIENT_ENCRYPTED,
STATE_CLIENT_FINISHED, true) ||
STATE_CLIENT_FINISHED, rec.is_orig, true) ||
$context.analyzer.transition(STATE_COMM_ENCRYPTED,
STATE_CONN_ESTABLISHED, false) ||
STATE_CONN_ESTABLISHED, rec.is_orig, false) ||
$context.analyzer.transition(STATE_COMM_ENCRYPTED,
STATE_CONN_ESTABLISHED, true) ||
STATE_CONN_ESTABLISHED, rec.is_orig, true) ||
$context.analyzer.transition(STATE_CONN_ESTABLISHED,
STATE_CONN_ESTABLISHED, false) ||
STATE_CONN_ESTABLISHED, rec.is_orig, false) ||
$context.analyzer.transition(STATE_CONN_ESTABLISHED,
STATE_CONN_ESTABLISHED, true) ||
STATE_CONN_ESTABLISHED, rec.is_orig, true) ||
$context.analyzer.lost_track();
};
@ -506,15 +654,9 @@ type CiphertextRecord = empty &let {
# initial datatype for binpac
######################################################################
type SSLPDU = case $context.analyzer.state() of {
STATE_ABBREV_SERVER_ENCRYPTED, STATE_CLIENT_ENCRYPTED,
STATE_COMM_ENCRYPTED, STATE_CONN_ESTABLISHED
-> ciphertext : CiphertextRecord;
default
-> plaintext : PlaintextRecord;
} &byteorder = bigendian, &let {
consumed : bool = $context.flow.consume_data();
};
type SSLPDU(is_orig: bool) = record {
records : SSLRecord(is_orig)[] &until($element == 0);
} &byteorder = bigendian;
######################################################################
@ -526,60 +668,48 @@ analyzer SSLAnalyzer {
downflow = SSLFlow(false);
%member{
int current_record_type_;
int current_record_version_;
int current_record_length_;
bool current_record_is_orig_;
int state_;
int old_state_;
bool hello_requested_;
%}
%init{
current_record_type_ = -1;
current_record_version_ = -1;
current_record_length_ = -1;
current_record_is_orig_ = false;
state_ = STATE_INITIAL;
old_state_ = STATE_INITIAL;
hello_requested_ = false;
%}
function current_record_type() : int
%{ return current_record_type_; %}
function current_record_version() : int
%{ return current_record_version_; %}
function current_record_length() : int
%{ return current_record_length_; %}
function current_record_is_orig() : bool
%{ return current_record_is_orig_; %}
function next_record(rec : const_bytestring, type : int,
version : int, is_orig : bool) : bool
function determine_ssl_version(head0 : uint8, head1 : uint8,
head2 : uint8) : int
%{
current_record_type_ = type;
current_record_version_ = version;
current_record_length_ = rec.length();
current_record_is_orig_ = is_orig;
if ( head0 >= 20 && head0 <= 23 &&
head1 == 0x03 && head2 < 0x03 )
// This is most probably SSL version 3.
return (head1 << 8) | head2;
NewData(is_orig, rec.begin(), rec.end());
else if ( head0 >= 128 && head2 < 5 && head2 != 3 )
// Not very strong evidence, but we suspect
// this to be SSLv2.
return SSLv20;
return true;
else
return UNKNOWN_VERSION;
%}
function state() : int %{ return state_; %}
function old_state() : int %{ return old_state_; %}
function transition(olds : AnalyzerState, news : AnalyzerState,
is_orig : bool) : bool
current_record_is_orig : bool, is_orig : bool) : bool
%{
if ( (olds != STATE_ANY && olds != state_) ||
current_record_is_orig_ != is_orig )
current_record_is_orig != is_orig )
return false;
old_state_ = state_;
state_ = news;
//printf("transitioning from %s to %s\n", state_label(old_state()).c_str(), state_label(state()).c_str());
return true;
%}
@ -602,29 +732,3 @@ analyzer SSLAnalyzer {
return val;
%}
};
######################################################################
# binpac flow for SSL
######################################################################
flow SSLFlow(is_orig : bool) {
flowunit = SSLPDU withcontext(connection, this);
function discard_data() : bool
%{
flow_buffer_->DiscardData();
return true;
%}
function data_available() : bool
%{
return flow_buffer_->data_available();
%}
function consume_data() : bool
%{
flow_buffer_->NewFrame(0, false);
return true;
%}
};

View file

@ -1,141 +0,0 @@
# $Id:$
# binpac analyzer representing the SSLv3 record layer
#
# This additional layering in the analyzer hierarchy is necessary due to
# fragmentation that can be introduced in the SSL record layer.
%include binpac.pac
%include bro.pac
analyzer SSLRecordLayer withcontext {
analyzer : SSLRecordLayerAnalyzer;
flow : SSLRecordLayerFlow;
};
%include ssl-defs.pac
%extern{
#include "ssl_pac.h"
using binpac::SSL::SSLAnalyzer;
%}
extern type const_bytestring;
type SSLPDU = record {
head0 : uint8;
head1 : uint8;
head2 : uint8;
head3 : uint8;
head4 : uint8;
fragment : bytestring &restofdata;
} &length = 5 + length, &byteorder = bigendian, &let {
version : int =
$context.analyzer.determine_ssl_version(head0, head1, head2);
length : int = case version of {
UNKNOWN_VERSION -> 0;
SSLv20 -> (((head0 & 0x7f) << 8) | head1) - 3;
default -> (head3 << 8) | head4;
};
fw : bool = case version of {
UNKNOWN_VERSION ->
$context.analyzer.forward_record(const_bytestring(),
UNKNOWN_OR_V2_ENCRYPTED, UNKNOWN_VERSION,
$context.flow.is_orig)
&& $context.flow.discard_data();
SSLv20 -> $context.analyzer.forward_v2_record(head2, head3, head4,
fragment, $context.flow.is_orig);
default -> $context.analyzer.forward_record(fragment, head0,
(head1 << 8) | head2, $context.flow.is_orig);
};
};
# binpac-specific definitions
analyzer SSLRecordLayerAnalyzer {
upflow = SSLRecordLayerFlow(true);
downflow = SSLRecordLayerFlow(false);
%member{
SSLAnalyzer* ssl_analyzer_;
int ssl_version_;
int record_length_;
%}
%init{
ssl_analyzer_ = 0;
ssl_version_ = UNKNOWN_VERSION;
record_length_ = 0;
%}
%eof{
ssl_analyzer_->FlowEOF(true);
ssl_analyzer_->FlowEOF(false);
%}
function set_ssl_analyzer(a : SSLAnalyzer) : void
%{ ssl_analyzer_ = a; %}
function ssl_version() : int %{ return ssl_version_; %}
function record_length() : int %{ return record_length_; %}
function determine_ssl_version(head0 : uint8, head1 : uint8,
head2 : uint8) : int
%{
if ( head0 >= 20 && head0 <= 23 &&
head1 == 0x03 && head2 < 0x03 )
// This is most probably SSL version 3.
ssl_version_ = (head1 << 8) | head2;
else if ( head0 >= 128 && head2 < 5 && head2 != 3 )
// Not very strong evidence, but we suspect
// this to be SSLv2.
ssl_version_ = SSLv20;
else
ssl_version_ = UNKNOWN_VERSION;
return ssl_version_;
%}
function forward_record(fragment : const_bytestring, type : int,
version : uint16, is_orig : bool) : bool
%{
return ssl_analyzer_->next_record(fragment, type,
version, is_orig);
%}
function forward_v2_record(b1 : uint8, b2 : uint8, b3 : uint8,
fragment : const_bytestring,
is_orig : bool) : bool
%{
uint8* buffer = new uint8[2 + fragment.length()];
// Byte 1 is the record type.
buffer[0] = b2;
buffer[1] = b3;
memcpy(buffer + 2, fragment.begin(), fragment.length());
const_bytestring bs(buffer, 2 + fragment.length());
bool ret = ssl_analyzer_->next_record(bs, 300 + b1, SSLv20,
is_orig);
delete [] buffer;
return ret;
%}
};
flow SSLRecordLayerFlow(is_orig : bool) {
flowunit = SSLPDU withcontext(connection, this);
function discard_data() : bool
%{
flow_buffer_->DiscardData();
return true;
%}
};

View file

@ -15,8 +15,10 @@ analyzer SSL withcontext {
flow : SSLFlow;
};
%include ssl-defs.pac
%include ssl-protocol.pac
%include ssl-analyzer.pac
%include ssl-defs.pac
flow SSLFlow(is_orig : bool) {
flowunit = SSLPDU(is_orig) withcontext(connection, this);
};

27
src/syslog-analyzer.pac Normal file
View file

@ -0,0 +1,27 @@
connection Syslog_Conn(bro_analyzer: BroAnalyzer)
{
upflow = Syslog_Flow;
downflow = Syslog_Flow;
};
flow Syslog_Flow
{
datagram = Syslog_Message withcontext(connection, this);
function process_syslog_message(m: Syslog_Message): bool
%{
BifEvent::generate_syslog_message(connection()->bro_analyzer(),
connection()->bro_analyzer()->Conn(),
${m.PRI.facility},
${m.PRI.severity},
new StringVal(${m.msg}.length(), (const char*) ${m.msg}.begin())
);
return true;
%}
};
refine typeattr Syslog_Message += &let {
proc_syslog_message = $context.flow.process_syslog_message(this);
};

15
src/syslog-protocol.pac Normal file
View file

@ -0,0 +1,15 @@
type Syslog_Message = record {
PRI: Syslog_Priority;
msg: bytestring &restofdata;
} &byteorder = littleendian;
type Syslog_Priority = record {
lt : uint8 &check(lt == "<");
val : RE/[[:digit:]]+/;
gt : uint8 &check(gt == ">");
} &let {
val_length: int = sizeof(val) - 1;
int_val: int = bytestring_to_int(val, 10);
severity: int = (int_val & 0x07);
facility: int = (int_val & 0x03f8) >> 3;
};

10
src/syslog.pac Normal file
View file

@ -0,0 +1,10 @@
%include binpac.pac
%include bro.pac
analyzer Syslog withcontext {
connection: Syslog_Conn;
flow: Syslog_Flow;
};
%include syslog-protocol.pac
%include syslog-analyzer.pac

View file

@ -52,33 +52,34 @@ enum rpc_status %{
%}
module NFS3;
enum proc_t %{ # NFSv3 procedures
PROC_NULL = 0, # done
PROC_GETATTR = 1, # done
PROC_SETATTR = 2,
PROC_LOOKUP = 3, # done
PROC_ACCESS = 4,
PROC_READLINK = 5, # done
PROC_READ = 6, # done
PROC_WRITE = 7, # done
PROC_CREATE = 8, # partial
PROC_MKDIR = 9, # partial
PROC_SYMLINK = 10,
PROC_MKNOD = 11,
PROC_REMOVE = 12, # done
PROC_RMDIR = 13, # done
PROC_RENAME = 14,
PROC_LINK = 15,
PROC_READDIR = 16, # done
PROC_READDIRPLUS = 17, # done
PROC_FSSTAT = 18,
PROC_FSINFO = 19,
PROC_PATHCONF = 20,
PROC_COMMIT = 21,
PROC_END_OF_PROCS = 22,
enum proc_t %{ # NFSv3 procedures
PROC_NULL = 0, # done
PROC_GETATTR = 1, # done
PROC_SETATTR = 2, # not implemented
PROC_LOOKUP = 3, # done
PROC_ACCESS = 4, # not implemented
PROC_READLINK = 5, # done
PROC_READ = 6, # done
PROC_WRITE = 7, # done
PROC_CREATE = 8, # partial
PROC_MKDIR = 9, # partial
PROC_SYMLINK = 10, # not implemented
PROC_MKNOD = 11, # not implemented
PROC_REMOVE = 12, # done
PROC_RMDIR = 13, # done
PROC_RENAME = 14, # not implemented
PROC_LINK = 15, # not implemented
PROC_READDIR = 16, # done
PROC_READDIRPLUS = 17, # done
PROC_FSSTAT = 18, # not implemented
PROC_FSINFO = 19, # not implemented
PROC_PATHCONF = 20, # not implemented
PROC_COMMIT = 21, # not implemented
PROC_END_OF_PROCS = 22, # not implemented
%}
enum status_t %{ #NFSv3 return status
enum status_t %{ # NFSv3 return status
NFS3ERR_OK = 0,
NFS3ERR_PERM = 1,
NFS3ERR_NOENT = 2,
@ -111,14 +112,13 @@ enum status_t %{ #NFSv3 return status
NFS3ERR_UNKNOWN = 0xffffffff,
%}
enum file_type_t %{
FTYPE_REG = 1,
FTYPE_DIR = 2,
FTYPE_BLK = 3,
FTYPE_CHR = 4,
FTYPE_LNK = 5,
FTYPE_SOCK = 6,
FTYPE_REG = 1,
FTYPE_DIR = 2,
FTYPE_BLK = 3,
FTYPE_CHR = 4,
FTYPE_LNK = 5,
FTYPE_SOCK = 6,
FTYPE_FIFO = 7,
%}
@ -134,8 +134,8 @@ enum createmode_t %{
EXCLUSIVE = 2,
%}
# Decleare record types that we want to access from the C++
# These are defined in bro.init
# Decleare record types that we want to access from the even engine. These are
# defined in bro.init.
type info_t: record;
type fattr_t: record;
type diropargs_t: record;
@ -153,7 +153,6 @@ type direntry_t: record;
type direntry_vec_t: vector;
type readdir_reply_t: record;
type fsstat_t: record;
module Log;

View file

@ -344,15 +344,27 @@ template<class T> int atoi_n(int len, const char* s, const char** end, int base,
template int atoi_n<int>(int len, const char* s, const char** end, int base, int& result);
template int atoi_n<int64_t>(int len, const char* s, const char** end, int base, int64_t& result);
char* uitoa_n(uint64 value, char* str, int n, int base)
char* uitoa_n(uint64 value, char* str, int n, int base, const char* prefix)
{
static char dig[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
assert(n);
int i = 0;
uint64 v;
char* p, *q;
char c;
if ( prefix )
{
strncpy(str, prefix, n);
str[n-1] = '\0';
i += strlen(prefix);
}
if ( i >= n )
return str;
v = value;
do {
@ -868,21 +880,45 @@ const char* bro_prefixes()
return p;
}
FILE* open_file(const char* filename, const char** full_filename)
static const char* PACKAGE_LOADER = "__load__.bro";
// If filename is pointing to a directory that contains a file called
// PACKAGE_LOADER, returns the files path. Otherwise returns filename itself.
// In both cases, the returned string is newly allocated.
static const char* check_for_dir(const char* filename, bool load_pkgs)
{
if ( load_pkgs && is_dir(filename) )
{
char init_filename_buf[1024];
safe_snprintf(init_filename_buf, sizeof(init_filename_buf),
"%s/%s", filename, PACKAGE_LOADER);
if ( access(init_filename_buf, R_OK) == 0 )
return copy_string(init_filename_buf);
}
return copy_string(filename);
}
FILE* open_file(const char* filename, const char** full_filename, bool load_pkgs)
{
filename = check_for_dir(filename, load_pkgs);
if ( full_filename )
*full_filename = copy_string(filename);
FILE* f = fopen(filename, "r");
delete [] filename;
return f;
}
FILE* search_for_file(const char* filename, const char* ext,
const char** full_filename)
const char** full_filename, bool load_pkgs)
{
if ( filename[0] == '/' || filename[0] == '.' )
return open_file(filename, full_filename);
return open_file(filename, full_filename, load_pkgs);
char path[1024], full_filename_buf[1024];
safe_strncpy(path, bro_path(), sizeof(path));
@ -905,13 +941,12 @@ FILE* search_for_file(const char* filename, const char* ext,
"%s/%s.%s", dir_beginning, filename, ext);
if ( access(full_filename_buf, R_OK) == 0 &&
! is_dir(full_filename_buf) )
return open_file(full_filename_buf, full_filename);
return open_file(full_filename_buf, full_filename, load_pkgs);
safe_snprintf(full_filename_buf, sizeof(full_filename_buf),
"%s/%s", dir_beginning, filename);
if ( access(full_filename_buf, R_OK) == 0 &&
! is_dir(full_filename_buf) )
return open_file(full_filename_buf, full_filename);
if ( access(full_filename_buf, R_OK) == 0 )
return open_file(full_filename_buf, full_filename, load_pkgs);
dir_beginning = ++dir_ending;
}
@ -1099,6 +1134,56 @@ int time_compare(struct timeval* tv_a, struct timeval* tv_b)
return tv_a->tv_sec - tv_b->tv_sec;
}
static uint64 uid_counter; // Counter for unique IDs.
static uint64 uid_instance; // Instance ID, computed once.
uint64 calculate_unique_id()
{
if ( uid_instance == 0 )
{
// This is the first time we need a UID.
if ( ! have_random_seed() )
{
// If we don't need deterministic output (as
// indicated by a set seed), we calculate the
// instance ID by hashing something likely to be
// globally unique.
struct {
char hostname[128];
struct timeval time;
pid_t pid;
int rnd;
} unique;
gethostname(unique.hostname, 128);
unique.hostname[sizeof(unique.hostname)-1] = '\0';
gettimeofday(&unique.time, 0);
unique.pid = getpid();
unique.rnd = bro_random();
uid_instance = HashKey::HashBytes(&unique, sizeof(unique));
++uid_instance; // Now it's larger than zero.
}
else
// Generate determistic UIDs.
uid_instance = 1;
}
// Now calculate the unique ID.
struct {
uint64 counter;
hash_t instance;
} key;
key.counter = ++uid_counter;
key.instance = uid_instance;
uint64_t h = HashKey::HashBytes(&key, sizeof(key));
return h;
}
void out_of_memory(const char* where)
{
fprintf( stderr, "bro: out of memory in %s.\n", where );

View file

@ -116,7 +116,7 @@ extern char* strcasestr(const char* s, const char* find);
#endif
extern const char* strpbrk_n(size_t len, const char* s, const char* charset);
template<class T> int atoi_n(int len, const char* s, const char** end, int base, T& result);
extern char* uitoa_n(uint64 value, char* str, int n, int base);
extern char* uitoa_n(uint64 value, char* str, int n, int base, const char* prefix=0);
int strstr_n(const int big_len, const unsigned char* big,
const int little_len, const unsigned char* little);
extern int fputs(int len, const char* s, FILE* fp);
@ -195,7 +195,7 @@ extern int int_list_cmp(const void* v1, const void* v2);
extern const char* bro_path();
extern const char* bro_prefixes();
extern FILE* search_for_file(const char* filename, const char* ext,
const char** full_filename);
const char** full_filename, bool load_pkgs);
// Renames the given file to a new temporary name, and opens a new file with
// the original name. Returns new file or NULL on error. Inits rotate_info if
@ -238,6 +238,10 @@ extern struct timeval double_to_timeval(double t);
// Return > 0 if tv_a > tv_b, 0 if equal, < 0 if tv_a < tv_b.
extern int time_compare(struct timeval* tv_a, struct timeval* tv_b);
// Returns an integer that's very likely to be unique, even across Bro
// instances.
extern uint64 calculate_unique_id();
// For now, don't use hash_maps - they're not fully portable.
#if 0
// Use for hash_map's string keys.

View file

@ -0,0 +1 @@
6

View file

@ -0,0 +1,3 @@
A-UWkUyAuUGXf
B-56gKBmhBBB6
C-50da4BEzauh

View file

@ -1 +1 @@
18
62

View file

@ -1,34 +1,78 @@
[orig_h=141.142.220.118, orig_p=48649/tcp, resp_h=208.80.152.118, resp_p=80/tcp], UWkUyAuUGXf
[orig_h=141.142.220.118, orig_p=48649/tcp, resp_h=208.80.152.118, resp_p=80/tcp], UWkUyAuUGXf
[orig_h=141.142.220.118, orig_p=48649/tcp, resp_h=208.80.152.118, resp_p=80/tcp], UWkUyAuUGXf
[orig_h=141.142.220.118, orig_p=48649/tcp, resp_h=208.80.152.118, resp_p=80/tcp], UWkUyAuUGXf
[orig_h=141.142.220.118, orig_p=49996/tcp, resp_h=208.80.152.3, resp_p=80/tcp], 56gKBmhBBB6
[orig_h=141.142.220.118, orig_p=49996/tcp, resp_h=208.80.152.3, resp_p=80/tcp], 56gKBmhBBB6
[orig_h=141.142.220.118, orig_p=49997/tcp, resp_h=208.80.152.3, resp_p=80/tcp], 50da4BEzauh
[orig_h=141.142.220.118, orig_p=49997/tcp, resp_h=208.80.152.3, resp_p=80/tcp], 50da4BEzauh
[orig_h=141.142.220.118, orig_p=49998/tcp, resp_h=208.80.152.3, resp_p=80/tcp], WUjEZFOdSS
[orig_h=141.142.220.118, orig_p=49998/tcp, resp_h=208.80.152.3, resp_p=80/tcp], WUjEZFOdSS
[orig_h=141.142.220.118, orig_p=49999/tcp, resp_h=208.80.152.3, resp_p=80/tcp], ecqdozAET6c
[orig_h=141.142.220.118, orig_p=49999/tcp, resp_h=208.80.152.3, resp_p=80/tcp], ecqdozAET6c
[orig_h=141.142.220.118, orig_p=50000/tcp, resp_h=208.80.152.3, resp_p=80/tcp], tdkrEYpj5ja
[orig_h=141.142.220.118, orig_p=50000/tcp, resp_h=208.80.152.3, resp_p=80/tcp], tdkrEYpj5ja
[orig_h=141.142.220.118, orig_p=50001/tcp, resp_h=208.80.152.3, resp_p=80/tcp], F5XgctwO3Vl
[orig_h=141.142.220.118, orig_p=50001/tcp, resp_h=208.80.152.3, resp_p=80/tcp], F5XgctwO3Vl
[orig_h=141.142.220.118, orig_p=35642/tcp, resp_h=208.80.152.2, resp_p=80/tcp], svqqNKN9CFj
[orig_h=141.142.220.118, orig_p=35642/tcp, resp_h=208.80.152.2, resp_p=80/tcp], svqqNKN9CFj
[orig_h=141.142.220.118, orig_p=49997/tcp, resp_h=208.80.152.3, resp_p=80/tcp], 50da4BEzauh
[orig_h=141.142.220.118, orig_p=49997/tcp, resp_h=208.80.152.3, resp_p=80/tcp], 50da4BEzauh
[orig_h=141.142.220.118, orig_p=49996/tcp, resp_h=208.80.152.3, resp_p=80/tcp], 56gKBmhBBB6
[orig_h=141.142.220.118, orig_p=49996/tcp, resp_h=208.80.152.3, resp_p=80/tcp], 56gKBmhBBB6
[orig_h=141.142.220.118, orig_p=49998/tcp, resp_h=208.80.152.3, resp_p=80/tcp], WUjEZFOdSS
[orig_h=141.142.220.118, orig_p=49998/tcp, resp_h=208.80.152.3, resp_p=80/tcp], WUjEZFOdSS
[orig_h=141.142.220.118, orig_p=50000/tcp, resp_h=208.80.152.3, resp_p=80/tcp], tdkrEYpj5ja
[orig_h=141.142.220.118, orig_p=50000/tcp, resp_h=208.80.152.3, resp_p=80/tcp], tdkrEYpj5ja
[orig_h=141.142.220.118, orig_p=49999/tcp, resp_h=208.80.152.3, resp_p=80/tcp], ecqdozAET6c
[orig_h=141.142.220.118, orig_p=49999/tcp, resp_h=208.80.152.3, resp_p=80/tcp], ecqdozAET6c
[orig_h=141.142.220.118, orig_p=50001/tcp, resp_h=208.80.152.3, resp_p=80/tcp], F5XgctwO3Vl
[orig_h=141.142.220.118, orig_p=50001/tcp, resp_h=208.80.152.3, resp_p=80/tcp], F5XgctwO3Vl
[orig_h=141.142.220.118, orig_p=35642/tcp, resp_h=208.80.152.2, resp_p=80/tcp], svqqNKN9CFj
[orig_h=141.142.220.118, orig_p=35642/tcp, resp_h=208.80.152.2, resp_p=80/tcp], svqqNKN9CFj
[orig_h=141.142.220.235, orig_p=6705/tcp, resp_h=173.192.163.128, resp_p=80/tcp], UZkBBvjF0r8
[orig_h=141.142.220.235, orig_p=6705/tcp, resp_h=173.192.163.128, resp_p=80/tcp], UZkBBvjF0r8
[orig_h=141.142.220.202, orig_p=5353/udp, resp_h=224.0.0.251, resp_p=5353/udp], UWkUyAuUGXf
[orig_h=141.142.220.202, orig_p=5353/udp, resp_h=224.0.0.251, resp_p=5353/udp], UWkUyAuUGXf
[orig_h=141.142.220.50, orig_p=5353/udp, resp_h=224.0.0.251, resp_p=5353/udp], 56gKBmhBBB6
[orig_h=141.142.220.50, orig_p=5353/udp, resp_h=224.0.0.251, resp_p=5353/udp], 56gKBmhBBB6
[orig_h=141.142.220.118, orig_p=35634/tcp, resp_h=208.80.152.2, resp_p=80/tcp], 50da4BEzauh
[orig_h=141.142.220.118, orig_p=35634/tcp, resp_h=208.80.152.2, resp_p=80/tcp], 50da4BEzauh
[orig_h=141.142.220.118, orig_p=48649/tcp, resp_h=208.80.152.118, resp_p=80/tcp], WUjEZFOdSS
[orig_h=141.142.220.118, orig_p=48649/tcp, resp_h=208.80.152.118, resp_p=80/tcp], WUjEZFOdSS
[orig_h=141.142.220.118, orig_p=48649/tcp, resp_h=208.80.152.118, resp_p=80/tcp], WUjEZFOdSS
[orig_h=141.142.220.118, orig_p=48649/tcp, resp_h=208.80.152.118, resp_p=80/tcp], WUjEZFOdSS
[orig_h=141.142.220.118, orig_p=43927/udp, resp_h=141.142.2.2, resp_p=53/udp], ecqdozAET6c
[orig_h=141.142.220.118, orig_p=43927/udp, resp_h=141.142.2.2, resp_p=53/udp], ecqdozAET6c
[orig_h=141.142.220.118, orig_p=37676/udp, resp_h=141.142.2.2, resp_p=53/udp], tdkrEYpj5ja
[orig_h=141.142.220.118, orig_p=37676/udp, resp_h=141.142.2.2, resp_p=53/udp], tdkrEYpj5ja
[orig_h=141.142.220.118, orig_p=40526/udp, resp_h=141.142.2.2, resp_p=53/udp], F5XgctwO3Vl
[orig_h=141.142.220.118, orig_p=40526/udp, resp_h=141.142.2.2, resp_p=53/udp], F5XgctwO3Vl
[orig_h=141.142.220.118, orig_p=49996/tcp, resp_h=208.80.152.3, resp_p=80/tcp], svqqNKN9CFj
[orig_h=141.142.220.118, orig_p=49996/tcp, resp_h=208.80.152.3, resp_p=80/tcp], svqqNKN9CFj
[orig_h=141.142.220.118, orig_p=49997/tcp, resp_h=208.80.152.3, resp_p=80/tcp], UZkBBvjF0r8
[orig_h=141.142.220.118, orig_p=49997/tcp, resp_h=208.80.152.3, resp_p=80/tcp], UZkBBvjF0r8
[orig_h=141.142.220.118, orig_p=32902/udp, resp_h=141.142.2.2, resp_p=53/udp], nSEQzFk1LZc
[orig_h=141.142.220.118, orig_p=32902/udp, resp_h=141.142.2.2, resp_p=53/udp], nSEQzFk1LZc
[orig_h=141.142.220.118, orig_p=59816/udp, resp_h=141.142.2.2, resp_p=53/udp], rmXOq6wncn1
[orig_h=141.142.220.118, orig_p=59816/udp, resp_h=141.142.2.2, resp_p=53/udp], rmXOq6wncn1
[orig_h=141.142.220.118, orig_p=59714/udp, resp_h=141.142.2.2, resp_p=53/udp], 4YYJTjETe1i
[orig_h=141.142.220.118, orig_p=59714/udp, resp_h=141.142.2.2, resp_p=53/udp], 4YYJTjETe1i
[orig_h=141.142.220.118, orig_p=49998/tcp, resp_h=208.80.152.3, resp_p=80/tcp], OldlyspNIr7
[orig_h=141.142.220.118, orig_p=49998/tcp, resp_h=208.80.152.3, resp_p=80/tcp], OldlyspNIr7
[orig_h=141.142.220.118, orig_p=58206/udp, resp_h=141.142.2.2, resp_p=53/udp], R8BqVlcp23e
[orig_h=141.142.220.118, orig_p=58206/udp, resp_h=141.142.2.2, resp_p=53/udp], R8BqVlcp23e
[orig_h=141.142.220.118, orig_p=38911/udp, resp_h=141.142.2.2, resp_p=53/udp], duYdXg7bTa3
[orig_h=141.142.220.118, orig_p=38911/udp, resp_h=141.142.2.2, resp_p=53/udp], duYdXg7bTa3
[orig_h=141.142.220.118, orig_p=59746/udp, resp_h=141.142.2.2, resp_p=53/udp], yzqaQTU9DXe
[orig_h=141.142.220.118, orig_p=59746/udp, resp_h=141.142.2.2, resp_p=53/udp], yzqaQTU9DXe
[orig_h=141.142.220.118, orig_p=49999/tcp, resp_h=208.80.152.3, resp_p=80/tcp], OPM7xFSDNw3
[orig_h=141.142.220.118, orig_p=49999/tcp, resp_h=208.80.152.3, resp_p=80/tcp], OPM7xFSDNw3
[orig_h=141.142.220.118, orig_p=50000/tcp, resp_h=208.80.152.3, resp_p=80/tcp], j5w2LueK8Ti
[orig_h=141.142.220.118, orig_p=50000/tcp, resp_h=208.80.152.3, resp_p=80/tcp], j5w2LueK8Ti
[orig_h=141.142.220.118, orig_p=45000/udp, resp_h=141.142.2.2, resp_p=53/udp], N6rbUGwigQ7
[orig_h=141.142.220.118, orig_p=45000/udp, resp_h=141.142.2.2, resp_p=53/udp], N6rbUGwigQ7
[orig_h=141.142.220.118, orig_p=48479/udp, resp_h=141.142.2.2, resp_p=53/udp], 8b9q7qPtzhd
[orig_h=141.142.220.118, orig_p=48479/udp, resp_h=141.142.2.2, resp_p=53/udp], 8b9q7qPtzhd
[orig_h=141.142.220.118, orig_p=48128/udp, resp_h=141.142.2.2, resp_p=53/udp], KOdlL7sC9z2
[orig_h=141.142.220.118, orig_p=48128/udp, resp_h=141.142.2.2, resp_p=53/udp], KOdlL7sC9z2
[orig_h=141.142.220.118, orig_p=50001/tcp, resp_h=208.80.152.3, resp_p=80/tcp], hvOo97vj60k
[orig_h=141.142.220.118, orig_p=50001/tcp, resp_h=208.80.152.3, resp_p=80/tcp], hvOo97vj60k
[orig_h=141.142.220.118, orig_p=56056/udp, resp_h=141.142.2.2, resp_p=53/udp], FHu81uYujA9
[orig_h=141.142.220.118, orig_p=56056/udp, resp_h=141.142.2.2, resp_p=53/udp], FHu81uYujA9
[orig_h=141.142.220.118, orig_p=55092/udp, resp_h=141.142.2.2, resp_p=53/udp], 2M1wDTa0C7a
[orig_h=141.142.220.118, orig_p=55092/udp, resp_h=141.142.2.2, resp_p=53/udp], 2M1wDTa0C7a
[orig_h=141.142.220.118, orig_p=35642/tcp, resp_h=208.80.152.2, resp_p=80/tcp], OKiJdtzKWPk
[orig_h=141.142.220.118, orig_p=35642/tcp, resp_h=208.80.152.2, resp_p=80/tcp], OKiJdtzKWPk
[orig_h=141.142.220.118, orig_p=49997/tcp, resp_h=208.80.152.3, resp_p=80/tcp], UZkBBvjF0r8
[orig_h=141.142.220.118, orig_p=49997/tcp, resp_h=208.80.152.3, resp_p=80/tcp], UZkBBvjF0r8
[orig_h=141.142.220.118, orig_p=49996/tcp, resp_h=208.80.152.3, resp_p=80/tcp], svqqNKN9CFj
[orig_h=141.142.220.118, orig_p=49996/tcp, resp_h=208.80.152.3, resp_p=80/tcp], svqqNKN9CFj
[orig_h=141.142.220.118, orig_p=49998/tcp, resp_h=208.80.152.3, resp_p=80/tcp], OldlyspNIr7
[orig_h=141.142.220.118, orig_p=49998/tcp, resp_h=208.80.152.3, resp_p=80/tcp], OldlyspNIr7
[orig_h=141.142.220.118, orig_p=50000/tcp, resp_h=208.80.152.3, resp_p=80/tcp], j5w2LueK8Ti
[orig_h=141.142.220.118, orig_p=50000/tcp, resp_h=208.80.152.3, resp_p=80/tcp], j5w2LueK8Ti
[orig_h=141.142.220.118, orig_p=49999/tcp, resp_h=208.80.152.3, resp_p=80/tcp], OPM7xFSDNw3
[orig_h=141.142.220.118, orig_p=49999/tcp, resp_h=208.80.152.3, resp_p=80/tcp], OPM7xFSDNw3
[orig_h=141.142.220.118, orig_p=50001/tcp, resp_h=208.80.152.3, resp_p=80/tcp], hvOo97vj60k
[orig_h=141.142.220.118, orig_p=50001/tcp, resp_h=208.80.152.3, resp_p=80/tcp], hvOo97vj60k
[orig_h=141.142.220.118, orig_p=35642/tcp, resp_h=208.80.152.2, resp_p=80/tcp], OKiJdtzKWPk
[orig_h=141.142.220.118, orig_p=35642/tcp, resp_h=208.80.152.2, resp_p=80/tcp], OKiJdtzKWPk
[orig_h=141.142.220.235, orig_p=6705/tcp, resp_h=173.192.163.128, resp_p=80/tcp], tpUWfNdSLE
[orig_h=141.142.220.235, orig_p=6705/tcp, resp_h=173.192.163.128, resp_p=80/tcp], tpUWfNdSLE
[orig_h=141.142.220.44, orig_p=5353/udp, resp_h=224.0.0.251, resp_p=5353/udp], ra1C6ZLut4b
[orig_h=141.142.220.44, orig_p=5353/udp, resp_h=224.0.0.251, resp_p=5353/udp], ra1C6ZLut4b
[orig_h=141.142.220.226, orig_p=137/udp, resp_h=141.142.220.255, resp_p=137/udp], UElDH5b9qA5
[orig_h=141.142.220.226, orig_p=137/udp, resp_h=141.142.220.255, resp_p=137/udp], UElDH5b9qA5
[orig_h=141.142.220.226, orig_p=55131/udp, resp_h=224.0.0.252, resp_p=5355/udp], sO3mBXBav1h
[orig_h=141.142.220.226, orig_p=55131/udp, resp_h=224.0.0.252, resp_p=5355/udp], sO3mBXBav1h
[orig_h=141.142.220.226, orig_p=55671/udp, resp_h=224.0.0.252, resp_p=5355/udp], xAQqZE8Wdp4
[orig_h=141.142.220.226, orig_p=55671/udp, resp_h=224.0.0.252, resp_p=5355/udp], xAQqZE8Wdp4
[orig_h=141.142.220.238, orig_p=56641/udp, resp_h=141.142.220.255, resp_p=137/udp], zVecVnfOlsf
[orig_h=141.142.220.238, orig_p=56641/udp, resp_h=141.142.220.255, resp_p=137/udp], zVecVnfOlsf

View file

@ -1,36 +1,80 @@
[orig_h=141.142.220.118, orig_p=48649/tcp, resp_h=208.80.152.118, resp_p=80/tcp], UWkUyAuUGXf
[orig_h=141.142.220.118, orig_p=48649/tcp, resp_h=208.80.152.118, resp_p=80/tcp], UWkUyAuUGXf
[orig_h=141.142.220.118, orig_p=48649/tcp, resp_h=208.80.152.118, resp_p=80/tcp], UWkUyAuUGXf
[orig_h=141.142.220.118, orig_p=48649/tcp, resp_h=208.80.152.118, resp_p=80/tcp], UWkUyAuUGXf
[orig_h=141.142.220.118, orig_p=49996/tcp, resp_h=208.80.152.3, resp_p=80/tcp], 56gKBmhBBB6
[orig_h=141.142.220.118, orig_p=49996/tcp, resp_h=208.80.152.3, resp_p=80/tcp], 56gKBmhBBB6
[orig_h=141.142.220.118, orig_p=49997/tcp, resp_h=208.80.152.3, resp_p=80/tcp], 50da4BEzauh
[orig_h=141.142.220.118, orig_p=49997/tcp, resp_h=208.80.152.3, resp_p=80/tcp], 50da4BEzauh
[orig_h=141.142.220.118, orig_p=49998/tcp, resp_h=208.80.152.3, resp_p=80/tcp], WUjEZFOdSS
[orig_h=141.142.220.118, orig_p=49998/tcp, resp_h=208.80.152.3, resp_p=80/tcp], WUjEZFOdSS
[orig_h=141.142.220.118, orig_p=49999/tcp, resp_h=208.80.152.3, resp_p=80/tcp], ecqdozAET6c
[orig_h=141.142.220.118, orig_p=49999/tcp, resp_h=208.80.152.3, resp_p=80/tcp], ecqdozAET6c
[orig_h=141.142.220.118, orig_p=50000/tcp, resp_h=208.80.152.3, resp_p=80/tcp], tdkrEYpj5ja
[orig_h=141.142.220.118, orig_p=50000/tcp, resp_h=208.80.152.3, resp_p=80/tcp], tdkrEYpj5ja
[orig_h=141.142.220.118, orig_p=50001/tcp, resp_h=208.80.152.3, resp_p=80/tcp], F5XgctwO3Vl
[orig_h=141.142.220.118, orig_p=50001/tcp, resp_h=208.80.152.3, resp_p=80/tcp], F5XgctwO3Vl
[orig_h=141.142.220.118, orig_p=35642/tcp, resp_h=208.80.152.2, resp_p=80/tcp], svqqNKN9CFj
[orig_h=141.142.220.118, orig_p=35642/tcp, resp_h=208.80.152.2, resp_p=80/tcp], svqqNKN9CFj
[orig_h=141.142.220.118, orig_p=49997/tcp, resp_h=208.80.152.3, resp_p=80/tcp], 50da4BEzauh
[orig_h=141.142.220.118, orig_p=49997/tcp, resp_h=208.80.152.3, resp_p=80/tcp], 50da4BEzauh
[orig_h=141.142.220.118, orig_p=49996/tcp, resp_h=208.80.152.3, resp_p=80/tcp], 56gKBmhBBB6
[orig_h=141.142.220.118, orig_p=49996/tcp, resp_h=208.80.152.3, resp_p=80/tcp], 56gKBmhBBB6
[orig_h=141.142.220.118, orig_p=49998/tcp, resp_h=208.80.152.3, resp_p=80/tcp], WUjEZFOdSS
[orig_h=141.142.220.118, orig_p=49998/tcp, resp_h=208.80.152.3, resp_p=80/tcp], WUjEZFOdSS
[orig_h=141.142.220.118, orig_p=50000/tcp, resp_h=208.80.152.3, resp_p=80/tcp], tdkrEYpj5ja
[orig_h=141.142.220.118, orig_p=50000/tcp, resp_h=208.80.152.3, resp_p=80/tcp], tdkrEYpj5ja
[orig_h=141.142.220.118, orig_p=49999/tcp, resp_h=208.80.152.3, resp_p=80/tcp], ecqdozAET6c
[orig_h=141.142.220.118, orig_p=49999/tcp, resp_h=208.80.152.3, resp_p=80/tcp], ecqdozAET6c
[orig_h=141.142.220.118, orig_p=50001/tcp, resp_h=208.80.152.3, resp_p=80/tcp], F5XgctwO3Vl
[orig_h=141.142.220.118, orig_p=50001/tcp, resp_h=208.80.152.3, resp_p=80/tcp], F5XgctwO3Vl
[orig_h=141.142.220.118, orig_p=35642/tcp, resp_h=208.80.152.2, resp_p=80/tcp], svqqNKN9CFj
[orig_h=141.142.220.118, orig_p=35642/tcp, resp_h=208.80.152.2, resp_p=80/tcp], svqqNKN9CFj
[orig_h=141.142.220.235, orig_p=6705/tcp, resp_h=173.192.163.128, resp_p=80/tcp], UZkBBvjF0r8
[orig_h=141.142.220.235, orig_p=6705/tcp, resp_h=173.192.163.128, resp_p=80/tcp], UZkBBvjF0r8
[orig_h=141.142.220.235, orig_p=6705/tcp, resp_h=173.192.163.128, resp_p=80/tcp], UZkBBvjF0r8
[orig_h=141.142.220.235, orig_p=6705/tcp, resp_h=173.192.163.128, resp_p=80/tcp], UZkBBvjF0r8
[orig_h=141.142.220.202, orig_p=5353/udp, resp_h=224.0.0.251, resp_p=5353/udp], UWkUyAuUGXf
[orig_h=141.142.220.202, orig_p=5353/udp, resp_h=224.0.0.251, resp_p=5353/udp], UWkUyAuUGXf
[orig_h=141.142.220.50, orig_p=5353/udp, resp_h=224.0.0.251, resp_p=5353/udp], 56gKBmhBBB6
[orig_h=141.142.220.50, orig_p=5353/udp, resp_h=224.0.0.251, resp_p=5353/udp], 56gKBmhBBB6
[orig_h=141.142.220.118, orig_p=35634/tcp, resp_h=208.80.152.2, resp_p=80/tcp], 50da4BEzauh
[orig_h=141.142.220.118, orig_p=35634/tcp, resp_h=208.80.152.2, resp_p=80/tcp], 50da4BEzauh
[orig_h=141.142.220.118, orig_p=48649/tcp, resp_h=208.80.152.118, resp_p=80/tcp], WUjEZFOdSS
[orig_h=141.142.220.118, orig_p=48649/tcp, resp_h=208.80.152.118, resp_p=80/tcp], WUjEZFOdSS
[orig_h=141.142.220.118, orig_p=48649/tcp, resp_h=208.80.152.118, resp_p=80/tcp], WUjEZFOdSS
[orig_h=141.142.220.118, orig_p=48649/tcp, resp_h=208.80.152.118, resp_p=80/tcp], WUjEZFOdSS
[orig_h=141.142.220.118, orig_p=43927/udp, resp_h=141.142.2.2, resp_p=53/udp], ecqdozAET6c
[orig_h=141.142.220.118, orig_p=43927/udp, resp_h=141.142.2.2, resp_p=53/udp], ecqdozAET6c
[orig_h=141.142.220.118, orig_p=37676/udp, resp_h=141.142.2.2, resp_p=53/udp], tdkrEYpj5ja
[orig_h=141.142.220.118, orig_p=37676/udp, resp_h=141.142.2.2, resp_p=53/udp], tdkrEYpj5ja
[orig_h=141.142.220.118, orig_p=40526/udp, resp_h=141.142.2.2, resp_p=53/udp], F5XgctwO3Vl
[orig_h=141.142.220.118, orig_p=40526/udp, resp_h=141.142.2.2, resp_p=53/udp], F5XgctwO3Vl
[orig_h=141.142.220.118, orig_p=49996/tcp, resp_h=208.80.152.3, resp_p=80/tcp], svqqNKN9CFj
[orig_h=141.142.220.118, orig_p=49996/tcp, resp_h=208.80.152.3, resp_p=80/tcp], svqqNKN9CFj
[orig_h=141.142.220.118, orig_p=49997/tcp, resp_h=208.80.152.3, resp_p=80/tcp], UZkBBvjF0r8
[orig_h=141.142.220.118, orig_p=49997/tcp, resp_h=208.80.152.3, resp_p=80/tcp], UZkBBvjF0r8
[orig_h=141.142.220.118, orig_p=32902/udp, resp_h=141.142.2.2, resp_p=53/udp], nSEQzFk1LZc
[orig_h=141.142.220.118, orig_p=32902/udp, resp_h=141.142.2.2, resp_p=53/udp], nSEQzFk1LZc
[orig_h=141.142.220.118, orig_p=59816/udp, resp_h=141.142.2.2, resp_p=53/udp], rmXOq6wncn1
[orig_h=141.142.220.118, orig_p=59816/udp, resp_h=141.142.2.2, resp_p=53/udp], rmXOq6wncn1
[orig_h=141.142.220.118, orig_p=59714/udp, resp_h=141.142.2.2, resp_p=53/udp], 4YYJTjETe1i
[orig_h=141.142.220.118, orig_p=59714/udp, resp_h=141.142.2.2, resp_p=53/udp], 4YYJTjETe1i
[orig_h=141.142.220.118, orig_p=49998/tcp, resp_h=208.80.152.3, resp_p=80/tcp], OldlyspNIr7
[orig_h=141.142.220.118, orig_p=49998/tcp, resp_h=208.80.152.3, resp_p=80/tcp], OldlyspNIr7
[orig_h=141.142.220.118, orig_p=58206/udp, resp_h=141.142.2.2, resp_p=53/udp], R8BqVlcp23e
[orig_h=141.142.220.118, orig_p=58206/udp, resp_h=141.142.2.2, resp_p=53/udp], R8BqVlcp23e
[orig_h=141.142.220.118, orig_p=38911/udp, resp_h=141.142.2.2, resp_p=53/udp], duYdXg7bTa3
[orig_h=141.142.220.118, orig_p=38911/udp, resp_h=141.142.2.2, resp_p=53/udp], duYdXg7bTa3
[orig_h=141.142.220.118, orig_p=59746/udp, resp_h=141.142.2.2, resp_p=53/udp], yzqaQTU9DXe
[orig_h=141.142.220.118, orig_p=59746/udp, resp_h=141.142.2.2, resp_p=53/udp], yzqaQTU9DXe
[orig_h=141.142.220.118, orig_p=49999/tcp, resp_h=208.80.152.3, resp_p=80/tcp], OPM7xFSDNw3
[orig_h=141.142.220.118, orig_p=49999/tcp, resp_h=208.80.152.3, resp_p=80/tcp], OPM7xFSDNw3
[orig_h=141.142.220.118, orig_p=50000/tcp, resp_h=208.80.152.3, resp_p=80/tcp], j5w2LueK8Ti
[orig_h=141.142.220.118, orig_p=50000/tcp, resp_h=208.80.152.3, resp_p=80/tcp], j5w2LueK8Ti
[orig_h=141.142.220.118, orig_p=45000/udp, resp_h=141.142.2.2, resp_p=53/udp], N6rbUGwigQ7
[orig_h=141.142.220.118, orig_p=45000/udp, resp_h=141.142.2.2, resp_p=53/udp], N6rbUGwigQ7
[orig_h=141.142.220.118, orig_p=48479/udp, resp_h=141.142.2.2, resp_p=53/udp], 8b9q7qPtzhd
[orig_h=141.142.220.118, orig_p=48479/udp, resp_h=141.142.2.2, resp_p=53/udp], 8b9q7qPtzhd
[orig_h=141.142.220.118, orig_p=48128/udp, resp_h=141.142.2.2, resp_p=53/udp], KOdlL7sC9z2
[orig_h=141.142.220.118, orig_p=48128/udp, resp_h=141.142.2.2, resp_p=53/udp], KOdlL7sC9z2
[orig_h=141.142.220.118, orig_p=50001/tcp, resp_h=208.80.152.3, resp_p=80/tcp], hvOo97vj60k
[orig_h=141.142.220.118, orig_p=50001/tcp, resp_h=208.80.152.3, resp_p=80/tcp], hvOo97vj60k
[orig_h=141.142.220.118, orig_p=56056/udp, resp_h=141.142.2.2, resp_p=53/udp], FHu81uYujA9
[orig_h=141.142.220.118, orig_p=56056/udp, resp_h=141.142.2.2, resp_p=53/udp], FHu81uYujA9
[orig_h=141.142.220.118, orig_p=55092/udp, resp_h=141.142.2.2, resp_p=53/udp], 2M1wDTa0C7a
[orig_h=141.142.220.118, orig_p=55092/udp, resp_h=141.142.2.2, resp_p=53/udp], 2M1wDTa0C7a
[orig_h=141.142.220.118, orig_p=35642/tcp, resp_h=208.80.152.2, resp_p=80/tcp], OKiJdtzKWPk
[orig_h=141.142.220.118, orig_p=35642/tcp, resp_h=208.80.152.2, resp_p=80/tcp], OKiJdtzKWPk
[orig_h=141.142.220.118, orig_p=49997/tcp, resp_h=208.80.152.3, resp_p=80/tcp], UZkBBvjF0r8
[orig_h=141.142.220.118, orig_p=49997/tcp, resp_h=208.80.152.3, resp_p=80/tcp], UZkBBvjF0r8
[orig_h=141.142.220.118, orig_p=49996/tcp, resp_h=208.80.152.3, resp_p=80/tcp], svqqNKN9CFj
[orig_h=141.142.220.118, orig_p=49996/tcp, resp_h=208.80.152.3, resp_p=80/tcp], svqqNKN9CFj
[orig_h=141.142.220.118, orig_p=49998/tcp, resp_h=208.80.152.3, resp_p=80/tcp], OldlyspNIr7
[orig_h=141.142.220.118, orig_p=49998/tcp, resp_h=208.80.152.3, resp_p=80/tcp], OldlyspNIr7
[orig_h=141.142.220.118, orig_p=50000/tcp, resp_h=208.80.152.3, resp_p=80/tcp], j5w2LueK8Ti
[orig_h=141.142.220.118, orig_p=50000/tcp, resp_h=208.80.152.3, resp_p=80/tcp], j5w2LueK8Ti
[orig_h=141.142.220.118, orig_p=49999/tcp, resp_h=208.80.152.3, resp_p=80/tcp], OPM7xFSDNw3
[orig_h=141.142.220.118, orig_p=49999/tcp, resp_h=208.80.152.3, resp_p=80/tcp], OPM7xFSDNw3
[orig_h=141.142.220.118, orig_p=50001/tcp, resp_h=208.80.152.3, resp_p=80/tcp], hvOo97vj60k
[orig_h=141.142.220.118, orig_p=50001/tcp, resp_h=208.80.152.3, resp_p=80/tcp], hvOo97vj60k
[orig_h=141.142.220.118, orig_p=35642/tcp, resp_h=208.80.152.2, resp_p=80/tcp], OKiJdtzKWPk
[orig_h=141.142.220.118, orig_p=35642/tcp, resp_h=208.80.152.2, resp_p=80/tcp], OKiJdtzKWPk
[orig_h=141.142.220.235, orig_p=6705/tcp, resp_h=173.192.163.128, resp_p=80/tcp], tpUWfNdSLE
[orig_h=141.142.220.235, orig_p=6705/tcp, resp_h=173.192.163.128, resp_p=80/tcp], tpUWfNdSLE
[orig_h=141.142.220.235, orig_p=6705/tcp, resp_h=173.192.163.128, resp_p=80/tcp], tpUWfNdSLE
[orig_h=141.142.220.235, orig_p=6705/tcp, resp_h=173.192.163.128, resp_p=80/tcp], tpUWfNdSLE
[orig_h=141.142.220.44, orig_p=5353/udp, resp_h=224.0.0.251, resp_p=5353/udp], ra1C6ZLut4b
[orig_h=141.142.220.44, orig_p=5353/udp, resp_h=224.0.0.251, resp_p=5353/udp], ra1C6ZLut4b
[orig_h=141.142.220.226, orig_p=137/udp, resp_h=141.142.220.255, resp_p=137/udp], UElDH5b9qA5
[orig_h=141.142.220.226, orig_p=137/udp, resp_h=141.142.220.255, resp_p=137/udp], UElDH5b9qA5
[orig_h=141.142.220.226, orig_p=55131/udp, resp_h=224.0.0.252, resp_p=5355/udp], sO3mBXBav1h
[orig_h=141.142.220.226, orig_p=55131/udp, resp_h=224.0.0.252, resp_p=5355/udp], sO3mBXBav1h
[orig_h=141.142.220.226, orig_p=55671/udp, resp_h=224.0.0.252, resp_p=5355/udp], xAQqZE8Wdp4
[orig_h=141.142.220.226, orig_p=55671/udp, resp_h=224.0.0.252, resp_p=5355/udp], xAQqZE8Wdp4
[orig_h=141.142.220.238, orig_p=56641/udp, resp_h=141.142.220.255, resp_p=137/udp], zVecVnfOlsf
[orig_h=141.142.220.238, orig_p=56641/udp, resp_h=141.142.220.255, resp_p=137/udp], zVecVnfOlsf

Some files were not shown because too many files have changed in this diff Show more