Sync with master for merge.

This commit is contained in:
Zeke Medley 2019-06-24 09:40:43 -07:00
commit 6fd7d8c4d4
69 changed files with 910 additions and 3937 deletions

53
CHANGES
View file

@ -1,4 +1,57 @@
2.6-503 | 2019-06-21 11:17:58 -0700
* GH-417: Remove old, unmaintained p0f support. (Johanna Amann, Corelight)
2.6-500 | 2019-06-20 20:54:15 -0700
* Add new RDP event: rdp_client_cluster_data (Jeff Atkinson)
* Added "options" field to RDP::ClientChannelDef (Jeff Atkinson)
2.6-494 | 2019-06-20 20:24:38 -0700
* Renaming src/StateAccess.{h,cc} to src/Notifier.{h,cc}.
The old names did not reflect the content of the files anymore. (Robin Sommer, Corelight)
* Remove MutableVal, StateAccess classes, enum Opcode. (Robin Sommer, Corelight)
* Redo API for notifiers.
There's now an notifier::Modifiable interface class that class
supposed to signal modifications are to be derived from. This takes
the place of the former MutableValue class and also unifies how Val
and IDs signal modifications. (Robin Sommer, Corelight)
* Redo NotfifierRegistry to no longer rely on StateAccess.
We simplify the API to a simple Modified() operation. (Robin Sommer, Corelight)
* Add new test for when-statement watching global variables. (Robin Sommer, Corelight)
2.6-482 | 2019-06-20 19:57:20 -0700
* Make configure complain if submodules are not checked out. (Johanna Amann, Corelight)
* Improve C++ header includes to improve build time (Jon Siwek, Corelight)
2.6-479 | 2019-06-20 18:31:58 -0700
* Fix TableVal::DoClone to use CloneState cache (Jon Siwek, Corelight)
2.6-478 | 2019-06-20 14:19:11 -0700
* Remove old Broccoli SSL options (Jon Siwek, Corelight)
- ssl_ca_certificate
- ssl_private_key
- ssl_passphrase
2.6-477 | 2019-06-20 14:00:22 -0700
* Remove unused SerialInfo.h and SerialTypes.h headers (Jon Siwek, Corelight)
2.6-476 | 2019-06-20 13:23:22 -0700 2.6-476 | 2019-06-20 13:23:22 -0700
* Remove opaque of ocsp_resp. (Johanna Amann, Corelight) * Remove opaque of ocsp_resp. (Johanna Amann, Corelight)

10
NEWS
View file

@ -87,6 +87,7 @@ New Functionality
- New events: - New events:
- rdp_client_network_data - rdp_client_network_data
- rdp_client_security_data - rdp_client_security_data
- rdp_client_cluster_data
- rdp_native_encrypted_data - rdp_native_encrypted_data
- Add a new "client_channels" field to rdp.log based on data parsed from - Add a new "client_channels" field to rdp.log based on data parsed from
@ -418,6 +419,9 @@ Removed Functionality
- ``log_encryption_key`` - ``log_encryption_key``
- ``state_dir`` - ``state_dir``
- ``state_write_delay`` - ``state_write_delay``
- ``ssl_ca_certificate``
- ``ssl_private_key``
- ``ssl_passphrase``
- The following constants were used as part of deprecated functionality in version 2.6 - The following constants were used as part of deprecated functionality in version 2.6
or below and are removed from this release: or below and are removed from this release:
@ -450,6 +454,12 @@ Removed Functionality
anc was basically untested. The ``-R`` command-line option (replay) anc was basically untested. The ``-R`` command-line option (replay)
as well as the ``capture_events`` function were removed. as well as the ``capture_events`` function were removed.
- Removed p0f (passive OS fingerprinting) support. The version of
p0f shipped with zeek was ancient, probably did not give
any reliable support anymore and did not offer a clear
upgrade path. The ``OS_version_found`` event as well as the
``generate_OS_version_event`` configuration option were removed.
Deprecated Functionality Deprecated Functionality
------------------------ ------------------------

View file

@ -1 +1 @@
2.6-476 2.6-503

12
configure vendored
View file

@ -106,6 +106,18 @@ Usage: $0 [OPTION]... [VAR=VALUE]...
sourcedir="$( cd "$( dirname "$0" )" && pwd )" sourcedir="$( cd "$( dirname "$0" )" && pwd )"
if [ ! -e "$sourcedir/cmake/COPYING" ] && [ -d "$sourcedir/.git" ]; then
echo "\
You seem to be missing the content of the cmake directory.
This typically means that you performed a non-recursive git clone of
Zeek. To check out the required subdirectories, please execute:
( cd $sourcedir && git submodule update --recursive --init )
" >&2;
exit 1;
fi
# Function to append a CMake cache entry definition to the # Function to append a CMake cache entry definition to the
# CMakeCacheEntries variable. # CMakeCacheEntries variable.
# $1 is the cache entry variable name # $1 is the cache entry variable name

View file

@ -1844,9 +1844,6 @@ function add_signature_file(sold: string, snew: string): string
## since that can search paths relative to the current script. ## since that can search paths relative to the current script.
global signature_files = "" &add_func = add_signature_file; global signature_files = "" &add_func = add_signature_file;
## ``p0f`` fingerprint file to use. Will be searched relative to ``ZEEKPATH``.
const passive_fingerprint_file = "base/misc/p0f.fp" &redef;
## Definition of "secondary filters". A secondary filter is a BPF filter given ## Definition of "secondary filters". A secondary filter is a BPF filter given
## as index in this table. For each such filter, the corresponding event is ## as index in this table. For each such filter, the corresponding event is
## raised for all matching packets. ## raised for all matching packets.
@ -3991,30 +3988,6 @@ type software: record {
version: software_version; version: software_version;
}; };
## Quality of passive fingerprinting matches.
##
## .. zeek:see:: OS_version
type OS_version_inference: enum {
direct_inference, ##< TODO.
generic_inference, ##< TODO.
fuzzy_inference, ##< TODO.
};
## Passive fingerprinting match.
##
## .. zeek:see:: OS_version_found
type OS_version: record {
genre: string; ##< Linux, Windows, AIX, ...
detail: string; ##< Kernel version or such.
dist: count; ##< How far is the host away from the sensor (TTL)?.
match_type: OS_version_inference; ##< Quality of the match.
};
## Defines for which subnets we should do passive fingerprinting.
##
## .. zeek:see:: OS_version_found
global generate_OS_version_event: set[subnet] &redef;
# Type used to report load samples via :zeek:see:`load_sample`. For now, it's a # Type used to report load samples via :zeek:see:`load_sample`. For now, it's a
# set of names (event names, source file names, and perhaps ``<source file, line # set of names (event names, source file names, and perhaps ``<source file, line
# number>``), which were seen during the sample. # number>``), which were seen during the sample.
@ -4279,6 +4252,8 @@ export {
type RDP::ClientChannelDef: record { type RDP::ClientChannelDef: record {
## A unique name for the channel ## A unique name for the channel
name: string; name: string;
## Channel Def raw options as count
options: count;
## Absence of this flag indicates that this channel is ## Absence of this flag indicates that this channel is
## a placeholder and that the server MUST NOT set it up. ## a placeholder and that the server MUST NOT set it up.
initialized: bool; initialized: bool;
@ -4304,6 +4279,30 @@ export {
persistent: bool; persistent: bool;
}; };
## The TS_UD_CS_CLUSTER data block is sent by the client to the server
## either to advertise that it can support the Server Redirection PDUs
## or to request a connection to a given session identifier.
type RDP::ClientClusterData: record {
## Cluster information flags.
flags: count;
## If the *redir_sessionid_field_valid* flag is set, this field
## contains a valid session identifier to which the client requests
## to connect.
redir_session_id: count;
## The client can receive server session redirection packets.
## If this flag is set, the *svr_session_redir_version_mask*
## field MUST contain the server session redirection version that
## the client supports.
redir_supported: bool;
## The server session redirection version that the client supports.
svr_session_redir_version_mask: count;
## Whether the *redir_session_id* field identifies a session on
## the server to associate with the connection.
redir_sessionid_field_valid: bool;
## The client logged on with a smart card.
redir_smartcard: bool;
};
## The list of channels requested by the client. ## The list of channels requested by the client.
type RDP::ClientChannelList: vector of ClientChannelDef; type RDP::ClientChannelList: vector of ClientChannelDef;
} }
@ -4710,22 +4709,6 @@ const report_gaps_for_partial = F &redef;
## controlled for reproducing results. ## controlled for reproducing results.
const exit_only_after_terminate = F &redef; const exit_only_after_terminate = F &redef;
## The CA certificate file to authorize remote Zeeks/Broccolis.
##
## .. zeek:see:: ssl_private_key ssl_passphrase
const ssl_ca_certificate = "<undefined>" &redef;
## File containing our private key and our certificate.
##
## .. zeek:see:: ssl_ca_certificate ssl_passphrase
const ssl_private_key = "<undefined>" &redef;
## The passphrase for our private key. Keeping this undefined
## causes Zeek to prompt for the passphrase.
##
## .. zeek:see:: ssl_private_key ssl_ca_certificate
const ssl_passphrase = "<undefined>" &redef;
## Default mode for Zeek's user-space dynamic packet filter. If true, packets ## Default mode for Zeek's user-space dynamic packet filter. If true, packets
## that aren't explicitly allowed through, are dropped from any further ## that aren't explicitly allowed through, are dropped from any further
## processing. ## processing.

View file

