mirror of
https://github.com/zeek/zeek.git
synced 2025-10-09 18:18:19 +00:00
Merge remote-tracking branch 'origin/master' into topic/johanna/tls13-details
This commit is contained in:
commit
6707328c55
182 changed files with 2281 additions and 1613 deletions
|
@ -1 +0,0 @@
|
|||
Support for Unified2 files in the file analysis framework.
|
|
@ -1 +0,0 @@
|
|||
@load ./main
|
|
@ -1,297 +0,0 @@
|
|||
|
||||
@load base/utils/dir
|
||||
@load base/utils/paths
|
||||
|
||||
module Unified2;
|
||||
|
||||
export {
|
||||
redef enum Log::ID += { LOG };
|
||||
|
||||
## File to watch for Unified2 files.
|
||||
const watch_file = "" &redef;
|
||||
|
||||
## Directory to watch for Unified2 records.
|
||||
const watch_dir = "" &redef;
|
||||
|
||||
## The sid-msg.map file you would like to use for your alerts.
|
||||
const sid_msg = "" &redef;
|
||||
|
||||
## The gen-msg.map file you would like to use for your alerts.
|
||||
const gen_msg = "" &redef;
|
||||
|
||||
## The classification.config file you would like to use for your alerts.
|
||||
const classification_config = "" &redef;
|
||||
|
||||
## Reconstructed "alert" which combines related events
|
||||
## and packets.
|
||||
global alert: event(f: fa_file, ev: Unified2::IDSEvent, pkt: Unified2::Packet);
|
||||
|
||||
type PacketID: record {
|
||||
src_ip: addr;
|
||||
src_p: port;
|
||||
dst_ip: addr;
|
||||
dst_p: port;
|
||||
} &log;
|
||||
|
||||
type Info: record {
|
||||
## Timestamp attached to the alert.
|
||||
ts: time &log;
|
||||
## Addresses and ports for the connection.
|
||||
id: PacketID &log;
|
||||
## Sensor that originated this event.
|
||||
sensor_id: count &log;
|
||||
## Sig id for this generator.
|
||||
signature_id: count &log;
|
||||
## A string representation of the *signature_id* field if a sid_msg.map file was loaded.
|
||||
signature: string &log &optional;
|
||||
## Which generator generated the alert?
|
||||
generator_id: count &log;
|
||||
## A string representation of the *generator_id* field if a gen_msg.map file was loaded.
|
||||
generator: string &log &optional;
|
||||
## Sig revision for this id.
|
||||
signature_revision: count &log;
|
||||
## Event classification.
|
||||
classification_id: count &log;
|
||||
## Descriptive classification string.
|
||||
classification: string &log &optional;
|
||||
## Event priority.
|
||||
priority_id: count &log;
|
||||
## Event ID.
|
||||
event_id: count &log;
|
||||
## Some of the packet data.
|
||||
packet: string &log &optional;
|
||||
} &log;
|
||||
|
||||
## The event for accessing logged records.
|
||||
global log_unified2: event(rec: Info);
|
||||
}
|
||||
|
||||
# Mappings for extended information from alerts.
|
||||
global classification_map: table[count] of string;
|
||||
global sid_map: table[count] of string;
|
||||
global gen_map: table[count] of string;
|
||||
|
||||
global num_classification_map_reads = 0;
|
||||
global num_sid_map_reads = 0;
|
||||
global num_gen_map_reads = 0;
|
||||
global watching = F;
|
||||
|
||||
# For reading in config files.
|
||||
type OneLine: record {
|
||||
line: string;
|
||||
};
|
||||
|
||||
function mappings_initialized(): bool
|
||||
{
|
||||
return num_classification_map_reads > 0 &&
|
||||
num_sid_map_reads > 0 &&
|
||||
num_gen_map_reads > 0;
|
||||
}
|
||||
|
||||
function start_watching()
|
||||
{
|
||||
if ( watching )
|
||||
return;
|
||||
|
||||
watching = T;
|
||||
|
||||
if ( watch_dir != "" )
|
||||
{
|
||||
Dir::monitor(watch_dir, function(fname: string)
|
||||
{
|
||||
Input::add_analysis([$source=fname,
|
||||
$reader=Input::READER_BINARY,
|
||||
$mode=Input::STREAM,
|
||||
$name=fname]);
|
||||
}, 10secs);
|
||||
}
|
||||
|
||||
if ( watch_file != "" )
|
||||
{
|
||||
Input::add_analysis([$source=watch_file,
|
||||
$reader=Input::READER_BINARY,
|
||||
$mode=Input::STREAM,
|
||||
$name=watch_file]);
|
||||
}
|
||||
}
|
||||
|
||||
function create_info(ev: IDSEvent): Info
|
||||
{
|
||||
local info = Info($ts=ev$ts,
|
||||
$id=PacketID($src_ip=ev$src_ip, $src_p=ev$src_p,
|
||||
$dst_ip=ev$dst_ip, $dst_p=ev$dst_p),
|
||||
$sensor_id=ev$sensor_id,
|
||||
$signature_id=ev$signature_id,
|
||||
$generator_id=ev$generator_id,
|
||||
$signature_revision=ev$signature_revision,
|
||||
$classification_id=ev$classification_id,
|
||||
$priority_id=ev$priority_id,
|
||||
$event_id=ev$event_id);
|
||||
|
||||
if ( ev$signature_id in sid_map )
|
||||
info$signature=sid_map[ev$signature_id];
|
||||
if ( ev$generator_id in gen_map )
|
||||
info$generator=gen_map[ev$generator_id];
|
||||
if ( ev$classification_id in classification_map )
|
||||
info$classification=classification_map[ev$classification_id];
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
redef record fa_file += {
|
||||
## Recently received IDS events. This is primarily used
|
||||
## for tying together Unified2 events and packets.
|
||||
u2_events: table[count] of Unified2::IDSEvent
|
||||
&optional &create_expire=5sec
|
||||
&expire_func=function(t: table[count] of Unified2::IDSEvent, event_id: count): interval
|
||||
{
|
||||
Log::write(LOG, create_info(t[event_id]));
|
||||
return 0secs;
|
||||
};
|
||||
};
|
||||
|
||||
event Unified2::read_sid_msg_line(desc: Input::EventDescription, tpe: Input::Event, line: string)
|
||||
{
|
||||
local parts = split_string_n(line, / \|\| /, F, 100);
|
||||
if ( |parts| >= 2 && /^[0-9]+$/ in parts[0] )
|
||||
sid_map[to_count(parts[0])] = parts[1];
|
||||
}
|
||||
|
||||
event Unified2::read_gen_msg_line(desc: Input::EventDescription, tpe: Input::Event, line: string)
|
||||
{
|
||||
local parts = split_string_n(line, / \|\| /, F, 3);
|
||||
if ( |parts| >= 2 && /^[0-9]+$/ in parts[0] )
|
||||
gen_map[to_count(parts[0])] = parts[2];
|
||||
}
|
||||
|
||||
event Unified2::read_classification_line(desc: Input::EventDescription, tpe: Input::Event, line: string)
|
||||
{
|
||||
local parts = split_string_n(line, /: /, F, 2);
|
||||
if ( |parts| == 2 )
|
||||
{
|
||||
local parts2 = split_string_n(parts[1], /,/, F, 4);
|
||||
if ( |parts2| > 1 )
|
||||
classification_map[|classification_map|+1] = parts2[0];
|
||||
}
|
||||
}
|
||||
|
||||
event Input::end_of_data(name: string, source: string)
|
||||
{
|
||||
if ( name == classification_config )
|
||||
++num_classification_map_reads;
|
||||
else if ( name == sid_msg )
|
||||
++num_sid_map_reads;
|
||||
else if ( name == gen_msg )
|
||||
++num_gen_map_reads;
|
||||
else
|
||||
return;
|
||||
|
||||
if ( watching )
|
||||
return;
|
||||
|
||||
if ( mappings_initialized() )
|
||||
start_watching();
|
||||
}
|
||||
|
||||
event zeek_init() &priority=5
|
||||
{
|
||||
Log::create_stream(Unified2::LOG, [$columns=Info, $ev=log_unified2, $path="unified2"]);
|
||||
|
||||
if ( sid_msg == "" )
|
||||
{
|
||||
num_sid_map_reads = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Input::add_event([$source=sid_msg,
|
||||
$reader=Input::READER_RAW,
|
||||
$mode=Input::REREAD,
|
||||
$name=sid_msg,
|
||||
$fields=Unified2::OneLine,
|
||||
$want_record=F,
|
||||
$ev=Unified2::read_sid_msg_line]);
|
||||
}
|
||||
|
||||
if ( gen_msg == "" )
|
||||
{
|
||||
num_gen_map_reads = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Input::add_event([$source=gen_msg,
|
||||
$name=gen_msg,
|
||||
$reader=Input::READER_RAW,
|
||||
$mode=Input::REREAD,
|
||||
$fields=Unified2::OneLine,
|
||||
$want_record=F,
|
||||
$ev=Unified2::read_gen_msg_line]);
|
||||
}
|
||||
|
||||
if ( classification_config == "" )
|
||||
{
|
||||
num_classification_map_reads = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Input::add_event([$source=classification_config,
|
||||
$name=classification_config,
|
||||
$reader=Input::READER_RAW,
|
||||
$mode=Input::REREAD,
|
||||
$fields=Unified2::OneLine,
|
||||
$want_record=F,
|
||||
$ev=Unified2::read_classification_line]);
|
||||
}
|
||||
|
||||
if ( mappings_initialized() )
|
||||
start_watching();
|
||||
}
|
||||
|
||||
event file_new(f: fa_file)
|
||||
{
|
||||
local file_dir = "";
|
||||
local parts = split_string_all(f$source, /\/[^\/]*$/);
|
||||
if ( |parts| == 3 )
|
||||
file_dir = parts[0];
|
||||
|
||||
if ( (watch_file != "" && f$source == watch_file) ||
|
||||
(watch_dir != "" && compress_path(watch_dir) == file_dir) )
|
||||
{
|
||||
Files::add_analyzer(f, Files::ANALYZER_UNIFIED2);
|
||||
f$u2_events = table();
|
||||
}
|
||||
}
|
||||
|
||||
event unified2_event(f: fa_file, ev: Unified2::IDSEvent)
|
||||
{
|
||||
f$u2_events[ev$event_id] = ev;
|
||||
}
|
||||
|
||||
event unified2_packet(f: fa_file, pkt: Unified2::Packet)
|
||||
{
|
||||
if ( f?$u2_events && pkt$event_id in f$u2_events)
|
||||
{
|
||||
local ev = f$u2_events[pkt$event_id];
|
||||
event Unified2::alert(f, ev, pkt);
|
||||
delete f$u2_events[pkt$event_id];
|
||||
}
|
||||
}
|
||||
|
||||
event Unified2::alert(f: fa_file, ev: IDSEvent, pkt: Packet)
|
||||
{
|
||||
local info = create_info(ev);
|
||||
info$packet=pkt$data;
|
||||
Log::write(LOG, info);
|
||||
}
|
||||
|
||||
event file_state_remove(f: fa_file)
|
||||
{
|
||||
if ( f?$u2_events )
|
||||
{
|
||||
# In case any events never had matching packets, flush
|
||||
# the extras to the log.
|
||||
for ( i, ev in f$u2_events )
|
||||
{
|
||||
Log::write(LOG, create_info(ev));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,7 +3,6 @@
|
|||
@load ./plugins
|
||||
@load ./drop
|
||||
@load ./shunt
|
||||
@load ./catch-and-release
|
||||
|
||||
# The cluster framework must be loaded first.
|
||||
@load base/frameworks/cluster
|
||||
|
|
|
@ -1,535 +0,0 @@
|
|||
##! Implementation of catch-and-release functionality for NetControl.
|
||||
|
||||
module NetControl;
|
||||
|
||||
@load base/frameworks/cluster
|
||||
@load ./main
|
||||
@load ./drop
|
||||
|
||||
export {
|
||||
|
||||
redef enum Log::ID += { CATCH_RELEASE };
|
||||
|
||||
## This record is used for storing information about current blocks that are
|
||||
## part of catch and release.
|
||||
type BlockInfo: record {
|
||||
## Absolute time indicating until when a block is inserted using NetControl.
|
||||
block_until: time &optional;
|
||||
## Absolute time indicating until when an IP address is watched to reblock it.
|
||||
watch_until: time;
|
||||
## Number of times an IP address was reblocked.
|
||||
num_reblocked: count &default=0;
|
||||
## Number indicating at which catch and release interval we currently are.
|
||||
current_interval: count;
|
||||
## ID of the inserted block, if any.
|
||||
current_block_id: string;
|
||||
## User specified string.
|
||||
location: string &optional;
|
||||
};
|
||||
|
||||
## The enum that contains the different kinds of messages that are logged by
|
||||
## catch and release.
|
||||
type CatchReleaseActions: enum {
|
||||
## Log lines marked with info are purely informational; no action was taken.
|
||||
INFO,
|
||||
## A rule for the specified IP address already existed in NetControl (outside
|
||||
## of catch-and-release). Catch and release did not add a new rule, but is now
|
||||
## watching the IP address and will add a new rule after the current rule expires.
|
||||
ADDED,
|
||||
## A drop was requested by catch and release.
|
||||
DROP,
|
||||
## An address was successfully blocked by catch and release.
|
||||
DROPPED,
|
||||
## An address was unblocked after the timeout expired.
|
||||
UNBLOCK,
|
||||
## An address was forgotten because it did not reappear within the `watch_until` interval.
|
||||
FORGOTTEN,
|
||||
## A watched IP address was seen again; catch and release will re-block it.
|
||||
SEEN_AGAIN
|
||||
};
|
||||
|
||||
## The record type that is used for representing and logging
|
||||
type CatchReleaseInfo: record {
|
||||
## The absolute time indicating when the action for this log-line occured.
|
||||
ts: time &log;
|
||||
## The rule id that this log line refers to.
|
||||
rule_id: string &log &optional;
|
||||
## The IP address that this line refers to.
|
||||
ip: addr &log;
|
||||
## The action that was taken in this log-line.
|
||||
action: CatchReleaseActions &log;
|
||||
## The current block_interaval (for how long the address is blocked).
|
||||
block_interval: interval &log &optional;
|
||||
## The current watch_interval (for how long the address will be watched and re-block if it reappears).
|
||||
watch_interval: interval &log &optional;
|
||||
## The absolute time until which the address is blocked.
|
||||
blocked_until: time &log &optional;
|
||||
## The absolute time until which the address will be monitored.
|
||||
watched_until: time &log &optional;
|
||||
## Number of times that this address was blocked in the current cycle.
|
||||
num_blocked: count &log &optional;
|
||||
## The user specified location string.
|
||||
location: string &log &optional;
|
||||
## Additional informational string by the catch and release framework about this log-line.
|
||||
message: string &log &optional;
|
||||
};
|
||||
|
||||
## Stops all packets involving an IP address from being forwarded. This function
|
||||
## uses catch-and-release functionality, where the IP address is only dropped for
|
||||
## a short amount of time that is incremented steadily when the IP is encountered
|
||||
## again.
|
||||
##
|
||||
## In cluster mode, this function works on workers as well as the manager. On managers,
|
||||
## the returned :zeek:see:`NetControl::BlockInfo` record will not contain the block ID,
|
||||
## which will be assigned on the manager.
|
||||
##
|
||||
## a: The address to be dropped.
|
||||
##
|
||||
## t: How long to drop it, with 0 being indefinitely.
|
||||
##
|
||||
## location: An optional string describing where the drop was triggered.
|
||||
##
|
||||
## Returns: The :zeek:see:`NetControl::BlockInfo` record containing information about
|
||||
## the inserted block.
|
||||
global drop_address_catch_release: function(a: addr, location: string &default="") : BlockInfo;
|
||||
|
||||
## Removes an address from being watched with catch and release. Returns true if the
|
||||
## address was found and removed; returns false if it was unknown to catch and release.
|
||||
##
|
||||
## If the address is currently blocked, and the block was inserted by catch and release,
|
||||
## the block is removed.
|
||||
##
|
||||
## a: The address to be unblocked.
|
||||
##
|
||||
## reason: A reason for the unblock.
|
||||
##
|
||||
## Returns: True if the address was unblocked.
|
||||
global unblock_address_catch_release: function(a: addr, reason: string &default="") : bool;
|
||||
|
||||
## This function can be called to notify the catch and release script that activity by
|
||||
## an IP address was seen. If the respective IP address is currently monitored by catch and
|
||||
## release and not blocked, the block will be reinstated. See the documentation of watch_new_connection
|
||||
## which events the catch and release functionality usually monitors for activity.
|
||||
##
|
||||
## a: The address that was seen and should be re-dropped if it is being watched.
|
||||
global catch_release_seen: function(a: addr);
|
||||
|
||||
## Get the :zeek:see:`NetControl::BlockInfo` record for an address currently blocked by catch and release.
|
||||
## If the address is unknown to catch and release, the watch_until time will be set to 0.
|
||||
##
|
||||
## In cluster mode, this function works on the manager and workers. On workers, the data will
|
||||
## lag slightly behind the manager; if you add a block, it will not be instantly available via
|
||||
## this function.
|
||||
##
|
||||
## a: The address to get information about.
|
||||
##
|
||||
## Returns: The :zeek:see:`NetControl::BlockInfo` record containing information about
|
||||
## the inserted block.
|
||||
global get_catch_release_info: function(a: addr) : BlockInfo;
|
||||
|
||||
## Event is raised when catch and release cases management of an IP address because no
|
||||
## activity was seen within the watch_until period.
|
||||
##
|
||||
## a: The address that is no longer being managed.
|
||||
##
|
||||
## bi: The :zeek:see:`NetControl::BlockInfo` record containing information about the block.
|
||||
global catch_release_forgotten: event(a: addr, bi: BlockInfo);
|
||||
|
||||
## If true, catch_release_seen is called on the connection originator in new_connection,
|
||||
## connection_established, partial_connection, connection_attempt, connection_rejected,
|
||||
## connection_reset and connection_pending
|
||||
const watch_connections = T &redef;
|
||||
|
||||
## If true, catch and release warns if packets of an IP address are still seen after it
|
||||
## should have been blocked.
|
||||
option catch_release_warn_blocked_ip_encountered = F;
|
||||
|
||||
## Time intervals for which subsequent drops of the same IP take
|
||||
## effect.
|
||||
const catch_release_intervals: vector of interval = vector(10min, 1hr, 24hrs, 7days) &redef;
|
||||
|
||||
## Event that can be handled to access the :zeek:type:`NetControl::CatchReleaseInfo`
|
||||
## record as it is sent on to the logging framework.
|
||||
global log_netcontrol_catch_release: event(rec: CatchReleaseInfo);
|
||||
|
||||
# Cluster events for catch and release
|
||||
global catch_release_block_new: event(a: addr, b: BlockInfo);
|
||||
global catch_release_block_delete: event(a: addr);
|
||||
global catch_release_add: event(a: addr, location: string);
|
||||
global catch_release_delete: event(a: addr, reason: string);
|
||||
global catch_release_encountered: event(a: addr);
|
||||
}
|
||||
|
||||
# Set that is used to only send seen notifications to the master every ~30 seconds.
|
||||
global catch_release_recently_notified: set[addr] &create_expire=30secs;
|
||||
|
||||
event zeek_init() &priority=5
|
||||
{
|
||||
Log::create_stream(NetControl::CATCH_RELEASE, [$columns=CatchReleaseInfo, $ev=log_netcontrol_catch_release, $path="netcontrol_catch_release"]);
|
||||
}
|
||||
|
||||
function get_watch_interval(current_interval: count): interval
|
||||
{
|
||||
if ( (current_interval + 1) in catch_release_intervals )
|
||||
return catch_release_intervals[current_interval+1];
|
||||
else
|
||||
return catch_release_intervals[current_interval];
|
||||
}
|
||||
|
||||
function populate_log_record(ip: addr, bi: BlockInfo, action: CatchReleaseActions): CatchReleaseInfo
|
||||
{
|
||||
local log = CatchReleaseInfo($ts=network_time(), $ip=ip, $action=action,
|
||||
$block_interval=catch_release_intervals[bi$current_interval],
|
||||
$watch_interval=get_watch_interval(bi$current_interval),
|
||||
$watched_until=bi$watch_until,
|
||||
$num_blocked=bi$num_reblocked+1
|
||||
);
|
||||
|
||||
if ( bi?$block_until )
|
||||
log$blocked_until = bi$block_until;
|
||||
|
||||
if ( bi?$current_block_id && bi$current_block_id != "" )
|
||||
log$rule_id = bi$current_block_id;
|
||||
|
||||
if ( bi?$location )
|
||||
log$location = bi$location;
|
||||
|
||||
return log;
|
||||
}
|
||||
|
||||
function per_block_interval(t: table[addr] of BlockInfo, idx: addr): interval
|
||||
{
|
||||
local remaining_time = t[idx]$watch_until - network_time();
|
||||
if ( remaining_time < 0secs )
|
||||
remaining_time = 0secs;
|
||||
|
||||
@if ( ! Cluster::is_enabled() || ( Cluster::is_enabled() && Cluster::local_node_type() == Cluster::MANAGER ) )
|
||||
if ( remaining_time == 0secs )
|
||||
{
|
||||
local log = populate_log_record(idx, t[idx], FORGOTTEN);
|
||||
Log::write(CATCH_RELEASE, log);
|
||||
|
||||
event NetControl::catch_release_forgotten(idx, t[idx]);
|
||||
}
|
||||
@endif
|
||||
|
||||
return remaining_time;
|
||||
}
|
||||
|
||||
# This is the internally maintained table containing all the addresses that are currently being
|
||||
# watched to see if they will re-surface. After the time is reached, monitoring of that specific
|
||||
# IP will stop.
|
||||
global blocks: table[addr] of BlockInfo = {}
|
||||
&create_expire=0secs
|
||||
&expire_func=per_block_interval;
|
||||
|
||||
|
||||
@if ( Cluster::is_enabled() )
|
||||
|
||||
@if ( Cluster::local_node_type() == Cluster::MANAGER )
|
||||
event zeek_init()
|
||||
{
|
||||
Broker::auto_publish(Cluster::worker_topic, NetControl::catch_release_block_new);
|
||||
Broker::auto_publish(Cluster::worker_topic, NetControl::catch_release_block_delete);
|
||||
}
|
||||
@else
|
||||
event zeek_init()
|
||||
{
|
||||
Broker::auto_publish(Cluster::manager_topic, NetControl::catch_release_add);
|
||||
Broker::auto_publish(Cluster::manager_topic, NetControl::catch_release_delete);
|
||||
Broker::auto_publish(Cluster::manager_topic, NetControl::catch_release_encountered);
|
||||
}
|
||||
@endif
|
||||
|
||||
@endif
|
||||
|
||||
function cr_check_rule(r: Rule): bool
|
||||
{
|
||||
if ( r$ty == DROP && r$entity$ty == ADDRESS )
|
||||
{
|
||||
local ip = r$entity$ip;
|
||||
if ( ( is_v4_subnet(ip) && subnet_width(ip) == 32 ) || ( is_v6_subnet(ip) && subnet_width(ip) == 128 ) )
|
||||
{
|
||||
if ( subnet_to_addr(ip) in blocks )
|
||||
return T;
|
||||
}
|
||||
}
|
||||
|
||||
return F;
|
||||
}
|
||||
|
||||
@if ( ! Cluster::is_enabled() || ( Cluster::is_enabled() && Cluster::local_node_type() == Cluster::MANAGER ) )
|
||||
|
||||
event rule_added(r: Rule, p: PluginState, msg: string &default="")
|
||||
{
|
||||
if ( !cr_check_rule(r) )
|
||||
return;
|
||||
|
||||
local ip = subnet_to_addr(r$entity$ip);
|
||||
local bi = blocks[ip];
|
||||
|
||||
local log = populate_log_record(ip, bi, DROPPED);
|
||||
if ( msg != "" )
|
||||
log$message = msg;
|
||||
Log::write(CATCH_RELEASE, log);
|
||||
}
|
||||
|
||||
|
||||
event rule_timeout(r: Rule, i: FlowInfo, p: PluginState)
|
||||
{
|
||||
if ( !cr_check_rule(r) )
|
||||
return;
|
||||
|
||||
local ip = subnet_to_addr(r$entity$ip);
|
||||
local bi = blocks[ip];
|
||||
|
||||
local log = populate_log_record(ip, bi, UNBLOCK);
|
||||
if ( bi?$block_until )
|
||||
{
|
||||
local difference: interval = network_time() - bi$block_until;
|
||||
if ( interval_to_double(difference) > 60 || interval_to_double(difference) < -60 )
|
||||
log$message = fmt("Difference between network_time and block time excessive: %f", difference);
|
||||
}
|
||||
|
||||
Log::write(CATCH_RELEASE, log);
|
||||
}
|
||||
|
||||
@endif
|
||||
|
||||
@if ( Cluster::is_enabled() && Cluster::local_node_type() == Cluster::MANAGER )
|
||||
event catch_release_add(a: addr, location: string)
|
||||
{
|
||||
drop_address_catch_release(a, location);
|
||||
}
|
||||
|
||||
event catch_release_delete(a: addr, reason: string)
|
||||
{
|
||||
unblock_address_catch_release(a, reason);
|
||||
}
|
||||
|
||||
event catch_release_encountered(a: addr)
|
||||
{
|
||||
catch_release_seen(a);
|
||||
}
|
||||
@endif
|
||||
|
||||
@if ( Cluster::is_enabled() && Cluster::local_node_type() != Cluster::MANAGER )
|
||||
event catch_release_block_new(a: addr, b: BlockInfo)
|
||||
{
|
||||
blocks[a] = b;
|
||||
}
|
||||
|
||||
event catch_release_block_delete(a: addr)
|
||||
{
|
||||
if ( a in blocks )
|
||||
delete blocks[a];
|
||||
}
|
||||
@endif
|
||||
|
||||
@if ( Cluster::is_enabled() && Cluster::local_node_type() == Cluster::MANAGER )
|
||||
@endif
|
||||
|
||||
function get_catch_release_info(a: addr): BlockInfo
|
||||
{
|
||||
if ( a in blocks )
|
||||
return blocks[a];
|
||||
|
||||
return BlockInfo($watch_until=double_to_time(0), $current_interval=0, $current_block_id="");
|
||||
}
|
||||
|
||||
function drop_address_catch_release(a: addr, location: string &default=""): BlockInfo
|
||||
{
|
||||
local bi: BlockInfo;
|
||||
local log: CatchReleaseInfo;
|
||||
|
||||
if ( a in blocks )
|
||||
{
|
||||
log = populate_log_record(a, blocks[a], INFO);
|
||||
log$message = "Already blocked using catch-and-release - ignoring duplicate";
|
||||
Log::write(CATCH_RELEASE, log);
|
||||
|
||||
return blocks[a];
|
||||
}
|
||||
|
||||
local e = Entity($ty=ADDRESS, $ip=addr_to_subnet(a));
|
||||
if ( [e,DROP] in rule_entities )
|
||||
{
|
||||
local r = rule_entities[e,DROP];
|
||||
|
||||
bi = BlockInfo($watch_until=network_time()+catch_release_intervals[1], $current_interval=0, $current_block_id=r$id);
|
||||
if ( location != "" )
|
||||
bi$location = location;
|
||||
@if ( ! Cluster::is_enabled() || ( Cluster::is_enabled() && Cluster::local_node_type() == Cluster::MANAGER ) )
|
||||
log = populate_log_record(a, bi, ADDED);
|
||||
log$message = "Address already blocked outside of catch-and-release. Catch and release will monitor and only actively block if it appears in network traffic.";
|
||||
Log::write(CATCH_RELEASE, log);
|
||||
blocks[a] = bi;
|
||||
event NetControl::catch_release_block_new(a, bi);
|
||||
@endif
|
||||
@if ( Cluster::is_enabled() && Cluster::local_node_type() != Cluster::MANAGER )
|
||||
event NetControl::catch_release_add(a, location);
|
||||
@endif
|
||||
return bi;
|
||||
}
|
||||
|
||||
local block_interval = catch_release_intervals[0];
|
||||
|
||||
@if ( ! Cluster::is_enabled() || ( Cluster::is_enabled() && Cluster::local_node_type() == Cluster::MANAGER ) )
|
||||
local ret = drop_address(a, block_interval, location);
|
||||
|
||||
if ( ret != "" )
|
||||
{
|
||||
bi = BlockInfo($watch_until=network_time()+catch_release_intervals[1], $block_until=network_time()+block_interval, $current_interval=0, $current_block_id=ret);
|
||||
if ( location != "" )
|
||||
bi$location = location;
|
||||
blocks[a] = bi;
|
||||
event NetControl::catch_release_block_new(a, bi);
|
||||
blocks[a] = bi;
|
||||
log = populate_log_record(a, bi, DROP);
|
||||
Log::write(CATCH_RELEASE, log);
|
||||
return bi;
|
||||
}
|
||||
Reporter::error(fmt("Catch and release could not add block for %s; failing.", a));
|
||||
return BlockInfo($watch_until=double_to_time(0), $current_interval=0, $current_block_id="");
|
||||
@endif
|
||||
|
||||
@if ( Cluster::is_enabled() && Cluster::local_node_type() != Cluster::MANAGER )
|
||||
bi = BlockInfo($watch_until=network_time()+catch_release_intervals[1], $block_until=network_time()+block_interval, $current_interval=0, $current_block_id="");
|
||||
event NetControl::catch_release_add(a, location);
|
||||
return bi;
|
||||
@endif
|
||||
|
||||
}
|
||||
|
||||
function unblock_address_catch_release(a: addr, reason: string &default=""): bool
|
||||
{
|
||||
if ( a !in blocks )
|
||||
return F;
|
||||
|
||||
@if ( ! Cluster::is_enabled() || ( Cluster::is_enabled() && Cluster::local_node_type() == Cluster::MANAGER ) )
|
||||
local bi = blocks[a];
|
||||
local log = populate_log_record(a, bi, UNBLOCK);
|
||||
if ( reason != "" )
|
||||
log$message = reason;
|
||||
Log::write(CATCH_RELEASE, log);
|
||||
delete blocks[a];
|
||||
if ( bi?$block_until && bi$block_until > network_time() && bi$current_block_id != "" )
|
||||
remove_rule(bi$current_block_id, reason);
|
||||
@endif
|
||||
@if ( Cluster::is_enabled() && Cluster::local_node_type() == Cluster::MANAGER )
|
||||
event NetControl::catch_release_block_delete(a);
|
||||
@endif
|
||||
@if ( Cluster::is_enabled() && Cluster::local_node_type() != Cluster::MANAGER )
|
||||
event NetControl::catch_release_delete(a, reason);
|
||||
@endif
|
||||
|
||||
return T;
|
||||
}
|
||||
|
||||
function catch_release_seen(a: addr)
|
||||
{
|
||||
if ( a in blocks )
|
||||
{
|
||||
@if ( ! Cluster::is_enabled() || ( Cluster::is_enabled() && Cluster::local_node_type() == Cluster::MANAGER ) )
|
||||
local bi = blocks[a];
|
||||
local log: CatchReleaseInfo;
|
||||
local e = Entity($ty=ADDRESS, $ip=addr_to_subnet(a));
|
||||
|
||||
if ( [e,DROP] in rule_entities )
|
||||
{
|
||||
if ( catch_release_warn_blocked_ip_encountered == F )
|
||||
return;
|
||||
|
||||
# This should be blocked - block has not been applied yet by hardware? Ignore for the moment...
|
||||
log = populate_log_record(a, bi, INFO);
|
||||
log$action = INFO;
|
||||
log$message = "Block seen while in rule_entities. No action taken.";
|
||||
Log::write(CATCH_RELEASE, log);
|
||||
return;
|
||||
}
|
||||
|
||||
# ok, this one returned again while still in the backoff period.
|
||||
|
||||
local try = bi$current_interval;
|
||||
if ( (try+1) in catch_release_intervals )
|
||||
++try;
|
||||
|
||||
bi$current_interval = try;
|
||||
if ( (try+1) in catch_release_intervals )
|
||||
bi$watch_until = network_time() + catch_release_intervals[try+1];
|
||||
else
|
||||
bi$watch_until = network_time() + catch_release_intervals[try];
|
||||
|
||||
bi$block_until = network_time() + catch_release_intervals[try];
|
||||
++bi$num_reblocked;
|
||||
|
||||
local block_interval = catch_release_intervals[try];
|
||||
local location = "";
|
||||
if ( bi?$location )
|
||||
location = bi$location;
|
||||
local drop = drop_address(a, block_interval, fmt("Re-drop by catch-and-release: %s", location));
|
||||
bi$current_block_id = drop;
|
||||
|
||||
blocks[a] = bi;
|
||||
|
||||
log = populate_log_record(a, bi, SEEN_AGAIN);
|
||||
Log::write(CATCH_RELEASE, log);
|
||||
@endif
|
||||
@if ( Cluster::is_enabled() && Cluster::local_node_type() == Cluster::MANAGER )
|
||||
event NetControl::catch_release_block_new(a, bi);
|
||||
@endif
|
||||
@if ( Cluster::is_enabled() && Cluster::local_node_type() != Cluster::MANAGER )
|
||||
if ( a in catch_release_recently_notified )
|
||||
return;
|
||||
|
||||
event NetControl::catch_release_encountered(a);
|
||||
add catch_release_recently_notified[a];
|
||||
@endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
event new_connection(c: connection)
|
||||
{
|
||||
if ( watch_connections )
|
||||
catch_release_seen(c$id$orig_h);
|
||||
}
|
||||
|
||||
event connection_established(c: connection)
|
||||
{
|
||||
if ( watch_connections )
|
||||
catch_release_seen(c$id$orig_h);
|
||||
}
|
||||
|
||||
event partial_connection(c: connection)
|
||||
{
|
||||
if ( watch_connections )
|
||||
catch_release_seen(c$id$orig_h);
|
||||
}
|
||||
|
||||
event connection_attempt(c: connection)
|
||||
{
|
||||
if ( watch_connections )
|
||||
catch_release_seen(c$id$orig_h);
|
||||
}
|
||||
|
||||
event connection_rejected(c: connection)
|
||||
{
|
||||
if ( watch_connections )
|
||||
catch_release_seen(c$id$orig_h);
|
||||
}
|
||||
|
||||
event connection_reset(c: connection)
|
||||
{
|
||||
if ( watch_connections )
|
||||
catch_release_seen(c$id$orig_h);
|
||||
}
|
||||
|
||||
event connection_pending(c: connection)
|
||||
{
|
||||
if ( watch_connections )
|
||||
catch_release_seen(c$id$orig_h);
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
##! Implementation of the drop functionality for NetControl.
|
||||
|
||||
module NetControl;
|
||||
|
||||
@load ./main
|
||||
|
||||
module NetControl;
|
||||
|
||||
export {
|
||||
redef enum Log::ID += { DROP };
|
||||
|
||||
|
|
|
@ -10,11 +10,11 @@
|
|||
##! provides convenience functions for a set of common operations. The
|
||||
##! low-level API provides full flexibility.
|
||||
|
||||
module NetControl;
|
||||
|
||||
@load ./plugin
|
||||
@load ./types
|
||||
|
||||
module NetControl;
|
||||
|
||||
export {
|
||||
## The framework's logging stream identifier.
|
||||
redef enum Log::ID += { LOG };
|
||||
|
@ -889,7 +889,7 @@ function remove_rule_impl(id: string, reason: string) : bool
|
|||
function rule_expire_impl(r: Rule, p: PluginState) &priority=-5
|
||||
{
|
||||
# do not emit timeout events on shutdown
|
||||
if ( bro_is_terminating() )
|
||||
if ( zeek_is_terminating() )
|
||||
return;
|
||||
|
||||
if ( r$id !in rules )
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
module NetControl;
|
||||
|
||||
@load ./main
|
||||
|
||||
module NetControl;
|
||||
|
||||
function activate(p: PluginState, priority: int)
|
||||
{
|
||||
activate_impl(p, priority);
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
##! This file defines the plugin interface for NetControl.
|
||||
|
||||
module NetControl;
|
||||
|
||||
@load ./types
|
||||
|
||||
module NetControl;
|
||||
|
||||
export {
|
||||
## This record keeps the per instance state of a plugin.
|
||||
##
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
##! Acld plugin for the netcontrol framework.
|
||||
|
||||
module NetControl;
|
||||
|
||||
@load ../main
|
||||
@load ../plugin
|
||||
@load base/frameworks/broker
|
||||
|
||||
module NetControl;
|
||||
|
||||
export {
|
||||
type AclRule : record {
|
||||
command: string;
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
##! used in NetControl on to Broker to allow for easy handling, e.g., of
|
||||
##! command-line scripts.
|
||||
|
||||
module NetControl;
|
||||
|
||||
@load ../main
|
||||
@load ../plugin
|
||||
@load base/frameworks/broker
|
||||
|
||||
module NetControl;
|
||||
|
||||
export {
|
||||
## This record specifies the configuration that is passed to :zeek:see:`NetControl::create_broker`.
|
||||
type BrokerConfig: record {
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
##! and can only add/remove filters for addresses, this is quite
|
||||
##! limited in scope at the moment.
|
||||
|
||||
module NetControl;
|
||||
|
||||
@load ../plugin
|
||||
|
||||
module NetControl;
|
||||
|
||||
export {
|
||||
## Instantiates the packetfilter plugin.
|
||||
global create_packetfilter: function() : PluginState;
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
# There should be no overhead imposed by loading notice actions so we
|
||||
# load them all.
|
||||
@load ./actions/drop
|
||||
@load ./actions/email_admin
|
||||
@load ./actions/page
|
||||
@load ./actions/add-geodata
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
##! This script extends the built in notice code to implement the IP address
|
||||
##! dropping functionality.
|
||||
|
||||
@load ../main
|
||||
@load base/frameworks/netcontrol
|
||||
|
||||
module Notice;
|
||||
|
||||
export {
|
||||
redef enum Action += {
|
||||
## Drops the address via :zeek:see:`NetControl::drop_address_catch_release`.
|
||||
ACTION_DROP
|
||||
};
|
||||
|
||||
redef record Info += {
|
||||
## Indicate if the $src IP address was dropped and denied
|
||||
## network access.
|
||||
dropped: bool &log &default=F;
|
||||
};
|
||||
}
|
||||
|
||||
hook notice(n: Notice::Info) &priority=-5
|
||||
{
|
||||
if ( ACTION_DROP in n$actions )
|
||||
{
|
||||
local ci = NetControl::get_catch_release_info(n$src);
|
||||
if ( ci$watch_until == double_to_time(0) )
|
||||
{
|
||||
# we have not seen this one yet. Drop it.
|
||||
local addl = n?$msg ? fmt("ACTION_DROP: %s", n?$msg) : "ACTION_DROP";
|
||||
local res = NetControl::drop_address_catch_release(n$src, addl);
|
||||
n$dropped = res$watch_until != double_to_time(0);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -405,7 +405,7 @@ function email_headers(subject_desc: string, dest: string): string
|
|||
"From: ", mail_from, "\n",
|
||||
"Subject: ", mail_subject_prefix, " ", subject_desc, "\n",
|
||||
"To: ", dest, "\n",
|
||||
"User-Agent: Bro-IDS/", bro_version(), "\n");
|
||||
"User-Agent: Bro-IDS/", zeek_version(), "\n");
|
||||
if ( reply_to != "" )
|
||||
header_text = string_cat(header_text, "Reply-To: ", reply_to, "\n");
|
||||
return header_text;
|
||||
|
|
|
@ -11,7 +11,7 @@ const COOKIE_BID_SIZE = 16777216;
|
|||
# start at bit 40 (1 << 40)
|
||||
const COOKIE_BID_START = 1099511627776;
|
||||
# Zeek specific cookie ID shall have the 42 bit set (1 << 42)
|
||||
const BRO_COOKIE_ID = 4;
|
||||
const ZEEK_COOKIE_ID = 4;
|
||||
# 8 bits group identifier
|
||||
const COOKIE_GID_SIZE = 256;
|
||||
# start at bit 32 (1 << 32)
|
||||
|
|
|
@ -198,7 +198,7 @@ function match_conn(id: conn_id, reverse: bool &default=F): ofp_match
|
|||
# 42 bit of the cookie set.
|
||||
function generate_cookie(cookie: count &default=0): count
|
||||
{
|
||||
local c = BRO_COOKIE_ID * COOKIE_BID_START;
|
||||
local c = ZEEK_COOKIE_ID * COOKIE_BID_START;
|
||||
|
||||
if ( cookie >= COOKIE_UID_SIZE )
|
||||
Reporter::warning(fmt("The given cookie uid '%d' is > 32bit and will be discarded", cookie));
|
||||
|
@ -211,7 +211,7 @@ function generate_cookie(cookie: count &default=0): count
|
|||
# local function to check if a given flow_mod cookie is forged from this framework.
|
||||
function is_valid_cookie(cookie: count): bool
|
||||
{
|
||||
if ( cookie / COOKIE_BID_START == BRO_COOKIE_ID )
|
||||
if ( cookie / COOKIE_BID_START == ZEEK_COOKIE_ID )
|
||||
return T;
|
||||
|
||||
Reporter::warning(fmt("The given Openflow cookie '%d' is not valid", cookie));
|
||||
|
@ -231,7 +231,7 @@ function get_cookie_gid(cookie: count): count
|
|||
{
|
||||
if( is_valid_cookie(cookie) )
|
||||
return (
|
||||
(cookie - (COOKIE_BID_START * BRO_COOKIE_ID) -
|
||||
(cookie - (COOKIE_BID_START * ZEEK_COOKIE_ID) -
|
||||
(cookie - ((cookie / COOKIE_GID_START) * COOKIE_GID_START))) /
|
||||
COOKIE_GID_START
|
||||
);
|
||||
|
|
|
@ -89,7 +89,7 @@ export {
|
|||
## Opaque controller-issued identifier.
|
||||
# This is optional in the specification - but let's force
|
||||
# it so we always can identify our flows...
|
||||
cookie: count; # &default=BRO_COOKIE_ID * COOKIE_BID_START;
|
||||
cookie: count; # &default=ZEEK_COOKIE_ID * COOKIE_BID_START;
|
||||
# Flow actions
|
||||
## Table to put the flow in. OFPTT_ALL can be used for delete,
|
||||
## to delete flows from all matching tables.
|
||||
|
|
|
@ -35,7 +35,7 @@ event SumStats::finish_epoch(ss: SumStat)
|
|||
{
|
||||
local data = result_store[ss$name];
|
||||
local now = network_time();
|
||||
if ( bro_is_terminating() )
|
||||
if ( zeek_is_terminating() )
|
||||
{
|
||||
for ( key, val in data )
|
||||
ss$epoch_result(now, key, val);
|
||||
|
|
|
@ -4282,6 +4282,22 @@ export {
|
|||
dig_product_id: string &optional;
|
||||
};
|
||||
|
||||
## The TS_UD_CS_SEC data block contains security-related information used
|
||||
## to advertise client cryptographic support.
|
||||
type RDP::ClientSecurityData: record {
|
||||
## Cryptographic encryption methods supported by the client and used in
|
||||
## conjunction with Standard RDP Security. Known flags:
|
||||
##
|
||||
## - 0x00000001: support for 40-bit session encryption keys
|
||||
## - 0x00000002: support for 128-bit session encryption keys
|
||||
## - 0x00000008: support for 56-bit session encryption keys
|
||||
## - 0x00000010: support for FIPS compliant encryption and MAC methods
|
||||
encryption_methods: count;
|
||||
## Only used in French locale and designates the encryption method. If
|
||||
## non-zero, then encryption_methods should be set to 0.
|
||||
ext_encryption_methods: count;
|
||||
};
|
||||
|
||||
## Name and flags for a single channel requested by the client.
|
||||
type RDP::ClientChannelDef: record {
|
||||
## A unique name for the channel
|
||||
|
@ -4749,7 +4765,7 @@ const packet_filter_default = F &redef;
|
|||
const sig_max_group_size = 50 &redef;
|
||||
|
||||
## Description transmitted to remote communication peers for identification.
|
||||
const peer_description = "bro" &redef;
|
||||
const peer_description = "zeek" &redef;
|
||||
|
||||
## The number of IO chunks allowed to be buffered between the child
|
||||
## and parent process of remote communication before Zeek starts dropping
|
||||
|
|
|
@ -74,7 +74,6 @@
|
|||
@load base/files/pe
|
||||
@load base/files/hash
|
||||
@load base/files/extract
|
||||
@load base/files/unified2
|
||||
@load base/files/x509
|
||||
|
||||
@load base/misc/find-checksum-offloading
|
||||
|
|
|
@ -78,10 +78,10 @@ export {
|
|||
## The format of the number is ABBCC with A being the major version,
|
||||
## bb being the minor version (2 digits) and CC being the patchlevel (2 digits).
|
||||
## As an example, Zeek 2.4.1 results in the number 20401
|
||||
const number = Version::parse(bro_version())$version_number;
|
||||
const number = Version::parse(zeek_version())$version_number;
|
||||
|
||||
## `VersionDescription` record pertaining to the currently running version of Zeek.
|
||||
const info = Version::parse(bro_version());
|
||||
const info = Version::parse(zeek_version());
|
||||
}
|
||||
|
||||
function at_least(version_string: string): bool
|
||||
|
|
|
@ -141,7 +141,7 @@ function join_data_expiration(t: table[count] of Info, idx: count): interval
|
|||
# Also, if Zeek is shutting down.
|
||||
if ( (now - info$last_message_ts) > 5sec ||
|
||||
(now - info$ts) > max_txid_watch_time ||
|
||||
bro_is_terminating() )
|
||||
zeek_is_terminating() )
|
||||
{
|
||||
Log::write(LOG, info);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue