##! Implements a generic API to throw events when a connection crosses a ##! fixed threshold of bytes or packets. module ConnThreshold; export { type Thresholds: record { orig_byte: set[count] &default=count_set(); ##< current originator byte thresholds we watch for resp_byte: set[count] &default=count_set(); ##< current responder byte thresholds we watch for orig_packet: set[count] &default=count_set(); ##< current originator packet thresholds we watch for resp_packet: set[count] &default=count_set(); ##< current responder packet thresholds we watch for duration: set[interval] &default=interval_set(); ##< current duration thresholds we watch for }; ## Sets a byte threshold for connection sizes, adding it to potentially already existing thresholds. ## conn_bytes_threshold_crossed will be raised for each set threshold. ## ## cid: The connection id. ## ## threshold: Threshold in bytes. ## ## is_orig: If true, threshold is set for bytes from originator, otherwise for bytes from responder. ## ## Returns: T on success, F on failure. global set_bytes_threshold: function(c: connection, threshold: count, is_orig: bool): bool; ## Sets a packet threshold for connection sizes, adding it to potentially already existing thresholds. ## conn_packets_threshold_crossed will be raised for each set threshold. ## ## cid: The connection id. ## ## threshold: Threshold in packets. ## ## is_orig: If true, threshold is set for packets from originator, otherwise for packets from responder. ## ## Returns: T on success, F on failure. global set_packets_threshold: function(c: connection, threshold: count, is_orig: bool): bool; ## Sets a duration threshold for a connection, adding it to potentially already existing thresholds. ## conn_duration_threshold_crossed will be raised for each set threshold. ## ## cid: The connection id. ## ## threshold: Threshold in seconds. ## ## Returns: T on success, F on failure. global set_duration_threshold: function(c: connection, threshold: interval): bool; ## Deletes a byte threshold for connection sizes. ## ## cid: The connection id. ## ## threshold: Threshold in bytes to remove. ## ## is_orig: If true, threshold is removed for packets from originator, otherwhise for packets from responder. ## ## Returns: T on success, F on failure. global delete_bytes_threshold: function(c: connection, threshold: count, is_orig: bool): bool; ## Deletes a packet threshold for connection sizes. ## ## cid: The connection id. ## ## threshold: Threshold in packets. ## ## is_orig: If true, threshold is removed for packets from originator, otherwise for packets from responder. ## ## Returns: T on success, F on failure. global delete_packets_threshold: function(c: connection, threshold: count, is_orig: bool): bool; ## Deletes a duration threshold for a connection. ## ## cid: The connection id. ## ## threshold: Threshold in packets. ## ## Returns: T on success, F on failure. global delete_duration_threshold: function(c: connection, threshold: interval): bool; ## Generated for a connection that crossed a set byte threshold ## ## c: the connection ## ## threshold: the threshold that was set ## ## is_orig: True if the threshold was crossed by the originator of the connection global bytes_threshold_crossed: event(c: connection, threshold: count, is_orig: bool); ## Generated for a connection that crossed a set byte threshold ## ## c: the connection ## ## threshold: the threshold that was set ## ## is_orig: True if the threshold was crossed by the originator of the connection global packets_threshold_crossed: event(c: connection, threshold: count, is_orig: bool); ## Generated for a connection that crossed a set duration threshold. Note that this event is ## not raised at the exact moment that a duration threshold is crossed; instead it is raised ## when the next packet is seen after the threshold has been crossed. On a connection that is ## idle, this can be raised significantly later. ## ## c: the connection ## ## threshold: the threshold that was set ## ## is_orig: True if the threshold was crossed by the originator of the connection global duration_threshold_crossed: event(c: connection, threshold: interval, is_orig: bool); } redef record connection += { thresholds: ConnThreshold::Thresholds &optional; }; type threshold_type: enum { BYTES, PACKETS, DURATION }; function set_conn(c: connection) { if ( c?$thresholds ) return; c$thresholds = Thresholds(); } function find_min_threshold(t: set[count]): count { if ( |t| == 0 ) return 0; local first = T; local min: count = 0; for ( i in t ) { if ( first ) { min = i; first = F; } else { if ( i < min ) min = i; } } return min; } function find_min_duration_threshold(t: set[interval]): interval { if ( |t| == 0 ) return 0secs; local first = T; local min: interval = 0 secs; for ( i in t ) { if ( first ) { min = i; first = F; } else { if ( i < min ) min = i; } } return min; } function set_current_threshold(c: connection, ttype: threshold_type, is_orig: bool): bool { local t: count = 0; local cur: count = 0; local td: interval = 0 secs; local curd: interval = 0 secs; if ( ttype == BYTES && is_orig ) { t = find_min_threshold(c$thresholds$orig_byte); cur = get_current_conn_bytes_threshold(c$id, is_orig); } else if ( ttype == BYTES && ! is_orig ) { t = find_min_threshold(c$thresholds$resp_byte); cur = get_current_conn_bytes_threshold(c$id, is_orig); } else if ( ttype == PACKETS && is_orig ) { t = find_min_threshold(c$thresholds$orig_packet); cur = get_current_conn_packets_threshold(c$id, is_orig); } else if ( ttype == PACKETS && ! is_orig ) { t = find_min_threshold(c$thresholds$resp_packet); cur = get_current_conn_packets_threshold(c$id, is_orig); } else if ( ttype == DURATION ) { td = find_min_duration_threshold(c$thresholds$duration); curd = get_current_conn_duration_threshold(c$id); } if ( t == cur && td == curd ) return T; if ( ttype == BYTES && is_orig ) return set_current_conn_bytes_threshold(c$id, t, T); else if ( ttype == BYTES && ! is_orig ) return set_current_conn_bytes_threshold(c$id, t, F); else if ( ttype == PACKETS && is_orig ) return set_current_conn_packets_threshold(c$id, t, T); else if ( ttype == PACKETS && ! is_orig ) return set_current_conn_packets_threshold(c$id, t, F); else # ttype == DURATION return set_current_conn_duration_threshold(c$id, td); } function set_bytes_threshold(c: connection, threshold: count, is_orig: bool): bool { set_conn(c); if ( threshold == 0 ) return F; if ( is_orig ) add c$thresholds$orig_byte[threshold]; else add c$thresholds$resp_byte[threshold]; return set_current_threshold(c, BYTES, is_orig); } function set_packets_threshold(c: connection, threshold: count, is_orig: bool): bool { set_conn(c); if ( threshold == 0 ) return F; if ( is_orig ) add c$thresholds$orig_packet[threshold]; else add c$thresholds$resp_packet[threshold]; return set_current_threshold(c, PACKETS, is_orig); } function set_duration_threshold(c: connection, threshold: interval): bool { set_conn(c); if ( threshold == 0 secs ) return F; add c$thresholds$duration[threshold]; return set_current_threshold(c, DURATION, T); } function delete_bytes_threshold(c: connection, threshold: count, is_orig: bool): bool { set_conn(c); if ( is_orig && threshold in c$thresholds$orig_byte ) { delete c$thresholds$orig_byte[threshold]; set_current_threshold(c, BYTES, is_orig); return T; } else if ( ! is_orig && threshold in c$thresholds$resp_byte ) { delete c$thresholds$resp_byte[threshold]; set_current_threshold(c, BYTES, is_orig); return T; } return F; } function delete_packets_threshold(c: connection, threshold: count, is_orig: bool): bool { set_conn(c); if ( is_orig && threshold in c$thresholds$orig_packet ) { delete c$thresholds$orig_packet[threshold]; set_current_threshold(c, PACKETS, is_orig); return T; } else if ( ! is_orig && threshold in c$thresholds$resp_packet ) { delete c$thresholds$resp_packet[threshold]; set_current_threshold(c, PACKETS, is_orig); return T; } return F; } function delete_duration_threshold(c: connection, threshold: interval): bool { set_conn(c); if ( threshold in c$thresholds$duration ) { delete c$thresholds$duration[threshold]; set_current_threshold(c, DURATION, T); return T; } return F; } event conn_bytes_threshold_crossed(c: connection, threshold: count, is_orig: bool) &priority=5 { if ( ! c?$thresholds ) return; if ( is_orig && threshold in c$thresholds$orig_byte ) { delete c$thresholds$orig_byte[threshold]; event ConnThreshold::bytes_threshold_crossed(c, threshold, is_orig); } else if ( ! is_orig && threshold in c$thresholds$resp_byte ) { delete c$thresholds$resp_byte[threshold]; event ConnThreshold::bytes_threshold_crossed(c, threshold, is_orig); } set_current_threshold(c, BYTES, is_orig); } event conn_packets_threshold_crossed(c: connection, threshold: count, is_orig: bool) &priority=5 { if ( ! c?$thresholds ) return; if ( is_orig && threshold in c$thresholds$orig_packet ) { delete c$thresholds$orig_packet[threshold]; event ConnThreshold::packets_threshold_crossed(c, threshold, is_orig); } else if ( ! is_orig && threshold in c$thresholds$resp_packet ) { delete c$thresholds$resp_packet[threshold]; event ConnThreshold::packets_threshold_crossed(c, threshold, is_orig); } set_current_threshold(c, PACKETS, is_orig); } event conn_duration_threshold_crossed(c: connection, threshold: interval, is_orig: bool) &priority=5 { if ( ! c?$thresholds ) return; if ( threshold in c$thresholds$duration ) { delete c$thresholds$duration[threshold]; event ConnThreshold::duration_threshold_crossed(c, threshold, is_orig); } set_current_threshold(c, DURATION, is_orig); }