@ -1,834 +0,0 @@
#
# p0f - SYN fingerprints
# ----------------------
#
# .-------------------------------------------------------------------------.
# | The purpose of this file is to cover signatures for incoming TCP/IP |
# | connections (SYN packets). This is the default mode of operation for |
# | p0f. This is also the biggest and most up-to-date set of signatures |
# | shipped with this project. The file also contains a detailed discussion |
# | of all metrics examined by p0f, and some practical notes on how to |
# | add new signatures. |
# `-------------------------------------------------------------------------'
#
# (C) Copyright 2000-2006 by Michal Zalewski <lcamtuf@coredump.cx>
#
# Each line in this file specifies a single fingerprint. Please read the
# information below carefully before attempting to append any signatures
# reported by p0f as UNKNOWN to this file to avoid mistakes. Note that
# this file is compatible only with the default operation mode, and not
# with -R or -A options (SYN+ACK and RST+ modes).
#
# We use the following set metrics for fingerprinting:
#
# - Window size (WSS) - a highly OS dependent setting used for TCP/IP
# performance control (max. amount of data to be sent without ACK).
# Some systems use a fixed value for initial packets. On other
# systems, it is a multiple of MSS or MTU (MSS+40). In some rare
# cases, the value is just arbitrary.
#
# NEW SIGNATURE: if p0f reported a special value of 'Snn', the number
# appears to be a multiple of MSS (MSS*nn); a special value of 'Tnn'
# means it is a multiple of MTU ((MSS+40)*nn). Unless you notice the
# value of nn is not fixed (unlikely), just copy the Snn or Tnn token
# literally. If you know this device has a simple stack and a fixed
# MTU, you can however multiply S value by MSS, or T value by MSS+40,
# and put it instead of Snn or Tnn. One system may exhibit several T
# or S values. In some situations, this might be a source of some
# additional information about the setup if you have some time to dig
# thru the kernel sources; in some other cases, like Windows, there seem
# to be a multitude of variants and WSS selection algorithms, but it's
# rather difficult to find a pattern without having the source.
#
# If WSS looks like a regular fixed value (for example is a power of two),
# or if you can confirm the value is fixed by looking at several
# fingerprints, please quote it literaly. If there's no apparent pattern
# in WSS chosen, you should consider wildcarding this value - but this
# should be the last option.
#
# NOTE: Some NAT devices, such as Linux iptables with --set-mss, will
# modify MSS, but not WSS. As a result, MSS is changed to reflect
# the MTU of the NAT device, but WSS remains a multiple of the original
# MSS. Fortunately for us, the source device would almost always be
# hooked up to Ethernet. P0f handles it automatically for the original
# MSS of 1460, by adding "NAT!" tag to the result.
#
# In certain configurations, Linux erratically (?) uses MTU from another
# interface on the default gw interface. This only happens on systems with
# two network interfaces. Thus, some Linux systems that do not go thru NAT,
# but have multiple interfaces instead, will be also tagged this way.
#
# P0f recognizes and automatically wildcards WSS of 12345, as generated
# by sendack and sendsyn utilities shipped with the program, when
# reporting a new signature. See test/sendack.c and test/sendsyn.c for more
# information about this.
#
# - Overall packet size - a function of all IP and TCP options and bugs.
# While this is partly redundant in the real world, we record this value
# to capture rare cases when there are IP options (which we do not currently
# examine) or packet data past the headers. Both situations are rare.
#
# Packet size MAY be wildcarded, but the meaning of the wildcard is
# very special, and means the packet must be larger than PACKET_BIG
# (defined in config.h as 100). This is usually not necessary, except
# for some really broken implementations in RST+ mode. For more information,
# see p0fr.fp. P0f automatically wildcards big packets when reporting
# new signatures.
#
# NEW SIGNATURE: Copy this value literally.
#
# - Initial TTL - We check the actual TTL of a received packet. It can't
# be higher than the initial TTL, and also shouldn't be dramatically
# lower (maximum distance is defined in config.h as 40 hops).
#
# NEW SIGNATURE: *Never* copy TTL from a p0f-reported signature literally.
# You need to determine the initial TTL. The best way to do it is to
# check the documentation for a remote system, or check its settings.
# A fairly good method is to simply round the observed TTL up to
# 32, 64, 128, or 255, but it should be noted that some obscure devices
# might not use round TTLs (in particular, some shoddy appliances and
# IRIX and Tru64 are known to use "original" initial TTL settings). If not
# sure, use traceroute or mtr to see how far you are from the host.
#
# Note that -F option overrides this check if no signature can be found.
#
# - Don't fragment flag (DF) - some modern OSes set this to implement PMTU
# discovery. Others do not bother.
#
# NEW SIGNATURE: Copy this value literally. Note: this setting is
# sometimes cleared by firewalls and/or certain connectivity clients.
# Try to find out what's the actual state for a given OS if you see both,
# and add the right one. P0f will automatically detect a case when a
# firewall removed the DF flag and will append "(firewall!)" suffix to
# the signature, so if the DF version is the right one, don't add no-DF
# variant, unless it has a different meaning.
#
# - Maximum segment size (MSS) - this setting is usually link-dependent. P0f
# uses it to determine link type of the remote host.
#
# NEW SIGNATURE: Always wildcard this value, except for rare cases when
# you have an appliance with a fixed value, know the system supports only
# a very limited number of network interface types, or know the system
# is using a value it pulled out of nowhere. I use specific unique MSS
# to tell Google crawlbots from the rest of Linux population, for example.
#
# If a specific MSS/MTU is unique to a certain link type, be sure to
# add it to mtu.h instead of creating several variants of each signature.
#
# - Window scaling (WSCALE) - this feature is used to scale WSS.
# It extends the size of a TCP/IP window to 32 bits, of sorts. Some modern
# systems implement this feature.
#
# NEW SIGNATURE: Observe several signatures. Initial WSCALE is often set
# to zero or other low value. There's usually no need to wildcard this
# parameter.
#
# - Timestamp - some systems that implement timestamps set them to
# zero in the initial SYN. This case is detected and handled appropriately.
#
# NEW SIGNATURE: Copy T or T0 option literally.
#
# - Selective ACK permitted - a flag set by systems that implement
# selective ACK functionality,
#
# NEW SIGNATURE: copy S option literally.
#
# - NOP option - its presence, count and sequence is a useful OS-dependent
# characteristic,
#
# NEW SIGNATURE: copy N options literally.
#
# - Other and unrecognized options (TTCP-related and such) - implemented by
# some eccentric or very buggy TCP/IP stacks ;-),
#
# NEW SIGNATURE: copy ? options literally.
#
# - EOL option. Contrary to the popular belief, the presence of EOL
# option is actually quite rare, most systems just NOP-pad to the
# packet boundary.
#
# NEW SIGNATURE: copy E option literally.
#
# - The sequence of TCP all options mentioned above - this is very
# specific to the implementation,
#
# NEW SIGNATURE: Copy the sequence literally.
#
# - Quirks. Some buggy stacks set certain values that should be zeroed in a
# TCP packet to non-zero values. This has no effect as of today, but is
# a valuable source of information. Some systems actually seem to leak
# memory there. Other systems just exhibit harmful but very specific
# behavior. This section captures all unusual yes-no properties not
# related to the main and expected header layout. We detect the following:
#
# - Data past the headers. Neither SYN nor SYN+ACK packets are supposed
# to carry any payload. If they do, we should take notice. The actual
# payload is not examined, but will be displayed if use the -X option.
# Note that payload is not unusual in RST+ mode (see p0fr.fp), very
# rare otherwise.
#
# - Options past EOL. Some systems have some trailing data past EOL
# in the options section of TCP/IP headers. P0f does not examine this
# data as of today, simply detects its presence. If there is a
# confirmed sizable population of systems that have data past EOL, it
# might be a good idea to look at it. Until then, you have to recompile
# p0f with DEBUG_EXTRAS set or use -x to display this data,
#
# - Zero IP ID. This again is a (mostly) harmless setting to use a fixed
# IP ID for packets with DF set. Some systems reportedly use zero ID,
# most OSes do not. There is a very slight probability of a false
# positive when IP ID is "naturally" chosen to be zero on a system
# that otherwise does set proper values, but the probability is
# neglible (if it becomes a problem, recompile p0f with IGNORE_ZEROID
# set in the sources).
#
# - IP options specified. Usually, packets do not have any IP options
# set, but there can be some. Until there is a confirmed sizable
# population of systems that do have IP options in a packet, p0f
# does not examine those in detail, but it might change (use
# DEBUG_EXTRAS or -x to display IP options if any found),
#
# - URG pointer value. SYN packets do not have URG flag set, so the
# value in URG pointer in TCP header is ignored. Most systems set it
# to zero, but some OSes (some versions of Windows, for example) do
# not zero this field or even simply leak memory; the actual value is
# not examined, because most cases seem to be just random garbage
# (you can use DEBUG_EXTRAS or -x to report this information though);
# see doc/win-memleak.txt for more information,
#
# - "Unused" field value. This should be always zero, but some systems
# forget to clear it. This might result in some funny issues in the
# future. P0f checks for non-zero value (and will display it if
# DEBUG_EXTRAS is set, or you can use -x),
#
# - ACK number non-zero. ACK value in SYN packets with no ACK flag
# is disregarded and is usually set to zero (just like with URG
# pointer), but some systems forget to do it. The exact value is
# not examined (but will be displayed with DEBUG_EXTRAS, or you can
# use -x). Note that this is not an anomaly in SYN+ACK and RST+ modes,
#
# - Non-zero second timestamp. The initial SYN packet should have the
# second timestamp always zeroed. SYN+ACK and RST+ may "legally" have
# this quirk though,
#
# - Unusual flags. If, in addition to SYN (or SYN+ACK), there are some
# auxilinary flags that do not modify the very meaning of a packet,
# p0f records this (this can be URG, PUSH, or something else).
#
# Note: ECN flags (ECE and CWR) are ignored and denoted in a separate
# way. ECN is never by default, because some systems can't handle it,
# and it probably does not make much sense to include it in signatures
# right now.
#
# - TCP option segment parsing problems. If p0f fails to decode options
# because of a badly broken packet, it records this fact.
#
# There are several other quirks valid only in RST+ mode, see p0fr.fp for
# more information. Those quirks are unheard of in SYN and SYN+ACK
# modes.
#
# NEW SIGNATURE: Copy "quirks" section literally.
#
# We DO NOT use ToS for fingerprinting. While the original TCP/IP
# fingerprinting research believed this value would be useful for this
# purpose, it is not. The setting is way too often tweaked by network
# devices.
#
# To wildcard MSS, WSS or WSCALE, replace it with '*'. You can also use a
# modulo operator to match any values that divide by nnn - '%nnn' (and,
# as stated above, WSS also supports special values Snn and Tnn).
#
# Fingerprint entry format:
#
# wwww:ttt:D:ss:OOO...:QQ:OS:Details
#
# wwww - window size (can be * or %nnn or Sxx or Txx)
# "Snn" (multiple of MSS) and "Tnn" (multiple of MTU) are allowed.
# ttt - initial TTL
# D - don't fragment bit (0 - not set, 1 - set)
# ss - overall SYN packet size (* has a special meaning)
# OOO - option value and order specification (see below)
# QQ - quirks list (see below)
# OS - OS genre (Linux, Solaris, Windows)
# details - OS description (2.0.27 on x86, etc)
#
# If OS genre starts with '*', p0f will not show distance, link type
# and timestamp data. It is useful for userland TCP/IP stacks of
# network scanners and so on, where many settings are randomized or
# bogus.
#
# If OS genre starts with @, it denotes an approximate hit for a group
# of operating systems (signature reporting still enabled in this case).
# Use this feature at the end of this file to catch cases for which
# you don't have a precise match, but can tell it's Windows or FreeBSD
# or whatnot by looking at, say, flag layout alone.
#
# If OS genre starts with - (which can prefix @ or *), the entry is
# not considered to be a real operating system (but userland stack
# instead). It is important to mark all scanners and so on with -,
# so that they are not used for masquerade detection (also add this
# prefix for signatures of application-induced behavior, such as
# increased window size with Opera browser).
#
# Option block description is a list of comma or space separated
# options in the order they appear in the packet:
#
# N - NOP option
# E - EOL option
# Wnnn - window scaling option, value nnn (or * or %nnn)
# Mnnn - maximum segment size option, value nnn (or * or %nnn)
# S - selective ACK OK
# T - timestamp
# T0 - timestamp with zero value
# ?n - unrecognized option number n.
#
# P0f can sometimes report ?nn among the options. This means it couldn't
# recognize this option (option number nn). It's either a bug in p0f, or
# a faulty TCP/IP stack, or, if the number is listed here:
#
# http://www.iana.org/assignments/tcp-parameters
#
# ...the stack might be simply quite exotic.
#
# To denote no TCP options, use a single '.'.
#
# Quirks section is usually an empty list ('.') of oddities or bugs of this
# particular stack. List items are not separated in any way. Possible values:
#
# P - options past EOL,
# Z - zero IP ID,
# I - IP options specified,
# U - urg pointer non-zero,
# X - unused (x2) field non-zero,
# A - ACK number non-zero,
# T - non-zero second timestamp,
# F - unusual flags (PUSH, URG, etc),
# D - data payload,
# ! - broken options segment.
#
# WARNING WARNING WARNING
# -----------------------
#
# Do not add a system X as OS Y just because NMAP says so. It is often
# the case that X is a NAT firewall. While nmap is talking to the
# device itself, p0f is fingerprinting the guy behind the firewall
# instead.
#
# When in doubt, use common sense, don't add something that looks like
# a completely different system as Linux or FreeBSD or LinkSys router.
# Check DNS name, establish a connection to the remote host and look
# at SYN+ACK (p0f -A -S should do) - does it look similar?
#
# Some users tweak their TCP/IP settings - enable or disable RFC1323,
# RFC1644 or RFC2018 support, disable PMTU discovery, change MTU, initial
# TTL and so on. Always compare a new rule to other fingerprints for
# this system, and verify the system isn't "customized". It is OK to
# add signature variants caused by commonly used software (PFs, security
# packages, etc), but it makes no sense to try to add every single
# possible /proc/sys/net/ipv4/* tweak on Linux or so.
#
# KEEP IN MIND: Some packet firewalls configured to normalize outgoing
# traffic (OpenBSD pf with "scrub" enabled, for example) will, well,
# normalize packets. Signatures will not correspond to the originating
# system (and probably not quite to the firewall either).
#
# NOTE: Try to keep this file in some reasonable order, from most to
# least likely systems. This will speed up operation. Also keep most
# generic and broad rules near ehe end.
#
# Still decided to add signature? Let us know - mail a copy of your discovery
# to lcamtuf@coredump.cx. You can help make p0f better, and I can help you
# make your signature more accurate.
#
##########################
# Standard OS signatures #
##########################
# ----------------- AIX ---------------------
# AIX is first because its signatures are close to NetBSD, MacOS X and
# Linux 2.0, but it uses a fairly rare MSSes, at least sometimes...
# This is a shoddy hack, though.
45046:64:0:44:M*:.:AIX:4.3
16384:64:0:44:M512:.:AIX:4.3.2 and earlier
16384:64:0:60:M512,N,W%2,N,N,T:.:AIX:4.3.3-5.2 (1)
32768:64:0:60:M512,N,W%2,N,N,T:.:AIX:4.3.3-5.2 (2)
65535:64:0:60:M512,N,W%2,N,N,T:.:AIX:4.3.3-5.2 (3)
65535:64:0:64:M*,N,W1,N,N,T,N,N,S:.:AIX:5.3 ML1
# ----------------- Linux -------------------
S1:64:0:44:M*:A:Linux:1.2.x
512:64:0:44:M*:.:Linux:2.0.3x (1)
16384:64:0:44:M*:.:Linux:2.0.3x (2)
# Endian snafu! Nelson says "ha-ha":
2:64:0:44:M*:.:Linux:2.0.3x (MkLinux) on Mac (1)
64:64:0:44:M*:.:Linux:2.0.3x (MkLinux) on Mac (2)
S4:64:1:60:M1360,S,T,N,W0:.:Linux:2.4 (Google crawlbot)
S4:64:1:60:M1430,S,T,N,W0:.:Linux:2.4-2.6 (Google crawlbot)
S2:64:1:60:M*,S,T,N,W0:.:Linux:2.4 (large MTU?)
S3:64:1:60:M*,S,T,N,W0:.:Linux:2.4 (newer)
S4:64:1:60:M*,S,T,N,W0:.:Linux:2.4-2.6
S3:64:1:60:M*,S,T,N,W1:.:Linux:2.6, seldom 2.4 (older, 1)
S4:64:1:60:M*,S,T,N,W1:.:Linux:2.6, seldom 2.4 (older, 2)
S3:64:1:60:M*,S,T,N,W2:.:Linux:2.6, seldom 2.4 (older, 3)
S4:64:1:60:M*,S,T,N,W2:.:Linux:2.6, seldom 2.4 (older, 4)
T4:64:1:60:M*,S,T,N,W2:.:Linux:2.6 (older, 5)
S4:64:1:60:M*,S,T,N,W5:.:Linux:2.6 (newer, 1)
S4:64:1:60:M*,S,T,N,W6:.:Linux:2.6 (newer, 2)
S4:64:1:60:M*,S,T,N,W7:.:Linux:2.6 (newer, 3)
T4:64:1:60:M*,S,T,N,W7:.:Linux:2.6 (newer, 4)
S20:64:1:60:M*,S,T,N,W0:.:Linux:2.2 (1)
S22:64:1:60:M*,S,T,N,W0:.:Linux:2.2 (2)
S11:64:1:60:M*,S,T,N,W0:.:Linux:2.2 (3)
# Popular cluster config scripts disable timestamps and
# selective ACK:
S4:64:1:48:M1460,N,W0:.:Linux:2.4 in cluster
# This happens only over loopback, but let's make folks happy:
32767:64:1:60:M16396,S,T,N,W0:.:Linux:2.4 (loopback)
32767:64:1:60:M16396,S,T,N,W2:.:Linux:2.6 (newer, loopback)
S8:64:1:60:M3884,S,T,N,W0:.:Linux:2.2 (loopback)
# Opera visitors:
16384:64:1:60:M*,S,T,N,W0:.:-Linux:2.2 (Opera?)
32767:64:1:60:M*,S,T,N,W0:.:-Linux:2.4 (Opera?)
# Some fairly common mods & oddities:
S22:64:1:52:M*,N,N,S,N,W0:.:Linux:2.2 (tstamp-)
S4:64:1:52:M*,N,N,S,N,W0:.:Linux:2.4 (tstamp-)
S4:64:1:52:M*,N,N,S,N,W2:.:Linux:2.6 (tstamp-)
S4:64:1:44:M*:.:Linux:2.6? (barebone, rare!)
T4:64:1:60:M1412,S,T,N,W0:.:Linux:2.4 (rare!)
# ----------------- FreeBSD -----------------
16384:64:1:44:M*:.:FreeBSD:2.0-4.2
16384:64:1:60:M*,N,W0,N,N,T:.:FreeBSD:4.4 (1)
1024:64:1:60:M*,N,W0,N,N,T:.:FreeBSD:4.4 (2)
57344:64:1:44:M*:.:FreeBSD:4.6-4.8 (RFC1323-)
57344:64:1:60:M*,N,W0,N,N,T:.:FreeBSD:4.6-4.9
32768:64:1:60:M*,N,W0,N,N,T:.:FreeBSD:4.8-5.1 (or MacOS X 10.2-10.3)
65535:64:1:60:M*,N,W0,N,N,T:.:FreeBSD:4.7-5.2 (or MacOS X 10.2-10.4) (1)
65535:64:1:60:M*,N,W1,N,N,T:.:FreeBSD:4.7-5.2 (or MacOS X 10.2-10.4) (2)
65535:64:1:60:M*,N,W0,N,N,T:Z:FreeBSD:5.1 (1)
65535:64:1:60:M*,N,W1,N,N,T:Z:FreeBSD:5.1 (2)
65535:64:1:60:M*,N,W2,N,N,T:Z:FreeBSD:5.1 (3)
65535:64:1:64:M*,N,N,S,N,W1,N,N,T:.:FreeBSD:5.3-5.4
65535:64:1:64:M*,N,W1,N,N,T,S,E:P:FreeBSD:6.x (1)
65535:64:1:64:M*,N,W0,N,N,T,S,E:P:FreeBSD:6.x (2)
65535:64:1:44:M*:Z:FreeBSD:5.2 (RFC1323-)
# 16384:64:1:60:M*,N,N,N,N,N,N,T:.:FreeBSD:4.4 (tstamp-)
# ----------------- NetBSD ------------------
16384:64:0:60:M*,N,W0,N,N,T:.:NetBSD:1.3
65535:64:0:60:M*,N,W0,N,N,T0:.:-NetBSD:1.6 (Opera)
16384:64:1:60:M*,N,W0,N,N,T0:.:NetBSD:1.6
65535:64:1:60:M*,N,W1,N,N,T0:.:NetBSD:1.6W-current (DF)
65535:64:1:60:M*,N,W0,N,N,T0:.:NetBSD:1.6X (DF)
32768:64:1:60:M*,N,W0,N,N,T0:.:NetBSD:1.6Z or 2.0 (DF)
32768:64:1:64:M1416,N,W0,S,N,N,N,N,T0:.:NetBSD:2.0G (DF)
32768:64:1:64:M*,N,W0,S,N,N,N,N,T0:.:NetBSD:3.0 (DF)
# ----------------- OpenBSD -----------------
16384:64:1:64:M*,N,N,S,N,W0,N,N,T:.:OpenBSD:3.0-3.9
57344:64:1:64:M*,N,N,S,N,W0,N,N,T:.:OpenBSD:3.3-3.4
16384:64:0:64:M*,N,N,S,N,W0,N,N,T:.:OpenBSD:3.0-3.4 (scrub)
65535:64:1:64:M*,N,N,S,N,W0,N,N,T:.:-OpenBSD:3.0-3.4 (Opera?)
32768:64:1:64:M*,N,N,S,N,W0,N,N,T:.:OpenBSD:3.7
# ----------------- Solaris -----------------
S17:64:1:64:N,W3,N,N,T0,N,N,S,M*:.:Solaris:8 (RFC1323 on)
S17:64:1:48:N,N,S,M*:.:Solaris:8 (1)
S17:255:1:44:M*:.:Solaris:2.5-7 (1)
# Sometimes, just sometimes, Solaris feels like coming up with
# rather arbitrary MSS values ;-)
S6:255:1:44:M*:.:Solaris:2.5-7 (2)
S23:64:1:48:N,N,S,M*:.:Solaris:8 (2)
S34:64:1:48:M*,N,N,S:.:Solaris:9
S34:64:1:48:M*,N,N,N,N:.:Solaris:9 (no sack)
S44:255:1:44:M*:.:Solaris:7
4096:64:0:44:M1460:.:SunOS:4.1.x
S34:64:1:52:M*,N,W0,N,N,S:.:Solaris:10 (beta)
32850:64:1:64:M*,N,N,T,N,W1,N,N,S:.:Solaris:10 (1203?)
32850:64:1:64:M*,N,W1,N,N,T,N,N,S:.:Solaris:9.1
# ----------------- IRIX --------------------
49152:60:0:44:M*:.:IRIX:6.2-6.4
61440:60:0:44:M*:.:IRIX:6.2-6.5
49152:60:0:52:M*,N,W2,N,N,S:.:IRIX:6.5 (RFC1323+) (1)
49152:60:0:52:M*,N,W3,N,N,S:.:IRIX:6.5 (RFC1323+) (2)
61440:60:0:48:M*,N,N,S:.:IRIX:6.5.12-6.5.21 (1)
49152:60:0:48:M*,N,N,S:.:IRIX:6.5.12-6.5.21 (2)
49152:60:0:64:M*,N,W2,N,N,T,N,N,S:.:IRIX:6.5 IP27
# ----------------- Tru64 -------------------
# Tru64 and OpenVMS share the same stack on occassions.
# Relax.
32768:60:1:48:M*,N,W0:.:Tru64:4.0 (or OS/2 Warp 4)
32768:60:0:48:M*,N,W0:.:Tru64:5.0 (or OpenVMS 7.x on Compaq 5.0 stack)
8192:60:0:44:M1460:.:Tru64:5.1 (no RFC1323) (or QNX 6)
61440:60:0:48:M*,N,W0:.:Tru64:v5.1a JP4 (or OpenVMS 7.x on Compaq 5.x stack)
# ----------------- OpenVMS -----------------
6144:64:1:60:M*,N,W0,N,N,T:.:OpenVMS:7.2 (Multinet 4.3-4.4 stack)
# ----------------- MacOS -------------------
S2:255:1:48:M*,W0,E:.:MacOS:8.6 classic
16616:255:1:48:M*,W0,E:.:MacOS:7.3-8.6 (OTTCP)
16616:255:1:48:M*,N,N,N,E:.:MacOS:8.1-8.6 (OTTCP)
32768:255:1:48:M*,W0,N:.:MacOS:9.0-9.2
32768:255:1:48:M1380,N,N,N,N:.:MacOS:9.1 (OT 2.7.4) (1)
65535:255:1:48:M*,N,N,N,N:.:MacOS:9.1 (OT 2.7.4) (2)
# ----------------- Windows -----------------
# Windows TCP/IP stack is a mess. For most recent XP, 2000 and
# even 98, the pathlevel, not the actual OS version, is more
# relevant to the signature. They share the same code, so it would
# seem. Luckily for us, almost all Windows 9x boxes have an
# awkward MSS of 536, which I use to tell one from another
# in most difficult cases.
8192:32:1:44:M*:.:Windows:3.11 (Tucows)
S44:64:1:64:M*,N,W0,N,N,T0,N,N,S:.:Windows:95
8192:128:1:64:M*,N,W0,N,N,T0,N,N,S:.:Windows:95b
# There were so many tweaking tools and so many stack versions for
# Windows 98 it is no longer possible to tell them from each other
# without some very serious research. Until then, there's an insane
# number of signatures, for your amusement:
S44:32:1:48:M*,N,N,S:.:Windows:98 (low TTL) (1)
8192:32:1:48:M*,N,N,S:.:Windows:98 (low TTL) (2)
%8192:64:1:48:M536,N,N,S:.:Windows:98 (13)
%8192:128:1:48:M536,N,N,S:.:Windows:98 (15)
S4:64:1:48:M*,N,N,S:.:Windows:98 (1)
S6:64:1:48:M*,N,N,S:.:Windows:98 (2)
S12:64:1:48:M*,N,N,S:.:Windows:98 (3
T30:64:1:64:M1460,N,W0,N,N,T0,N,N,S:.:Windows:98 (16)
32767:64:1:48:M*,N,N,S:.:Windows:98 (4)
37300:64:1:48:M*,N,N,S:.:Windows:98 (5)
46080:64:1:52:M*,N,W3,N,N,S:.:Windows:98 (RFC1323+)
65535:64:1:44:M*:.:Windows:98 (no sack)
S16:128:1:48:M*,N,N,S:.:Windows:98 (6)
S16:128:1:64:M*,N,W0,N,N,T0,N,N,S:.:Windows:98 (7)
S26:128:1:48:M*,N,N,S:.:Windows:98 (8)
T30:128:1:48:M*,N,N,S:.:Windows:98 (9)
32767:128:1:52:M*,N,W0,N,N,S:.:Windows:98 (10)
60352:128:1:48:M*,N,N,S:.:Windows:98 (11)
60352:128:1:64:M*,N,W2,N,N,T0,N,N,S:.:Windows:98 (12)
# What's with 1414 on NT?
T31:128:1:44:M1414:.:Windows:NT 4.0 SP6a (1)
64512:128:1:44:M1414:.:Windows:NT 4.0 SP6a (2)
8192:128:1:44:M*:.:Windows:NT 4.0 (older)
# Windows XP and 2000. Most of the signatures that were
# either dubious or non-specific (no service pack data)
# were deleted and replaced with generics at the end.
65535:128:1:48:M*,N,N,S:.:Windows:2000 SP4, XP SP1+
%8192:128:1:48:M*,N,N,S:.:Windows:2000 SP2+, XP SP1+ (seldom 98)
S20:128:1:48:M*,N,N,S:.:Windows:SP3
S45:128:1:48:M*,N,N,S:.:Windows:2000 SP4, XP SP1+ (2)
40320:128:1:48:M*,N,N,S:.:Windows:2000 SP4
S6:128:1:48:M*,N,N,S:.:Windows:XP, 2000 SP2+
S12:128:1:48:M*,N,N,S:.:Windows:XP SP1+ (1)
S44:128:1:48:M*,N,N,S:.:Windows:XP SP1+, 2000 SP3
64512:128:1:48:M*,N,N,S:.:Windows:XP SP1+, 2000 SP3 (2)
32767:128:1:48:M*,N,N,S:.:Windows:XP SP1+, 2000 SP4 (3)
# Windows 2003 & Vista
8192:128:1:52:M*,W8,N,N,N,S:.:Windows:Vista (beta)
32768:32:1:52:M1460,N,W0,N,N,S:.:Windows:2003 AS
65535:64:1:52:M1460,N,W2,N,N,S:.:Windows:2003 (1)
65535:64:1:48:M1460,N,N,S:.:Windows:2003 (2)
# Odds, ends, mods:
S52:128:1:48:M1260,N,N,S:.:Windows:XP/2000 via Cisco
65520:128:1:48:M*,N,N,S:.:Windows:XP bare-bone
16384:128:1:52:M536,N,W0,N,N,S:.:Windows:2000 w/ZoneAlarm?
2048:255:0:40:.:.:Windows:.NET Enterprise Server
44620:64:0:48:M*,N,N,S:.:Windows:ME no SP (?)
S6:255:1:48:M536,N,N,S:.:Windows:95 winsock 2
32000:128:0:48:M*,N,N,S:.:Windows:XP w/Winroute?
16384:64:1:48:M1452,N,N,S:.:Windows:XP w/Sygate? (1)
17256:64:1:48:M1460,N,N,S:.:Windows:XP w/Sygate? (2)
# No need to be more specific, it passes:
*:128:1:48:M*,N,N,S:U:-Windows:XP/2000 while downloading (leak!)
# ----------------- HP/UX -------------------
32768:64:1:44:M*:.:HP-UX:B.10.20
32768:64:1:48:M*,W0,N:.:HP-UX:11.00-11.11
# Whoa. Hardcore WSS.
0:64:0:48:M*,W0,N:.:HP-UX:B.11.00 A (RFC1323+)
# ----------------- RiscOS ------------------
16384:64:1:68:M1460,N,W0,N,N,T,N,N,?12:.:RISC OS:3.70-4.36 (inet 5.04)
12288:32:0:44:M536:.:RISC OS:3.70 inet 4.10
4096:64:1:56:M1460,N,N,T:T:RISC OS:3.70 freenet 2.00
# ----------------- BSD/OS ------------------
8192:64:1:60:M1460,N,W0,N,N,T:.:BSD/OS:3.1-4.3 (or MacOS X 10.2)
# ---------------- NetwonOS -----------------
4096:64:0:44:M1420:.:NewtonOS:2.1
# ---------------- NeXTSTEP -----------------
S8:64:0:44:M512:.:NeXTSTEP:3.3 (1)
S4:64:0:44:M1024:.:NeXTSTEP:3.3 (2)
# ------------------ BeOS -------------------
1024:255:0:48:M*,N,W0:.:BeOS:5.0-5.1
12288:255:0:44:M*:.:BeOS:5.0.x
# ------------------ OS/400 -----------------
8192:64:1:60:M1440,N,W0,N,N,T:.:OS/400:V4R4/R5
8192:64:0:44:M536:.:OS/400:V4R3/M0
4096:64:1:60:M1440,N,W0,N,N,T:.:OS/400:V4R5 + CF67032
28672:64:0:44:M1460:A:OS/390:?
# ------------------ ULTRIX -----------------
16384:64:0:40:.:.:ULTRIX:4.5
# ------------------- QNX -------------------
S16:64:0:44:M512:.:QNX:demodisk
16384:64:0:60:M1460,N,W0,N,N,T0:.:QNX:6.x
# ------------------ Novell -----------------
16384:128:1:44:M1460:.:Novell:NetWare 5.0
6144:128:1:44:M1460:.:Novell:IntranetWare 4.11
6144:128:1:44:M1368:.:Novell:BorderManager ?
# According to rfp:
6144:128:1:52:M*,W0,N,S,N,N:.:Novell:Netware 6 SP3
# -------------- SCO UnixWare ---------------
S3:64:1:60:M1460,N,W0,N,N,T:.:SCO:UnixWare 7.1
S17:64:1:60:M*,N,W0,N,N,T:.:SCO:UnixWare 7.1.x
S23:64:1:44:M1380:.:SCO:OpenServer 5.0
# ------------------- DOS -------------------
2048:255:0:44:M536:.:DOS:Arachne via WATTCP/1.05
T2:255:0:44:M984:.:DOS:Arachne via WATTCP/1.05 (eepro)
16383:64:0:44:M536:.:DOS:Unknown via WATTCP (epppd)
# ------------------ OS/2 -------------------
S56:64:0:44:M512:.:OS/2:4
28672:64:0:44:M1460:.:OS/2:Warp 4.0
# ----------------- TOPS-20 -----------------
# Another hardcore MSS, one of the ACK leakers hunted down.
0:64:0:44:M1460:A:TOPS-20:version 7
# ------------------ AMIGA ------------------
S32:64:1:56:M*,N,N,S,N,N,?12:.:AMIGA:3.9 BB2 with Miami stack
# ------------------ Minix ------------------
# Not quite sure.
# 8192:210:0:44:M1460:X:@Minix:?
# ------------------ Plan9 ------------------
65535:255:0:48:M1460,W0,N:.:Plan9:edition 4
# ----------------- AMIGAOS -----------------
16384:64:1:48:M1560,N,N,S:.:AMIGAOS:3.9 BB2 MiamiDX
# ----------------- FreeMiNT ----------------
S44:255:0:44:M536:.:FreeMiNT:1 patch 16A (Atari)
###########################################
# Appliance / embedded / other signatures #
###########################################
# ---------- Firewalls / routers ------------
S12:64:1:44:M1460:.:@Checkpoint:(unknown 1)
S12:64:1:48:N,N,S,M1460:.:@Checkpoint:(unknown 2)
4096:32:0:44:M1460:.:ExtremeWare:4.x
S32:64:0:68:M512,N,W0,N,N,T,N,N,?12:.:Nokia:IPSO w/Checkpoint NG FP3
S16:64:0:68:M1024,N,W0,N,N,T,N,N,?12:.:Nokia:IPSO 3.7 build 026
S4:64:1:60:W0,N,S,T,M1460:.:FortiNet:FortiGate 50
8192:64:1:44:M1460:.:@Eagle:Secure Gateway
# ------- Switches and other stuff ----------
4128:255:0:44:M*:Z:Cisco:7200, Catalyst 3500, etc
S8:255:0:44:M*:.:Cisco:12008
S4:255:0:44:M536:Z:Cisco:IOS 11.0
60352:128:1:64:M1460,N,W2,N,N,T,N,N,S:.:Alteon:ACEswitch
64512:128:1:44:M1370:.:Nortel:Contivity Client
# ---------- Caches and whatnots ------------
8190:255:0:44:M1428:.:Google:Wireless Transcoder (1)
8190:255:0:44:M1460:.:Google:Wireless Transcoder (2)
8192:64:1:64:M1460,N,N,S,N,W0,N,N,T:.:NetCache:5.2
16384:64:1:64:M1460,N,N,S,N,W0,N:.:NetCache:5.3
65535:64:1:64:M1460,N,N,S,N,W*,N,N,T:.:NetCache:5.3-5.5 (or FreeBSD 5.4)
20480:64:1:64:M1460,N,N,S,N,W0,N,N,T:.:NetCache:4.1
S44:64:1:64:M1460,N,N,S,N,W0,N,N,T:.:NetCache:5.5
32850:64:1:64:N,W1,N,N,T,N,N,S,M*:.:NetCache:Data OnTap 5.x
65535:64:0:60:M1460,N,W0,N,N,T:.:CacheFlow:CacheOS 4.1
8192:64:0:60:M1380,N,N,N,N,N,N,T:.:CacheFlow:CacheOS 1.1
S4:64:0:48:M1460,N,N,S:.:Cisco:Content Engine
27085:128:0:40:.:.:Dell:PowerApp cache (Linux-based)
65535:255:1:48:N,W1,M1460:.:Inktomi:crawler
S1:255:1:60:M1460,S,T,N,W0:.:LookSmart:ZyBorg
16384:255:0:40:.:.:Proxyblocker:(what's this?)
65535:255:0:48:M*,N,N,S:.:Redline: T|X 2200
# ----------- Embedded systems --------------
S9:255:0:44:M536:.:PalmOS:Tungsten T3/C
S5:255:0:44:M536:.:PalmOS:3/4
S4:255:0:44:M536:.:PalmOS:3.5
2948:255:0:44:M536:.:PalmOS:3.5.3 (Handera)
S29:255:0:44:M536:.:PalmOS:5.0
16384:255:0:44:M1398:.:PalmOS:5.2 (Clie)
S14:255:0:44:M1350:.:PalmOS:5.2.1 (Treo)
16384:255:0:44:M1400:.:PalmOS:5.2 (Sony)
S23:64:1:64:N,W1,N,N,T,N,N,S,M1460:.:SymbianOS:7
8192:255:0:44:M1460:.:SymbianOS:6048 (Nokia 7650?)
8192:255:0:44:M536:.:SymbianOS:(Nokia 9210?)
S22:64:1:56:M1460,T,S:.:SymbianOS:? (SE P800?)
S36:64:1:56:M1360,T,S:.:SymbianOS:60xx (Nokia 6600?)
S36:64:1:60:M1360,T,S,W0,E:.:SymbianOS:60xx
32768:32:1:44:M1460:.:Windows:CE 3
# Perhaps S4?
5840:64:1:60:M1452,S,T,N,W1:.:Zaurus:3.10
32768:128:1:64:M1460,N,W0,N,N,T0,N,N,S:.:PocketPC:2002
S1:255:0:44:M346:.:Contiki:1.1-rc0
4096:128:0:44:M1460:.:Sega:Dreamcast Dreamkey 3.0
T5:64:0:44:M536:.:Sega:Dreamcast HKT-3020 (browser disc 51027)
S22:64:1:44:M1460:.:Sony:Playstation 2 (SOCOM?)
S12:64:0:44:M1452:.:AXIS:Printer Server 5600 v5.64
3100:32:1:44:M1460:.:Windows:CE 2.0
####################
# Fancy signatures #
####################
1024:64:0:40:.:.:-*NMAP:syn scan (1)
2048:64:0:40:.:.:-*NMAP:syn scan (2)
3072:64:0:40:.:.:-*NMAP:syn scan (3)
4096:64:0:40:.:.:-*NMAP:syn scan (4)
1024:64:0:40:.:A:-*NMAP:TCP sweep probe (1)
2048:64:0:40:.:A:-*NMAP:TCP sweep probe (2)
3072:64:0:40:.:A:-*NMAP:TCP sweep probe (3)
4096:64:0:40:.:A:-*NMAP:TCP sweep probe (4)
1024:64:0:60:W10,N,M265,T,E:P:-*NMAP:OS detection probe (1)
2048:64:0:60:W10,N,M265,T,E:P:-*NMAP:OS detection probe (2)
3072:64:0:60:W10,N,M265,T,E:P:-*NMAP:OS detection probe (3)
4096:64:0:60:W10,N,M265,T,E:P:-*NMAP:OS detection probe (4)
1024:64:0:60:W10,N,M265,T,E:PF:-*NMAP:OS detection probe w/flags (1)
2048:64:0:60:W10,N,M265,T,E:PF:-*NMAP:OS detection probe w/flags (2)
3072:64:0:60:W10,N,M265,T,E:PF:-*NMAP:OS detection probe w/flags (3)
4096:64:0:60:W10,N,M265,T,E:PF:-*NMAP:OS detection probe w/flags (4)
32767:64:0:40:.:.:-*NAST:syn scan
12345:255:0:40:.:A:-p0f:sendsyn utility
# UFO - see tmp/*:
56922:128:0:40:.:A:-@Mysterious:port scanner (?)
5792:64:1:60:M1460,S,T,N,W0:T:-@Mysterious:NAT device (2nd tstamp)
S12:128:1:48:M1460,E:P:@Mysterious:Chello proxy (?)
S23:64:1:64:N,W1,N,N,T,N,N,S,M1380:.:@Mysterious:GPRS gateway (?)
#####################################
# Generic signatures - just in case #
#####################################
*:128:1:52:M*,N,W0,N,N,S:.:@Windows:XP/2000 (RFC1323+, w, tstamp-)
*:128:1:52:M*,N,W*,N,N,S:.:@Windows:XP/2000 (RFC1323+, w+, tstamp-)
*:128:1:52:M*,N,N,T0,N,N,S:.:@Windows:XP/2000 (RFC1323+, w-, tstamp+)
*:128:1:64:M*,N,W0,N,N,T0,N,N,S:.:@Windows:XP/2000 (RFC1323+, w, tstamp+)
*:128:1:64:M*,N,W*,N,N,T0,N,N,S:.:@Windows:XP/2000 (RFC1323+, w+, tstamp+)
*:128:1:48:M536,N,N,S:.:@Windows:98
*:128:1:48:M*,N,N,S:.:@Windows:XP/2000

View file

@ -284,7 +284,6 @@ set(bro_SRCS
NetVar.cc NetVar.cc
Obj.cc Obj.cc
OpaqueVal.cc OpaqueVal.cc
OSFinger.cc
PacketFilter.cc PacketFilter.cc
Pipe.cc Pipe.cc
PolicyFile.cc PolicyFile.cc
@ -302,7 +301,7 @@ set(bro_SRCS
Scope.cc Scope.cc
SerializationFormat.cc SerializationFormat.cc
Sessions.cc Sessions.cc
StateAccess.cc Notifier.cc
Stats.cc Stats.cc
Stmt.cc Stmt.cc
Tag.cc Tag.cc

View file

@ -12,7 +12,7 @@ DebugLogger debug_logger;
// Same order here as in DebugStream. // Same order here as in DebugStream.
DebugLogger::Stream DebugLogger::streams[NUM_DBGS] = { DebugLogger::Stream DebugLogger::streams[NUM_DBGS] = {
{ "serial", 0, false }, { "rules", 0, false }, { "serial", 0, false }, { "rules", 0, false },
{ "state", 0, false }, {"string", 0, false }, { "string", 0, false },
{ "notifiers", 0, false }, { "main-loop", 0, false }, { "notifiers", 0, false }, { "main-loop", 0, false },
{ "dpd", 0, false }, { "tm", 0, false }, { "dpd", 0, false }, { "tm", 0, false },
{ "logging", 0, false }, {"input", 0, false }, { "logging", 0, false }, {"input", 0, false },

View file

@ -16,9 +16,8 @@
enum DebugStream { enum DebugStream {
DBG_SERIAL, // Serialization DBG_SERIAL, // Serialization
DBG_RULES, // Signature matching DBG_RULES, // Signature matching
DBG_STATE, // StateAccess logging
DBG_STRING, // String code DBG_STRING, // String code
DBG_NOTIFIERS, // Notifiers (see StateAccess.h) DBG_NOTIFIERS, // Notifiers
DBG_MAINLOOP, // Main IOSource loop DBG_MAINLOOP, // Main IOSource loop
DBG_ANALYZER, // Analyzer framework DBG_ANALYZER, // Analyzer framework
DBG_TM, // Time-machine packet input via Brocolli DBG_TM, // Time-machine packet input via Brocolli

View file

@ -97,7 +97,7 @@ void Expr::EvalIntoAggregate(const BroType* /* t */, Val* /* aggr */,
Internal("Expr::EvalIntoAggregate called"); Internal("Expr::EvalIntoAggregate called");
} }
void Expr::Assign(Frame* /* f */, Val* /* v */, Opcode /* op */) void Expr::Assign(Frame* /* f */, Val* /* v */)
{ {
Internal("Expr::Assign called"); Internal("Expr::Assign called");
} }
@ -261,10 +261,10 @@ Expr* NameExpr::MakeLvalue()
return new RefExpr(this); return new RefExpr(this);
} }
void NameExpr::Assign(Frame* f, Val* v, Opcode op) void NameExpr::Assign(Frame* f, Val* v)
{ {
if ( id->IsGlobal() ) if ( id->IsGlobal() )
id->SetVal(v, op); id->SetVal(v);
else else
f->SetElement(id->Offset(), v); f->SetElement(id->Offset(), v);
} }
@ -1007,18 +1007,18 @@ Val* IncrExpr::Eval(Frame* f) const
if ( elt ) if ( elt )
{ {
Val* new_elt = DoSingleEval(f, elt); Val* new_elt = DoSingleEval(f, elt);
v_vec->Assign(i, new_elt, OP_INCR); v_vec->Assign(i, new_elt);
} }
else else
v_vec->Assign(i, 0, OP_INCR); v_vec->Assign(i, 0);
} }
op->Assign(f, v_vec, OP_INCR); op->Assign(f, v_vec);
} }
else else
{ {
Val* old_v = v; Val* old_v = v;
op->Assign(f, v = DoSingleEval(f, old_v), OP_INCR); op->Assign(f, v = DoSingleEval(f, old_v));
Unref(old_v); Unref(old_v);
} }
@ -2041,9 +2041,9 @@ Expr* RefExpr::MakeLvalue()
return this; return this;
} }
void RefExpr::Assign(Frame* f, Val* v, Opcode opcode) void RefExpr::Assign(Frame* f, Val* v)
{ {
op->Assign(f, v, opcode); op->Assign(f, v);
} }
AssignExpr::AssignExpr(Expr* arg_op1, Expr* arg_op2, int arg_is_init, AssignExpr::AssignExpr(Expr* arg_op1, Expr* arg_op2, int arg_is_init,
@ -2743,7 +2743,7 @@ Val* IndexExpr::Fold(Val* v1, Val* v2) const
return 0; return 0;
} }
void IndexExpr::Assign(Frame* f, Val* v, Opcode op) void IndexExpr::Assign(Frame* f, Val* v)
{ {
if ( IsError() ) if ( IsError() )
return; return;
@ -2783,7 +2783,7 @@ void IndexExpr::Assign(Frame* f, Val* v, Opcode op)
for ( auto idx = 0u; idx < v_vect->Size(); idx++, first++ ) for ( auto idx = 0u; idx < v_vect->Size(); idx++, first++ )
v1_vect->Insert(first, v_vect->Lookup(idx)->Ref()); v1_vect->Insert(first, v_vect->Lookup(idx)->Ref());
} }
else if ( ! v1_vect->Assign(v2, v, op) ) else if ( ! v1_vect->Assign(v2, v) )
{ {
if ( v ) if ( v )
{ {
@ -2803,7 +2803,7 @@ void IndexExpr::Assign(Frame* f, Val* v, Opcode op)
} }
case TYPE_TABLE: case TYPE_TABLE:
if ( ! v1->AsTableVal()->Assign(v2, v, op) ) if ( ! v1->AsTableVal()->Assign(v2, v) )
{ {
if ( v ) if ( v )
{ {
@ -2884,9 +2884,8 @@ FieldExpr::FieldExpr(Expr* arg_op, const char* arg_field_name)
SetType(rt->FieldType(field)->Ref()); SetType(rt->FieldType(field)->Ref());
td = rt->FieldDecl(field); td = rt->FieldDecl(field);
if ( td->FindAttr(ATTR_DEPRECATED) ) if ( rt->IsFieldDeprecated(field) )
reporter->Warning("deprecated (%s$%s)", rt->GetName().c_str(), reporter->Warning("%s", rt->GetFieldDeprecationWarning(field, false).c_str());
field_name);
} }
} }
} }
@ -2906,7 +2905,7 @@ int FieldExpr::CanDel() const
return td->FindAttr(ATTR_DEFAULT) || td->FindAttr(ATTR_OPTIONAL); return td->FindAttr(ATTR_DEFAULT) || td->FindAttr(ATTR_OPTIONAL);
} }
void FieldExpr::Assign(Frame* f, Val* v, Opcode opcode) void FieldExpr::Assign(Frame* f, Val* v)
{ {
if ( IsError() ) if ( IsError() )
return; return;
@ -2915,14 +2914,14 @@ void FieldExpr::Assign(Frame* f, Val* v, Opcode opcode)
if ( op_v ) if ( op_v )
{ {
RecordVal* r = op_v->AsRecordVal(); RecordVal* r = op_v->AsRecordVal();
r->Assign(field, v, opcode); r->Assign(field, v);
Unref(r); Unref(r);
} }
} }
void FieldExpr::Delete(Frame* f) void FieldExpr::Delete(Frame* f)
{ {
Assign(f, 0, OP_ASSIGN_IDX); Assign(f, 0);
} }
Val* FieldExpr::Fold(Val* v) const Val* FieldExpr::Fold(Val* v) const
@ -2975,9 +2974,8 @@ HasFieldExpr::HasFieldExpr(Expr* arg_op, const char* arg_field_name)
if ( field < 0 ) if ( field < 0 )
ExprError("no such field in record"); ExprError("no such field in record");
else if ( rt->FieldDecl(field)->FindAttr(ATTR_DEPRECATED) ) else if ( rt->IsFieldDeprecated(field) )
reporter->Warning("deprecated (%s?$%s)", rt->GetName().c_str(), reporter->Warning("%s", rt->GetFieldDeprecationWarning(field, true).c_str());
field_name);
SetType(base_type(TYPE_BOOL)); SetType(base_type(TYPE_BOOL));
} }
@ -3659,13 +3657,8 @@ RecordCoerceExpr::RecordCoerceExpr(Expr* op, RecordType* r)
break; break;
} }
} }
else else if ( t_r->IsFieldDeprecated(i) )
{ reporter->Warning("%s", t_r->GetFieldDeprecationWarning(i, false).c_str());
if ( t_r->FieldDecl(i)->FindAttr(ATTR_DEPRECATED) )
reporter->Warning("deprecated (%s$%s)",
t_r->GetName().c_str(),
t_r->FieldName(i));
}
} }
} }
} }
@ -4753,7 +4746,7 @@ Expr* ListExpr::MakeLvalue()
return new RefExpr(this); return new RefExpr(this);
} }
void ListExpr::Assign(Frame* f, Val* v, Opcode op) void ListExpr::Assign(Frame* f, Val* v)
{ {
ListVal* lv = v->AsListVal(); ListVal* lv = v->AsListVal();
@ -4761,7 +4754,7 @@ void ListExpr::Assign(Frame* f, Val* v, Opcode op)
RuntimeError("mismatch in list lengths"); RuntimeError("mismatch in list lengths");
loop_over_list(exprs, i) loop_over_list(exprs, i)
exprs[i]->Assign(f, (*lv->Vals())[i]->Ref(), op); exprs[i]->Assign(f, (*lv->Vals())[i]->Ref());
Unref(lv); Unref(lv);
} }

