diff --git a/NEWS b/NEWS
index 0378fb74d3..b7d3b71185 100644
--- a/NEWS
+++ b/NEWS
@@ -40,6 +40,23 @@ Changed Functionality
- The tcp_option event is now correctly raised.
+- The base scripts shipped with Zeek now use the ``successful_connection_remove``
+ event instead of ``connection_state_remove`` where possible
+ (when the logic doesn't pertain to unestablished TCP connections).
+ There's a performance benefit to this switch, but potentially breaks
+ custom scripts that depended on accessing or modifying state via
+ specific &priority ordering of ``connection_state_remove`` event handlers.
+ Since most of Zeek's base scripts previously just used that event with
+ the intention of writing a finalized log as the last thing executed
+ for a given connection and the new ``successful_connection_remove``
+ event handlers all run after ``connection_state_remove``, it's not
+ likely this change to the base scripts causes any incompatibility
+ with user scripts.
+
+ There's also a new event called ``connection_successful`` and a new
+ ``connection`` record field named "successful" to help indicate this new
+ property of connections.
+
Removed Functionality
---------------------
diff --git a/scripts/base/frameworks/tunnels/main.zeek b/scripts/base/frameworks/tunnels/main.zeek
index 09441c177c..f457cafe5f 100644
--- a/scripts/base/frameworks/tunnels/main.zeek
+++ b/scripts/base/frameworks/tunnels/main.zeek
@@ -144,7 +144,7 @@ event tunnel_changed(c: connection, e: EncapsulatingConnVector) &priority=5
register_all(e);
}
-event connection_state_remove(c: connection) &priority=-5
+event successful_connection_remove(c: connection) &priority=-5
{
if ( c$id in active )
close(active[c$id], CLOSE);
diff --git a/scripts/base/init-bare.zeek b/scripts/base/init-bare.zeek
index ec067be6de..2c408320ca 100644
--- a/scripts/base/init-bare.zeek
+++ b/scripts/base/init-bare.zeek
@@ -419,6 +419,13 @@ type connection: record {
## The inner VLAN, if applicable for this connection.
inner_vlan: int &optional;
+
+ ## This is always true for protocols other than TCP. For TCP, this is
+ ## true if the responder host ever sent a packet or if the originator host
+ ## ever sends a packet that is not a SYN. This field will be true
+ ## only if :zeek:see:`connection_successful` has already been generated for
+ ## a given connection.
+ successful: bool;
};
## Default amount of time a file can be inactive before the file analysis
diff --git a/scripts/base/protocols/conn/main.zeek b/scripts/base/protocols/conn/main.zeek
index 653aa6816d..ea249edee1 100644
--- a/scripts/base/protocols/conn/main.zeek
+++ b/scripts/base/protocols/conn/main.zeek
@@ -300,6 +300,11 @@ event connection_state_remove(c: connection) &priority=5
event connection_state_remove(c: connection) &priority=-5
{
- Log::write(Conn::LOG, c$conn);
+ if ( ! c$successful )
+ Log::write(Conn::LOG, c$conn);
}
+event successful_connection_remove(c: connection) &priority=-5
+ {
+ Log::write(Conn::LOG, c$conn);
+ }
diff --git a/scripts/base/protocols/dce-rpc/main.zeek b/scripts/base/protocols/dce-rpc/main.zeek
index 1b318265e8..285e32b385 100644
--- a/scripts/base/protocols/dce-rpc/main.zeek
+++ b/scripts/base/protocols/dce-rpc/main.zeek
@@ -209,7 +209,7 @@ event dce_rpc_response(c: connection, fid: count, ctx_id: count, opnum: count, s
}
}
-event connection_state_remove(c: connection)
+event successful_connection_remove(c: connection)
{
if ( ! c?$dce_rpc )
return;
diff --git a/scripts/base/protocols/dnp3/main.zeek b/scripts/base/protocols/dnp3/main.zeek
index 184816c59f..347958704e 100644
--- a/scripts/base/protocols/dnp3/main.zeek
+++ b/scripts/base/protocols/dnp3/main.zeek
@@ -63,7 +63,7 @@ event dnp3_application_response_header(c: connection, is_orig: bool, application
delete c$dnp3;
}
-event connection_state_remove(c: connection) &priority=-5
+event successful_connection_remove(c: connection) &priority=-5
{
if ( ! c?$dnp3 )
return;
diff --git a/scripts/base/protocols/dns/main.zeek b/scripts/base/protocols/dns/main.zeek
index 3906ab5cf0..7b7f6c2176 100644
--- a/scripts/base/protocols/dns/main.zeek
+++ b/scripts/base/protocols/dns/main.zeek
@@ -571,7 +571,7 @@ event dns_rejected(c: connection, msg: dns_msg, query: string, qtype: count, qcl
c$dns$rejected = T;
}
-event connection_state_remove(c: connection) &priority=-5
+event successful_connection_remove(c: connection) &priority=-5
{
if ( ! c?$dns_state )
return;
diff --git a/scripts/base/protocols/ftp/main.zeek b/scripts/base/protocols/ftp/main.zeek
index 30ffc145bf..31a1b549b2 100644
--- a/scripts/base/protocols/ftp/main.zeek
+++ b/scripts/base/protocols/ftp/main.zeek
@@ -322,7 +322,7 @@ event connection_reused(c: connection) &priority=5
c$ftp_data_reuse = T;
}
-event connection_state_remove(c: connection) &priority=-5
+event successful_connection_remove(c: connection) &priority=-5
{
if ( c$ftp_data_reuse ) return;
if ( [c$id$resp_h, c$id$resp_p] in ftp_data_expected )
@@ -334,8 +334,8 @@ event connection_state_remove(c: connection) &priority=-5
}
}
-# Use state remove event to cover connections terminated by RST.
-event connection_state_remove(c: connection) &priority=-5
+# Use remove event to cover connections terminated by RST.
+event successful_connection_remove(c: connection) &priority=-5
{
if ( ! c?$ftp ) return;
diff --git a/scripts/base/protocols/http/main.zeek b/scripts/base/protocols/http/main.zeek
index ef0561efb4..cabda29999 100644
--- a/scripts/base/protocols/http/main.zeek
+++ b/scripts/base/protocols/http/main.zeek
@@ -321,7 +321,7 @@ event http_message_done(c: connection, is_orig: bool, stat: http_message_stat) &
}
}
-event connection_state_remove(c: connection) &priority=-5
+event successful_connection_remove(c: connection) &priority=-5
{
# Flush all pending but incomplete request/response pairs.
if ( c?$http_state )
diff --git a/scripts/base/protocols/irc/dcc-send.zeek b/scripts/base/protocols/irc/dcc-send.zeek
index bf5094a4f2..d5eab64b53 100644
--- a/scripts/base/protocols/irc/dcc-send.zeek
+++ b/scripts/base/protocols/irc/dcc-send.zeek
@@ -124,7 +124,7 @@ event scheduled_analyzer_applied(c: connection, a: Analyzer::Tag) &priority=10
add c$service["irc-dcc-data"];
}
-event connection_state_remove(c: connection) &priority=-5
+event successful_connection_remove(c: connection) &priority=-5
{
if ( [c$id$resp_h, c$id$resp_p] in dcc_expected_transfers )
{
diff --git a/scripts/base/protocols/krb/files.zeek b/scripts/base/protocols/krb/files.zeek
index c7dde949f2..1851dd31da 100644
--- a/scripts/base/protocols/krb/files.zeek
+++ b/scripts/base/protocols/krb/files.zeek
@@ -118,7 +118,7 @@ event krb_tgs_response(c: connection, msg: KDC_Response)
fill_in_subjects(c);
}
-event connection_state_remove(c: connection)
+event successful_connection_remove(c: connection)
{
fill_in_subjects(c);
}
diff --git a/scripts/base/protocols/krb/main.zeek b/scripts/base/protocols/krb/main.zeek
index cdcdf48f58..7ca08e1069 100644
--- a/scripts/base/protocols/krb/main.zeek
+++ b/scripts/base/protocols/krb/main.zeek
@@ -228,7 +228,7 @@ event krb_tgs_response(c: connection, msg: KDC_Response) &priority=-5
do_log(c);
}
-event connection_state_remove(c: connection) &priority=-5
+event successful_connection_remove(c: connection) &priority=-5
{
do_log(c);
}
diff --git a/scripts/base/protocols/mysql/main.zeek b/scripts/base/protocols/mysql/main.zeek
index e4c76dd5bc..916de90cc2 100644
--- a/scripts/base/protocols/mysql/main.zeek
+++ b/scripts/base/protocols/mysql/main.zeek
@@ -122,7 +122,7 @@ event mysql_ok(c: connection, affected_rows: count) &priority=-5
}
}
-event connection_state_remove(c: connection) &priority=-5
+event successful_connection_remove(c: connection) &priority=-5
{
if ( c?$mysql )
{
diff --git a/scripts/base/protocols/ntlm/main.zeek b/scripts/base/protocols/ntlm/main.zeek
index 231f90473d..fb10a9868f 100644
--- a/scripts/base/protocols/ntlm/main.zeek
+++ b/scripts/base/protocols/ntlm/main.zeek
@@ -106,7 +106,7 @@ event gssapi_neg_result(c: connection, state: count) &priority=-3
}
}
-event connection_state_remove(c: connection) &priority=-5
+event successful_connection_remove(c: connection) &priority=-5
{
if ( c?$ntlm && ! c$ntlm$done )
{
diff --git a/scripts/base/protocols/radius/main.zeek b/scripts/base/protocols/radius/main.zeek
index bffe996402..4899ac52fb 100644
--- a/scripts/base/protocols/radius/main.zeek
+++ b/scripts/base/protocols/radius/main.zeek
@@ -138,7 +138,7 @@ event radius_message(c: connection, result: RADIUS::Message) &priority=-5
}
}
-event connection_state_remove(c: connection) &priority=-5
+event successful_connection_remove(c: connection) &priority=-5
{
if ( c?$radius && ! c$radius$logged )
{
diff --git a/scripts/base/protocols/rdp/main.zeek b/scripts/base/protocols/rdp/main.zeek
index 11148de27c..2d6fd833f7 100644
--- a/scripts/base/protocols/rdp/main.zeek
+++ b/scripts/base/protocols/rdp/main.zeek
@@ -272,7 +272,7 @@ event protocol_violation(c: connection, atype: Analyzer::Tag, aid: count, reason
write_log(c);
}
-event connection_state_remove(c: connection) &priority=-5
+event successful_connection_remove(c: connection) &priority=-5
{
# If the connection is removed, then log the record immediately.
if ( c?$rdp )
diff --git a/scripts/base/protocols/rfb/main.zeek b/scripts/base/protocols/rfb/main.zeek
index 8217ff8e71..9b7ea61a3e 100644
--- a/scripts/base/protocols/rfb/main.zeek
+++ b/scripts/base/protocols/rfb/main.zeek
@@ -151,7 +151,7 @@ event rfb_share_flag(c: connection, flag: bool) &priority=5
c$rfb$share_flag = flag;
}
-event connection_state_remove(c: connection) &priority=-5
+event successful_connection_remove(c: connection) &priority=-5
{
if ( c?$rfb )
{
diff --git a/scripts/base/protocols/sip/main.zeek b/scripts/base/protocols/sip/main.zeek
index e0647e6494..62bc80b6d2 100644
--- a/scripts/base/protocols/sip/main.zeek
+++ b/scripts/base/protocols/sip/main.zeek
@@ -289,7 +289,7 @@ event sip_end_entity(c: connection, is_request: bool) &priority = -5
}
}
-event connection_state_remove(c: connection) &priority=-5
+event successful_connection_remove(c: connection) &priority=-5
{
if ( c?$sip_state )
{
diff --git a/scripts/base/protocols/smtp/main.zeek b/scripts/base/protocols/smtp/main.zeek
index b13bbadb8d..0d9b4e97ab 100644
--- a/scripts/base/protocols/smtp/main.zeek
+++ b/scripts/base/protocols/smtp/main.zeek
@@ -298,7 +298,7 @@ event mime_one_header(c: connection, h: mime_header_rec) &priority=3
c$smtp$path += ip;
}
-event connection_state_remove(c: connection) &priority=-5
+event successful_connection_remove(c: connection) &priority=-5
{
if ( c?$smtp )
smtp_message(c);
diff --git a/scripts/base/protocols/snmp/main.zeek b/scripts/base/protocols/snmp/main.zeek
index 606d3e9c76..f2ef63743d 100644
--- a/scripts/base/protocols/snmp/main.zeek
+++ b/scripts/base/protocols/snmp/main.zeek
@@ -93,7 +93,7 @@ function init_state(c: connection, h: SNMP::Header): Info
}
-event connection_state_remove(c: connection) &priority=-5
+event successful_connection_remove(c: connection) &priority=-5
{
if ( c?$snmp )
Log::write(LOG, c$snmp);
diff --git a/scripts/base/protocols/socks/main.zeek b/scripts/base/protocols/socks/main.zeek
index 2ca9dfc175..4c2a3996fb 100644
--- a/scripts/base/protocols/socks/main.zeek
+++ b/scripts/base/protocols/socks/main.zeek
@@ -111,7 +111,7 @@ event socks_login_userpass_reply(c: connection, code: count) &priority=5
c$socks$status = v5_status[code];
}
-event connection_state_remove(c: connection)
+event successful_connection_remove(c: connection)
{
# This will handle the case where the analyzer failed in some way and was
# removed. We probably don't want to log these connections.
diff --git a/scripts/base/protocols/ssh/main.zeek b/scripts/base/protocols/ssh/main.zeek
index 293c529b6d..e8f8f25e58 100644
--- a/scripts/base/protocols/ssh/main.zeek
+++ b/scripts/base/protocols/ssh/main.zeek
@@ -247,7 +247,7 @@ event ssh_capabilities(c: connection, cookie: string, capabilities: Capabilities
server_caps$server_host_key_algorithms);
}
-event connection_state_remove(c: connection)
+event successful_connection_remove(c: connection)
{
if ( c?$ssh && !c$ssh$logged )
{
diff --git a/scripts/base/protocols/ssl/main.zeek b/scripts/base/protocols/ssl/main.zeek
index cc656d44b8..2c5e5d796b 100644
--- a/scripts/base/protocols/ssl/main.zeek
+++ b/scripts/base/protocols/ssl/main.zeek
@@ -329,13 +329,13 @@ event ssl_established(c: connection) &priority=-5
finish(c, T);
}
-event connection_state_remove(c: connection) &priority=20
+event successful_connection_remove(c: connection) &priority=20
{
if ( c?$ssl && ! c$ssl$logged )
hook ssl_finishing(c);
}
-event connection_state_remove(c: connection) &priority=-5
+event successful_connection_remove(c: connection) &priority=-5
{
if ( c?$ssl )
# called in case a SSL connection that has not been established terminates
diff --git a/scripts/policy/frameworks/dpd/detect-protocols.zeek b/scripts/policy/frameworks/dpd/detect-protocols.zeek
index 714600f9b2..92929cf051 100644
--- a/scripts/policy/frameworks/dpd/detect-protocols.zeek
+++ b/scripts/policy/frameworks/dpd/detect-protocols.zeek
@@ -182,7 +182,7 @@ event ProtocolDetector::check_connection(c: connection)
}
}
-event connection_state_remove(c: connection)
+event successful_connection_remove(c: connection)
{
if ( c$id !in conns )
{
diff --git a/scripts/policy/protocols/conn/known-services.zeek b/scripts/policy/protocols/conn/known-services.zeek
index 1fe40e1cbc..359e3485df 100644
--- a/scripts/policy/protocols/conn/known-services.zeek
+++ b/scripts/policy/protocols/conn/known-services.zeek
@@ -250,7 +250,7 @@ event protocol_confirmation(c: connection, atype: Analyzer::Tag, aid: count) &pr
}
# Handle the connection ending in case no protocol was ever detected.
-event connection_state_remove(c: connection) &priority=-5
+event successful_connection_remove(c: connection) &priority=-5
{
if ( c$known_services_done )
return;
diff --git a/scripts/policy/protocols/conn/speculative-service.zeek b/scripts/policy/protocols/conn/speculative-service.zeek
index ba1162d809..fc4c4e0c65 100644
--- a/scripts/policy/protocols/conn/speculative-service.zeek
+++ b/scripts/policy/protocols/conn/speculative-service.zeek
@@ -25,7 +25,7 @@ event protocol_late_match(c: connection, atype: Analyzer::Tag)
add c$speculative_service[analyzer];
}
-event connection_state_remove(c: connection)
+event successful_connection_remove(c: connection)
{
local sp_service = "";
for ( s in c$speculative_service )
diff --git a/src/Conn.cc b/src/Conn.cc
index c242d3c9d1..3b9f66347d 100644
--- a/src/Conn.cc
+++ b/src/Conn.cc
@@ -72,6 +72,7 @@ Connection::Connection(NetSessions* s, const ConnIDKey& k, double t, const ConnI
resp_flow_label = 0;
saw_first_orig_packet = 1;
saw_first_resp_packet = 0;
+ is_successful = false;
if ( pkt->l2_src )
memcpy(orig_l2_addr, pkt->l2_src, sizeof(orig_l2_addr));
@@ -204,11 +205,18 @@ void Connection::NextPacket(double t, int is_orig,
if ( root_analyzer )
{
+ auto was_successful = is_successful;
record_current_packet = record_packet;
record_current_content = record_content;
root_analyzer->NextPacket(len, data, is_orig, -1, ip, caplen);
record_packet = record_current_packet;
record_content = record_current_content;
+
+ if ( ConnTransport() != TRANSPORT_TCP )
+ is_successful = true;
+
+ if ( ! was_successful && is_successful && connection_successful )
+ ConnectionEventFast(connection_successful, nullptr, {BuildConnVal()});
}
else
last_time = t;
@@ -300,7 +308,7 @@ void Connection::InactivityTimer(double t)
void Connection::RemoveConnectionTimer(double t)
{
- Event(connection_state_remove, 0);
+ RemovalEvent();
sessions->Remove(this);
}
@@ -396,6 +404,7 @@ RecordVal* Connection::BuildConnVal()
conn_val->Assign(3, new Val(start_time, TYPE_TIME)); // ###
conn_val->Assign(4, new Val(last_time - start_time, TYPE_INTERVAL));
conn_val->Assign(6, new StringVal(history.c_str()));
+ conn_val->Assign(11, val_mgr->GetBool(is_successful));
conn_val->SetOrigin(this);
@@ -448,6 +457,19 @@ void Connection::Match(Rule::PatternType type, const u_char* data, int len, bool
primary_PIA->Match(type, data, len, is_orig, bol, eol, clear_state);
}
+void Connection::RemovalEvent()
+ {
+ auto cv = BuildConnVal();
+
+ if ( connection_state_remove )
+ ConnectionEventFast(connection_state_remove, nullptr, {cv->Ref()});
+
+ if ( is_successful && successful_connection_remove )
+ ConnectionEventFast(successful_connection_remove, nullptr, {cv->Ref()});
+
+ Unref(cv);
+ }
+
void Connection::Event(EventHandlerPtr f, analyzer::Analyzer* analyzer, const char* name)
{
if ( ! f )
diff --git a/src/Conn.h b/src/Conn.h
index fd30f469de..07e669d11f 100644
--- a/src/Conn.h
+++ b/src/Conn.h
@@ -114,6 +114,9 @@ public:
TransportProto ConnTransport() const { return proto; }
+ bool IsSuccessful() const { return is_successful; };
+ void SetSuccessful() { is_successful = true; }
+
// True if we should record subsequent packets (either headers or
// in their entirety, depending on record_contents). We still
// record subsequent SYN/FIN/RST, regardless of how this is set.
@@ -162,6 +165,11 @@ public:
void Match(Rule::PatternType type, const u_char* data, int len,
bool is_orig, bool bol, bool eol, bool clear_state);
+ /**
+ * Generates connection removal event(s).
+ */
+ void RemovalEvent();
+
// If a handler exists for 'f', an event will be generated. If 'name' is
// given that event's first argument will be it, and it's second will be
// the connection value. If 'name' is null, then the event's first
@@ -339,6 +347,7 @@ protected:
unsigned int record_packets:1, record_contents:1;
unsigned int record_current_packet:1, record_current_content:1;
unsigned int saw_first_orig_packet:1, saw_first_resp_packet:1;
+ unsigned int is_successful:1;
// Count number of connections.
static uint64_t total_connections;
diff --git a/src/Sessions.cc b/src/Sessions.cc
index d3042784a0..9ec15841e5 100644
--- a/src/Sessions.cc
+++ b/src/Sessions.cc
@@ -1046,9 +1046,7 @@ void NetSessions::Remove(Connection* c)
}
c->Done();
-
- if ( connection_state_remove )
- c->Event(connection_state_remove, 0);
+ c->RemovalEvent();
// Zero out c's copy of the key, so that if c has been Ref()'d
// up, we know on a future call to Remove() that it's no
@@ -1141,21 +1139,21 @@ void NetSessions::Drain()
{
Connection* tc = entry.second;
tc->Done();
- tc->Event(connection_state_remove, 0);
+ tc->RemovalEvent();
}
for ( const auto& entry : udp_conns )
{
Connection* uc = entry.second;
uc->Done();
- uc->Event(connection_state_remove, 0);
+ uc->RemovalEvent();
}
for ( const auto& entry : icmp_conns )
{
Connection* ic = entry.second;
ic->Done();
- ic->Event(connection_state_remove, 0);
+ ic->RemovalEvent();
}
ExpireTimerMgrs();
diff --git a/src/analyzer/protocol/tcp/TCP.cc b/src/analyzer/protocol/tcp/TCP.cc
index 873f5d6689..543f767a2b 100644
--- a/src/analyzer/protocol/tcp/TCP.cc
+++ b/src/analyzer/protocol/tcp/TCP.cc
@@ -1197,6 +1197,12 @@ void TCP_Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig,
// TCP Fast Open).
CheckPIA_FirstPacket(is_orig, ip);
+ // Note the similar/inverse logic to connection_attempt.
+ if ( resp->state != TCP_ENDPOINT_INACTIVE ||
+ (orig->state != TCP_ENDPOINT_SYN_SENT &&
+ orig->state != TCP_ENDPOINT_SYN_ACK_SENT))
+ Conn()->SetSuccessful();
+
if ( DEBUG_tcp_data_sent )
{
DEBUG_MSG("%.6f before DataSent: len=%d caplen=%d skip=%d\n",
diff --git a/src/analyzer/protocol/tcp/events.bif b/src/analyzer/protocol/tcp/events.bif
index 2450df1828..9c6be2ab38 100644
--- a/src/analyzer/protocol/tcp/events.bif
+++ b/src/analyzer/protocol/tcp/events.bif
@@ -27,6 +27,7 @@ event new_connection_contents%(c: connection%);
## connection_rejected connection_reset connection_reused connection_state_remove
## connection_status_update connection_timeout scheduled_analyzer_applied
## new_connection new_connection_contents partial_connection
+## connection_successful successful_connection_remove
event connection_attempt%(c: connection%);
## Generated when seeing a SYN-ACK packet from the responder in a TCP
@@ -45,6 +46,7 @@ event connection_attempt%(c: connection%);
## connection_rejected connection_reset connection_reused connection_state_remove
## connection_status_update connection_timeout scheduled_analyzer_applied
## new_connection new_connection_contents partial_connection
+## connection_successful successful_connection_remove
event connection_established%(c: connection%);
## Generated for a new active TCP connection if Zeek did not see the initial
diff --git a/src/event.bif b/src/event.bif
index 4618931d28..562144f4fa 100644
--- a/src/event.bif
+++ b/src/event.bif
@@ -143,8 +143,48 @@ event connection_timeout%(c: connection%);
## connection_status_update connection_timeout scheduled_analyzer_applied
## new_connection new_connection_contents partial_connection udp_inactivity_timeout
## tcp_inactivity_timeout icmp_inactivity_timeout conn_stats
+## connection_successful successful_connection_remove
event connection_state_remove%(c: connection%);
+## Like :zeek:see:`connection_state_remove`, but excludes TCP connections
+## that were never established. Removal of such "never established"
+## connections is implied by the :zeek:see:`connection_attempt` event
+## instead. Handlers for this event will run after handlers for
+## :zeek:see:`connection_state_remove`.
+##
+## c: The connection being removed.
+##
+## .. zeek:see:: connection_EOF connection_SYN_packet connection_attempt
+## connection_established connection_external connection_finished
+## connection_first_ACK connection_half_finished connection_partial_close
+## connection_pending connection_rejected connection_reset connection_reused
+## connection_status_update connection_timeout scheduled_analyzer_applied
+## new_connection new_connection_contents partial_connection udp_inactivity_timeout
+## tcp_inactivity_timeout icmp_inactivity_timeout conn_stats connection_state_remove
+## connection_successful
+event successful_connection_remove%(c: connection%);
+
+## Generated for every new connection that is deemed "successful" according to
+## transport-layer-dependent criteria. Zeek uses a flow-based definition of
+## "connection" here that includes not only TCP sessions but also UDP and ICMP
+## flows. For anything except TCP, this event is raised with the first packet
+## of a previously unknown connection. For TCP, this event is raised if the
+## responder host ever sends a packet or if the originator host ever sends a
+## packet that is not a SYN (i.e. the "success" status of a connection can be
+## useful to help weed out SYN scans).
+##
+## c: The new connection.
+##
+## .. zeek:see:: connection_EOF connection_SYN_packet connection_attempt
+## connection_established connection_external connection_finished
+## connection_first_ACK connection_half_finished connection_partial_close
+## connection_pending connection_rejected connection_reset connection_reused
+## connection_status_update connection_timeout scheduled_analyzer_applied
+## new_connection new_connection_contents partial_connection udp_inactivity_timeout
+## tcp_inactivity_timeout icmp_inactivity_timeout conn_stats connection_state_remove
+## successful_connection_remove
+event connection_successful%(c: connection%);
+
## Generated when a connection 4-tuple is reused. This event is raised when Zeek
## sees a new TCP session or UDP flow using a 4-tuple matching that of an
## earlier connection it still considers active.
diff --git a/testing/btest/Baseline/core.connection-successful/http.out b/testing/btest/Baseline/core.connection-successful/http.out
new file mode 100644
index 0000000000..f0c226e7b4
--- /dev/null
+++ b/testing/btest/Baseline/core.connection-successful/http.out
@@ -0,0 +1,4 @@
+connection_established, T
+connection_successful, T
+connection_state_remove, T
+successful_connection_remove, T
diff --git a/testing/btest/Baseline/core.connection-successful/icmp.out b/testing/btest/Baseline/core.connection-successful/icmp.out
new file mode 100644
index 0000000000..72187c9c5b
--- /dev/null
+++ b/testing/btest/Baseline/core.connection-successful/icmp.out
@@ -0,0 +1,3 @@
+connection_successful, T
+connection_state_remove, T
+successful_connection_remove, T
diff --git a/testing/btest/Baseline/core.connection-successful/no-handshake.out b/testing/btest/Baseline/core.connection-successful/no-handshake.out
new file mode 100644
index 0000000000..72187c9c5b
--- /dev/null
+++ b/testing/btest/Baseline/core.connection-successful/no-handshake.out
@@ -0,0 +1,3 @@
+connection_successful, T
+connection_state_remove, T
+successful_connection_remove, T
diff --git a/testing/btest/Baseline/core.connection-successful/syn-synack.out b/testing/btest/Baseline/core.connection-successful/syn-synack.out
new file mode 100644
index 0000000000..f0c226e7b4
--- /dev/null
+++ b/testing/btest/Baseline/core.connection-successful/syn-synack.out
@@ -0,0 +1,4 @@
+connection_established, T
+connection_successful, T
+connection_state_remove, T
+successful_connection_remove, T
diff --git a/testing/btest/Baseline/core.connection-successful/syn.out b/testing/btest/Baseline/core.connection-successful/syn.out
new file mode 100644
index 0000000000..8892d60f4c
--- /dev/null
+++ b/testing/btest/Baseline/core.connection-successful/syn.out
@@ -0,0 +1 @@
+connection_state_remove, F
diff --git a/testing/btest/Baseline/core.connection-successful/udp.out b/testing/btest/Baseline/core.connection-successful/udp.out
new file mode 100644
index 0000000000..72187c9c5b
--- /dev/null
+++ b/testing/btest/Baseline/core.connection-successful/udp.out
@@ -0,0 +1,3 @@
+connection_successful, T
+connection_state_remove, T
+successful_connection_remove, T
diff --git a/testing/btest/Baseline/plugins.hooks/output b/testing/btest/Baseline/plugins.hooks/output
index 187f2b9fcc..face82ab89 100644
--- a/testing/btest/Baseline/plugins.hooks/output
+++ b/testing/btest/Baseline/plugins.hooks/output
@@ -274,7 +274,7 @@
0.000000 MetaHookPost CallFunction(Log::__create_stream, , (Weird::LOG, [columns=Weird::Info, ev=Weird::log_weird, path=weird])) ->
0.000000 MetaHookPost CallFunction(Log::__create_stream, , (X509::LOG, [columns=X509::Info, ev=X509::log_x509, path=x509])) ->
0.000000 MetaHookPost CallFunction(Log::__create_stream, , (mysql::LOG, [columns=MySQL::Info, ev=MySQL::log_mysql, path=mysql])) ->
-0.000000 MetaHookPost CallFunction(Log::__write, , (PacketFilter::LOG, [ts=1572023675.246977, node=zeek, filter=ip or not ip, init=T, success=T])) ->
+0.000000 MetaHookPost CallFunction(Log::__write, , (PacketFilter::LOG, [ts=1573527265.694831, node=zeek, filter=ip or not ip, init=T, success=T])) ->
0.000000 MetaHookPost CallFunction(Log::add_default_filter, , (Broker::LOG)) ->
0.000000 MetaHookPost CallFunction(Log::add_default_filter, , (Cluster::LOG)) ->
0.000000 MetaHookPost CallFunction(Log::add_default_filter, , (Config::LOG)) ->
@@ -455,7 +455,7 @@
0.000000 MetaHookPost CallFunction(Log::create_stream, , (Weird::LOG, [columns=Weird::Info, ev=Weird::log_weird, path=weird])) ->
0.000000 MetaHookPost CallFunction(Log::create_stream, , (X509::LOG, [columns=X509::Info, ev=X509::log_x509, path=x509])) ->
0.000000 MetaHookPost CallFunction(Log::create_stream, , (mysql::LOG, [columns=MySQL::Info, ev=MySQL::log_mysql, path=mysql])) ->
-0.000000 MetaHookPost CallFunction(Log::write, , (PacketFilter::LOG, [ts=1572023675.246977, node=zeek, filter=ip or not ip, init=T, success=T])) ->
+0.000000 MetaHookPost CallFunction(Log::write, , (PacketFilter::LOG, [ts=1573527265.694831, node=zeek, filter=ip or not ip, init=T, success=T])) ->
0.000000 MetaHookPost CallFunction(NetControl::check_plugins, , ()) ->
0.000000 MetaHookPost CallFunction(NetControl::init, , ()) ->
0.000000 MetaHookPost CallFunction(Notice::want_pp, , ()) ->
@@ -1170,7 +1170,7 @@
0.000000 MetaHookPre CallFunction(Log::__create_stream, , (Weird::LOG, [columns=Weird::Info, ev=Weird::log_weird, path=weird]))
0.000000 MetaHookPre CallFunction(Log::__create_stream, , (X509::LOG, [columns=X509::Info, ev=X509::log_x509, path=x509]))
0.000000 MetaHookPre CallFunction(Log::__create_stream, , (mysql::LOG, [columns=MySQL::Info, ev=MySQL::log_mysql, path=mysql]))
-0.000000 MetaHookPre CallFunction(Log::__write, , (PacketFilter::LOG, [ts=1572023675.246977, node=zeek, filter=ip or not ip, init=T, success=T]))
+0.000000 MetaHookPre CallFunction(Log::__write, , (PacketFilter::LOG, [ts=1573527265.694831, node=zeek, filter=ip or not ip, init=T, success=T]))
0.000000 MetaHookPre CallFunction(Log::add_default_filter, , (Broker::LOG))
0.000000 MetaHookPre CallFunction(Log::add_default_filter, , (Cluster::LOG))
0.000000 MetaHookPre CallFunction(Log::add_default_filter, , (Config::LOG))
@@ -1351,7 +1351,7 @@
0.000000 MetaHookPre CallFunction(Log::create_stream, , (Weird::LOG, [columns=Weird::Info, ev=Weird::log_weird, path=weird]))
0.000000 MetaHookPre CallFunction(Log::create_stream, , (X509::LOG, [columns=X509::Info, ev=X509::log_x509, path=x509]))
0.000000 MetaHookPre CallFunction(Log::create_stream, , (mysql::LOG, [columns=MySQL::Info, ev=MySQL::log_mysql, path=mysql]))
-0.000000 MetaHookPre CallFunction(Log::write, , (PacketFilter::LOG, [ts=1572023675.246977, node=zeek, filter=ip or not ip, init=T, success=T]))
+0.000000 MetaHookPre CallFunction(Log::write, , (PacketFilter::LOG, [ts=1573527265.694831, node=zeek, filter=ip or not ip, init=T, success=T]))
0.000000 MetaHookPre CallFunction(NetControl::check_plugins, , ())
0.000000 MetaHookPre CallFunction(NetControl::init, , ())
0.000000 MetaHookPre CallFunction(Notice::want_pp, , ())
@@ -2065,7 +2065,7 @@
0.000000 | HookCallFunction Log::__create_stream(Weird::LOG, [columns=Weird::Info, ev=Weird::log_weird, path=weird])
0.000000 | HookCallFunction Log::__create_stream(X509::LOG, [columns=X509::Info, ev=X509::log_x509, path=x509])
0.000000 | HookCallFunction Log::__create_stream(mysql::LOG, [columns=MySQL::Info, ev=MySQL::log_mysql, path=mysql])
-0.000000 | HookCallFunction Log::__write(PacketFilter::LOG, [ts=1572023675.246977, node=zeek, filter=ip or not ip, init=T, success=T])
+0.000000 | HookCallFunction Log::__write(PacketFilter::LOG, [ts=1573527265.694831, node=zeek, filter=ip or not ip, init=T, success=T])
0.000000 | HookCallFunction Log::add_default_filter(Broker::LOG)
0.000000 | HookCallFunction Log::add_default_filter(Cluster::LOG)
0.000000 | HookCallFunction Log::add_default_filter(Config::LOG)
@@ -2246,7 +2246,7 @@
0.000000 | HookCallFunction Log::create_stream(Weird::LOG, [columns=Weird::Info, ev=Weird::log_weird, path=weird])
0.000000 | HookCallFunction Log::create_stream(X509::LOG, [columns=X509::Info, ev=X509::log_x509, path=x509])
0.000000 | HookCallFunction Log::create_stream(mysql::LOG, [columns=MySQL::Info, ev=MySQL::log_mysql, path=mysql])
-0.000000 | HookCallFunction Log::write(PacketFilter::LOG, [ts=1572023675.246977, node=zeek, filter=ip or not ip, init=T, success=T])
+0.000000 | HookCallFunction Log::write(PacketFilter::LOG, [ts=1573527265.694831, node=zeek, filter=ip or not ip, init=T, success=T])
0.000000 | HookCallFunction NetControl::check_plugins()
0.000000 | HookCallFunction NetControl::init()
0.000000 | HookCallFunction Notice::want_pp()
@@ -2681,7 +2681,7 @@
0.000000 | HookLoadFile base<...>/xmpp
0.000000 | HookLoadFile base<...>/zeek.bif.zeek
0.000000 | HookLogInit packet_filter 1/1 {ts (time), node (string), filter (string), init (bool), success (bool)}
-0.000000 | HookLogWrite packet_filter [ts=1572023675.246977, node=zeek, filter=ip or not ip, init=T, success=T]
+0.000000 | HookLogWrite packet_filter [ts=1573527265.694831, node=zeek, filter=ip or not ip, init=T, success=T]
0.000000 | HookQueueEvent NetControl::init()
0.000000 | HookQueueEvent filter_change_tracking()
0.000000 | HookQueueEvent zeek_init()
@@ -2689,22 +2689,22 @@
1362692526.869344 MetaHookPost CallFunction(ChecksumOffloading::check, , ()) ->
1362692526.869344 MetaHookPost CallFunction(filter_change_tracking, , ()) ->
1362692526.869344 MetaHookPost CallFunction(get_net_stats, , ()) ->
-1362692526.869344 MetaHookPost CallFunction(new_connection, , ([id=[orig_h=141.142.228.5, orig_p=59856<...>/tcp], orig=[size=0, state=0, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=c8:bc:c8:96:d2:a0], resp=[size=0, state=0, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=00:10:db:88:d2:ef], start_time=1362692526.869344, duration=0.0, service={}, history=, uid=CHhAvVGS1DHFjwGM9, tunnel=, vlan=, inner_vlan=, dpd=, dpd_state=, conn=, extract_orig=F, extract_resp=F, thresholds=, dce_rpc=, dce_rpc_state=, dce_rpc_backing=, dhcp=, dnp3=, dns=, dns_state=, ftp=, ftp_data_reuse=F, ssl=, http=, http_state=, irc=, krb=, modbus=, mysql=, ntlm=, ntp=, radius=, rdp=, rfb=, sip=, sip_state=, snmp=, smb_state=, smtp=, smtp_state=, socks=, ssh=, syslog=])) ->
+1362692526.869344 MetaHookPost CallFunction(new_connection, , ([id=[orig_h=141.142.228.5, orig_p=59856<...>/tcp], orig=[size=0, state=0, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=c8:bc:c8:96:d2:a0], resp=[size=0, state=0, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=00:10:db:88:d2:ef], start_time=1362692526.869344, duration=0.0, service={}, history=, uid=CHhAvVGS1DHFjwGM9, tunnel=, vlan=, inner_vlan=, successful=F, dpd=, dpd_state=, conn=, extract_orig=F, extract_resp=F, thresholds=, dce_rpc=, dce_rpc_state=, dce_rpc_backing=, dhcp=, dnp3=, dns=, dns_state=, ftp=, ftp_data_reuse=F, ssl=, http=, http_state=, irc=, krb=, modbus=, mysql=, ntlm=, ntp=, radius=, rdp=, rfb=, sip=, sip_state=, snmp=, smb_state=, smtp=, smtp_state=, socks=, ssh=, syslog=])) ->
1362692526.869344 MetaHookPost DrainEvents() ->
1362692526.869344 MetaHookPost QueueEvent(ChecksumOffloading::check()) -> false
1362692526.869344 MetaHookPost QueueEvent(filter_change_tracking()) -> false
-1362692526.869344 MetaHookPost QueueEvent(new_connection([id=[orig_h=141.142.228.5, orig_p=59856<...>/tcp], orig=[size=0, state=0, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=c8:bc:c8:96:d2:a0], resp=[size=0, state=0, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=00:10:db:88:d2:ef], start_time=1362692526.869344, duration=0.0, service={}, history=, uid=CHhAvVGS1DHFjwGM9, tunnel=, vlan=, inner_vlan=, dpd=, dpd_state=, conn=, extract_orig=F, extract_resp=F, thresholds=, dce_rpc=, dce_rpc_state=, dce_rpc_backing=, dhcp=, dnp3=, dns=, dns_state=, ftp=, ftp_data_reuse=F, ssl=, http=, http_state=, irc=, krb=, modbus=, mysql=, ntlm=, ntp=, radius=, rdp=, rfb=, sip=, sip_state=, snmp=, smb_state=, smtp=, smtp_state=, socks=, ssh=, syslog=])) -> false
+1362692526.869344 MetaHookPost QueueEvent(new_connection([id=[orig_h=141.142.228.5, orig_p=59856<...>/tcp], orig=[size=0, state=0, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=c8:bc:c8:96:d2:a0], resp=[size=0, state=0, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=00:10:db:88:d2:ef], start_time=1362692526.869344, duration=0.0, service={}, history=, uid=CHhAvVGS1DHFjwGM9, tunnel=, vlan=, inner_vlan=, successful=F, dpd=, dpd_state=, conn=, extract_orig=F, extract_resp=F, thresholds=, dce_rpc=, dce_rpc_state=, dce_rpc_backing=, dhcp=, dnp3=, dns=, dns_state=, ftp=, ftp_data_reuse=F, ssl=, http=, http_state=, irc=, krb=, modbus=, mysql=, ntlm=, ntp=, radius=, rdp=, rfb=, sip=, sip_state=, snmp=, smb_state=, smtp=, smtp_state=, socks=, ssh=, syslog=])) -> false
1362692526.869344 MetaHookPost SetupAnalyzerTree(1362692526.869344(1362692526.869344) TCP 141.142.228.5:59856 -> 192.150.187.43:80) ->
1362692526.869344 MetaHookPost UpdateNetworkTime(1362692526.869344) ->
1362692526.869344 MetaHookPre BroObjDtor()
1362692526.869344 MetaHookPre CallFunction(ChecksumOffloading::check, , ())
1362692526.869344 MetaHookPre CallFunction(filter_change_tracking, , ())
1362692526.869344 MetaHookPre CallFunction(get_net_stats, , ())
-1362692526.869344 MetaHookPre CallFunction(new_connection, , ([id=[orig_h=141.142.228.5, orig_p=59856<...>/tcp], orig=[size=0, state=0, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=c8:bc:c8:96:d2:a0], resp=[size=0, state=0, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=00:10:db:88:d2:ef], start_time=1362692526.869344, duration=0.0, service={}, history=, uid=CHhAvVGS1DHFjwGM9, tunnel=, vlan=, inner_vlan=, dpd=, dpd_state=, conn=, extract_orig=F, extract_resp=F, thresholds=, dce_rpc=, dce_rpc_state=, dce_rpc_backing=, dhcp=, dnp3=, dns=, dns_state=, ftp=, ftp_data_reuse=F, ssl=, http=, http_state=, irc=, krb=, modbus=, mysql=, ntlm=, ntp=, radius=, rdp=, rfb=, sip=, sip_state=, snmp=, smb_state=, smtp=, smtp_state=, socks=, ssh=, syslog=]))
+1362692526.869344 MetaHookPre CallFunction(new_connection, , ([id=[orig_h=141.142.228.5, orig_p=59856<...>/tcp], orig=[size=0, state=0, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=c8:bc:c8:96:d2:a0], resp=[size=0, state=0, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=00:10:db:88:d2:ef], start_time=1362692526.869344, duration=0.0, service={}, history=, uid=CHhAvVGS1DHFjwGM9, tunnel=, vlan=, inner_vlan=, successful=F, dpd=, dpd_state=, conn=, extract_orig=F, extract_resp=F, thresholds=, dce_rpc=, dce_rpc_state=, dce_rpc_backing=, dhcp=, dnp3=, dns=, dns_state=, ftp=, ftp_data_reuse=F, ssl=, http=, http_state=, irc=, krb=, modbus=, mysql=, ntlm=, ntp=, radius=, rdp=, rfb=, sip=, sip_state=, snmp=, smb_state=, smtp=, smtp_state=, socks=, ssh=, syslog=]))
1362692526.869344 MetaHookPre DrainEvents()
1362692526.869344 MetaHookPre QueueEvent(ChecksumOffloading::check())
1362692526.869344 MetaHookPre QueueEvent(filter_change_tracking())
-1362692526.869344 MetaHookPre QueueEvent(new_connection([id=[orig_h=141.142.228.5, orig_p=59856<...>/tcp], orig=[size=0, state=0, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=c8:bc:c8:96:d2:a0], resp=[size=0, state=0, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=00:10:db:88:d2:ef], start_time=1362692526.869344, duration=0.0, service={}, history=, uid=CHhAvVGS1DHFjwGM9, tunnel=, vlan=, inner_vlan=, dpd=