View file

@ -86,7 +86,7 @@ public:
const; const;
// Assign to the given value, if appropriate. // Assign to the given value, if appropriate.
virtual void Assign(Frame* f, Val* v, Opcode op = OP_ASSIGN); virtual void Assign(Frame* f, Val* v);
// Returns the type corresponding to this expression interpreted // Returns the type corresponding to this expression interpreted
// as an initialization. The type should be Unref()'d when done // as an initialization. The type should be Unref()'d when done
@ -239,7 +239,7 @@ public:
ID* Id() const { return id; } ID* Id() const { return id; }
Val* Eval(Frame* f) const override; Val* Eval(Frame* f) const override;
void Assign(Frame* f, Val* v, Opcode op = OP_ASSIGN) override; void Assign(Frame* f, Val* v) override;
Expr* MakeLvalue() override; Expr* MakeLvalue() override;
int IsPure() const override; int IsPure() const override;
@ -586,7 +586,7 @@ class RefExpr : public UnaryExpr {
public: public:
explicit RefExpr(Expr* op); explicit RefExpr(Expr* op);
void Assign(Frame* f, Val* v, Opcode op = OP_ASSIGN) override; void Assign(Frame* f, Val* v) override;
Expr* MakeLvalue() override; Expr* MakeLvalue() override;
protected: protected:
@ -639,7 +639,7 @@ public:
void Add(Frame* f) override; void Add(Frame* f) override;
void Delete(Frame* f) override; void Delete(Frame* f) override;
void Assign(Frame* f, Val* v, Opcode op = OP_ASSIGN) override; void Assign(Frame* f, Val* v) override;
Expr* MakeLvalue() override; Expr* MakeLvalue() override;
// Need to override Eval since it can take a vector arg but does // Need to override Eval since it can take a vector arg but does
@ -671,7 +671,7 @@ public:
int CanDel() const override; int CanDel() const override;
void Assign(Frame* f, Val* v, Opcode op = OP_ASSIGN) override; void Assign(Frame* f, Val* v) override;
void Delete(Frame* f) override; void Delete(Frame* f) override;
Expr* MakeLvalue() override; Expr* MakeLvalue() override;
@ -991,7 +991,7 @@ public:
BroType* InitType() const override; BroType* InitType() const override;
Val* InitVal(const BroType* t, Val* aggr) const override; Val* InitVal(const BroType* t, Val* aggr) const override;
Expr* MakeLvalue() override; Expr* MakeLvalue() override;
void Assign(Frame* f, Val* v, Opcode op = OP_ASSIGN) override; void Assign(Frame* f, Val* v) override;
TraversalCode Traverse(TraversalCallback* cb) const override; TraversalCode Traverse(TraversalCallback* cb) const override;

View file

@ -59,34 +59,14 @@ void ID::ClearVal()
val = 0; val = 0;
} }
void ID::SetVal(Val* v, Opcode op, bool arg_weak_ref) void ID::SetVal(Val* v, bool arg_weak_ref)
{ {
if ( op != OP_NONE )
{
MutableVal::Properties props = 0;
if ( attrs && attrs->FindAttr(ATTR_TRACKED) )
props |= MutableVal::TRACKED;
if ( props )
{
if ( v->IsMutableVal() )
v->AsMutableVal()->AddProperties(props);
}
#ifndef DEBUG
if ( props )
#else
if ( debug_logger.IsVerbose() || props )
#endif
StateAccess::Log(new StateAccess(op, this, v, val));
}
if ( ! weak_ref ) if ( ! weak_ref )
Unref(val); Unref(val);
val = v; val = v;
weak_ref = arg_weak_ref; weak_ref = arg_weak_ref;
Modified();
#ifdef DEBUG #ifdef DEBUG
UpdateValID(); UpdateValID();
@ -175,16 +155,6 @@ void ID::UpdateValAttrs()
if ( ! attrs ) if ( ! attrs )
return; return;
MutableVal::Properties props = 0;
if ( val && val->IsMutableVal() )
{
if ( attrs->FindAttr(ATTR_TRACKED) )
props |= MutableVal::TRACKED;
val->AsMutableVal()->AddProperties(props);
}
if ( val && val->Type()->Tag() == TYPE_TABLE ) if ( val && val->Type()->Tag() == TYPE_TABLE )
val->AsTableVal()->SetAttrs(attrs); val->AsTableVal()->SetAttrs(attrs);
@ -219,15 +189,35 @@ void ID::UpdateValAttrs()
} }
} }
void ID::MakeDeprecated() void ID::MakeDeprecated(Expr* deprecation)
{ {
if ( IsDeprecated() ) if ( IsDeprecated() )
return; return;
attr_list* attr = new attr_list{new Attr(ATTR_DEPRECATED)}; attr_list* attr = new attr_list{new Attr(ATTR_DEPRECATED, deprecation)};
AddAttrs(new Attributes(attr, Type(), false)); AddAttrs(new Attributes(attr, Type(), false));
} }
string ID::GetDeprecationWarning() const
{
string result;
Attr* depr_attr = FindAttr(ATTR_DEPRECATED);
if ( depr_attr )
{
ConstExpr* expr = static_cast<ConstExpr*>(depr_attr->AttrExpr());
if ( expr )
{
StringVal* text = expr->Value()->AsStringVal();
result = text->CheckString();
}
}
if ( result.empty() )
return fmt("deprecated (%s)", Name());
else
return fmt("deprecated (%s): %s", Name(), result.c_str());
}
void ID::AddAttrs(Attributes* a) void ID::AddAttrs(Attributes* a)
{ {
if ( attrs ) if ( attrs )
@ -242,16 +232,6 @@ void ID::RemoveAttr(attr_tag a)
{ {
if ( attrs ) if ( attrs )
attrs->RemoveAttr(a); attrs->RemoveAttr(a);
if ( val && val->IsMutableVal() )
{
MutableVal::Properties props = 0;
if ( a == ATTR_TRACKED )
props |= MutableVal::TRACKED;
val->AsMutableVal()->RemoveProperties(props);
}
} }
void ID::SetOption() void ID::SetOption()

View file

@ -5,7 +5,7 @@
#include "Type.h" #include "Type.h"
#include "Attr.h" #include "Attr.h"
#include "StateAccess.h" #include "Notifier.h"
#include "TraverseTypes.h" #include "TraverseTypes.h"
#include <string> #include <string>
@ -15,7 +15,7 @@ class Func;
typedef enum { INIT_NONE, INIT_FULL, INIT_EXTRA, INIT_REMOVE, } init_class; typedef enum { INIT_NONE, INIT_FULL, INIT_EXTRA, INIT_REMOVE, } init_class;
typedef enum { SCOPE_FUNCTION, SCOPE_MODULE, SCOPE_GLOBAL } IDScope; typedef enum { SCOPE_FUNCTION, SCOPE_MODULE, SCOPE_GLOBAL } IDScope;
class ID : public BroObj { class ID : public BroObj, public notifier::Modifiable {
public: public:
ID(const char* name, IDScope arg_scope, bool arg_is_export); ID(const char* name, IDScope arg_scope, bool arg_is_export);
~ID() override; ~ID() override;
@ -46,7 +46,7 @@ public:
// reference to the Val, the Val will be destroyed (naturally, // reference to the Val, the Val will be destroyed (naturally,
// you have to take care that it will not be accessed via // you have to take care that it will not be accessed via
// the ID afterwards). // the ID afterwards).
void SetVal(Val* v, Opcode op = OP_ASSIGN, bool weak_ref = false); void SetVal(Val* v, bool weak_ref = false);
void SetVal(Val* v, init_class c); void SetVal(Val* v, init_class c);
void SetVal(Expr* ev, init_class c); void SetVal(Expr* ev, init_class c);
@ -70,10 +70,6 @@ public:
bool IsRedefinable() const { return FindAttr(ATTR_REDEF) != 0; } bool IsRedefinable() const { return FindAttr(ATTR_REDEF) != 0; }
// Returns true if ID is one of those internal globally unique IDs
// to which MutableVals are bound (there name start with a '#').
bool IsInternalGlobal() const { return name && name[0] == '#'; }
void SetAttrs(Attributes* attr); void SetAttrs(Attributes* attr);
void AddAttrs(Attributes* attr); void AddAttrs(Attributes* attr);
void RemoveAttr(attr_tag a); void RemoveAttr(attr_tag a);
@ -86,7 +82,9 @@ public:
bool IsDeprecated() const bool IsDeprecated() const
{ return FindAttr(ATTR_DEPRECATED) != 0; } { return FindAttr(ATTR_DEPRECATED) != 0; }
void MakeDeprecated(); void MakeDeprecated(Expr* deprecation);
string GetDeprecationWarning() const;
void Error(const char* msg, const BroObj* o2 = 0); void Error(const char* msg, const BroObj* o2 = 0);

View file

@ -140,9 +140,6 @@ RecordType* backdoor_endp_stats;
RecordType* software; RecordType* software;
RecordType* software_version; RecordType* software_version;
RecordType* OS_version;
EnumType* OS_version_inference;
TableVal* generate_OS_version_event;
double table_expire_interval; double table_expire_interval;
double table_expire_delay; double table_expire_delay;
@ -165,10 +162,6 @@ StringVal* log_rotate_base_time;
StringVal* peer_description; StringVal* peer_description;
bro_uint_t chunked_io_buffer_soft_cap; bro_uint_t chunked_io_buffer_soft_cap;
StringVal* ssl_ca_certificate;
StringVal* ssl_private_key;
StringVal* ssl_passphrase;
Val* profiling_file; Val* profiling_file;
double profiling_interval; double profiling_interval;
int expensive_profiling_multiple; int expensive_profiling_multiple;
@ -244,10 +237,6 @@ void init_general_global_var()
internal_val("peer_description")->AsStringVal(); internal_val("peer_description")->AsStringVal();
chunked_io_buffer_soft_cap = opt_internal_unsigned("chunked_io_buffer_soft_cap"); chunked_io_buffer_soft_cap = opt_internal_unsigned("chunked_io_buffer_soft_cap");
ssl_ca_certificate = internal_val("ssl_ca_certificate")->AsStringVal();
ssl_private_key = internal_val("ssl_private_key")->AsStringVal();
ssl_passphrase = internal_val("ssl_passphrase")->AsStringVal();
packet_filter_default = opt_internal_int("packet_filter_default"); packet_filter_default = opt_internal_int("packet_filter_default");
sig_max_group_size = opt_internal_int("sig_max_group_size"); sig_max_group_size = opt_internal_int("sig_max_group_size");
@ -425,10 +414,6 @@ void init_net_var()
software = internal_type("software")->AsRecordType(); software = internal_type("software")->AsRecordType();
software_version = internal_type("software_version")->AsRecordType(); software_version = internal_type("software_version")->AsRecordType();
OS_version = internal_type("OS_version")->AsRecordType();
OS_version_inference = internal_type("OS_version_inference")->AsEnumType();
generate_OS_version_event =
opt_internal_table("generate_OS_version_event");
packet_type = internal_type("packet")->AsRecordType(); packet_type = internal_type("packet")->AsRecordType();

View file

@ -143,9 +143,6 @@ extern RecordType* backdoor_endp_stats;
extern RecordType* software; extern RecordType* software;
extern RecordType* software_version; extern RecordType* software_version;
extern RecordType* OS_version;
extern EnumType* OS_version_inference;
extern TableVal* generate_OS_version_event;
extern double table_expire_interval; extern double table_expire_interval;
extern double table_expire_delay; extern double table_expire_delay;
@ -168,10 +165,6 @@ extern StringVal* log_rotate_base_time;
extern StringVal* peer_description; extern StringVal* peer_description;
extern bro_uint_t chunked_io_buffer_soft_cap; extern bro_uint_t chunked_io_buffer_soft_cap;
extern StringVal* ssl_ca_certificate;
extern StringVal* ssl_private_key;
extern StringVal* ssl_passphrase;
extern Val* profiling_file; extern Val* profiling_file;
extern double profiling_interval; extern double profiling_interval;
extern int expensive_profiling_multiple; extern int expensive_profiling_multiple;

72
src/Notifier.cc Normal file
View file

@ -0,0 +1,72 @@
// See the file "COPYING" in the main distribution directory for copyright.
#include "DebugLogger.h"
#include "Notifier.h"
notifier::Registry notifier::registry;
notifier::Receiver::Receiver()
{
DBG_LOG(DBG_NOTIFIERS, "creating receiver %p", this);
}
notifier::Receiver::~Receiver()
{
DBG_LOG(DBG_NOTIFIERS, "deleting receiver %p", this);
}
notifier::Registry::~Registry()
{
while ( registrations.begin() != registrations.end() )
Unregister(registrations.begin()->first);
}
void notifier::Registry::Register(Modifiable* m, notifier::Receiver* r)
{
DBG_LOG(DBG_NOTIFIERS, "registering object %p for receiver %p", m, r);
registrations.insert({m, r});
++m->num_receivers;
}
void notifier::Registry::Unregister(Modifiable* m, notifier::Receiver* r)
{
DBG_LOG(DBG_NOTIFIERS, "unregistering object %p from receiver %p", m, r);
auto x = registrations.equal_range(m);
for ( auto i = x.first; i != x.second; i++ )
{
if ( i->second == r )
{
--i->first->num_receivers;
registrations.erase(i);
break;
}
}
}
void notifier::Registry::Unregister(Modifiable* m)
{
DBG_LOG(DBG_NOTIFIERS, "unregistering object %p from all notifiers", m);
auto x = registrations.equal_range(m);
for ( auto i = x.first; i != x.second; i++ )
--i->first->num_receivers;
registrations.erase(x.first, x.second);
}
void notifier::Registry::Modified(Modifiable* m)
{
DBG_LOG(DBG_NOTIFIERS, "object %p has been modified", m);
auto x = registrations.equal_range(m);
for ( auto i = x.first; i != x.second; i++ )
i->second->Modified(m);
}
notifier::Modifiable::~Modifiable()
{
if ( num_receivers )
registry.Unregister(this);
}

116
src/Notifier.h Normal file
View file

@ -0,0 +1,116 @@
// See the file "COPYING" in the main distribution directory for copyright.
//
// A notification framework to inform interested parties of modifications to
// selected global objects. To get notified about a change, derive a class
// from notifier::Receiver and register the interesting objects with the
// notification::Registry.
#ifndef NOTIFIER_H
#define NOTIFIER_H
#include <set>
#include <unordered_map>
#include <string>
#include "util.h"
#include "DebugLogger.h"
namespace notifier {
class Modifiable;
/** Interface class for receivers of notifications. */
class Receiver {
public:
Receiver();
virtual ~Receiver();
/**
* Callback executed when a register object has been modified.
*
* @param m object that was modified
*/
virtual void Modified(Modifiable* m) = 0;
};
/** Singleton class tracking all notification requests globally. */
class Registry {
public:
~Registry();
/**
* Registers a receiver to be informed when a modifiable object has
* changed.
*
* @param m object to track. Does not take ownership, but the object
* will automatically unregister itself on destruction.
*
* @param r receiver to notify on changes. Does not take ownershop,
* the receiver must remain valid as long as the registration stays
* in place.
*/
void Register(Modifiable* m, Receiver* r);
/**
* Cancels a receiver's request to be informed about an object's
* modification. The arguments to the method must match what was
* originally registered.
*
* @param m object to no loger track.
*
* @param r receiver to no longer notify.
*/
void Unregister(Modifiable* m, Receiver* Receiver);
/**
* Cancels any active receiver requests to be informed about a
* partilar object's modifications.
*
* @param m object to no loger track.
*/
void Unregister(Modifiable* m);
private:
friend class Modifiable;
// Inform all registered receivers of a modification to an object.
// Will be called from the object itself.
void Modified(Modifiable* m);
typedef std::unordered_multimap<Modifiable*, Receiver*> ModifiableMap;
ModifiableMap registrations;
};
/**
* Singleton object tracking all global notification requests.
*/
extern Registry registry;
/**
* Base class for objects that can trigger notifications to receivers when
* modified.
*/
class Modifiable {
public:
/**
* Calling this method signals to all registered receivers that the
* object has been modified.
*/
void Modified()
{
if ( num_receivers )
registry.Modified(this);
}
protected:
friend class Registry;
virtual ~Modifiable();
// Number of currently registered receivers.
uint64 num_receivers = 0;
};
}
#endif

View file

@ -1,689 +0,0 @@
/*
Taken with permission from:
p0f - passive OS fingerprinting (GNU LESSER GENERAL PUBLIC LICENSE)
-------------------------------------------------------------------
"If you sit down at a poker game and don't see a sucker,
get up. You're the sucker."
(C) Copyright 2000-2003 by Michal Zalewski <lcamtuf@coredump.cx>
*/
// To make it easier to upgrade this file to newer releases of p0f,
// it remains in the coding style used by p0f rather than Bro.
#include "OSFinger.h"
#include "net_util.h"
#include "util.h"
#include "Var.h"
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
void int_delete_func(void* v)
{
delete (int*) v;
}
// Initializes data structures for fingerprinting in the given mode.
OSFingerprint::OSFingerprint(FingerprintMode arg_mode)
{
err = 0;
mode = arg_mode;
sigcnt=gencnt=0;
problems=0;
char* fname;
memset(sig, 0, sizeof(struct fp_entry)*MAXSIGS);
memset(bh, 0, sizeof(struct fp_entry*)*OSHSIZE);
os_matches.SetDeleteFunc(int_delete_func);
if (mode == SYN_FINGERPRINT_MODE)
{
fname = copy_string(internal_val("passive_fingerprint_file")->AsString()->CheckString());
load_config(fname);
delete [] fname;
}
else if (mode == SYN_ACK_FINGERPRINT_MODE)
{//not yet supported
load_config("p0fsynack.sig");
}
else if (mode == RST_FINGERPRINT_MODE)
{//not yet supported
load_config("p0frst.sig");
}
else
{
Error("OS fingerprinting: unknown mode!");
}
}
bool OSFingerprint::CacheMatch(const IPAddr& addr, int id)
{
HashKey* key = addr.GetHashKey();
int* pid = new int;
*pid=id;
int* prev = os_matches.Insert(key, pid);
bool ret = (prev ? *prev != id : 1);
if (prev)
delete prev;
delete key;
return ret;
}
// Determines whether the signature file had any collisions.
void OSFingerprint::collide(uint32 id)
{
uint32 i,j;
uint32 cur;
if (sig[id].ttl % 32 && sig[id].ttl != 255 && sig[id].ttl % 30)
{
problems=1;
reporter->Warning("OS fingerprinting: [!] Unusual TTL (%d) for signature '%s %s' (line %d).",
sig[id].ttl,sig[id].os,sig[id].desc,sig[id].line);
}
for (i=0;i<id;i++)
{
if (!strcmp(sig[i].os,sig[id].os) &&
!strcmp(sig[i].desc,sig[id].desc)) {
problems=1;
reporter->Warning("OS fingerprinting: [!] Duplicate signature name: '%s %s' (line %d and %d).",
sig[i].os,sig[i].desc,sig[i].line,sig[id].line);
}
/* If TTLs are sufficiently away from each other, the risk of
a collision is lower. */
if (abs((int)sig[id].ttl - (int)sig[i].ttl) > 25) continue;
if (sig[id].df ^ sig[i].df) continue;
if (sig[id].zero_stamp ^ sig[i].zero_stamp) continue;
/* Zero means >= PACKET_BIG */
if (sig[id].size) { if (sig[id].size ^ sig[i].size) continue; }
else if (sig[i].size < PACKET_BIG) continue;
if (sig[id].optcnt ^ sig[i].optcnt) continue;
if (sig[id].quirks ^ sig[i].quirks) continue;
switch (sig[id].wsize_mod) {
case 0: /* Current: const */
cur=sig[id].wsize;
do_const:
switch (sig[i].wsize_mod) {
case 0: /* Previous is also const */
/* A problem if values match */
if (cur ^ sig[i].wsize) continue;
break;
case MOD_CONST: /* Current: const, prev: modulo (or *) */
/* A problem if current value is a multiple of that modulo */
if (cur % sig[i].wsize) continue;
break;
case MOD_MSS: /* Current: const, prev: mod MSS */
if (sig[i].mss_mod || sig[i].wsize *
(sig[i].mss ? sig[i].mss : 1460 ) != (int) cur)
continue;
break;
case MOD_MTU: /* Current: const, prev: mod MTU */
if (sig[i].mss_mod || sig[i].wsize * (
(sig[i].mss ? sig[i].mss : 1460 )+40) != (int) cur)
continue;
break;
}
break;
case 1: /* Current signature is modulo something */
/* A problem only if this modulo is a multiple of the
previous modulo */
if (sig[i].wsize_mod != MOD_CONST) continue;
if (sig[id].wsize % sig[i].wsize) continue;
break;
case MOD_MSS: /* Current is modulo MSS */
/* There's likely a problem only if the previous one is close
to '*'; we do not check known MTUs, because this particular
signature can be made with some uncommon MTUs in mind. The
problem would also appear if current signature has a fixed
MSS. */
if (sig[i].wsize_mod != MOD_CONST || sig[i].wsize >= 8) {
if (!sig[id].mss_mod) {
cur = (sig[id].mss ? sig[id].mss : 1460 ) * sig[id].wsize;
goto do_const;
}
continue;
}
break;
case MOD_MTU: /* Current is modulo MTU */
if (sig[i].wsize_mod != MOD_CONST || sig[i].wsize <= 8) {
if (!sig[id].mss_mod) {
cur = ( (sig[id].mss ? sig[id].mss : 1460 ) +40) * sig[id].wsize;
goto do_const;
}
continue;
}
break;
}
/* Same for wsc */
switch (sig[id].wsc_mod) {
case 0: /* Current: const */
cur=sig[id].wsc;
switch (sig[i].wsc_mod) {
case 0: /* Previous is also const */
/* A problem if values match */
if (cur ^ sig[i].wsc) continue;
break;
case 1: /* Current: const, prev: modulo (or *) */
/* A problem if current value is a multiple of that modulo */
if (cur % sig[i].wsc) continue;
break;
}
break;
case MOD_CONST: /* Current signature is modulo something */
/* A problem only if this modulo is a multiple of the
previous modulo */
if (!sig[i].wsc_mod) continue;
if (sig[id].wsc % sig[i].wsc) continue;
break;
}
/* Same for mss */
switch (sig[id].mss_mod) {
case 0: /* Current: const */
cur=sig[id].mss;
switch (sig[i].mss_mod) {
case 0: /* Previous is also const */
/* A problem if values match */
if (cur ^ sig[i].mss) continue;
break;
case 1: /* Current: const, prev: modulo (or *) */
/* A problem if current value is a multiple of that modulo */
if (cur % sig[i].mss) continue;
break;
}
break;
case MOD_CONST: /* Current signature is modulo something */
/* A problem only if this modulo is a multiple of the
previous modulo */
if (!sig[i].mss_mod) continue;
if ((sig[id].mss ? sig[id].mss : 1460 ) %
(sig[i].mss ? sig[i].mss : 1460 )) continue;
break;
}
/* Now check option sequence */
for (j=0;j<sig[id].optcnt;j++)
if (sig[id].opt[j] ^ sig[i].opt[j]) goto reloop;
problems=1;
reporter->Warning("OS fingerprinting: [!] Signature '%s %s' (line %d)\n"
" is already covered by '%s %s' (line %d).",
sig[id].os,sig[id].desc,sig[id].line,sig[i].os,sig[i].desc,
sig[i].line);
reloop:
;
}
}
// Loads a given file into to classes data structures.
void OSFingerprint::load_config(const char* file)
{
uint32 ln=0;
char buf[MAXLINE];
char* p;
FILE* c = open_file(find_file(file, bro_path(), ".osf"));
if (!c)
{
Error("Can't open OS passive fingerprinting signature file", file);
return;
}
sigcnt=0; //every time we read config we reset it to 0;
while ((p=fgets(buf,sizeof(buf),c)))
{
uint32 l;
char obuf[MAXLINE],genre[MAXLINE],desc[MAXLINE],quirks[MAXLINE];
char w[MAXLINE],sb[MAXLINE];
char* gptr = genre;
uint32 t,d,s;
struct fp_entry* e;
ln++;
/* Remove leading and trailing blanks */
while (isspace(*p)) p++;
l=strlen(p);
while (l && isspace(*(p+l-1))) *(p+(l--)-1)=0;
/* Skip empty lines and comments */
if (!l) continue;
if (*p == '#') continue;
if (sscanf(p,"%[0-9%*()ST]:%d:%d:%[0-9()*]:%[^:]:%[^ :]:%[^:]:%[^:]",
w, &t,&d,sb, obuf, quirks,genre,desc) != 8)
Error("OS fingerprinting: Syntax error in p0f signature config line %d.\n",(uint32)ln);
gptr = genre;
if (*sb != '*') s = atoi(sb); else s = 0;
reparse_ptr:
switch (*gptr)
{
case '-': sig[sigcnt].userland = 1; gptr++; goto reparse_ptr;
case '*': sig[sigcnt].no_detail = 1; gptr++; goto reparse_ptr;
case '@': sig[sigcnt].generic = 1; gptr++; gencnt++; goto reparse_ptr;
case 0: Error("OS fingerprinting: Empty OS genre in line",(uint32)ln);
}
sig[sigcnt].os = strdup(gptr);
sig[sigcnt].desc = strdup(desc);
sig[sigcnt].ttl = t;
sig[sigcnt].size = s;
sig[sigcnt].df = d;
if (w[0] == '*')
{
sig[sigcnt].wsize = 1;
sig[sigcnt].wsize_mod = MOD_CONST;
}
else if (tolower(w[0]) == 's')
{
sig[sigcnt].wsize_mod = MOD_MSS;
if (!isdigit(*(w+1)))
Error("OS fingerprinting: Bad Snn value in WSS in line",(uint32)ln);
sig[sigcnt].wsize = atoi(w+1);
}
else if (tolower(w[0]) == 't')
{
sig[sigcnt].wsize_mod = MOD_MTU;
if (!isdigit(*(w+1)))
Error("OS fingerprinting: Bad Tnn value in WSS in line",(uint32)ln);
sig[sigcnt].wsize = atoi(w+1);
}
else if (w[0] == '%')
{
if (!(sig[sigcnt].wsize = atoi(w+1)))
Error("OS fingerprinting: Null modulo for window size in config line",(uint32)ln);
sig[sigcnt].wsize_mod = MOD_CONST;
}
else
sig[sigcnt].wsize = atoi(w);
/* Now let's parse options */
p=obuf;
sig[sigcnt].zero_stamp = 1;
if (*p=='.') p++;
while (*p)
{
uint8 optcnt = sig[sigcnt].optcnt;
switch (tolower(*p))
{
case 'n': sig[sigcnt].opt[optcnt] = TCPOPT_NOP;
break;
case 'e': sig[sigcnt].opt[optcnt] = TCPOPT_EOL;
if (*(p+1))
Error("OS fingerprinting: EOL not the last option, line",(uint32)ln);
break;
case 's': sig[sigcnt].opt[optcnt] = TCPOPT_SACK_PERMITTED;
break;
case 't': sig[sigcnt].opt[optcnt] = TCPOPT_TIMESTAMP;
if (*(p+1)!='0')
{
sig[sigcnt].zero_stamp=0;
if (isdigit(*(p+1)))
Error("OS fingerprinting: Bogus Tstamp specification in line",(uint32)ln);
}
break;
case 'w': sig[sigcnt].opt[optcnt] = TCPOPT_WINDOW;
if (p[1] == '*')
{
sig[sigcnt].wsc = 1;
sig[sigcnt].wsc_mod = MOD_CONST;
}
else if (p[1] == '%')
{
if (!(sig[sigcnt].wsc = atoi(p+2)))
Error("OS fingerprinting: Null modulo for wscale in config line",(uint32)ln);
sig[sigcnt].wsc_mod = MOD_CONST;
}
else if (!isdigit(*(p+1)))
Error("OS fingerprinting: Incorrect W value in line",(uint32)ln);
else sig[sigcnt].wsc = atoi(p+1);
break;
case 'm': sig[sigcnt].opt[optcnt] = TCPOPT_MAXSEG;
if (p[1] == '*')
{
sig[sigcnt].mss = 1;
sig[sigcnt].mss_mod = MOD_CONST;
}
else if (p[1] == '%')
{
if (!(sig[sigcnt].mss = atoi(p+2)))
Error("OS fingerprinting: Null modulo for MSS in config line",(uint32)ln);
sig[sigcnt].mss_mod = MOD_CONST;
}
else if (!isdigit(*(p+1)))
Error("OS fingerprinting: Incorrect M value in line",(uint32)ln);
else sig[sigcnt].mss = atoi(p+1);
break;
/* Yuck! */
case '?': if (!isdigit(*(p+1)))
Error("OS fingerprinting: Bogus ?nn value in line",(uint32)ln);
else sig[sigcnt].opt[optcnt] = atoi(p+1);
break;
default: Error("OS fingerprinting: Unknown TCP option in config line",(uint32)ln);
}
if (++sig[sigcnt].optcnt >= MAXOPT)
Error("OS fingerprinting: Too many TCP options specified in config line",(uint32)ln);
/* Skip separators */
do { p++; } while (*p && !isalpha(*p) && *p != '?');
}
sig[sigcnt].line = ln;
p = quirks;
while (*p)
switch (toupper(*(p++)))
{
case 'E':
Error("OS fingerprinting: Quirk 'E' is obsolete. Remove it, append E to the options. Line",(uint32)ln);
break;
case 'K':
if ( mode != RST_FINGERPRINT_MODE )
Error("OS fingerprinting: Quirk 'K' is valid only in RST+ (-R) mode (wrong config file?). Line",(uint32)ln);
sig[sigcnt].quirks |= QUIRK_RSTACK;
break;
case 'Q': sig[sigcnt].quirks |= QUIRK_SEQEQ; break;
case '0': sig[sigcnt].quirks |= QUIRK_SEQ0; break;
case 'P': sig[sigcnt].quirks |= QUIRK_PAST; break;
case 'Z': sig[sigcnt].quirks |= QUIRK_ZEROID; break;
case 'I': sig[sigcnt].quirks |= QUIRK_IPOPT; break;
case 'U': sig[sigcnt].quirks |= QUIRK_URG; break;
case 'X': sig[sigcnt].quirks |= QUIRK_X2; break;
case 'A': sig[sigcnt].quirks |= QUIRK_ACK; break;
case 'T': sig[sigcnt].quirks |= QUIRK_T2; break;
case 'F': sig[sigcnt].quirks |= QUIRK_FLAGS; break;
case 'D': sig[sigcnt].quirks |= QUIRK_DATA; break;
case '!': sig[sigcnt].quirks |= QUIRK_BROKEN; break;
case '.': break;
default: Error("OS fingerprinting: Bad quirk in line",(uint32)ln);
}
e = bh[SIGHASH(s,sig[sigcnt].optcnt,sig[sigcnt].quirks,d)];
if (!e)
{
bh[SIGHASH(s,sig[sigcnt].optcnt,sig[sigcnt].quirks,d)] = &sig[sigcnt];
}
else
{
while (e->next) e = e->next;
e->next = &sig[sigcnt];
}
collide(sigcnt);
if (++sigcnt >= MAXSIGS)
Error("OS fingerprinting: Maximum signature count exceeded.\n");
}
fclose(c);
if (!sigcnt)
Error("OS fingerprinting: no signatures loaded from config file.");
}
// Does the actual match between the packet and the signature database.
// Modifies retval and contains OS Type and other useful information.
// Returns config-file line of the matching signature as id.
int OSFingerprint::FindMatch(struct os_type* retval, uint16 tot,uint8 df,
uint8 ttl,uint16 wss,uint8 ocnt,uint8* op,
uint16 mss,uint8 wsc,uint32 tstamp,
uint32 quirks,uint8 ecn) const
{
uint32 j; //used for counter in loops
struct fp_entry* p;
uint8 orig_df = df;
struct fp_entry* fuzzy = 0;
uint8 fuzzy_now = 0;
int id = 0; //return value: 0 indicates no match.
retval->os="UNKNOWN";
retval->desc=NULL;
retval->gadgets=0;
retval->match=0;
retval->uptime=0;
re_lookup:
p = bh[SIGHASH(tot,ocnt,quirks,df)];
while (p)
{
/* Cheap and specific checks first... */
/* psize set to zero means >= PACKET_BIG */
if (p->size) { if (tot ^ p->size) { p = p->next; continue; } }
else if (tot < PACKET_BIG) { p = p->next; continue; }
if (ocnt ^ p->optcnt) { p = p->next; continue; }
if (p->zero_stamp ^ (!tstamp)) { p = p->next; continue; }
if (p->df ^ df) { p = p->next; continue; }
if (p->quirks ^ quirks) { p = p->next; continue; }
/* Check MSS and WSCALE... */
if (!p->mss_mod) {
if (mss ^ p->mss) { p = p->next; continue; }
} else if (mss % p->mss) { p = p->next; continue; }
if (!p->wsc_mod) {
if (wsc ^ p->wsc) { p = p->next; continue; }
} else if (wsc % p->wsc) { p = p->next; continue; }
/* Then proceed with the most complex WSS check... */
switch (p->wsize_mod)
{
case 0:
if (wss ^ p->wsize) { p = p->next; continue; }
break;
case MOD_CONST:
if (wss % p->wsize) { p = p->next; continue; }
break;
case MOD_MSS:
if (mss && !(wss % mss))
{
if ((wss / mss) ^ p->wsize) { p = p->next; continue; }
}
else if (!(wss % 1460))
{
if ((wss / 1460) ^ p->wsize) { p = p->next; continue; }
}
else { p = p->next; continue; }
break;
case MOD_MTU:
if (mss && !(wss % (mss+40)))
{
if ((wss / (mss+40)) ^ p->wsize) { p = p->next; continue; }
}
else if (!(wss % 1500))
{
if ((wss / 1500) ^ p->wsize) { p = p->next; continue; }
}
else { p = p->next; continue; }
break;
}
/* Numbers agree. Let's check options */
for (j=0;j<ocnt;j++)
if (p->opt[j] ^ op[j]) goto continue_search;
/* Check TTLs last because we might want to go fuzzy. */
if (p->ttl < ttl)
{
if ( mode != RST_FINGERPRINT_MODE )fuzzy = p;
p = p->next;
continue;
}
/* Naah... can't happen ;-) */
if (!p->no_detail)
if (p->ttl - ttl > MAXDIST)
{
if (mode != RST_FINGERPRINT_MODE ) fuzzy = p;
p = p->next;
continue;
}
continue_fuzzy:
/* Match! */
id = p->line;
if (mss & wss)
{
if (p->wsize_mod == MOD_MSS)
{
if ((wss % mss) && !(wss % 1460)) retval->gadgets|=GADGETNAT;
}
else if (p->wsize_mod == MOD_MTU)
{
if ((wss % (mss+40)) && !(wss % 1500)) retval->gadgets|=GADGETNAT2;
}
}
retval->os=p->os;
retval->desc=p->desc;
retval->dist=p->ttl-ttl;
if (ecn) retval->gadgets|=GADGETECN;
if (orig_df ^ df) retval->gadgets|=GADGETFIREWALL;
if (p->generic) retval->match=MATCHGENERIC;
if (fuzzy_now) retval->match=MATCHFUZZY;
if (!p->no_detail && tstamp)
{
retval->uptime=tstamp/360000;
retval->gadgets|=GADGETUPTIME;
}
return id;
continue_search:
p = p->next;
}
if (!df) { df = 1; goto re_lookup; } //not found with df=0 do df=1
if (fuzzy)
{
df = orig_df;
fuzzy_now = 1;
p = fuzzy;
fuzzy = 0;
goto continue_fuzzy;
}
if (mss & wss)
{
if ((wss % mss) && !(wss % 1460)) retval->gadgets|=GADGETNAT;
else if ((wss % (mss+40)) && !(wss % 1500)) retval->gadgets|=GADGETNAT2;
}
if (ecn) retval->gadgets|=GADGETECN;
if (tstamp)
{
retval->uptime=tstamp/360000;
retval->gadgets|=GADGETUPTIME;
}
return id;
}

View file

@ -1,161 +0,0 @@
// Taken with permission from:
//
// p0f - passive OS fingerprinting (GNU LESSER GENERAL PUBLIC LICENSE)
// -------------------------------------------------------------------
//
// "If you sit down at a poker game and don't see a sucker,
// get up. You're the sucker."
//
// (C) Copyright 2000-2003 by Michal Zalewski <lcamtuf@coredump.cx>
#ifndef osfinger_h
#define osfinger_h
#include "util.h"
#include "Dict.h"
#include "Reporter.h"
#include "IPAddr.h"
// Size limit for size wildcards.
#define PACKET_BIG 100
// Maximum number of signatures allowed in the config file.
#define MAXSIGS 1024
// Max signature line length.
#define MAXLINE 1024
// Maximum distance from a host to be taken seriously. Between 35 and 64
// is sane. Making it too high might result in some (very rare) false
// positives, too low will result in needless UNKNOWNs.
#define MAXDIST 40
// Maximum number of TCP options. A TCP packet can have at most 64 bytes
// of header, 20 of which are non-options. Thus, if a single option
// consumes 1 bytes (the minimum, there can only be 44 bytes of options.
// We err on the safe side.
#define MAXOPT 64
declare(PDict,int);
struct os_type {
const char* os;
char* desc;
uint8 dist;
uint16 gadgets;
uint16 match;
uint32 uptime;
};
struct fp_entry {
struct fp_entry* next;
char* os; // OS genre
char* desc; // OS description
uint8 no_detail; // disable guesstimates
uint8 generic; // generic hit
uint8 userland; // userland stack
uint16 wsize; // window size
uint8 wsize_mod; // MOD_* for wsize
uint8 ttl; // TTL
uint8 df; // don't fragment bit
uint8 zero_stamp; // timestamp option but zero value?
uint16 size; // packet size
uint8 optcnt; // option count
uint8 opt[MAXOPT]; // TCPOPT_*
uint16 wsc; // window scaling option
uint16 mss; // MSS option
uint8 wsc_mod; // modulo for WSCALE (NONE or CONST)
uint8 mss_mod; // modulo for MSS (NONE or CONST)
uint32 quirks; // packet quirks and bugs
uint32 line; // config file line
};
struct mtu_def {
uint16 mtu;
char* dev;
};
enum FingerprintMode {
SYN_FINGERPRINT_MODE, SYN_ACK_FINGERPRINT_MODE, RST_FINGERPRINT_MODE,
};
class OSFingerprint {
public:
explicit OSFingerprint(FingerprintMode mode);
~OSFingerprint() {}
bool Error() const { return err; }
int FindMatch(struct os_type* retval, uint16 tot, uint8 DF_flag,
uint8 TTL, uint16 WSS, uint8 ocnt, uint8* op, uint16 MSS,
uint8 win_scale, uint32 tstamp, uint32 quirks, uint8 ECN) const;
bool CacheMatch(const IPAddr& addr, int id);
void load_config(const char* file);
protected:
void collide(uint32 id);
void Error(const char* msg)
{
reporter->Error("%s", msg);
err = true;
}
void Error(const char* msg, int n)
{
reporter->Error(msg, n);
err = true;
}
void Error(const char* msg, const char* s)
{
reporter->Error(msg, s);
err = true;
}
private:
bool err; // if true, a fatal error has occurred
unsigned int mode;
uint32 sigcnt, gencnt;
uint8 problems;
struct fp_entry sig[MAXSIGS];
/* By hash */
#define OSHSIZE 16
struct fp_entry* bh[OSHSIZE];
PDict(int) os_matches;
};
#define SIGHASH(tsize, optcnt, q, df) \
((uint8(((tsize) << 1) ^ ((optcnt) << 1) ^ (df) ^ (q) )) & 0x0f)
#define MOD_NONE 0
#define MOD_CONST 1
#define MOD_MSS 2
#define MOD_MTU 3
#define QUIRK_PAST 0x1 /* P */
#define QUIRK_ZEROID 0x2 /* Z */
#define QUIRK_IPOPT 0x4 /* I */
#define QUIRK_URG 0x8 /* U */
#define QUIRK_X2 0x10 /* X */
#define QUIRK_ACK 0x20 /* A */
#define QUIRK_T2 0x40 /* T */
#define QUIRK_FLAGS 0x80 /* F */
#define QUIRK_DATA 0x100 /* D */
#define QUIRK_BROKEN 0x200 /* ! */
#define QUIRK_RSTACK 0x400 /* K */
#define QUIRK_SEQEQ 0x800 /* Q */
#define QUIRK_SEQ0 0x1000 /* 0 */
#define GADGETNAT 0x1
#define GADGETNAT2 0x2
#define GADGETFIREWALL 0x4
#define GADGETECN 0x8
#define GADGETUPTIME 0x10
#define MATCHGENERIC 0x1
#define MATCHFUZZY 0x2
#endif

View file

@ -1,23 +0,0 @@
// See the file "COPYING" in the main distribution directory for copyright.
#ifndef op_h
#define op_h
// BRO operations.
typedef enum {
OP_INCR, OP_DECR, OP_NOT, OP_NEGATE,
OP_PLUS, OP_MINUS, OP_TIMES, OP_DIVIDE, OP_MOD,
OP_AND, OP_OR,
OP_LT, OP_LE, OP_EQ, OP_NE, OP_GE, OP_GT,
OP_MATCH,
OP_ASSIGN,
OP_INDEX, OP_FIELD,
OP_IN,
OP_LIST,
OP_CALL,
OP_SCHED,
OP_NAME, OP_CONST, OP_THIS
} BroOP;
#endif

View file

@ -6,6 +6,8 @@
#include "probabilistic/BloomFilter.h" #include "probabilistic/BloomFilter.h"
#include "probabilistic/CardinalityCounter.h" #include "probabilistic/CardinalityCounter.h"
#include <broker/error.hh>
// Helper to retrieve a broker value out of a broker::vector at a specified // Helper to retrieve a broker value out of a broker::vector at a specified
// index, and casted to the expected destination type. // index, and casted to the expected destination type.
template<typename S, typename V, typename D> template<typename S, typename V, typename D>

View file

@ -3,9 +3,14 @@
#ifndef OPAQUEVAL_H #ifndef OPAQUEVAL_H
#define OPAQUEVAL_H #define OPAQUEVAL_H
#include <typeinfo>
#include <memory> // std::unique_ptr #include <memory> // std::unique_ptr
#include <broker/data.hh>
#include <broker/expected.hh>
#include "RandTest.h" #include "RandTest.h"
#include "Val.h" #include "Val.h"
#include "digest.h" #include "digest.h"

View file

@ -1,160 +0,0 @@
// Helper classes to pass data between serialization methods.
#ifndef serialinfo_h
#define serialinfo_h
class SerialInfo {
public:
SerialInfo(Serializer* arg_s)
{
s = arg_s;
may_suspend = clear_containers = false;
cache = globals_as_names = true;
type = SER_NONE;
pid_32bit = false;
include_locations = true;
new_cache_strategy = false;
}
SerialInfo(const SerialInfo& info)
{
s = info.s;
may_suspend = info.may_suspend;
cache = info.cache;
type = info.type;
clear_containers = info.clear_containers;
globals_as_names = info.globals_as_names;
pid_32bit = info.pid_32bit;
include_locations = info.include_locations;
new_cache_strategy = info.new_cache_strategy;
}
// Parameters that control serialization.
Serializer* s; // serializer to use
bool cache; // true if object caching is ok
bool may_suspend; // if true, suspending serialization is ok
bool clear_containers; // if true, store container values as empty
bool include_locations; // if true, include locations in serialization
// If true, for NameExpr's serialize just the names of globals, just
// their value.
bool globals_as_names;
bool pid_32bit; // if true, use old-style 32-bit permanent IDs
// If true, we support keeping objs in cache permanently.
bool new_cache_strategy;
// Attributes set during serialization.
SerialType type; // type of currently serialized object
// State for suspending/resuming serialization
Continuation cont;
};
class UnserialInfo {
public:
UnserialInfo(Serializer* arg_s)
{
s = arg_s;
cache = true;
type = SER_NONE;
install_globals = install_conns = true;
install_uniques = false;
ignore_callbacks = false;
id_policy = Replace;
print = 0;
pid_32bit = false;
new_cache_strategy = false;
}
UnserialInfo(const UnserialInfo& info)
{
s = info.s;
cache = info.cache;
type = info.type;
install_globals = info.install_globals;
install_uniques = info.install_uniques;
install_conns = info.install_conns;
ignore_callbacks = info.ignore_callbacks;
id_policy = info.id_policy;
print = info.print;
pid_32bit = info.pid_32bit;
new_cache_strategy = info.new_cache_strategy;
}
// Parameters that control unserialization.
Serializer* s; // serializer to use
bool cache; // if true, object caching is ok
FILE* print; // print read objects to given file (human-readable)
bool install_globals; // if true, install unknown globals
// in global scope
bool install_conns; // if true, add connections to session table
bool install_uniques; // if true, install unknown globally
// unique IDs in global scope
bool ignore_callbacks; // if true, don't call Got*() callbacks
bool pid_32bit; // if true, use old-style 32-bit permanent IDs.
// If true, we support keeping objs in cache permanently.
bool new_cache_strategy;
// If a global ID already exits, of these policies is used.
enum {
Keep, // keep the old ID and ignore the new
Replace, // install the new ID (default)
// Keep current ID instance but copy the new value into it
// (types have to match).
CopyNewToCurrent,
// Install the new ID instance but replace its value
// with that of the old one (types have to match).
CopyCurrentToNew,
// Instantiate a new ID, but do not insert it into the global
// space.
InstantiateNew,
} id_policy;
// Attributes set during unserialization.
SerialType type; // type of currently unserialized object
};
// Helper class to temporarily disable suspending for all next-level calls
// using the given SerialInfo. It saves the current value of info.may_suspend
// and then sets it to false. When it goes out of scope, the original value
// is restored.
//
// We need this because not all classes derived from SerialObj are
// suspension-aware yet, i.e., they don't work correctly if one of the
// next-level functions suspends. Eventually this may change, but actually
// it's not very important: most classes don't need to suspend anyway as
// their data volume is very small. We have to make sure though that those
// which do (e.g. TableVals) support suspension.
class DisableSuspend {
public:
DisableSuspend(SerialInfo* arg_info)
{
info = arg_info;
old_may_suspend = info->may_suspend;
info->may_suspend = false;
}
~DisableSuspend() { Restore(); }
void Release() { info = 0; }
// Restores the suspension-state to its original value.
void Restore()
{
if ( info )
info->may_suspend = old_may_suspend;
}
private:
SerialInfo* info;
bool old_may_suspend;
};
#endif

View file

@ -1,240 +0,0 @@
#ifndef serialtypes_h
#define serialtypes_h
// Each serializable class gets a type.
//
// The type enables a form of poor man's type-checking:
// Bit 0-7: Number (unique relative to main parent (see below)).
// Bit 8-12: Main parent class (SER_IS_*)
// Bit 13: unused
// Bit 14: 1 if preference is to keep in cache.
// Bit 15: 1 if derived from BroObj.
typedef uint16 SerialType;
static const SerialType SER_TYPE_MASK_EXACT = 0x1fff;
static const SerialType SER_TYPE_MASK_PARENT = 0x1f00;
static const SerialType SER_IS_CACHE_STABLE = 0x4000;
static const SerialType SER_IS_BRO_OBJ = 0x8000;
#define SERIAL_CONST(name, val, type) \
const SerialType SER_ ## name = val | SER_IS_ ## type;
#define SERIAL_CONST2(name) SERIAL_CONST(name, 1, name)
#define SERIAL_IS(name, val) \
static const SerialType SER_IS_ ## name = val;
#define SERIAL_IS_BO(name, val) \
static const SerialType SER_IS_ ## name = val | SER_IS_BRO_OBJ;
#define SERIAL_IS_BO_AND_CACHE_STABLE(name, val) \
static const SerialType SER_IS_ ## name = val | (SER_IS_BRO_OBJ | SER_IS_CACHE_STABLE);
SERIAL_IS_BO(CONNECTION, 0x0100)
SERIAL_IS(TIMER, 0x0200)
SERIAL_IS(TCP_ENDPOINT, 0x0300)
SERIAL_IS_BO(TCP_ANALYZER, 0x0400)
SERIAL_IS_BO(TCP_ENDPOINT_ANALYZER, 0x0500)
SERIAL_IS(TCP_CONTENTS, 0x0600)
SERIAL_IS(REASSEMBLER, 0x0700)
SERIAL_IS_BO(VAL, 0x0800)
SERIAL_IS_BO_AND_CACHE_STABLE(EXPR, 0x0900)
SERIAL_IS_BO_AND_CACHE_STABLE(BRO_TYPE, 0x0a00)
SERIAL_IS_BO_AND_CACHE_STABLE(STMT, 0x0b00)
SERIAL_IS_BO_AND_CACHE_STABLE(ATTRIBUTES, 0x0c00)
SERIAL_IS_BO_AND_CACHE_STABLE(EVENT_HANDLER, 0x0d00)
SERIAL_IS_BO_AND_CACHE_STABLE(BRO_FILE, 0x0e00)
SERIAL_IS_BO_AND_CACHE_STABLE(FUNC, 0x0f00)
SERIAL_IS_BO(ID, 0x1000)
SERIAL_IS(STATE_ACCESS, 0x1100)
SERIAL_IS_BO(CASE, 0x1200)
SERIAL_IS(LOCATION, 0x1300)
SERIAL_IS(RE_MATCHER, 0x1400)
SERIAL_IS(BITVECTOR, 0x1500)
SERIAL_IS(COUNTERVECTOR, 0x1600)
SERIAL_IS(BLOOMFILTER, 0x1700)
SERIAL_IS(HASHER, 0x1800)
SERIAL_IS(PARAGLOB, 0x1900)
// These are the externally visible types.
const SerialType SER_NONE = 0;
SERIAL_CONST2(BRO_OBJ)
#define SERIAL_CONN(name, val) SERIAL_CONST(name, val, CONNECTION)
SERIAL_CONN(CONNECTION, 1)
SERIAL_CONN(ICMP_ANALYZER, 2)
// We use ICMP_Echo here rather than ICMP_ECHO because the latter gets
// macro expanded :-(.
SERIAL_CONN(ICMP_Echo, 3)
SERIAL_CONN(ICMP_CONTEXT, 4)
SERIAL_CONN(TCP_CONNECTION, 5)
SERIAL_CONN(TCP_CONNECTION_CONTENTS, 6)
SERIAL_CONN(FTP_CONN, 7)
SERIAL_CONN(UDP_CONNECTION, 8)
#define SERIAL_TIMER(name, val) SERIAL_CONST(name, val, TIMER)
SERIAL_TIMER(TIMER, 1)
SERIAL_TIMER(CONNECTION_TIMER, 2)
SERIAL_CONST2(TCP_ENDPOINT)
SERIAL_CONST2(TCP_ANALYZER)
SERIAL_CONST2(TCP_ENDPOINT_ANALYZER)
#define SERIAL_TCP_CONTENTS(name, val) SERIAL_CONST(name, val, TCP_CONTENTS)
SERIAL_TCP_CONTENTS(TCP_CONTENTS, 1)
SERIAL_TCP_CONTENTS(TCP_CONTENT_LINE, 2)
SERIAL_TCP_CONTENTS(TCP_NVT, 3)
#define SERIAL_REASSEMBLER(name, val) SERIAL_CONST(name, val, REASSEMBLER)
SERIAL_REASSEMBLER(REASSEMBLER, 1)
SERIAL_REASSEMBLER(TCP_REASSEMBLER, 2)
SERIAL_REASSEMBLER(FILE_REASSEMBLER, 3)
#define SERIAL_VAL(name, val) SERIAL_CONST(name, val, VAL)
SERIAL_VAL(VAL, 1)
SERIAL_VAL(INTERVAL_VAL, 2)
SERIAL_VAL(PORT_VAL, 3)
SERIAL_VAL(ADDR_VAL, 4)
SERIAL_VAL(SUBNET_VAL, 5)
SERIAL_VAL(STRING_VAL, 6)
SERIAL_VAL(PATTERN_VAL, 7)
SERIAL_VAL(LIST_VAL, 8)
SERIAL_VAL(TABLE_VAL, 9)
SERIAL_VAL(RECORD_VAL, 10)
SERIAL_VAL(ENUM_VAL, 11)
SERIAL_VAL(VECTOR_VAL, 12)
SERIAL_VAL(MUTABLE_VAL, 13)
SERIAL_VAL(OPAQUE_VAL, 14)
SERIAL_VAL(HASH_VAL, 15)
SERIAL_VAL(MD5_VAL, 16)
SERIAL_VAL(SHA1_VAL, 17)
SERIAL_VAL(SHA256_VAL, 18)
SERIAL_VAL(ENTROPY_VAL, 19)
SERIAL_VAL(TOPK_VAL, 20)
SERIAL_VAL(BLOOMFILTER_VAL, 21)
SERIAL_VAL(CARDINALITY_VAL, 22)
SERIAL_VAL(X509_VAL, 23)
SERIAL_VAL(COMM_STORE_HANDLE_VAL, 24)
SERIAL_VAL(COMM_DATA_VAL, 25)
SERIAL_VAL(OCSP_RESP_VAL, 26)
SERIAL_VAL(PARAGLOB_VAL, 27)
#define SERIAL_EXPR(name, val) SERIAL_CONST(name, val, EXPR)
SERIAL_EXPR(EXPR, 1)
SERIAL_EXPR(NAME_EXPR, 2)
SERIAL_EXPR(CONST_EXPR, 3)
SERIAL_EXPR(UNARY_EXPR, 4)
SERIAL_EXPR(BINARY_EXPR, 5)
SERIAL_EXPR(INCR_EXPR, 6)
SERIAL_EXPR(NOT_EXPR, 7)
SERIAL_EXPR(POS_EXPR, 8)
SERIAL_EXPR(NEG_EXPR, 9)
SERIAL_EXPR(ADD_EXPR, 10)
SERIAL_EXPR(SUB_EXPR, 11)
SERIAL_EXPR(TIMES_EXPR, 12)
SERIAL_EXPR(DIVIDE_EXPR, 13)
SERIAL_EXPR(MOD_EXPR, 14)
SERIAL_EXPR(BOOL_EXPR, 15)
SERIAL_EXPR(EQ_EXPR, 16)
SERIAL_EXPR(REL_EXPR, 17)
SERIAL_EXPR(COND_EXPR, 18)
SERIAL_EXPR(REF_EXPR, 19)
SERIAL_EXPR(ASSIGN_EXPR, 20)
SERIAL_EXPR(INDEX_EXPR, 21)
SERIAL_EXPR(FIELD_EXPR, 22)
SERIAL_EXPR(HAS_FIELD_EXPR, 23)
SERIAL_EXPR(RECORD_CONSTRUCTOR_EXPR, 24)
SERIAL_EXPR(FIELD_ASSIGN_EXPR, 25)
// There used to be a SERIAL_EXPR(RECORD_MATCH_EXPR, 26) here
SERIAL_EXPR(ARITH_COERCE_EXPR, 27)
SERIAL_EXPR(RECORD_COERCE_EXPR, 28)
SERIAL_EXPR(FLATTEN_EXPR, 29)
SERIAL_EXPR(SCHEDULE_EXPR, 30)
SERIAL_EXPR(IN_EXPR, 31)
SERIAL_EXPR(CALL_EXPR, 32)
SERIAL_EXPR(EVENT_EXPR, 33)
SERIAL_EXPR(LIST_EXPR, 34)
SERIAL_EXPR(RECORD_ASSIGN_EXPR, 35)
SERIAL_EXPR(ADD_TO_EXPR, 36)
SERIAL_EXPR(REMOVE_FROM_EXPR, 37)
SERIAL_EXPR(SIZE_EXPR, 38)
SERIAL_EXPR(CLONE_EXPR, 39)
SERIAL_EXPR(TABLE_CONSTRUCTOR_EXPR, 40)
SERIAL_EXPR(SET_CONSTRUCTOR_EXPR, 41)
SERIAL_EXPR(VECTOR_CONSTRUCTOR_EXPR, 42)
SERIAL_EXPR(TABLE_COERCE_EXPR, 43)
SERIAL_EXPR(VECTOR_COERCE_EXPR, 44)
SERIAL_EXPR(CAST_EXPR, 45)
SERIAL_EXPR(IS_EXPR_, 46) // Name conflict with internal SER_IS_EXPR constant.
SERIAL_EXPR(BIT_EXPR, 47)
SERIAL_EXPR(COMPLEMENT_EXPR, 48)
SERIAL_EXPR(INDEX_SLICE_ASSIGN_EXPR, 49)
#define SERIAL_STMT(name, val) SERIAL_CONST(name, val, STMT)
SERIAL_STMT(STMT, 1)
SERIAL_STMT(EXPR_LIST_STMT, 2)
// There used to be ALARM_STMT (3) here.
SERIAL_STMT(PRINT_STMT, 4)
SERIAL_STMT(EXPR_STMT, 5)
SERIAL_STMT(IF_STMT, 6)
SERIAL_STMT(SWITCH_STMT, 7)
SERIAL_STMT(ADD_STMT, 8)
SERIAL_STMT(DEL_STMT, 9)
SERIAL_STMT(EVENT_STMT, 10)
SERIAL_STMT(FOR_STMT, 11)
SERIAL_STMT(NEXT_STMT, 12)
SERIAL_STMT(BREAK_STMT, 13)
SERIAL_STMT(RETURN_STMT, 14)
SERIAL_STMT(STMT_LIST, 15)
SERIAL_STMT(EVENT_BODY_LIST, 16)
SERIAL_STMT(INIT_STMT, 17)
SERIAL_STMT(NULL_STMT, 18)
SERIAL_STMT(WHEN_STMT, 19)
SERIAL_STMT(FALLTHROUGH_STMT, 20)
SERIAL_STMT(WHILE_STMT, 21)
#define SERIAL_TYPE(name, val) SERIAL_CONST(name, val, BRO_TYPE)
SERIAL_TYPE(BRO_TYPE, 1)
SERIAL_TYPE(TYPE_LIST, 2)
SERIAL_TYPE(INDEX_TYPE, 3)
SERIAL_TYPE(TABLE_TYPE, 4)
SERIAL_TYPE(SET_TYPE, 5)
SERIAL_TYPE(FUNC_TYPE, 6)
SERIAL_TYPE(RECORD_TYPE, 7)
SERIAL_TYPE(SUBNET_TYPE, 8)
SERIAL_TYPE(FILE_TYPE, 9)
SERIAL_TYPE(ENUM_TYPE, 10)
SERIAL_TYPE(VECTOR_TYPE, 11)
SERIAL_TYPE(OPAQUE_TYPE, 12)
SERIAL_CONST2(ATTRIBUTES)
SERIAL_CONST2(EVENT_HANDLER)
SERIAL_CONST2(BRO_FILE)
#define SERIAL_FUNC(name, val) SERIAL_CONST(name, val, FUNC)
SERIAL_FUNC(FUNC, 1)
SERIAL_FUNC(BRO_FUNC, 2)
SERIAL_FUNC(DEBUG_FUNC, 3)
SERIAL_FUNC(BUILTIN_FUNC, 4)
#define SERIAL_BLOOMFILTER(name, val) SERIAL_CONST(name, val, BLOOMFILTER)
SERIAL_BLOOMFILTER(BLOOMFILTER, 1)
SERIAL_BLOOMFILTER(BASICBLOOMFILTER, 2)
SERIAL_BLOOMFILTER(COUNTINGBLOOMFILTER, 3)
#define SERIAL_HASHER(name, val) SERIAL_CONST(name, val, HASHER)
SERIAL_HASHER(HASHER, 1)
SERIAL_HASHER(DEFAULTHASHER, 2)
SERIAL_HASHER(DOUBLEHASHER, 3)
SERIAL_CONST(PARAGLOB, 1, PARAGLOB)
SERIAL_CONST2(ID)
SERIAL_CONST2(STATE_ACCESS)
SERIAL_CONST2(CASE)
SERIAL_CONST2(LOCATION)
SERIAL_CONST2(RE_MATCHER)
SERIAL_CONST2(BITVECTOR)
SERIAL_CONST2(COUNTERVECTOR)
#endif

View file

@ -14,7 +14,6 @@
#include "NetVar.h" #include "NetVar.h"
#include "Sessions.h" #include "Sessions.h"
#include "Reporter.h" #include "Reporter.h"
#include "OSFinger.h"
#include "analyzer/protocol/icmp/ICMP.h" #include "analyzer/protocol/icmp/ICMP.h"
#include "analyzer/protocol/udp/UDP.h" #include "analyzer/protocol/udp/UDP.h"
@ -130,15 +129,6 @@ NetSessions::NetSessions()
dump_this_packet = 0; dump_this_packet = 0;
num_packets_processed = 0; num_packets_processed = 0;
if ( OS_version_found )
{
SYN_OS_Fingerprinter = new OSFingerprint(SYN_FINGERPRINT_MODE);
if ( SYN_OS_Fingerprinter->Error() )
exit(1);
}
else
SYN_OS_Fingerprinter = 0;
if ( pkt_profile_mode && pkt_profile_freq > 0 && pkt_profile_file ) if ( pkt_profile_mode && pkt_profile_freq > 0 && pkt_profile_file )
pkt_profiler = new PacketProfiler(pkt_profile_mode, pkt_profiler = new PacketProfiler(pkt_profile_mode,
pkt_profile_freq, pkt_profile_file->AsFile()); pkt_profile_freq, pkt_profile_file->AsFile());
@ -155,7 +145,6 @@ NetSessions::~NetSessions()
{ {
delete ch; delete ch;
delete packet_filter; delete packet_filter;
delete SYN_OS_Fingerprinter;
delete pkt_profiler; delete pkt_profiler;
Unref(arp_analyzer); Unref(arp_analyzer);
delete discarder; delete discarder;
@ -987,24 +976,6 @@ FragReassembler* NetSessions::NextFragment(double t, const IP_Hdr* ip,
return f; return f;
} }
int NetSessions::Get_OS_From_SYN(struct os_type* retval,
uint16 tot, uint8 DF_flag, uint8 TTL, uint16 WSS,
uint8 ocnt, uint8* op, uint16 MSS, uint8 win_scale,
uint32 tstamp, /* uint8 TOS, */ uint32 quirks,
uint8 ECN) const
{
return SYN_OS_Fingerprinter ?
SYN_OS_Fingerprinter->FindMatch(retval, tot, DF_flag, TTL,
WSS, ocnt, op, MSS, win_scale, tstamp,
quirks, ECN) : 0;
}
bool NetSessions::CompareWithPreviousOSMatch(const IPAddr& addr, int id) const
{
return SYN_OS_Fingerprinter ?
SYN_OS_Fingerprinter->CacheMatch(addr, id) : 0;
}
Connection* NetSessions::FindConnection(Val* v) Connection* NetSessions::FindConnection(Val* v)
{ {
BroType* vt = v->Type(); BroType* vt = v->Type();

View file

@ -17,7 +17,6 @@
class EncapsulationStack; class EncapsulationStack;
class Connection; class Connection;
class OSFingerprint;
class ConnCompressor; class ConnCompressor;
struct ConnID; struct ConnID;
@ -77,14 +76,6 @@ public:
FragReassembler* NextFragment(double t, const IP_Hdr* ip, FragReassembler* NextFragment(double t, const IP_Hdr* ip,
const u_char* pkt); const u_char* pkt);
int Get_OS_From_SYN(struct os_type* retval,
uint16 tot, uint8 DF_flag, uint8 TTL, uint16 WSS,
uint8 ocnt, uint8* op, uint16 MSS, uint8 win_scale,
uint32 tstamp, /* uint8 TOS, */ uint32 quirks,
uint8 ECN) const;
bool CompareWithPreviousOSMatch(const IPAddr& addr, int id) const;
// Looks up the connection referred to by the given Val, // Looks up the connection referred to by the given Val,
// which should be a conn_id record. Returns nil if there's // which should be a conn_id record. Returns nil if there's
// no such connection or the Val is ill-formed. // no such connection or the Val is ill-formed.
@ -240,7 +231,6 @@ protected:
analyzer::stepping_stone::SteppingStoneManager* stp_manager; analyzer::stepping_stone::SteppingStoneManager* stp_manager;
Discarder* discarder; Discarder* discarder;
PacketFilter* packet_filter; PacketFilter* packet_filter;
OSFingerprint* SYN_OS_Fingerprinter;
int build_backdoor_analyzer; int build_backdoor_analyzer;
int dump_this_packet; // if true, current packet should be recorded int dump_this_packet; // if true, current packet should be recorded
uint64 num_packets_processed; uint64 num_packets_processed;

View file

@ -1,643 +0,0 @@
#include "Val.h"
#include "StateAccess.h"
#include "Event.h"
#include "NetVar.h"
#include "DebugLogger.h"
int StateAccess::replaying = 0;
StateAccess::StateAccess(Opcode arg_opcode,
const MutableVal* arg_target, const Val* arg_op1,
const Val* arg_op2, const Val* arg_op3)
{
opcode = arg_opcode;
target.val = const_cast<MutableVal*>(arg_target);
target_type = TYPE_MVAL;
op1.val = const_cast<Val*>(arg_op1);
op1_type = TYPE_VAL;
op2 = const_cast<Val*>(arg_op2);
op3 = const_cast<Val*>(arg_op3);
delete_op1_key = false;
RefThem();
}
StateAccess::StateAccess(Opcode arg_opcode,
const ID* arg_target, const Val* arg_op1,
const Val* arg_op2, const Val* arg_op3)
{
opcode = arg_opcode;
target.id = const_cast<ID*>(arg_target);
target_type = TYPE_ID;
op1.val = const_cast<Val*>(arg_op1);
op1_type = TYPE_VAL;
op2 = const_cast<Val*>(arg_op2);
op3 = const_cast<Val*>(arg_op3);
delete_op1_key = false;
RefThem();
}
StateAccess::StateAccess(Opcode arg_opcode,
const ID* arg_target, const HashKey* arg_op1,
const Val* arg_op2, const Val* arg_op3)
{
opcode = arg_opcode;
target.id = const_cast<ID*>(arg_target);
target_type = TYPE_ID;
op1.key = new HashKey(arg_op1->Key(), arg_op1->Size(), arg_op1->Hash());
op1_type = TYPE_KEY;
op2 = const_cast<Val*>(arg_op2);
op3 = const_cast<Val*>(arg_op3);
delete_op1_key = true;
RefThem();
}
StateAccess::StateAccess(Opcode arg_opcode,
const MutableVal* arg_target, const HashKey* arg_op1,
const Val* arg_op2, const Val* arg_op3)
{
opcode = arg_opcode;
target.val = const_cast<MutableVal*>(arg_target);
target_type = TYPE_MVAL;
op1.key = new HashKey(arg_op1->Key(), arg_op1->Size(), arg_op1->Hash());
op1_type = TYPE_KEY;
op2 = const_cast<Val*>(arg_op2);
op3 = const_cast<Val*>(arg_op3);
delete_op1_key = true;
RefThem();
}
StateAccess::StateAccess(const StateAccess& sa)
{
opcode = sa.opcode;
target_type = sa.target_type;
op1_type = sa.op1_type;
delete_op1_key = false;
if ( target_type == TYPE_ID )
target.id = sa.target.id;
else
target.val = sa.target.val;
if ( op1_type == TYPE_VAL )
op1.val = sa.op1.val;
else
{
// We need to copy the key as the pointer may not be
// valid anymore later.
op1.key = new HashKey(sa.op1.key->Key(), sa.op1.key->Size(),
sa.op1.key->Hash());
delete_op1_key = true;
}
op2 = sa.op2;
op3 = sa.op3;
RefThem();
}
StateAccess::~StateAccess()
{
if ( target_type == TYPE_ID )
Unref(target.id);
else
Unref(target.val);
if ( op1_type == TYPE_VAL )
Unref(op1.val);
else if ( delete_op1_key )
delete op1.key;
Unref(op2);
Unref(op3);
}
void StateAccess::RefThem()
{
if ( target_type == TYPE_ID )
Ref(target.id);
else
Ref(target.val);
if ( op1_type == TYPE_VAL && op1.val )
Ref(op1.val);
if ( op2 )
Ref(op2);
if ( op3 )
Ref(op3);
}
static Val* GetInteger(bro_int_t n, TypeTag t)
{
if ( t == TYPE_INT )
return val_mgr->GetInt(n);
return val_mgr->GetCount(n);
}
void StateAccess::Replay()
{
// For simplicity we assume that we only replay unserialized accesses.
assert(target_type == TYPE_ID && op1_type == TYPE_VAL);
if ( ! target.id )
return;
Val* v = target.id->ID_Val();
TypeTag t = v ? v->Type()->Tag() : TYPE_VOID;
if ( opcode != OP_ASSIGN && ! v )
{
// FIXME: I think this warrants an internal error,
// but let's check that first ...
// reporter->InternalError("replay id lacking a value");
reporter->Error("replay id lacks a value");
return;
}
++replaying;
switch ( opcode ) {
case OP_ASSIGN:
assert(op1.val);
// There mustn't be a direct assignment to a unique ID.
assert(target.id->Name()[0] != '#');
target.id->SetVal(op1.val->Ref());
break;
case OP_INCR:
if ( IsIntegral(t) )
{
assert(op1.val && op2);
// We derive the amount as difference between old
// and new value.
bro_int_t amount =
op1.val->CoerceToInt() - op2->CoerceToInt();
target.id->SetVal(GetInteger(v->CoerceToInt() + amount, t),
OP_INCR);
}
break;
case OP_ASSIGN_IDX:
assert(op1.val);
if ( t == TYPE_TABLE )
{
assert(op2);
v->AsTableVal()->Assign(op1.val, op2 ? op2->Ref() : 0);
}
else if ( t == TYPE_RECORD )
{
const char* field = op1.val->AsString()->CheckString();
int idx = v->Type()->AsRecordType()->FieldOffset(field);
if ( idx >= 0 )
v->AsRecordVal()->Assign(idx, op2 ? op2->Ref() : 0);
else
reporter->Error("access replay: unknown record field %s for assign", field);
}
else if ( t == TYPE_VECTOR )
{
assert(op2);
bro_uint_t index = op1.val->AsCount();
v->AsVectorVal()->Assign(index, op2 ? op2->Ref() : 0);
}
else
reporter->InternalError("unknown type in replaying index assign");
break;
case OP_INCR_IDX:
{
assert(op1.val && op2 && op3);
// We derive the amount as the difference between old
// and new value.
bro_int_t amount = op2->CoerceToInt() - op3->CoerceToInt();
if ( t == TYPE_TABLE )
{
t = v->Type()->AsTableType()->YieldType()->Tag();
Val* lookup_op1 = v->AsTableVal()->Lookup(op1.val);
int delta = lookup_op1->CoerceToInt() + amount;
Val* new_val = GetInteger(delta, t);
v->AsTableVal()->Assign(op1.val, new_val, OP_INCR );
}
else if ( t == TYPE_RECORD )
{
const char* field = op1.val->AsString()->CheckString();
int idx = v->Type()->AsRecordType()->FieldOffset(field);
if ( idx >= 0 )
{
t = v->Type()->AsRecordType()->FieldType(idx)->Tag();
Val* lookup_field =
v->AsRecordVal()->Lookup(idx);
bro_int_t delta =
lookup_field->CoerceToInt() + amount;
Val* new_val = GetInteger(delta, t);
v->AsRecordVal()->Assign(idx, new_val, OP_INCR);
}
else
reporter->Error("access replay: unknown record field %s for assign", field);
}
else if ( t == TYPE_VECTOR )
{
bro_uint_t index = op1.val->AsCount();
t = v->Type()->AsVectorType()->YieldType()->Tag();
Val* lookup_op1 = v->AsVectorVal()->Lookup(index);
int delta = lookup_op1->CoerceToInt() + amount;
Val* new_val = GetInteger(delta, t);
v->AsVectorVal()->Assign(index, new_val);
}
else
reporter->InternalError("unknown type in replaying index increment");
break;
}
case OP_ADD:
assert(op1.val);
if ( t == TYPE_TABLE )
{
v->AsTableVal()->Assign(op1.val, 0);
}
break;
case OP_DEL:
assert(op1.val);
if ( t == TYPE_TABLE )
{
Unref(v->AsTableVal()->Delete(op1.val));
}
break;
case OP_EXPIRE:
assert(op1.val);
if ( t == TYPE_TABLE )
{
// No old check for expire. It may have already
// been deleted by ourselves. Furthermore, we
// ignore the expire_func's return value.
TableVal* tv = v->AsTableVal();
if ( tv->Lookup(op1.val, false) )
{
// We want to propagate state updates which
// are performed in the expire_func.
StateAccess::ResumeReplay();
tv->CallExpireFunc(op1.val->Ref());
StateAccess::SuspendReplay();
Unref(tv->AsTableVal()->Delete(op1.val));
}
}
break;
case OP_PRINT:
assert(op1.val);
reporter->InternalError("access replay for print not implemented");
break;
case OP_READ_IDX:
if ( t == TYPE_TABLE )
{
assert(op1.val);
TableVal* tv = v->AsTableVal();
// Update the timestamp if we have a read_expire.
if ( tv->FindAttr(ATTR_EXPIRE_READ) )
{
tv->UpdateTimestamp(op1.val);
}
}
else
reporter->Error("read for non-table");
break;
default:
reporter->InternalError("access replay: unknown opcode for StateAccess");
break;
}
--replaying;
}
ID* StateAccess::Target() const
{
return target_type == TYPE_ID ? target.id : target.val->UniqueID();
}
void StateAccess::Describe(ODesc* d) const
{
const ID* id;
const char* id_str = "";
const char* unique_str = "";
d->SetShort();
if ( target_type == TYPE_ID )
{
id = target.id;
if ( ! id )
{
d->Add("(unknown id)");
return;
}
id_str = id->Name();
if ( id->ID_Val() && id->ID_Val()->IsMutableVal() &&
id->Name()[0] != '#' )
unique_str = fmt(" [id] (%s)", id->ID_Val()->AsMutableVal()->UniqueID()->Name());
}
else
{
id = target.val->UniqueID();
#ifdef DEBUG
if ( target.val->GetID() )
{
id_str = target.val->GetID()->Name();
unique_str = fmt(" [val] (%s)", id->Name());
}
else
#endif
id_str = id->Name();
}
const Val* op1 = op1_type == TYPE_VAL ?
this->op1.val :
id->ID_Val()->AsTableVal()->RecoverIndex(this->op1.key);
switch ( opcode ) {
case OP_ASSIGN:
assert(op1);
d->Add(id_str);
d->Add(" = ");
op1->Describe(d);
if ( op2 )
{
d->Add(" (");
op2->Describe(d);
d->Add(")");
}
d->Add(unique_str);
break;
case OP_INCR:
assert(op1 && op2);
d->Add(id_str);
d->Add(" += ");
d->Add(op1->CoerceToInt() - op2->CoerceToInt());
d->Add(unique_str);
break;
case OP_ASSIGN_IDX:
assert(op1);
d->Add(id_str);
d->Add("[");
op1->Describe(d);
d->Add("]");
d->Add(" = ");
if ( op2 )
op2->Describe(d);
else
d->Add("(null)");
if ( op3 )
{
d->Add(" (");
op3->Describe(d);
d->Add(")");
}
d->Add(unique_str);
break;
case OP_INCR_IDX:
assert(op1 && op2 && op3);
d->Add(id_str);
d->Add("[");
op1->Describe(d);
d->Add("]");
d->Add(" += ");
d->Add(op2->CoerceToInt() - op3->CoerceToInt());
d->Add(unique_str);
break;
case OP_ADD:
assert(op1);
d->Add("add ");
d->Add(id_str);
d->Add("[");
op1->Describe(d);
d->Add("]");
if ( op2 )
{
d->Add(" (");
op2->Describe(d);
d->Add(")");
}
d->Add(unique_str);
break;
case OP_DEL:
assert(op1);
d->Add("del ");
d->Add(id_str);
d->Add("[");
op1->Describe(d);
d->Add("]");
if ( op2 )
{
d->Add(" (");
op2->Describe(d);
d->Add(")");
}
d->Add(unique_str);
break;
case OP_EXPIRE:
assert(op1);
d->Add("expire ");
d->Add(id_str);
d->Add("[");
op1->Describe(d);
d->Add("]");
if ( op2 )
{
d->Add(" (");
op2->Describe(d);
d->Add(")");
}
d->Add(unique_str);
break;
case OP_PRINT:
assert(op1);
d->Add("print ");
d->Add(id_str);
op1->Describe(d);
d->Add(unique_str);
break;
case OP_READ_IDX:
assert(op1);
d->Add("read ");
d->Add(id_str);
d->Add("[");
op1->Describe(d);
d->Add("]");
break;
default:
reporter->InternalError("unknown opcode for StateAccess");
break;
}
if ( op1_type != TYPE_VAL )
Unref(const_cast<Val*>(op1));
}
void StateAccess::Log(StateAccess* access)
{
bool tracked = false;
if ( access->target_type == TYPE_ID )
{
if ( access->target.id->FindAttr(ATTR_TRACKED) )
tracked = true;
}
else
{
if ( access->target.val->GetProperties() & MutableVal::TRACKED )
tracked = true;
}
if ( tracked )
notifiers.AccessPerformed(*access);
#ifdef DEBUG
ODesc desc;
access->Describe(&desc);
DBG_LOG(DBG_STATE, "operation: %s%s",
desc.Description(), replaying > 0 ? " (replay)" : "");
#endif
delete access;
}
NotifierRegistry notifiers;
void NotifierRegistry::Register(ID* id, NotifierRegistry::Notifier* notifier)
{
DBG_LOG(DBG_NOTIFIERS, "registering ID %s for notifier %s",
id->Name(), notifier->Name());
Attr* attr = new Attr(ATTR_TRACKED);
if ( id->Attrs() )
{
if ( ! id->Attrs()->FindAttr(ATTR_TRACKED) )
id->Attrs()->AddAttr(attr);
}
else
{
attr_list* a = new attr_list{attr};
id->SetAttrs(new Attributes(a, id->Type(), false));
}
Unref(attr);
NotifierMap::iterator i = ids.find(id->Name());
if ( i != ids.end() )
i->second->insert(notifier);
else
{
NotifierSet* s = new NotifierSet;
s->insert(notifier);
ids.insert(NotifierMap::value_type(id->Name(), s));
}
Ref(id);
}
void NotifierRegistry::Register(Val* val, NotifierRegistry::Notifier* notifier)
{
if ( val->IsMutableVal() )
Register(val->AsMutableVal()->UniqueID(), notifier);
}
void NotifierRegistry::Unregister(ID* id, NotifierRegistry::Notifier* notifier)
{
DBG_LOG(DBG_NOTIFIERS, "unregistering ID %s for notifier %s",
id->Name(), notifier->Name());
NotifierMap::iterator i = ids.find(id->Name());
if ( i == ids.end() )
return;
Attr* attr = id->Attrs()->FindAttr(ATTR_TRACKED);
id->Attrs()->RemoveAttr(ATTR_TRACKED);
Unref(attr);
NotifierSet* s = i->second;
s->erase(notifier);
if ( s->size() == 0 )
{
delete s;
ids.erase(i);
}
Unref(id);
}
void NotifierRegistry::Unregister(Val* val, NotifierRegistry::Notifier* notifier)
{
if ( val->IsMutableVal() )
Unregister(val->AsMutableVal()->UniqueID(), notifier);
}
void NotifierRegistry::AccessPerformed(const StateAccess& sa)
{
ID* id = sa.Target();
NotifierMap::iterator i = ids.find(id->Name());
if ( i == ids.end() )
return;
DBG_LOG(DBG_NOTIFIERS, "modification to tracked ID %s", id->Name());
NotifierSet* s = i->second;
if ( id->IsInternalGlobal() )
for ( NotifierSet::iterator j = s->begin(); j != s->end(); j++ )
(*j)->Access(id->ID_Val(), sa);
else
for ( NotifierSet::iterator j = s->begin(); j != s->end(); j++ )
(*j)->Access(id, sa);
}
const char* NotifierRegistry::Notifier::Name() const
{
return fmt("%p", this);
}

View file

@ -1,138 +0,0 @@
// A class describing a state-modyfing access to a Value or an ID.
#ifndef STATEACESSS_H
#define STATEACESSS_H
#include <set>
#include <map>
#include <string>
class Val;
class ID;
class MutableVal;
class HashKey;
class ODesc;
class TableVal;
enum Opcode { // Op1 Op2 Op3 (Vals)
OP_NONE,
OP_ASSIGN, // new old
OP_ASSIGN_IDX, // idx new old
OP_ADD, // idx old
OP_INCR, // idx new old
OP_INCR_IDX, // idx new old
OP_DEL, // idx old
OP_PRINT, // args
OP_EXPIRE, // idx
OP_READ_IDX, // idx
};
class StateAccess {
public:
StateAccess(Opcode opcode, const ID* target, const Val* op1,
const Val* op2 = 0, const Val* op3 = 0);
StateAccess(Opcode opcode, const MutableVal* target, const Val* op1,
const Val* op2 = 0, const Val* op3 = 0);
// For tables, the idx operand may be given as an index HashKey.
// This is for efficiency. While we need to reconstruct the index
// if we are actually going to serialize the access, we can at
// least skip it if we don't.
StateAccess(Opcode opcode, const ID* target, const HashKey* op1,
const Val* op2 = 0, const Val* op3 = 0);
StateAccess(Opcode opcode, const MutableVal* target, const HashKey* op1,
const Val* op2 = 0, const Val* op3 = 0);
StateAccess(const StateAccess& sa);
virtual ~StateAccess();
// Replays this access in the our environment.
void Replay();
// Returns target ID which may be an internal one for unbound vals.
ID* Target() const;
void Describe(ODesc* d) const;
// Main entry point when StateAcesses are performed.
// For every state-changing operation, this has to be called.
static void Log(StateAccess* access);
// If we're going to make additional non-replaying accesses during a
// Replay(), we have to call these.
static void SuspendReplay() { --replaying; }
static void ResumeReplay() { ++replaying; }
private:
StateAccess() { target.id = 0; op1.val = op2 = op3 = 0; }
void RefThem();
Opcode opcode;
union {
ID* id;
MutableVal* val;
} target;
union {
Val* val;
const HashKey* key;
} op1;
Val* op2;
Val* op3;
enum Type { TYPE_ID, TYPE_VAL, TYPE_MVAL, TYPE_KEY };
Type target_type;
Type op1_type;
bool delete_op1_key;
static int replaying;
};
// We provide a notifier framework to inform interested parties of
// modifications to selected global IDs/Vals. To get notified about a change,
// derive a class from Notifier and register the interesting IDs/Vals with
// the NotifierRegistry.
//
// Note: For containers (e.g., tables), notifications are only issued if the
// container itself is modified, *not* for changes to the values contained
// therein.
class NotifierRegistry {
public:
class Notifier {
public:
virtual ~Notifier() { }
// Called when a change is being performed. Note that when these
// methods are called, it is undefined whether the change has
// already been done or is just going to be performed soon.
virtual void Access(ID* id, const StateAccess& sa) = 0;
virtual void Access(Val* val, const StateAccess& sa) = 0;
virtual const char* Name() const; // for debugging
};
NotifierRegistry() { }
~NotifierRegistry() { }
// Inform the given notifier if ID/Val changes.
void Register(ID* id, Notifier* notifier);
void Register(Val* val, Notifier* notifier);
// Cancel notification for this ID/Val.
void Unregister(ID* id, Notifier* notifier);
void Unregister(Val* val, Notifier* notifier);
private:
friend class StateAccess;
void AccessPerformed(const StateAccess& sa);
typedef std::set<Notifier*> NotifierSet;
typedef std::map<std::string, NotifierSet*> NotifierMap;
NotifierMap ids;
};
extern NotifierRegistry notifiers;
#endif

View file

@ -255,7 +255,7 @@ void ProfileLogger::Log()
while ( (id = globals->NextEntry(c)) ) while ( (id = globals->NextEntry(c)) )
// We don't show/count internal globals as they are always // We don't show/count internal globals as they are always
// contained in some other global user-visible container. // contained in some other global user-visible container.
if ( id->HasVal() && ! id->IsInternalGlobal() ) if ( id->HasVal() )
{ {
Val* v = id->ID_Val(); Val* v = id->ID_Val();

View file

@ -33,7 +33,7 @@ TraversalCode TriggerTraversalCallback::PreExpr(const Expr* expr)
trigger->Register(e->Id()); trigger->Register(e->Id());
Val* v = e->Id()->ID_Val(); Val* v = e->Id()->ID_Val();
if ( v && v->IsMutableVal() ) if ( v && v->Modifiable() )
trigger->Register(v); trigger->Register(v);
break; break;
}; };
@ -382,38 +382,35 @@ void Trigger::Timeout()
void Trigger::Register(ID* id) void Trigger::Register(ID* id)
{ {
assert(! disabled); assert(! disabled);
notifiers.Register(id, this); notifier::registry.Register(id, this);
Ref(id); Ref(id);
ids.insert(id); objs.push_back({id, id});
} }
void Trigger::Register(Val* val) void Trigger::Register(Val* val)
{ {
if ( ! val->Modifiable() )
return;
assert(! disabled); assert(! disabled);
notifiers.Register(val, this); notifier::registry.Register(val->Modifiable(), this);
Ref(val); Ref(val);
vals.insert(val); objs.emplace_back(val, val->Modifiable());
} }
void Trigger::UnregisterAll() void Trigger::UnregisterAll()
{ {
loop_over_list(ids, i) DBG_LOG(DBG_NOTIFIERS, "%s: unregistering all", Name());
for ( const auto& o : objs )
{ {
notifiers.Unregister(ids[i], this); notifier::registry.Unregister(o.second, this);
Unref(ids[i]); Unref(o.first);
} }
ids.clear(); objs.clear();
loop_over_list(vals, j)
{
notifiers.Unregister(vals[j], this);
Unref(vals[j]);
}
vals.clear();
} }
void Trigger::Attach(Trigger *trigger) void Trigger::Attach(Trigger *trigger)

View file

@ -4,7 +4,7 @@
#include <list> #include <list>
#include <map> #include <map>
#include "StateAccess.h" #include "Notifier.h"
#include "Traverse.h" #include "Traverse.h"
// Triggers are the heart of "when" statements: expressions that when // Triggers are the heart of "when" statements: expressions that when
@ -13,7 +13,7 @@
class TriggerTimer; class TriggerTimer;
class TriggerTraversalCallback; class TriggerTraversalCallback;
class Trigger : public NotifierRegistry::Notifier, public BroObj { class Trigger : public BroObj, public notifier::Receiver {
public: public:
// Don't access Trigger objects; they take care of themselves after // Don't access Trigger objects; they take care of themselves after
// instantiation. Note that if the condition is already true, the // instantiation. Note that if the condition is already true, the
@ -61,12 +61,10 @@ public:
{ d->Add("<trigger>"); } { d->Add("<trigger>"); }
// Overidden from Notifier. We queue the trigger and evaluate it // Overidden from Notifier. We queue the trigger and evaluate it
// later to avoid race conditions. // later to avoid race conditions.
void Access(ID* id, const StateAccess& sa) override void Modified(notifier::Modifiable* m) override
{ QueueTrigger(this); }
void Access(Val* val, const StateAccess& sa) override
{ QueueTrigger(this); } { QueueTrigger(this); }
const char* Name() const override; const char* Name() const;
static void QueueTrigger(Trigger* trigger); static void QueueTrigger(Trigger* trigger);
@ -104,8 +102,7 @@ private:
bool delayed; // true if a function call is currently being delayed bool delayed; // true if a function call is currently being delayed
bool disabled; bool disabled;
val_list vals; std::vector<std::pair<BroObj *, notifier::Modifiable*>> objs;
id_list ids;
typedef map<const CallExpr*, Val*> ValCache; typedef map<const CallExpr*, Val*> ValCache;
ValCache cache; ValCache cache;

View file

@ -985,6 +985,33 @@ void RecordType::DescribeFieldsReST(ODesc* d, bool func_args) const
d->PopIndentNoNL(); d->PopIndentNoNL();
} }
string RecordType::GetFieldDeprecationWarning(int field, bool has_check) const
{
const TypeDecl* decl = FieldDecl(field);
if ( decl)
{
string result;
if ( const Attr* deprecation = decl->FindAttr(ATTR_DEPRECATED) )
{
ConstExpr* expr = static_cast<ConstExpr*>(deprecation->AttrExpr());
if ( expr )
{
StringVal* text = expr->Value()->AsStringVal();
result = text->CheckString();
}
}
if ( result.empty() )
return fmt("deprecated (%s%s$%s)", GetName().c_str(), has_check ? "?" : "",
FieldName(field));
else
return fmt("deprecated (%s%s$%s): %s", GetName().c_str(), has_check ? "?" : "",
FieldName(field), result.c_str());
}
return "";
}
SubNetType::SubNetType() : BroType(TYPE_SUBNET) SubNetType::SubNetType() : BroType(TYPE_SUBNET)
{ {
} }
@ -1083,7 +1110,7 @@ EnumType::~EnumType()
// Note, we use reporter->Error() here (not Error()) to include the current script // Note, we use reporter->Error() here (not Error()) to include the current script
// location in the error message, rather than the one where the type was // location in the error message, rather than the one where the type was
// originally defined. // originally defined.
void EnumType::AddName(const string& module_name, const char* name, bool is_export, bool deprecated) void EnumType::AddName(const string& module_name, const char* name, bool is_export, Expr* deprecation)
{ {
/* implicit, auto-increment */ /* implicit, auto-increment */
if ( counter < 0) if ( counter < 0)
@ -1092,11 +1119,11 @@ void EnumType::AddName(const string& module_name, const char* name, bool is_expo
SetError(); SetError();
return; return;
} }
CheckAndAddName(module_name, name, counter, is_export, deprecated); CheckAndAddName(module_name, name, counter, is_export, deprecation);
counter++; counter++;
} }
void EnumType::AddName(const string& module_name, const char* name, bro_int_t val, bool is_export, bool deprecated) void EnumType::AddName(const string& module_name, const char* name, bro_int_t val, bool is_export, Expr* deprecation)
{ {
/* explicit value specified */ /* explicit value specified */
if ( counter > 0 ) if ( counter > 0 )
@ -1106,11 +1133,11 @@ void EnumType::AddName(const string& module_name, const char* name, bro_int_t va
return; return;
} }
counter = -1; counter = -1;
CheckAndAddName(module_name, name, val, is_export, deprecated); CheckAndAddName(module_name, name, val, is_export, deprecation);
} }
void EnumType::CheckAndAddName(const string& module_name, const char* name, void EnumType::CheckAndAddName(const string& module_name, const char* name,
bro_int_t val, bool is_export, bool deprecated) bro_int_t val, bool is_export, Expr* deprecation)
{ {
if ( Lookup(val) ) if ( Lookup(val) )
{ {
@ -1127,8 +1154,8 @@ void EnumType::CheckAndAddName(const string& module_name, const char* name,
id->SetType(this->Ref()); id->SetType(this->Ref());
id->SetEnumConst(); id->SetEnumConst();
if ( deprecated ) if ( deprecation )
id->MakeDeprecated(); id->MakeDeprecated(deprecation);
zeekygen_mgr->Identifier(id); zeekygen_mgr->Identifier(id);
} }

View file

@ -494,6 +494,14 @@ public:
void DescribeFields(ODesc* d) const; void DescribeFields(ODesc* d) const;
void DescribeFieldsReST(ODesc* d, bool func_args) const; void DescribeFieldsReST(ODesc* d, bool func_args) const;
bool IsFieldDeprecated(int field) const
{
const TypeDecl* decl = FieldDecl(field);
return decl && decl->FindAttr(ATTR_DEPRECATED) != 0;
}
string GetFieldDeprecationWarning(int field, bool has_check) const;
protected: protected:
RecordType() { types = 0; } RecordType() { types = 0; }
@ -551,12 +559,12 @@ public:
// The value of this name is next internal counter value, starting // The value of this name is next internal counter value, starting
// with zero. The internal counter is incremented. // with zero. The internal counter is incremented.
void AddName(const string& module_name, const char* name, bool is_export, bool deprecated); void AddName(const string& module_name, const char* name, bool is_export, Expr* deprecation = nullptr);
// The value of this name is set to val. Once a value has been // The value of this name is set to val. Once a value has been
// explicitly assigned using this method, no further names can be // explicitly assigned using this method, no further names can be
// added that aren't likewise explicitly initalized. // added that aren't likewise explicitly initalized.
void AddName(const string& module_name, const char* name, bro_int_t val, bool is_export, bool deprecated); void AddName(const string& module_name, const char* name, bro_int_t val, bool is_export, Expr* deprecation = nullptr);
// -1 indicates not found. // -1 indicates not found.
bro_int_t Lookup(const string& module_name, const char* name) const; bro_int_t Lookup(const string& module_name, const char* name) const;
@ -578,7 +586,7 @@ protected:
void CheckAndAddName(const string& module_name, void CheckAndAddName(const string& module_name,
const char* name, bro_int_t val, bool is_export, const char* name, bro_int_t val, bool is_export,
bool deprecated); Expr* deprecation = nullptr);
typedef std::map<std::string, bro_int_t> NameMap; typedef std::map<std::string, bro_int_t> NameMap;
NameMap names; NameMap names;
@ -696,10 +704,6 @@ bool is_atomic_type(const BroType* t);
// True if the given type tag corresponds to a function type. // True if the given type tag corresponds to a function type.
#define IsFunc(t) (t == TYPE_FUNC) #define IsFunc(t) (t == TYPE_FUNC)
// True if the given type tag corresponds to mutable type.
#define IsMutable(t) \
(t == TYPE_RECORD || t == TYPE_TABLE || t == TYPE_VECTOR)
// True if the given type type is a vector. // True if the given type type is a vector.
#define IsVector(t) (t == TYPE_VECTOR) #define IsVector(t) (t == TYPE_VECTOR)

View file

@ -380,128 +380,6 @@ bool Val::WouldOverflow(const BroType* from_type, const BroType* to_type, const
return false; return false;
} }
MutableVal::~MutableVal()
{
for ( list<ID*>::iterator i = aliases.begin(); i != aliases.end(); ++i )
{
if ( global_scope() )
global_scope()->Remove((*i)->Name());
(*i)->ClearVal(); // just to make sure.
Unref((*i));
}
if ( id )
{
if ( global_scope() )
global_scope()->Remove(id->Name());
id->ClearVal(); // just to make sure.
Unref(id);
}
}
bool MutableVal::AddProperties(Properties arg_props)
{
if ( (props | arg_props) == props )
// No change.
return false;
props |= arg_props;
if ( ! id )
Bind();
return true;
}
bool MutableVal::RemoveProperties(Properties arg_props)
{
if ( (props & ~arg_props) == props )
// No change.
return false;
props &= ~arg_props;
return true;
}
ID* MutableVal::Bind() const
{
static bool initialized = false;
assert(!id);
static unsigned int id_counter = 0;
static const int MAX_NAME_SIZE = 128;
static char name[MAX_NAME_SIZE];
static char* end_of_static_str = 0;
if ( ! initialized )
{
// Get local IP.
char host[MAXHOSTNAMELEN];
strcpy(host, "localhost");
gethostname(host, MAXHOSTNAMELEN);
host[MAXHOSTNAMELEN-1] = '\0';
#if 0
// We ignore errors.
struct hostent* ent = gethostbyname(host);
uint32 ip;
if ( ent && ent->h_addr_list[0] )
ip = *(uint32*) ent->h_addr_list[0];
else
ip = htonl(0x7f000001); // 127.0.0.1
safe_snprintf(name, MAX_NAME_SIZE, "#%s#%d#",
IPAddr(IPv4, &ip, IPAddr::Network)->AsString().c_str(),
getpid());
#else
safe_snprintf(name, MAX_NAME_SIZE, "#%s#%d#", host, getpid());
#endif
end_of_static_str = name + strlen(name);
initialized = true;
}
safe_snprintf(end_of_static_str, MAX_NAME_SIZE - (end_of_static_str - name),
"%u", ++id_counter);
name[MAX_NAME_SIZE-1] = '\0';
// DBG_LOG(DBG_STATE, "new unique ID %s", name);
id = new ID(name, SCOPE_GLOBAL, true);
id->SetType(const_cast<MutableVal*>(this)->Type()->Ref());
global_scope()->Insert(name, id);
id->SetVal(const_cast<MutableVal*>(this), OP_NONE, true);
return id;
}
void MutableVal::TransferUniqueID(MutableVal* mv)
{
const char* new_name = mv->UniqueID()->Name();
if ( ! id )
Bind();
DBG_LOG(DBG_STATE, "transfering ID (new %s, old/alias %s)", new_name, id->Name());
// Keep old name as alias.
aliases.push_back(id);
id = new ID(new_name, SCOPE_GLOBAL, true);
id->SetType(const_cast<MutableVal*>(this)->Type()->Ref());
global_scope()->Insert(new_name, id);
id->SetVal(const_cast<MutableVal*>(this), OP_NONE, true);
Unref(mv->id);
mv->id = 0;
}
IntervalVal::IntervalVal(double quantity, double units) : IntervalVal::IntervalVal(double quantity, double units) :
Val(quantity * units, TYPE_INTERVAL) Val(quantity * units, TYPE_INTERVAL)
{ {
@ -1056,7 +934,7 @@ static void table_entry_val_delete_func(void* val)
delete tv; delete tv;
} }
TableVal::TableVal(TableType* t, Attributes* a) : MutableVal(t) TableVal::TableVal(TableType* t, Attributes* a) : Val(t)
{ {
Init(t); Init(t);
SetAttrs(a); SetAttrs(a);
@ -1175,7 +1053,7 @@ void TableVal::CheckExpireAttr(attr_tag at)
} }
} }
int TableVal::Assign(Val* index, Val* new_val, Opcode op) int TableVal::Assign(Val* index, Val* new_val)
{ {
HashKey* k = ComputeHash(index); HashKey* k = ComputeHash(index);
if ( ! k ) if ( ! k )
@ -1185,10 +1063,10 @@ int TableVal::Assign(Val* index, Val* new_val, Opcode op)
return 0; return 0;
} }
return Assign(index, k, new_val, op); return Assign(index, k, new_val);
} }
int TableVal::Assign(Val* index, HashKey* k, Val* new_val, Opcode op) int TableVal::Assign(Val* index, HashKey* k, Val* new_val)
{ {
int is_set = table_type->IsSet(); int is_set = table_type->IsSet();
@ -1217,55 +1095,6 @@ int TableVal::Assign(Val* index, HashKey* k, Val* new_val, Opcode op)
subnets->Insert(index, new_entry_val); subnets->Insert(index, new_entry_val);
} }
if ( LoggingAccess() && op != OP_NONE )
{
Val* rec_index = 0;
if ( ! index )
index = rec_index = RecoverIndex(&k_copy);
if ( new_val )
{
// A table.
if ( new_val->IsMutableVal() )
new_val->AsMutableVal()->AddProperties(GetProperties());
bool unref_old_val = false;
Val* old_val = old_entry_val ?
old_entry_val->Value() : 0;
if ( op == OP_INCR && ! old_val )
// If it's an increment, somebody has already
// checked that the index is there. If it's
// not, that can only be due to using the
// default.
{
old_val = Default(index);
unref_old_val = true;
}
assert(op != OP_INCR || old_val);
StateAccess::Log(
new StateAccess(
op == OP_INCR ?
OP_INCR_IDX : OP_ASSIGN_IDX,
this, index, new_val, old_val));
if ( unref_old_val )
Unref(old_val);
}
else
{
// A set.
StateAccess::Log(
new StateAccess(OP_ADD, this,
index, 0, 0));
}
if ( rec_index )
Unref(rec_index);
}
// Keep old expiration time if necessary. // Keep old expiration time if necessary.
if ( old_entry_val && attrs && attrs->FindAttr(ATTR_EXPIRE_CREATE) ) if ( old_entry_val && attrs && attrs->FindAttr(ATTR_EXPIRE_CREATE) )
new_entry_val->SetExpireAccess(old_entry_val->ExpireAccessTime()); new_entry_val->SetExpireAccess(old_entry_val->ExpireAccessTime());
@ -1276,6 +1105,7 @@ int TableVal::Assign(Val* index, HashKey* k, Val* new_val, Opcode op)
delete old_entry_val; delete old_entry_val;
} }
Modified();
return 1; return 1;
} }
@ -1318,15 +1148,13 @@ int TableVal::AddTo(Val* val, int is_first_init, bool propagate_ops) const
if ( type->IsSet() ) if ( type->IsSet() )
{ {
if ( ! t->Assign(v->Value(), k, 0, if ( ! t->Assign(v->Value(), k, 0) )
propagate_ops ? OP_ASSIGN : OP_NONE) )
return 0; return 0;
} }
else else
{ {
v->Ref(); v->Ref();
if ( ! t->Assign(0, k, v->Value(), if ( ! t->Assign(0, k, v->Value()) )
propagate_ops ? OP_ASSIGN : OP_NONE) )
return 0; return 0;
} }
} }
@ -1595,11 +1423,7 @@ Val* TableVal::Lookup(Val* index, bool use_default_val)
if ( v ) if ( v )
{ {
if ( attrs && attrs->FindAttr(ATTR_EXPIRE_READ) ) if ( attrs && attrs->FindAttr(ATTR_EXPIRE_READ) )
{
v->SetExpireAccess(network_time); v->SetExpireAccess(network_time);
if ( LoggingAccess() && ExpirationEnabled() )
ReadOperation(index, v);
}
return v->Value() ? v->Value() : this; return v->Value() ? v->Value() : this;
} }
@ -1626,11 +1450,7 @@ Val* TableVal::Lookup(Val* index, bool use_default_val)
if ( v ) if ( v )
{ {
if ( attrs && attrs->FindAttr(ATTR_EXPIRE_READ) ) if ( attrs && attrs->FindAttr(ATTR_EXPIRE_READ) )
{
v->SetExpireAccess(network_time); v->SetExpireAccess(network_time);
if ( LoggingAccess() && ExpirationEnabled() )
ReadOperation(index, v);
}
return v->Value() ? v->Value() : this; return v->Value() ? v->Value() : this;
} }
@ -1684,11 +1504,7 @@ TableVal* TableVal::LookupSubnetValues(const SubNetVal* search)
if ( entry ) if ( entry )
{ {
if ( attrs && attrs->FindAttr(ATTR_EXPIRE_READ) ) if ( attrs && attrs->FindAttr(ATTR_EXPIRE_READ) )
{
entry->SetExpireAccess(network_time); entry->SetExpireAccess(network_time);
if ( LoggingAccess() && ExpirationEnabled() )
ReadOperation(s, entry);
}
} }
Unref(s); // assign does not consume index Unref(s); // assign does not consume index
@ -1718,8 +1534,6 @@ bool TableVal::UpdateTimestamp(Val* index)
return false; return false;
v->SetExpireAccess(network_time); v->SetExpireAccess(network_time);
if ( LoggingAccess() && attrs->FindAttr(ATTR_EXPIRE_READ) )
ReadOperation(index, v);
return true; return true;
} }
@ -1738,25 +1552,10 @@ Val* TableVal::Delete(const Val* index)
if ( subnets && ! subnets->Remove(index) ) if ( subnets && ! subnets->Remove(index) )
reporter->InternalWarning("index not in prefix table"); reporter->InternalWarning("index not in prefix table");
if ( LoggingAccess() )
{
if ( v )
{
// A set.
Val* has_old_val = val_mgr->GetInt(1);
StateAccess::Log(
new StateAccess(OP_DEL, this, index,
has_old_val));
Unref(has_old_val);
}
else
StateAccess::Log(
new StateAccess(OP_DEL, this, index, 0));
}
delete k; delete k;
delete v; delete v;
Modified();
return va; return va;
} }
@ -1775,9 +1574,7 @@ Val* TableVal::Delete(const HashKey* k)
delete v; delete v;
if ( LoggingAccess() ) Modified();
StateAccess::Log(new StateAccess(OP_DEL, this, k));
return va; return va;
} }
@ -1944,7 +1741,7 @@ int TableVal::ExpandCompoundAndInit(val_list* vl, int k, Val* new_val)
return 1; return 1;
} }
int TableVal::CheckAndAssign(Val* index, Val* new_val, Opcode op) int TableVal::CheckAndAssign(Val* index, Val* new_val)
{ {
Val* v = 0; Val* v = 0;
if ( subnets ) if ( subnets )
@ -1956,7 +1753,7 @@ int TableVal::CheckAndAssign(Val* index, Val* new_val, Opcode op)
if ( v ) if ( v )
index->Warn("multiple initializations for index"); index->Warn("multiple initializations for index");
return Assign(index, new_val, op); return Assign(index, new_val);
} }
void TableVal::InitTimer(double delay) void TableVal::InitTimer(double delay)
@ -1988,6 +1785,7 @@ void TableVal::DoExpire(double t)
HashKey* k = 0; HashKey* k = 0;
TableEntryVal* v = 0; TableEntryVal* v = 0;
TableEntryVal* v_saved = 0; TableEntryVal* v_saved = 0;
bool modified = false;
for ( int i = 0; i < table_incremental_step && for ( int i = 0; i < table_incremental_step &&
(v = tbl->NextEntry(k, expire_cookie)); ++i ) (v = tbl->NextEntry(k, expire_cookie)); ++i )
@ -2040,18 +1838,18 @@ void TableVal::DoExpire(double t)
Unref(index); Unref(index);
} }
if ( LoggingAccess() )
StateAccess::Log(
new StateAccess(OP_EXPIRE, this, k));
tbl->RemoveEntry(k); tbl->RemoveEntry(k);
Unref(v->Value()); Unref(v->Value());
delete v; delete v;
modified = true;
} }
delete k; delete k;
} }
if ( modified )
Modified();
if ( ! v ) if ( ! v )
{ {
expire_cookie = 0; expire_cookie = 0;
@ -2149,26 +1947,6 @@ double TableVal::CallExpireFunc(Val* idx)
return secs; return secs;
} }
void TableVal::ReadOperation(Val* index, TableEntryVal* v)
{
double timeout = GetExpireTime();
if ( timeout < 0 )
// Skip in case of unset/invalid expiration value. If it's an
// error, it has been reported already.
return;
// In theory we need to only propagate one update per &read_expire
// interval to prevent peers from expiring intervals. To account for
// practical issues such as latency, we send one update every half
// &read_expire.
if ( network_time - v->LastReadUpdate() > timeout / 2 )
{
StateAccess::Log(new StateAccess(OP_READ_IDX, this, index));
v->SetLastReadUpdate(network_time);
}
}
Val* TableVal::DoClone(CloneState* state) Val* TableVal::DoClone(CloneState* state)
{ {
auto tv = new TableVal(table_type); auto tv = new TableVal(table_type);
@ -2181,7 +1959,7 @@ Val* TableVal::DoClone(CloneState* state)
TableEntryVal* val; TableEntryVal* val;
while ( (val = tbl->NextEntry(key, cookie)) ) while ( (val = tbl->NextEntry(key, cookie)) )
{ {
TableEntryVal* nval = val->Clone(); TableEntryVal* nval = val->Clone(state);
tv->AsNonConstTable()->Insert(key, nval); tv->AsNonConstTable()->Insert(key, nval);
if ( subnets ) if ( subnets )
@ -2219,48 +1997,6 @@ Val* TableVal::DoClone(CloneState* state)
return tv; return tv;
} }
bool TableVal::AddProperties(Properties arg_props)
{
if ( ! MutableVal::AddProperties(arg_props) )
return false;
if ( Type()->IsSet() || ! RecursiveProps(arg_props) )
return true;
// For a large table, this could get expensive. So, let's hope
// that nobody creates such a table *before* making it persistent
// (for example by inserting it into another table).
TableEntryVal* v;
PDict(TableEntryVal)* tbl = val.table_val;
IterCookie* c = tbl->InitForIteration();
while ( (v = tbl->NextEntry(c)) )
if ( v->Value()->IsMutableVal() )
v->Value()->AsMutableVal()->AddProperties(RecursiveProps(arg_props));
return true;
}
bool TableVal::RemoveProperties(Properties arg_props)
{
if ( ! MutableVal::RemoveProperties(arg_props) )
return false;
if ( Type()->IsSet() || ! RecursiveProps(arg_props) )
return true;
// For a large table, this could get expensive. So, let's hope
// that nobody creates such a table *before* making it persistent
// (for example by inserting it into another table).
TableEntryVal* v;
PDict(TableEntryVal)* tbl = val.table_val;
IterCookie* c = tbl->InitForIteration();
while ( (v = tbl->NextEntry(c)) )
if ( v->Value()->IsMutableVal() )
v->Value()->AsMutableVal()->RemoveProperties(RecursiveProps(arg_props));
return true;
}
unsigned int TableVal::MemoryAllocation() const unsigned int TableVal::MemoryAllocation() const
{ {
unsigned int size = 0; unsigned int size = 0;
@ -2282,7 +2018,7 @@ unsigned int TableVal::MemoryAllocation() const
vector<RecordVal*> RecordVal::parse_time_records; vector<RecordVal*> RecordVal::parse_time_records;
RecordVal::RecordVal(RecordType* t, bool init_fields) : MutableVal(t) RecordVal::RecordVal(RecordType* t, bool init_fields) : Val(t)
{ {
origin = 0; origin = 0;
int n = t->NumFields(); int n = t->NumFields();
@ -2343,24 +2079,11 @@ RecordVal::~RecordVal()
delete_vals(AsNonConstRecord()); delete_vals(AsNonConstRecord());
} }
void RecordVal::Assign(int field, Val* new_val, Opcode op) void RecordVal::Assign(int field, Val* new_val)
{ {
Val* old_val = AsNonConstRecord()->replace(field, new_val); Val* old_val = AsNonConstRecord()->replace(field, new_val);
if ( LoggingAccess() && op != OP_NONE )
{
if ( new_val && new_val->IsMutableVal() )
new_val->AsMutableVal()->AddProperties(GetProperties());
StringVal* index = new StringVal(Type()->AsRecordType()->FieldName(field));
StateAccess::Log(
new StateAccess(
op == OP_INCR ? OP_INCR_IDX : OP_ASSIGN_IDX,
this, index, new_val, old_val));
Unref(index); // The logging may keep a cached copy.
}
Unref(old_val); Unref(old_val);
Modified();
} }
Val* RecordVal::Lookup(int field) const Val* RecordVal::Lookup(int field) const
@ -2570,41 +2293,6 @@ Val* RecordVal::DoClone(CloneState* state)
return rv; return rv;
} }
bool RecordVal::AddProperties(Properties arg_props)
{
if ( ! MutableVal::AddProperties(arg_props) )
return false;
if ( ! RecursiveProps(arg_props) )
return true;
loop_over_list(*val.val_list_val, i)
{
Val* v = (*val.val_list_val)[i];
if ( v && v->IsMutableVal() )
v->AsMutableVal()->AddProperties(RecursiveProps(arg_props));
}
return true;
}
bool RecordVal::RemoveProperties(Properties arg_props)
{
if ( ! MutableVal::RemoveProperties(arg_props) )
return false;
if ( ! RecursiveProps(arg_props) )
return true;
loop_over_list(*val.val_list_val, i)
{
Val* v = (*val.val_list_val)[i];
if ( v && v->IsMutableVal() )
v->AsMutableVal()->RemoveProperties(RecursiveProps(arg_props));
}
return true;
}
unsigned int RecordVal::MemoryAllocation() const unsigned int RecordVal::MemoryAllocation() const
{ {
unsigned int size = 0; unsigned int size = 0;
@ -2637,7 +2325,7 @@ Val* EnumVal::DoClone(CloneState* state)
return Ref(); return Ref();
} }
VectorVal::VectorVal(VectorType* t) : MutableVal(t) VectorVal::VectorVal(VectorType* t) : Val(t)
{ {
vector_type = t->Ref()->AsVectorType(); vector_type = t->Ref()->AsVectorType();
val.vector_val = new vector<Val*>(); val.vector_val = new vector<Val*>();
@ -2653,7 +2341,7 @@ VectorVal::~VectorVal()
delete val.vector_val; delete val.vector_val;
} }
bool VectorVal::Assign(unsigned int index, Val* element, Opcode op) bool VectorVal::Assign(unsigned int index, Val* element)
{ {
if ( element && if ( element &&
! same_type(element->Type(), vector_type->YieldType(), 0) ) ! same_type(element->Type(), vector_type->YieldType(), 0) )
@ -2669,19 +2357,6 @@ bool VectorVal::Assign(unsigned int index, Val* element, Opcode op)
else else
val.vector_val->resize(index + 1); val.vector_val->resize(index + 1);
if ( LoggingAccess() && op != OP_NONE )
{
if ( element->IsMutableVal() )
element->AsMutableVal()->AddProperties(GetProperties());
Val* ival = val_mgr->GetCount(index);
StateAccess::Log(new StateAccess(op == OP_INCR ?
OP_INCR_IDX : OP_ASSIGN_IDX,
this, ival, element, val_at_index));
Unref(ival);
}
Unref(val_at_index); Unref(val_at_index);
// Note: we do *not* Ref() the element, if any, at this point. // Note: we do *not* Ref() the element, if any, at this point.
@ -2689,6 +2364,7 @@ bool VectorVal::Assign(unsigned int index, Val* element, Opcode op)
// to do it similarly. // to do it similarly.
(*val.vector_val)[index] = element; (*val.vector_val)[index] = element;
Modified();
return true; return true;
} }
@ -2725,6 +2401,7 @@ bool VectorVal::Insert(unsigned int index, Val* element)
// to do it similarly. // to do it similarly.
val.vector_val->insert(it, element); val.vector_val->insert(it, element);
Modified();
return true; return true;
} }
@ -2738,6 +2415,7 @@ bool VectorVal::Remove(unsigned int index)
val.vector_val->erase(it); val.vector_val->erase(it);
Unref(val_at_index); Unref(val_at_index);
Modified();
return true; return true;
} }
@ -2790,37 +2468,6 @@ unsigned int VectorVal::ResizeAtLeast(unsigned int new_num_elements)
return Resize(new_num_elements); return Resize(new_num_elements);
} }
bool VectorVal::AddProperties(Properties arg_props)
{
if ( ! MutableVal::AddProperties(arg_props) )
return false;
if ( ! RecursiveProps(arg_props) )
return true;
for ( unsigned int i = 0; i < val.vector_val->size(); ++i )
if ( (*val.vector_val)[i]->IsMutableVal() )
(*val.vector_val)[i]->AsMutableVal()->AddProperties(RecursiveProps(arg_props));
return true;
}
bool VectorVal::RemoveProperties(Properties arg_props)
{
if ( ! MutableVal::RemoveProperties(arg_props) )
return false;
if ( ! RecursiveProps(arg_props) )
return true;
for ( unsigned int i = 0; i < val.vector_val->size(); ++i )
if ( (*val.vector_val)[i]->IsMutableVal() )
(*val.vector_val)[i]->AsMutableVal()->RemoveProperties(RecursiveProps(arg_props));
return true;
}
Val* VectorVal::DoClone(CloneState* state) Val* VectorVal::DoClone(CloneState* state)
{ {
auto vv = new VectorVal(vector_type); auto vv = new VectorVal(vector_type);

153
src/Val.h
View file

@ -3,15 +3,11 @@
#ifndef val_h #ifndef val_h
#define val_h #define val_h
// BRO values.
#include <vector> #include <vector>
#include <list> #include <list>
#include <array> #include <array>
#include <unordered_map> #include <unordered_map>
#include <broker/broker.hh>
#include "net_util.h" #include "net_util.h"
#include "Type.h" #include "Type.h"
#include "Dict.h" #include "Dict.h"
@ -21,7 +17,7 @@
#include "Timer.h" #include "Timer.h"
#include "ID.h" #include "ID.h"
#include "Scope.h" #include "Scope.h"
#include "StateAccess.h" #include "Notifier.h"
#include "IPAddr.h" #include "IPAddr.h"
#include "DebugLogger.h" #include "DebugLogger.h"
@ -52,7 +48,6 @@ class RecordVal;
class ListVal; class ListVal;
class StringVal; class StringVal;
class EnumVal; class EnumVal;
class MutableVal;
class OpaqueVal; class OpaqueVal;
class StateAccess; class StateAccess;
@ -328,28 +323,13 @@ public:
CONST_CONVERTER(TYPE_VECTOR, VectorVal*, AsVectorVal) CONST_CONVERTER(TYPE_VECTOR, VectorVal*, AsVectorVal)
CONST_CONVERTER(TYPE_OPAQUE, OpaqueVal*, AsOpaqueVal) CONST_CONVERTER(TYPE_OPAQUE, OpaqueVal*, AsOpaqueVal)
bool IsMutableVal() const
{
return IsMutable(type->Tag());
}
const MutableVal* AsMutableVal() const
{
if ( ! IsMutableVal() )
BadTag("Val::AsMutableVal", type_name(type->Tag()));
return (MutableVal*) this;
}
MutableVal* AsMutableVal()
{
if ( ! IsMutableVal() )
BadTag("Val::AsMutableVal", type_name(type->Tag()));
return (MutableVal*) this;
}
void Describe(ODesc* d) const override; void Describe(ODesc* d) const override;
virtual void DescribeReST(ODesc* d) const; virtual void DescribeReST(ODesc* d) const;
// To be overridden by mutable derived class to enable change
// notification.
virtual notifier::Modifiable* Modifiable() { return 0; }
#ifdef DEBUG #ifdef DEBUG
// For debugging, we keep a reference to the global ID to which a // For debugging, we keep a reference to the global ID to which a
// value has been bound *last*. // value has been bound *last*.
@ -374,6 +354,7 @@ protected:
friend class RecordVal; friend class RecordVal;
friend class VectorVal; friend class VectorVal;
friend class ValManager; friend class ValManager;
friend class TableEntryVal;
virtual void ValDescribe(ODesc* d) const; virtual void ValDescribe(ODesc* d) const;
virtual void ValDescribeReST(ODesc* d) const; virtual void ValDescribeReST(ODesc* d) const;
@ -517,69 +498,6 @@ private:
extern ValManager* val_mgr; extern ValManager* val_mgr;
class MutableVal : public Val {
public:
// Each MutableVal gets a globally unique ID that can be used to
// reference it no matter if it's directly bound to any user-visible
// ID. This ID is inserted into the global namespace.
ID* UniqueID() const { return id ? id : Bind(); }
// Returns true if we've already generated a unique ID.
bool HasUniqueID() const { return id; }
// Transfers the unique ID of the given value to this value. We keep our
// old ID as an alias.
void TransferUniqueID(MutableVal* mv);
// MutableVals can have properties (let's refrain from calling them
// attributes!). Most properties are recursive. If a derived object
// can contain MutableVals itself, the object has to override
// {Add,Remove}Properties(). RecursiveProp(state) masks out all non-
// recursive properties. If this is non-null, an overriden method must
// call itself with RecursiveProp(state) as argument for all contained
// values. (In any case, don't forget to call the parent's method.)
typedef char Properties;
// Tracked by NotifierRegistry, not recursive.
static const int TRACKED = 0x04;
int RecursiveProps(int prop) const { return prop & ~TRACKED; }
Properties GetProperties() const { return props; }
virtual bool AddProperties(Properties state);
virtual bool RemoveProperties(Properties state);
// Whether StateAccess:LogAccess needs to be called.
bool LoggingAccess() const
{
#ifndef DEBUG
return props & TRACKED;
#else
return debug_logger.IsVerbose() ||
(props & TRACKED);
#endif
}
protected:
explicit MutableVal(BroType* t) : Val(t)
{ props = 0; id = 0; }
MutableVal() { props = 0; id = 0; }
~MutableVal() override;
friend class ID;
friend class Val;
void SetID(ID* arg_id) { Unref(id); id = arg_id; }
private:
ID* Bind() const;
mutable ID* id;
list<ID*> aliases;
Properties props;
uint64 last_modified;
};
#define Microseconds 1e-6 #define Microseconds 1e-6
#define Milliseconds 1e-3 #define Milliseconds 1e-3
#define Seconds 1.0 #define Seconds 1.0
@ -800,16 +718,15 @@ public:
{ {
val = v; val = v;
last_access_time = network_time; last_access_time = network_time;
expire_access_time = last_read_update = expire_access_time =
int(network_time - bro_start_network_time); int(network_time - bro_start_network_time);
} }
TableEntryVal* Clone() TableEntryVal* Clone(Val::CloneState* state)
{ {
auto rval = new TableEntryVal(val ? val->Clone() : nullptr); auto rval = new TableEntryVal(val ? val->Clone(state) : nullptr);
rval->last_access_time = last_access_time; rval->last_access_time = last_access_time;
rval->expire_access_time = expire_access_time; rval->expire_access_time = expire_access_time;
rval->last_read_update = last_read_update;
return rval; return rval;
} }
@ -825,24 +742,16 @@ public:
void SetExpireAccess(double time) void SetExpireAccess(double time)
{ expire_access_time = int(time - bro_start_network_time); } { expire_access_time = int(time - bro_start_network_time); }
// Returns/sets time of when we propagated the last OP_READ_IDX
// for this item.
double LastReadUpdate() const
{ return bro_start_network_time + last_read_update; }
void SetLastReadUpdate(double time)
{ last_read_update = int(time - bro_start_network_time); }
protected: protected:
friend class TableVal; friend class TableVal;
Val* val; Val* val;
double last_access_time; double last_access_time;
// The next two entries store seconds since Bro's start. We use // The next entry stores seconds since Bro's start. We use ints here
// ints here to save a few bytes, as we do not need a high resolution // to save a few bytes, as we do not need a high resolution for these
// for these anyway. // anyway.
int expire_access_time; int expire_access_time;
int last_read_update;
}; };
class TableValTimer : public Timer { class TableValTimer : public Timer {
@ -859,7 +768,7 @@ protected:
}; };
class CompositeHash; class CompositeHash;
class TableVal : public MutableVal { class TableVal : public Val, public notifier::Modifiable {
public: public:
explicit TableVal(TableType* t, Attributes* attrs = 0); explicit TableVal(TableType* t, Attributes* attrs = 0);
~TableVal() override; ~TableVal() override;
@ -869,8 +778,8 @@ public:
// version takes a HashKey and Unref()'s it when done. If we're a // version takes a HashKey and Unref()'s it when done. If we're a
// set, new_val has to be nil. If we aren't a set, index may be nil // set, new_val has to be nil. If we aren't a set, index may be nil
// in the second version. // in the second version.
int Assign(Val* index, Val* new_val, Opcode op = OP_ASSIGN); int Assign(Val* index, Val* new_val);
int Assign(Val* index, HashKey* k, Val* new_val, Opcode op = OP_ASSIGN); int Assign(Val* index, HashKey* k, Val* new_val);
Val* SizeVal() const override { return val_mgr->GetCount(Size()); } Val* SizeVal() const override { return val_mgr->GetCount(Size()); }
@ -972,19 +881,17 @@ public:
HashKey* ComputeHash(const Val* index) const HashKey* ComputeHash(const Val* index) const
{ return table_hash->ComputeHash(index, 1); } { return table_hash->ComputeHash(index, 1); }
notifier::Modifiable* Modifiable() override { return this; }
protected: protected:
friend class Val; friend class Val;
friend class StateAccess;
TableVal() {} TableVal() {}
void Init(TableType* t); void Init(TableType* t);
void CheckExpireAttr(attr_tag at); void CheckExpireAttr(attr_tag at);
int ExpandCompoundAndInit(val_list* vl, int k, Val* new_val); int ExpandCompoundAndInit(val_list* vl, int k, Val* new_val);
int CheckAndAssign(Val* index, Val* new_val, Opcode op = OP_ASSIGN); int CheckAndAssign(Val* index, Val* new_val);
bool AddProperties(Properties arg_state) override;
bool RemoveProperties(Properties arg_state) override;
// Calculates default value for index. Returns 0 if none. // Calculates default value for index. Returns 0 if none.
Val* Default(Val* index); Val* Default(Val* index);
@ -1001,9 +908,6 @@ protected:
// takes ownership of the reference. // takes ownership of the reference.
double CallExpireFunc(Val *idx); double CallExpireFunc(Val *idx);
// Propagates a read operation if necessary.
void ReadOperation(Val* index, TableEntryVal *v);
Val* DoClone(CloneState* state) override; Val* DoClone(CloneState* state) override;
TableType* table_type; TableType* table_type;
@ -1017,7 +921,7 @@ protected:
Val* def_val; Val* def_val;
}; };
class RecordVal : public MutableVal { class RecordVal : public Val, public notifier::Modifiable {
public: public:
explicit RecordVal(RecordType* t, bool init_fields = true); explicit RecordVal(RecordType* t, bool init_fields = true);
~RecordVal() override; ~RecordVal() override;
@ -1025,7 +929,7 @@ public:
Val* SizeVal() const override Val* SizeVal() const override
{ return val_mgr->GetCount(Type()->AsRecordType()->NumFields()); } { return val_mgr->GetCount(Type()->AsRecordType()->NumFields()); }
void Assign(int field, Val* new_val, Opcode op = OP_ASSIGN); void Assign(int field, Val* new_val);
Val* Lookup(int field) const; // Does not Ref() value. Val* Lookup(int field) const; // Does not Ref() value.
Val* LookupWithDefault(int field) const; // Does Ref() value. Val* LookupWithDefault(int field) const; // Does Ref() value.
@ -1064,6 +968,8 @@ public:
unsigned int MemoryAllocation() const override; unsigned int MemoryAllocation() const override;
void DescribeReST(ODesc* d) const override; void DescribeReST(ODesc* d) const override;
notifier::Modifiable* Modifiable() override { return this; }
// Extend the underlying arrays of record instances created during // Extend the underlying arrays of record instances created during
// parsing to match the number of fields in the record type (they may // parsing to match the number of fields in the record type (they may
// mismatch as a result of parse-time record type redefinitions. // mismatch as a result of parse-time record type redefinitions.
@ -1073,9 +979,6 @@ protected:
friend class Val; friend class Val;
RecordVal() {} RecordVal() {}
bool AddProperties(Properties arg_state) override;
bool RemoveProperties(Properties arg_state) override;
Val* DoClone(CloneState* state) override; Val* DoClone(CloneState* state) override;
RecordType* record_type; RecordType* record_type;
@ -1111,7 +1014,7 @@ protected:
}; };
class VectorVal : public MutableVal { class VectorVal : public Val, public notifier::Modifiable {
public: public:
explicit VectorVal(VectorType* t); explicit VectorVal(VectorType* t);
~VectorVal() override; ~VectorVal() override;
@ -1125,11 +1028,11 @@ public:
// Note: does NOT Ref() the element! Remember to do so unless // Note: does NOT Ref() the element! Remember to do so unless
// the element was just created and thus has refcount 1. // the element was just created and thus has refcount 1.
// //
bool Assign(unsigned int index, Val* element, Opcode op = OP_ASSIGN); bool Assign(unsigned int index, Val* element);
bool Assign(Val* index, Val* element, Opcode op = OP_ASSIGN) bool Assign(Val* index, Val* element)
{ {
return Assign(index->AsListVal()->Index(0)->CoerceToUnsigned(), return Assign(index->AsListVal()->Index(0)->CoerceToUnsigned(),
element, op); element);
} }
// Assigns the value to how_many locations starting at index. // Assigns the value to how_many locations starting at index.
@ -1159,6 +1062,8 @@ public:
// Won't shrink size. // Won't shrink size.
unsigned int ResizeAtLeast(unsigned int new_num_elements); unsigned int ResizeAtLeast(unsigned int new_num_elements);
notifier::Modifiable* Modifiable() override { return this; }
// Insert an element at a specific position into the underlying vector. // Insert an element at a specific position into the underlying vector.
bool Insert(unsigned int index, Val* element); bool Insert(unsigned int index, Val* element);
@ -1169,8 +1074,6 @@ protected:
friend class Val; friend class Val;
VectorVal() { } VectorVal() { }
bool AddProperties(Properties arg_state) override;
bool RemoveProperties(Properties arg_state) override;
void ValDescribe(ODesc* d) const override; void ValDescribe(ODesc* d) const override;
Val* DoClone(CloneState* state) override; Val* DoClone(CloneState* state) override;

View file

@ -312,16 +312,21 @@ static void transfer_arg_defaults(RecordType* args, RecordType* recv)
} }
} }
static bool has_attr(const attr_list* al, attr_tag tag) static Attr* find_attr(const attr_list* al, attr_tag tag)
{ {
if ( ! al ) if ( ! al )
return false; return nullptr;
for ( int i = 0; i < al->length(); ++i ) for ( int i = 0; i < al->length(); ++i )
if ( (*al)[i]->Tag() == tag ) if ( (*al)[i]->Tag() == tag )
return true; return (*al)[i];
return false; return nullptr;
}
static bool has_attr(const attr_list* al, attr_tag tag)
{
return find_attr(al, tag) != nullptr;
} }
void begin_func(ID* id, const char* module_name, function_flavor flavor, void begin_func(ID* id, const char* module_name, function_flavor flavor,
@ -398,8 +403,8 @@ void begin_func(ID* id, const char* module_name, function_flavor flavor,
arg_id->SetType(arg_i->type->Ref()); arg_id->SetType(arg_i->type->Ref());
} }
if ( has_attr(attrs, ATTR_DEPRECATED) ) if ( Attr* depr_attr = find_attr(attrs, ATTR_DEPRECATED) )
id->MakeDeprecated(); id->MakeDeprecated(depr_attr->AttrExpr());
} }
class OuterIDBindingFinder : public TraversalCallback { class OuterIDBindingFinder : public TraversalCallback {

View file

@ -49,6 +49,13 @@ event rdp_client_security_data%(c: connection, data: RDP::ClientSecurityData%);
## channels: The channels that were requested ## channels: The channels that were requested
event rdp_client_network_data%(c: connection, channels: RDP::ClientChannelList%); event rdp_client_network_data%(c: connection, channels: RDP::ClientChannelList%);
## Generated for client cluster data packets.
##
## c: The connection record for the underlying transport-layer session/flow.
##
## data: The data contained in the client security data structure.
event rdp_client_cluster_data%(c: connection, data: RDP::ClientClusterData%);
## Generated for MCS server responses. ## Generated for MCS server responses.
## ##
## c: The connection record for the underlying transport-layer session/flow. ## c: The connection record for the underlying transport-layer session/flow.

View file

@ -130,18 +130,19 @@ refine flow RDP_Flow += {
RecordVal* channel_def = new RecordVal(BifType::Record::RDP::ClientChannelDef); RecordVal* channel_def = new RecordVal(BifType::Record::RDP::ClientChannelDef);
channel_def->Assign(0, bytestring_to_val(${cnetwork.channel_def_array[i].name})); channel_def->Assign(0, bytestring_to_val(${cnetwork.channel_def_array[i].name}));
channel_def->Assign(1, val_mgr->GetCount(${cnetwork.channel_def_array[i].options}));
channel_def->Assign(1, val_mgr->GetBool(${cnetwork.channel_def_array[i].CHANNEL_OPTION_INITIALIZED})); channel_def->Assign(2, val_mgr->GetBool(${cnetwork.channel_def_array[i].CHANNEL_OPTION_INITIALIZED}));
channel_def->Assign(2, val_mgr->GetBool(${cnetwork.channel_def_array[i].CHANNEL_OPTION_ENCRYPT_RDP})); channel_def->Assign(3, val_mgr->GetBool(${cnetwork.channel_def_array[i].CHANNEL_OPTION_ENCRYPT_RDP}));
channel_def->Assign(3, val_mgr->GetBool(${cnetwork.channel_def_array[i].CHANNEL_OPTION_ENCRYPT_SC})); channel_def->Assign(4, val_mgr->GetBool(${cnetwork.channel_def_array[i].CHANNEL_OPTION_ENCRYPT_SC}));
channel_def->Assign(4, val_mgr->GetBool(${cnetwork.channel_def_array[i].CHANNEL_OPTION_ENCRYPT_CS})); channel_def->Assign(5, val_mgr->GetBool(${cnetwork.channel_def_array[i].CHANNEL_OPTION_ENCRYPT_CS}));
channel_def->Assign(5, val_mgr->GetBool(${cnetwork.channel_def_array[i].CHANNEL_OPTION_PRI_HIGH})); channel_def->Assign(6, val_mgr->GetBool(${cnetwork.channel_def_array[i].CHANNEL_OPTION_PRI_HIGH}));
channel_def->Assign(6, val_mgr->GetBool(${cnetwork.channel_def_array[i].CHANNEL_OPTION_PRI_MED})); channel_def->Assign(7, val_mgr->GetBool(${cnetwork.channel_def_array[i].CHANNEL_OPTION_PRI_MED}));
channel_def->Assign(7, val_mgr->GetBool(${cnetwork.channel_def_array[i].CHANNEL_OPTION_PRI_LOW})); channel_def->Assign(8, val_mgr->GetBool(${cnetwork.channel_def_array[i].CHANNEL_OPTION_PRI_LOW}));
channel_def->Assign(8, val_mgr->GetBool(${cnetwork.channel_def_array[i].CHANNEL_OPTION_COMPRESS_RDP})); channel_def->Assign(9, val_mgr->GetBool(${cnetwork.channel_def_array[i].CHANNEL_OPTION_COMPRESS_RDP}));
channel_def->Assign(9, val_mgr->GetBool(${cnetwork.channel_def_array[i].CHANNEL_OPTION_COMPRESS})); channel_def->Assign(10, val_mgr->GetBool(${cnetwork.channel_def_array[i].CHANNEL_OPTION_COMPRESS}));
channel_def->Assign(10, val_mgr->GetBool(${cnetwork.channel_def_array[i].CHANNEL_OPTION_SHOW_PROTOCOL})); channel_def->Assign(11, val_mgr->GetBool(${cnetwork.channel_def_array[i].CHANNEL_OPTION_SHOW_PROTOCOL}));
channel_def->Assign(11, val_mgr->GetBool(${cnetwork.channel_def_array[i].REMOTE_CONTROL_PERSISTENT})); channel_def->Assign(12, val_mgr->GetBool(${cnetwork.channel_def_array[i].REMOTE_CONTROL_PERSISTENT}));
channels->Assign(channels->Size(), channel_def); channels->Assign(channels->Size(), channel_def);
} }
@ -154,6 +155,25 @@ refine flow RDP_Flow += {
return true; return true;
%} %}
function proc_rdp_client_cluster_data(ccluster: Client_Cluster_Data): bool
%{
if ( ! rdp_client_cluster_data )
return false;
RecordVal* ccld = new RecordVal(BifType::Record::RDP::ClientClusterData);
ccld->Assign(0, val_mgr->GetCount(${ccluster.flags}));
ccld->Assign(1, val_mgr->GetCount(${ccluster.redir_session_id}));
ccld->Assign(2, val_mgr->GetBool(${ccluster.REDIRECTION_SUPPORTED}));
ccld->Assign(3, val_mgr->GetCount(${ccluster.SERVER_SESSION_REDIRECTION_VERSION_MASK}));
ccld->Assign(4, val_mgr->GetBool(${ccluster.REDIRECTED_SESSIONID_FIELD_VALID}));
ccld->Assign(5, val_mgr->GetBool(${ccluster.REDIRECTED_SMARTCARD}));
BifEvent::generate_rdp_client_cluster_data(connection()->bro_analyzer(),
connection()->bro_analyzer()->Conn(),
ccld);
return true;
%}
function proc_rdp_server_security(ssd: Server_Security_Data): bool function proc_rdp_server_security(ssd: Server_Security_Data): bool
%{ %{
connection()->bro_analyzer()->ProtocolConfirmation(); connection()->bro_analyzer()->ProtocolConfirmation();
@ -226,6 +246,10 @@ refine typeattr Client_Network_Data += &let {
proc: bool = $context.flow.proc_rdp_client_network_data(this); proc: bool = $context.flow.proc_rdp_client_network_data(this);
}; };
refine typeattr Client_Cluster_Data += &let {
proc: bool = $context.flow.proc_rdp_client_cluster_data(this);
};
refine typeattr GCC_Server_Create_Response += &let { refine typeattr GCC_Server_Create_Response += &let {
proc: bool = $context.flow.proc_rdp_gcc_server_create_response(this); proc: bool = $context.flow.proc_rdp_gcc_server_create_response(this);
}; };

View file

@ -54,7 +54,7 @@ type Data_Block = record {
0xc001 -> client_core: Client_Core_Data; 0xc001 -> client_core: Client_Core_Data;
0xc002 -> client_security: Client_Security_Data; 0xc002 -> client_security: Client_Security_Data;
0xc003 -> client_network: Client_Network_Data; 0xc003 -> client_network: Client_Network_Data;
#0xc004 -> client_cluster: Client_Cluster_Data; 0xc004 -> client_cluster: Client_Cluster_Data;
#0xc005 -> client_monitor: Client_Monitor_Data; #0xc005 -> client_monitor: Client_Monitor_Data;
#0xc006 -> client_msgchannel: Client_MsgChannel_Data; #0xc006 -> client_msgchannel: Client_MsgChannel_Data;
#0xc008 -> client_monitor_ex: Client_MonitorExtended_Data; #0xc008 -> client_monitor_ex: Client_MonitorExtended_Data;
@ -230,6 +230,16 @@ type Client_Network_Data = record {
channel_def_array: Client_Channel_Def[channel_count]; channel_def_array: Client_Channel_Def[channel_count];
} &byteorder=littleendian; } &byteorder=littleendian;
type Client_Cluster_Data = record {
flags: uint32;
redir_session_id: uint32;
} &let {
REDIRECTION_SUPPORTED: bool = redir_session_id & 0x00000001;
SERVER_SESSION_REDIRECTION_VERSION_MASK: uint8 = (redir_session_id & 0x0000003C);
REDIRECTED_SESSIONID_FIELD_VALID: bool = (redir_session_id & 0x00000002);
REDIRECTED_SMARTCARD: bool = redir_session_id & 0x00000040;
} &byteorder=littleendian;
type Client_Channel_Def = record { type Client_Channel_Def = record {
name: bytestring &length=8; name: bytestring &length=8;
options: uint32; options: uint32;

View file

@ -5,6 +5,7 @@ type EarlyCapabilityFlags: record;
type ClientCoreData: record; type ClientCoreData: record;
type ClientSecurityData: record; type ClientSecurityData: record;
type ClientClusterData: record;
type ClientChannelList: vector; type ClientChannelList: vector;
type ClientChannelDef: record; type ClientChannelDef: record;

View file

@ -4,7 +4,6 @@
#include "NetVar.h" #include "NetVar.h"
#include "File.h" #include "File.h"
#include "OSFinger.h"
#include "Event.h" #include "Event.h"
#include "analyzer/protocol/pia/PIA.h" #include "analyzer/protocol/pia/PIA.h"
@ -115,201 +114,6 @@ static RecordVal* build_syn_packet_val(int is_orig, const IP_Hdr* ip,
return v; return v;
} }
static RecordVal* build_os_val(int is_orig, const IP_Hdr* ip,
const struct tcphdr* tcp, uint32 tcp_hdr_len)
{
if ( ! is_orig )
// Later we might use SYN-ACK fingerprinting here.
return 0;
// Passive OS fingerprinting wants to know a lot about IP and TCP
// options: how many options there are, and in which order.
int winscale = 0;
int MSS = 0;
int optcount = 0;
uint32 quirks = 0;
uint32 tstamp = 0;
uint8 op[MAXOPT];
if ( ip->HdrLen() > 20 )
quirks |= QUIRK_IPOPT;
if ( ip->ID() == 0 )
quirks |= QUIRK_ZEROID;
if ( tcp->th_seq == 0 )
quirks |= QUIRK_SEQ0;
if ( tcp->th_seq == tcp->th_ack )
quirks |= QUIRK_SEQEQ;
if ( tcp->th_flags & ~(TH_SYN|TH_ACK|TH_RST|TH_ECE|TH_CWR) )
quirks |= QUIRK_FLAGS;
if ( ip->TotalLen() - ip->HdrLen() - tcp_hdr_len > 0 )
quirks |= QUIRK_DATA; // SYN with data
if ( tcp->th_ack )
quirks |= QUIRK_ACK;
if ( tcp->th_urp )
quirks |= QUIRK_URG;
if ( tcp->th_x2 )
quirks |= QUIRK_X2;
// Parse TCP options.
u_char* options = (u_char*) tcp + sizeof(struct tcphdr);
u_char* opt_end = (u_char*) tcp + tcp_hdr_len;
while ( options < opt_end )
{
unsigned int opt = options[0];
if ( opt == TCPOPT_EOL )
{
op[optcount++] = TCPOPT_EOL;
if ( ++options < opt_end )
quirks |= QUIRK_PAST;
// All done - could flag if more junk left over ....
break;
}
if ( opt == TCPOPT_NOP )
{
op[optcount++] = TCPOPT_NOP;
++options;
continue;
}
if ( options + 1 >= opt_end )
{
// We've run off the end, no room for the length.
quirks |= QUIRK_BROKEN;
break;
}
unsigned int opt_len = options[1];
if ( options + opt_len > opt_end )
{
// No room for rest of the options.
quirks |= QUIRK_BROKEN;
break;
}
if ( opt_len == 0 )
// Trashed length field.
break;
switch ( opt ) {
case TCPOPT_SACK_PERMITTED:
// SACKOK LEN
op[optcount] = TCPOPT_SACK_PERMITTED;
break;
case TCPOPT_MAXSEG:
// MSS LEN D0 D1
if ( opt_len < 4 )
break; // bad length
op[optcount] = TCPOPT_MAXSEG;
MSS = (options[2] << 8) | options[3];
break;
case TCPOPT_WINDOW:
// WSCALE LEN D0
if ( opt_len < 3 )
break; // bad length
op[optcount] = TCPOPT_WINDOW;
winscale = options[2];
break;
case TCPOPT_TIMESTAMP:
// TSTAMP LEN T0 T1 T2 T3 A0 A1 A2 A3
if ( opt_len < 10 )
break; // bad length
op[optcount] = TCPOPT_TIMESTAMP;
tstamp = ntohl(extract_uint32(options + 2));
if ( extract_uint32(options + 6) )
quirks |= QUIRK_T2;
break;
default: // just skip over
op[optcount]=opt;
break;
}
if ( optcount < MAXOPT - 1 )
++optcount;
else
quirks |= QUIRK_BROKEN;
options += opt_len;
}
struct os_type os_from_print;
int id = sessions->Get_OS_From_SYN(&os_from_print,
uint16(ip->TotalLen()),
uint8(ip->DF()), uint8(ip->TTL()),
uint16(ntohs(tcp->th_win)),
uint8(optcount), op,
uint16(MSS), uint8(winscale),
tstamp, quirks,
uint8(tcp->th_flags & (TH_ECE|TH_CWR)));
if ( sessions->CompareWithPreviousOSMatch(ip->SrcAddr(), id) )
{
RecordVal* os = new RecordVal(OS_version);
os->Assign(0, new StringVal(os_from_print.os));
if ( os_from_print.desc )
os->Assign(1, new StringVal(os_from_print.desc));
else
os->Assign(1, val_mgr->GetEmptyString());
os->Assign(2, val_mgr->GetCount(os_from_print.dist));
os->Assign(3, OS_version_inference->GetVal(os_from_print.match));
return os;
}
return 0;
}
static void passive_fingerprint(TCP_Analyzer* tcp, bool is_orig,
const IP_Hdr* ip, const struct tcphdr* tp,
uint32 tcp_hdr_len)
{
// is_orig will be removed once we can do SYN-ACK fingerprinting
if ( OS_version_found && is_orig )
{
const IPAddr& orig_addr = tcp->Conn()->OrigAddr();
AddrVal* src_addr_val = new AddrVal(orig_addr);
if ( generate_OS_version_event->Size() == 0 ||
generate_OS_version_event->Lookup(src_addr_val) )
{
RecordVal* OS_val = build_os_val(is_orig, ip, tp, tcp_hdr_len);
if ( OS_val )
{ // found new OS version
tcp->ConnectionEventFast(OS_version_found, {
tcp->BuildConnVal(),
src_addr_val->Ref(),
OS_val,
});
}
}
Unref(src_addr_val);
}
}
TCP_Analyzer::TCP_Analyzer(Connection* conn) TCP_Analyzer::TCP_Analyzer(Connection* conn)
: TransportLayerAnalyzer("TCP", conn) : TransportLayerAnalyzer("TCP", conn)
@ -1286,8 +1090,6 @@ void TCP_Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig,
}); });
} }
passive_fingerprint(this, is_orig, ip, tp, tcp_hdr_len);
Unref(SYN_vals); Unref(SYN_vals);
} }

View file

@ -1,6 +1,9 @@
#include "Data.h" #include "Data.h"
#include "File.h" #include "File.h"
#include "broker/data.bif.h" #include "broker/data.bif.h"
#include <broker/error.hh>
#include <caf/stream_serializer.hpp> #include <caf/stream_serializer.hpp>
#include <caf/stream_deserializer.hpp> #include <caf/stream_deserializer.hpp>
#include <caf/streambuf.hpp> #include <caf/streambuf.hpp>

View file

@ -1,7 +1,9 @@
#ifndef BRO_COMM_DATA_H #ifndef BRO_COMM_DATA_H
#define BRO_COMM_DATA_H #define BRO_COMM_DATA_H
#include <broker/broker.hh> #include <broker/data.hh>
#include <broker/expected.hh>
#include "OpaqueVal.h" #include "OpaqueVal.h"
#include "Reporter.h" #include "Reporter.h"
#include "Frame.h" #include "Frame.h"

View file

@ -1,7 +1,17 @@
#ifndef BRO_COMM_MANAGER_H #ifndef BRO_COMM_MANAGER_H
#define BRO_COMM_MANAGER_H #define BRO_COMM_MANAGER_H
#include <broker/broker.hh> #include <broker/topic.hh>
#include <broker/data.hh>
#include <broker/store.hh>
#include <broker/status.hh>
#include <broker/error.hh>
#include <broker/endpoint.hh>
#include <broker/endpoint_info.hh>
#include <broker/peer_info.hh>
#include <broker/backend.hh>
#include <broker/backend_options.hh>
#include <broker/detail/hash.hh>
#include <broker/zeek.hh> #include <broker/zeek.hh>
#include <memory> #include <memory>
#include <string> #include <string>

View file

@ -8,7 +8,9 @@
#include "OpaqueVal.h" #include "OpaqueVal.h"
#include "Trigger.h" #include "Trigger.h"
#include <broker/broker.hh> #include <broker/store.hh>
#include <broker/backend.hh>
#include <broker/backend_options.hh>
namespace bro_broker { namespace bro_broker {

View file

@ -545,7 +545,7 @@ event signature_match%(state: signature_state, msg: string, data: string%);
## descr: The raw (unparsed) software identification string as extracted from ## descr: The raw (unparsed) software identification string as extracted from
## the protocol. ## the protocol.
## ##
## .. zeek:see:: software_parse_error software_unparsed_version_found OS_version_found ## .. zeek:see:: software_parse_error software_unparsed_version_found
event software_version_found%(c: connection, host: addr, event software_version_found%(c: connection, host: addr,
s: software, descr: string%); s: software, descr: string%);
@ -564,7 +564,6 @@ event software_version_found%(c: connection, host: addr,
## the protocol. ## the protocol.
## ##
## .. zeek:see:: software_version_found software_unparsed_version_found ## .. zeek:see:: software_version_found software_unparsed_version_found
## OS_version_found
event software_parse_error%(c: connection, host: addr, descr: string%); event software_parse_error%(c: connection, host: addr, descr: string%);
## Generated when a protocol analyzer finds an identification of a software ## Generated when a protocol analyzer finds an identification of a software
@ -581,25 +580,9 @@ event software_parse_error%(c: connection, host: addr, descr: string%);
## ##
## str: The software identification string as extracted from the protocol. ## str: The software identification string as extracted from the protocol.
## ##
## .. zeek:see:: software_parse_error software_version_found OS_version_found ## .. zeek:see:: software_parse_error software_version_found
event software_unparsed_version_found%(c: connection, host: addr, str: string%); event software_unparsed_version_found%(c: connection, host: addr, str: string%);
## Generated when an operating system has been fingerprinted. Zeek uses `p0f
## <http://lcamtuf.coredump.cx/p0f.shtml>`__ to fingerprint endpoints passively,
## and it raises this event for each system identified. The p0f fingerprints are
## defined by :zeek:id:`passive_fingerprint_file`.
##
## c: The connection.
##
## host: The host running the reported OS.
##
## OS: The OS version string.
##
## .. zeek:see:: passive_fingerprint_file software_parse_error
## software_version_found software_unparsed_version_found
## generate_OS_version_event
event OS_version_found%(c: connection, host: addr, OS: OS_version%);
## Generated each time Zeek's internal profiling log is updated. The file is ## Generated each time Zeek's internal profiling log is updated. The file is
## defined by :zeek:id:`profiling_file`, and its update frequency by ## defined by :zeek:id:`profiling_file`, and its update frequency by
## :zeek:id:`profiling_interval` and :zeek:id:`expensive_profiling_multiple`. ## :zeek:id:`profiling_interval` and :zeek:id:`expensive_profiling_multiple`.

View file

@ -10,6 +10,8 @@
#include "file_analysis/Manager.h" #include "file_analysis/Manager.h"
#include <broker/error.hh>
#include <openssl/x509.h> #include <openssl/x509.h>
#include <openssl/x509v3.h> #include <openssl/x509v3.h>
#include <openssl/asn1.h> #include <openssl/asn1.h>

View file

@ -33,7 +33,7 @@ Config::Config(ReaderFrontend *frontend) : ReaderBackend(frontend)
while ( auto id = globals->NextEntry(c) ) while ( auto id = globals->NextEntry(c) )
{ {
if ( id->IsInternalGlobal() || ! id->IsOption() ) if ( ! id->IsOption() )
continue; continue;
if ( id->Type()->Tag() == TYPE_RECORD || if ( id->Type()->Tag() == TYPE_RECORD ||

View file

@ -5,7 +5,7 @@
// Switching parser table type fixes ambiguity problems. // Switching parser table type fixes ambiguity problems.
%define lr.type ielr %define lr.type ielr
%expect 104 %expect 105
%token TOK_ADD TOK_ADD_TO TOK_ADDR TOK_ANY %token TOK_ADD TOK_ADD_TO TOK_ADDR TOK_ANY
%token TOK_ATENDIF TOK_ATELSE TOK_ATIF TOK_ATIFDEF TOK_ATIFNDEF %token TOK_ATENDIF TOK_ATELSE TOK_ATIF TOK_ATIFDEF TOK_ATIFNDEF
@ -50,14 +50,14 @@
%left '$' '[' ']' '(' ')' TOK_HAS_FIELD TOK_HAS_ATTR %left '$' '[' ']' '(' ')' TOK_HAS_FIELD TOK_HAS_ATTR
%nonassoc TOK_AS TOK_IS %nonassoc TOK_AS TOK_IS
%type <b> opt_no_test opt_no_test_block opt_deprecated TOK_PATTERN_END %type <b> opt_no_test opt_no_test_block TOK_PATTERN_END
%type <str> TOK_ID TOK_PATTERN_TEXT %type <str> TOK_ID TOK_PATTERN_TEXT
%type <id> local_id global_id def_global_id event_id global_or_event_id resolve_id begin_func case_type %type <id> local_id global_id def_global_id event_id global_or_event_id resolve_id begin_func case_type
%type <id_l> local_id_list case_type_list %type <id_l> local_id_list case_type_list
%type <ic> init_class %type <ic> init_class
%type <expr> opt_init %type <expr> opt_init
%type <val> TOK_CONSTANT %type <val> TOK_CONSTANT
%type <expr> expr opt_expr init anonymous_function index_slice %type <expr> expr opt_expr init anonymous_function index_slice opt_deprecated
%type <event_expr> event %type <event_expr> event
%type <stmt> stmt stmt_list func_body for_head %type <stmt> stmt stmt_list func_body for_head
%type <type> type opt_type enum_body %type <type> type opt_type enum_body
@ -700,7 +700,7 @@ expr:
$$ = new NameExpr(id); $$ = new NameExpr(id);
if ( id->IsDeprecated() ) if ( id->IsDeprecated() )
reporter->Warning("deprecated (%s)", id->Name()); reporter->Warning("%s", id->GetDeprecationWarning().c_str());
} }
} }
@ -1002,7 +1002,7 @@ type:
Ref($$); Ref($$);
if ( $1->IsDeprecated() ) if ( $1->IsDeprecated() )
reporter->Warning("deprecated (%s)", $1->Name()); reporter->Warning("%s", $1->GetDeprecationWarning().c_str());
} }
} }
; ;
@ -1327,6 +1327,19 @@ attr:
{ $$ = new Attr(ATTR_ERROR_HANDLER); } { $$ = new Attr(ATTR_ERROR_HANDLER); }
| TOK_ATTR_DEPRECATED | TOK_ATTR_DEPRECATED
{ $$ = new Attr(ATTR_DEPRECATED); } { $$ = new Attr(ATTR_DEPRECATED); }
| TOK_ATTR_DEPRECATED '=' TOK_CONSTANT
{
if ( IsString($3->Type()->Tag()) )
$$ = new Attr(ATTR_DEPRECATED, new ConstExpr($3));
else
{
ODesc d;
$3->Describe(&d);
reporter->Error("'&deprecated=%s' must use a string literal",
d.Description());
$$ = new Attr(ATTR_DEPRECATED);
}
}
; ;
stmt: stmt:
@ -1535,7 +1548,7 @@ event:
YYERROR; YYERROR;
} }
if ( id->IsDeprecated() ) if ( id->IsDeprecated() )
reporter->Warning("deprecated (%s)", id->Name()); reporter->Warning("%s", id->GetDeprecationWarning().c_str());
} }
$$ = new EventExpr($1, $3); $$ = new EventExpr($1, $3);
@ -1741,7 +1754,7 @@ global_or_event_id:
if ( t->Tag() != TYPE_FUNC || if ( t->Tag() != TYPE_FUNC ||
t->AsFuncType()->Flavor() != FUNC_FLAVOR_FUNCTION ) t->AsFuncType()->Flavor() != FUNC_FLAVOR_FUNCTION )
reporter->Warning("deprecated (%s)", $$->Name()); reporter->Warning("%s", $$->GetDeprecationWarning().c_str());
} }
delete [] $1; delete [] $1;
@ -1787,9 +1800,23 @@ opt_no_test_block:
opt_deprecated: opt_deprecated:
TOK_ATTR_DEPRECATED TOK_ATTR_DEPRECATED
{ $$ = true; } { $$ = new ConstExpr(new StringVal("")); }
| |
{ $$ = false; } TOK_ATTR_DEPRECATED '=' TOK_CONSTANT
{
if ( IsString($3->Type()->Tag()) )
$$ = new ConstExpr($3);
else
{
ODesc d;
$3->Describe(&d);
reporter->Error("'&deprecated=%s' must use a string literal",
d.Description());
$$ = new ConstExpr(new StringVal(""));
}
}
|
{ $$ = nullptr; }
%% %%

View file

@ -244,7 +244,7 @@ void ComponentManager<T, C>::RegisterComponent(C* component,
string id = fmt("%s%s", prefix.c_str(), cname.c_str()); string id = fmt("%s%s", prefix.c_str(), cname.c_str());
tag_enum_type->AddName(module, id.c_str(), tag_enum_type->AddName(module, id.c_str(),
component->Tag().AsEnumVal()->InternalInt(), true, component->Tag().AsEnumVal()->InternalInt(), true,
false); nullptr);
} }
} // namespace plugin } // namespace plugin

View file

@ -6,7 +6,8 @@
#include <iterator> #include <iterator>
#include <vector> #include <vector>
#include <broker/Data.h> #include <broker/data.hh>
#include <broker/expected.hh>
namespace probabilistic { namespace probabilistic {

View file

@ -4,6 +4,8 @@
#include <cmath> #include <cmath>
#include <limits> #include <limits>
#include <broker/error.hh>
#include "BloomFilter.h" #include "BloomFilter.h"
#include "CounterVector.h" #include "CounterVector.h"

View file

@ -5,7 +5,8 @@
#include <vector> #include <vector>
#include <broker/Data.h> #include <broker/data.hh>
#include <broker/expected.hh>
#include "BitVector.h" #include "BitVector.h"
#include "Hasher.h" #include "Hasher.h"

View file

@ -4,7 +4,11 @@
#define PROBABILISTIC_CARDINALITYCOUNTER_H #define PROBABILISTIC_CARDINALITYCOUNTER_H
#include <stdint.h> #include <stdint.h>
#include <OpaqueVal.h> #include <memory>
#include <vector>
#include <broker/data.hh>
#include <broker/expected.hh>
namespace probabilistic { namespace probabilistic {

View file

@ -5,6 +5,9 @@
#include <cassert> #include <cassert>
#include <limits> #include <limits>
#include "BitVector.h" #include "BitVector.h"
#include "util.h"
#include <broker/error.hh>
using namespace probabilistic; using namespace probabilistic;

View file

@ -6,7 +6,8 @@
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include <broker/Data.h> #include <broker/data.hh>
#include <broker/expected.hh>
namespace probabilistic { namespace probabilistic {

View file

@ -3,7 +3,10 @@
#ifndef PROBABILISTIC_HASHER_H #ifndef PROBABILISTIC_HASHER_H
#define PROBABILISTIC_HASHER_H #define PROBABILISTIC_HASHER_H
#include <broker/Data.h> #include <broker/data.hh>
#include <broker/expected.hh>
#include <memory>
#include "Hash.h" #include "Hash.h"

View file

@ -1,5 +1,7 @@
// See the file "COPYING" in the main distribution directory for copyright. // See the file "COPYING" in the main distribution directory for copyright.
#include <broker/error.hh>
#include "broker/Data.h" #include "broker/Data.h"
#include "probabilistic/Topk.h" #include "probabilistic/Topk.h"
#include "CompHash.h" #include "CompHash.h"

View file

@ -1902,7 +1902,7 @@ function global_sizes%(%): var_sizes
ID* id; ID* id;
while ( (id = globals->NextEntry(c)) ) while ( (id = globals->NextEntry(c)) )
if ( id->HasVal() && ! id->IsInternalGlobal() ) if ( id->HasVal() )
{ {
Val* id_name = new StringVal(id->Name()); Val* id_name = new StringVal(id->Name());
Val* id_size = val_mgr->GetCount(id->ID_Val()->MemoryAllocation()); Val* id_size = val_mgr->GetCount(id->ID_Val()->MemoryAllocation());
@ -1926,24 +1926,10 @@ function global_ids%(%): id_table
TableVal* ids = new TableVal(id_table); TableVal* ids = new TableVal(id_table);
PDict(ID)* globals = global_scope()->Vars(); PDict(ID)* globals = global_scope()->Vars();
IterCookie* c = globals->InitForIteration(); IterCookie* c = globals->InitForIteration();
#ifdef DEBUG
/**
* Explanation time: c needs to be a robust cookie when one is in debug mode,
* otherwise the Zeek process will crash in ~80% of cases when -B all is specified.
* The reason for this are the RecordVals that we create. RecordVal::Assign triggers
* a StateAccess::Log, which in turn (only in debug mode) triggers StateAccess::Describe,
* which creates a UniqueID for the variable, which triggers an insert into global_scope.
* Which invalidates the iteration cookie if it is not robust.
**/
globals->MakeRobustCookie(c);
#endif
ID* id; ID* id;
while ( (id = globals->NextEntry(c)) ) while ( (id = globals->NextEntry(c)) )
{ {
if ( id->IsInternalGlobal() )
continue;
RecordVal* rec = new RecordVal(script_id); RecordVal* rec = new RecordVal(script_id);
rec->Assign(0, new StringVal(type_name(id->Type()->Tag()))); rec->Assign(0, new StringVal(type_name(id->Type()->Tag())));
rec->Assign(1, val_mgr->GetBool(id->IsExport())); rec->Assign(1, val_mgr->GetBool(id->IsExport()));

View file

@ -1,2 +1,5 @@
direct assignment (PASS) direct assignment (PASS)
using copy (PASS) using copy (PASS)
F, T
F, T
[a=42], [a=42], [a=42], [a=42]

View file

@ -0,0 +1,28 @@
warning in ./no-warnings.zeek, line 27: deprecated (ONE)
warning in ./no-warnings.zeek, line 28: deprecated (TWO)
warning in ./no-warnings.zeek, line 30: deprecated (GREEN)
warning in ./no-warnings.zeek, line 31: deprecated (BLUE)
warning in ./no-warnings.zeek, line 33: deprecated (blah)
warning in ./no-warnings.zeek, line 37: deprecated (my_event)
warning in ./no-warnings.zeek, line 38: deprecated (my_event)
warning in ./no-warnings.zeek, line 39: deprecated (my_hook)
warning in ./no-warnings.zeek, line 41: deprecated (my_record$b)
warning in ./no-warnings.zeek, line 42: deprecated (my_record$b)
warning in ./no-warnings.zeek, line 43: deprecated (my_record$b)
warning in ./no-warnings.zeek, line 45: deprecated (my_record?$b)
warning in ./no-warnings.zeek, line 46: deprecated (my_record$b)
warning in ./no-warnings.zeek, line 49: deprecated (my_record$b)
warning in ./no-warnings.zeek, line 52: deprecated (my_event)
warning in ./no-warnings.zeek, line 57: deprecated (my_hook)
warning in ./no-warnings.zeek, line 62: deprecated (blah)
warning in ./no-warnings.zeek, line 71: deprecated (dont_use_me)
warning in ./no-warnings.zeek, line 76: deprecated (dont_use_me_either)
ZERO
ONE
TWO
RED
GREEN
BLUE
generate my_hook please
generate my_event please
schedule my_event please

View file

@ -1,28 +0,0 @@
warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.zeek, line 30: deprecated (ONE)
warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.zeek, line 31: deprecated (TWO)
warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.zeek, line 33: deprecated (GREEN)
warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.zeek, line 34: deprecated (BLUE)
warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.zeek, line 36: deprecated (blah)
warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.zeek, line 40: deprecated (my_event)
warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.zeek, line 41: deprecated (my_event)
warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.zeek, line 42: deprecated (my_hook)
warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.zeek, line 44: deprecated (my_record$b)
warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.zeek, line 45: deprecated (my_record$b)
warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.zeek, line 46: deprecated (my_record$b)
warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.zeek, line 48: deprecated (my_record?$b)
warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.zeek, line 49: deprecated (my_record$b)
warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.zeek, line 52: deprecated (my_record$b)
warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.zeek, line 55: deprecated (my_event)
warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.zeek, line 60: deprecated (my_hook)
warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.zeek, line 65: deprecated (blah)
warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.zeek, line 74: deprecated (dont_use_me)
warning in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.deprecated/deprecated.zeek, line 79: deprecated (dont_use_me_either)
ZERO
ONE
TWO
RED
GREEN
BLUE
generate my_hook please
generate my_event please
schedule my_event please

View file

@ -0,0 +1,28 @@
warning in ./warnings.zeek, line 27: deprecated (ONE): one warning
warning in ./warnings.zeek, line 28: deprecated (TWO): two warning
warning in ./warnings.zeek, line 30: deprecated (GREEN): green warning
warning in ./warnings.zeek, line 31: deprecated (BLUE): red warning
warning in ./warnings.zeek, line 33: deprecated (blah): type warning
warning in ./warnings.zeek, line 37: deprecated (my_event): event warning
warning in ./warnings.zeek, line 38: deprecated (my_event): event warning
warning in ./warnings.zeek, line 39: deprecated (my_hook): hook warning
warning in ./warnings.zeek, line 41: deprecated (my_record$b): record warning
warning in ./warnings.zeek, line 42: deprecated (my_record$b): record warning
warning in ./warnings.zeek, line 43: deprecated (my_record$b): record warning
warning in ./warnings.zeek, line 45: deprecated (my_record?$b): record warning
warning in ./warnings.zeek, line 46: deprecated (my_record$b): record warning
warning in ./warnings.zeek, line 49: deprecated (my_record$b): record warning
warning in ./warnings.zeek, line 52: deprecated (my_event): event warning
warning in ./warnings.zeek, line 57: deprecated (my_hook): hook warning
warning in ./warnings.zeek, line 62: deprecated (blah): type warning
warning in ./warnings.zeek, line 71: deprecated (dont_use_me): global function warning
warning in ./warnings.zeek, line 76: deprecated (dont_use_me_either): function warning
ZERO
ONE
TWO
RED
GREEN
BLUE
generate my_hook please
generate my_event please
schedule my_event please

View file

@ -0,0 +1,4 @@
"j" in x3[20]$x, expected timeout
15 in x2, T
x1 != 42, T
x2[10], T

View file

@ -0,0 +1,12 @@
RDP Client Cluster Data
Flags: 0000000d
RedirSessionId: 00000000
Redirection Supported: 00000000
ServerSessionRedirectionVersionMask: 00000000
RedirectionSessionIDFieldValid: 00000000
RedirectedSmartCard: 00000000
RDP Client Channel List Options
80800000
c0000000
c0800000
c0a00000

View file

@ -2,14 +2,12 @@
# @TEST-EXEC: btest-diff out # @TEST-EXEC: btest-diff out
function test_case(msg: string, expect: bool) function test_case(msg: string, expect: bool)
{ {
print fmt("%s (%s)", msg, expect ? "PASS" : "FAIL"); print fmt("%s (%s)", msg, expect ? "PASS" : "FAIL");
} }
event zeek_init() event zeek_init()
{ {
# "b" is not a copy of "a" # "b" is not a copy of "a"
local a: set[string] = set("this", "test"); local a: set[string] = set("this", "test");
local b: set[string] = a; local b: set[string] = a;
@ -25,6 +23,27 @@ event zeek_init()
delete c["this"]; delete c["this"];
test_case( "using copy", |d| == 2 && "this" in d); test_case( "using copy", |d| == 2 && "this" in d);
}
} type myrec: record {
a: count;
};
event zeek_init()
{
local v: vector of myrec;
local t: table[count] of myrec;
local mr = myrec($a = 42);
t[0] = mr;
t[1] = mr;
local tc = copy(t);
print same_object(t, tc), same_object(tc[0], tc[1]);
v[0] = mr;
v[1] = mr;
local vc = copy(v);
print same_object(v, vc), same_object(vc[0], vc[1]);
print tc[0], tc[1], vc[0], vc[1];
}

View file

@ -1,6 +1,10 @@
# @TEST-EXEC: zeek -b %INPUT >out 2>&1 # @TEST-EXEC: zeek -b no-warnings.zeek >no-warnings.out 2>&1
# @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff out # @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff no-warnings.out
# @TEST-EXEC: zeek -b warnings.zeek >warnings.out 2>&1
# @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff warnings.out
@TEST-START-FILE no-warnings.zeek
type blah: string &deprecated; type blah: string &deprecated;
global my_event: event(arg: string) &deprecated; global my_event: event(arg: string) &deprecated;
@ -21,7 +25,7 @@ type my_enum: enum {
type my_other_enum: enum { type my_other_enum: enum {
ZERO = 0, ZERO = 0,
ONE = 1 &deprecated, ONE = 1 &deprecated,
TWO = 2 &deprecated TWO = 2 &deprecated,
}; };
event zeek_init() event zeek_init()
@ -78,3 +82,84 @@ function dont_use_me_either() &deprecated
{ {
dont_use_me_either(); dont_use_me_either();
} }
@TEST-END-FILE
@TEST-START-FILE warnings.zeek
type blah: string &deprecated="type warning";
global my_event: event(arg: string) &deprecated="event warning";
global my_hook: hook(arg: string) &deprecated="hook warning";
type my_record: record {
a: count &default = 1;
b: string &optional &deprecated="record warning";
};
type my_enum: enum {
RED,
GREEN &deprecated="green warning",
BLUE &deprecated="red warning"
};
type my_other_enum: enum {
ZERO = 0,
ONE = 1 &deprecated="one warning",
TWO = 2 &deprecated="two warning",
};
event zeek_init()
{
print ZERO;
print ONE;
print TWO;
print RED;
print GREEN;
print BLUE;
local l: blah = "testing";
local ls: string = " test";
event my_event("generate my_event please");
schedule 1sec { my_event("schedule my_event please") };
hook my_hook("generate my_hook please");
local mr = my_record($a = 3, $b = "yeah");
mr = [$a = 4, $b = "ye"];
mr = record($a = 5, $b = "y");
if ( ! mr?$b )
mr$b = "nooooooo";
mr$a = 2;
mr$b = "noooo";
}
event my_event(arg: string)
{
print arg;
}
hook my_hook(arg: string)
{
print arg;
}
function hmm(b: blah)
{
print b;
}
global dont_use_me: function() &deprecated="global function warning";
function dont_use_me()
{
dont_use_me();
}
function dont_use_me_either() &deprecated="function warning"
{
dont_use_me_either();
}
@TEST-END-FILE

View file

@ -0,0 +1,71 @@
# @TEST-EXEC: zeek -b -r $TRACES/wikipedia.trace %INPUT | sort >out
# @TEST-EXEC: btest-diff out
redef exit_only_after_terminate = T;
type X: record {
s: string;
x: set[string] &optional;
};
global x1 = 42;
global x2: table[count] of X;
global x3: table[count] of X;
event quit()
{
terminate();
}
event zeek_init()
{
x2[10] = [$s="foo"];
x3[20] = [$s="bar", $x=set("i")];
when ( x1 != 42 )
{
print "x1 != 42", x1 != 42;
}
timeout 1sec
{
print "unexpected timeout (1)";
}
when ( 15 in x2 )
{
print "15 in x2", 10 in x2;
}
timeout 1sec
{
print "unexpected timeout (2)";
}
when ( x2[10]$s == "bar" )
{
print "x2[10]", x2[10]$s == "bar";
}
timeout 1sec
{
print "unexpected timeout (3)";
}
when ( "j" in x3[20]$x )
{
print "unexpected trigger";
}
timeout 1sec
{
print "\"j\" in x3[20]$x, expected timeout";
}
x1 = 100;
x2[15] = [$s="xyz"];
x2[10]$s = "bar";
# This will *NOT* trigger then when-condition because we're modifying
# an inner value that's not directly tracked.
add x3[20]$x["j"];
schedule 2secs { quit() };
}

View file

@ -0,0 +1,22 @@
# @TEST-EXEC: zeek -r $TRACES/rdp/rdp-proprietary-encryption.pcap %INPUT >out
# @TEST-EXEC: btest-diff out
@load base/protocols/rdp
event rdp_client_cluster_data(c: connection, data: RDP::ClientClusterData)
{
print "RDP Client Cluster Data";
print fmt("Flags: %08x",data$flags);
print fmt("RedirSessionId: %08x",data$redir_session_id);
print fmt("Redirection Supported: %08x",data$redir_supported);
print fmt("ServerSessionRedirectionVersionMask: %08x",data$svr_session_redir_version_mask);
print fmt("RedirectionSessionIDFieldValid: %08x",data$redir_sessionid_field_valid);
print fmt("RedirectedSmartCard: %08x",data$redir_smartcard);
}
event rdp_client_network_data(c: connection, channels: RDP::ClientChannelList)
{
print "RDP Client Channel List Options";
for ( i in channels )
print fmt("%08x", channels[i]$options);
}