diff --git a/cf-serverd/cf-serverd-enterprise-stubs.c b/cf-serverd/cf-serverd-enterprise-stubs.c
index e45ca0b4a5..a9698eefdc 100644
--- a/cf-serverd/cf-serverd-enterprise-stubs.c
+++ b/cf-serverd/cf-serverd-enterprise-stubs.c
@@ -106,6 +106,11 @@ ENTERPRISE_VOID_FUNC_0ARG_DEFINE_STUB(void, CollectCallMarkProcessed)
{
}
+ENTERPRISE_VOID_FUNC_1ARG_DEFINE_STUB(void, NotifyNewHostSeen,
+ ARG_UNUSED const char *, hostkey)
+{
+}
+
ENTERPRISE_VOID_FUNC_1ARG_DEFINE_STUB(void, FprintAvahiCfengineTag, FILE *, fp)
{
fprintf(fp,"CFEngine Community %s Policy Server on %s \n", Version(), "%h");
diff --git a/cf-serverd/cf-serverd-enterprise-stubs.h b/cf-serverd/cf-serverd-enterprise-stubs.h
index c3159b3aa7..a462ba5d17 100644
--- a/cf-serverd/cf-serverd-enterprise-stubs.h
+++ b/cf-serverd/cf-serverd-enterprise-stubs.h
@@ -50,6 +50,8 @@ ENTERPRISE_VOID_FUNC_0ARG_DECLARE(void, CleanReportBookFilterSet);
ENTERPRISE_VOID_FUNC_1ARG_DECLARE(void, FprintAvahiCfengineTag, FILE *, fp);
+ENTERPRISE_VOID_FUNC_1ARG_DECLARE(void, NotifyNewHostSeen, const char *, hostkey);
+
ENTERPRISE_VOID_FUNC_1ARG_DECLARE(void, CollectCallStart, ARG_UNUSED int, interval);
ENTERPRISE_VOID_FUNC_0ARG_DECLARE(void, CollectCallStop);
ENTERPRISE_FUNC_0ARG_DECLARE(bool, CollectCallHasPending);
diff --git a/cf-serverd/server_tls.c b/cf-serverd/server_tls.c
index edc185237b..456da6c088 100644
--- a/cf-serverd/server_tls.c
+++ b/cf-serverd/server_tls.c
@@ -423,9 +423,9 @@ bool ServerSendWelcome(const ServerConnectionState *conn)
"USERNAME", conn->username);
if (ret < 0)
{
- Log(LOG_LEVEL_ERR,
+ Log(LOG_LEVEL_ERR,
"Unexpected failure from snprintf (%d - %s) while "
- "constructing OK WELCOME message (ServerSendWelcome)",
+ "constructing OK WELCOME message (ServerSendWelcome)",
errno, GetErrorStr());
return false;
}
@@ -537,6 +537,8 @@ bool BasicServerTLSSessionEstablish(ServerConnectionState *conn, SSL_CTX *ssl_ct
*/
bool ServerTLSSessionEstablish(ServerConnectionState *conn, SSL_CTX *ssl_ctx)
{
+ assert (conn != NULL);
+
if (conn->conn_info->status == CONNECTIONINFO_STATUS_ESTABLISHED)
{
return true;
@@ -608,8 +610,13 @@ bool ServerTLSSessionEstablish(ServerConnectionState *conn, SSL_CTX *ssl_ctx)
conn->user_data_set = true;
conn->rsa_auth = true;
- LastSaw1(conn->ipaddr, KeyPrintableHash(ConnectionInfoKey(conn->conn_info)),
- LAST_SEEN_ROLE_ACCEPT);
+ const char *hostkey = KeyPrintableHash(ConnectionInfoKey(conn->conn_info));
+ bool is_new_host = LastSaw1(conn->ipaddr, hostkey, LAST_SEEN_ROLE_ACCEPT);
+ if (is_new_host)
+ {
+ /* This will trigger immediate report collection */
+ NotifyNewHostSeen(hostkey);
+ }
ServerSendWelcome(conn);
return true;
diff --git a/libpromises/lastseen.c b/libpromises/lastseen.c
index 34f848e6cd..18da29f791 100644
--- a/libpromises/lastseen.c
+++ b/libpromises/lastseen.c
@@ -34,7 +34,7 @@
#include
#endif
-void UpdateLastSawHost(const char *hostkey, const char *address,
+bool UpdateLastSawHost(const char *hostkey, const char *address,
bool incoming, time_t timestamp);
/*
@@ -80,40 +80,40 @@ void UpdateLastSawHost(const char *hostkey, const char *address,
* @brief Same as LastSaw() but the digest parameter is the hash as a
* "SHA=..." string, to avoid converting twice.
*/
-void LastSaw1(const char *ipaddress, const char *hashstr,
+bool LastSaw1(const char *ipaddress, const char *hashstr,
LastSeenRole role)
{
const char *mapip = MapAddress(ipaddress);
- UpdateLastSawHost(hashstr, mapip, role == LAST_SEEN_ROLE_ACCEPT, time(NULL));
+ return UpdateLastSawHost(hashstr, mapip, role == LAST_SEEN_ROLE_ACCEPT, time(NULL));
}
-void LastSaw(const char *ipaddress, const unsigned char *digest, LastSeenRole role)
+bool LastSaw(const char *ipaddress, const unsigned char *digest, LastSeenRole role)
{
char databuf[CF_HOSTKEY_STRING_SIZE];
if (strlen(ipaddress) == 0)
{
Log(LOG_LEVEL_INFO, "LastSeen registry for empty IP with role %d", role);
- return;
+ return false;
}
HashPrintSafe(databuf, sizeof(databuf), digest, CF_DEFAULT_DIGEST, true);
const char *mapip = MapAddress(ipaddress);
- UpdateLastSawHost(databuf, mapip, role == LAST_SEEN_ROLE_ACCEPT, time(NULL));
+ return UpdateLastSawHost(databuf, mapip, role == LAST_SEEN_ROLE_ACCEPT, time(NULL));
}
/*****************************************************************************/
-void UpdateLastSawHost(const char *hostkey, const char *address,
+bool UpdateLastSawHost(const char *hostkey, const char *address,
bool incoming, time_t timestamp)
{
DBHandle *db = NULL;
if (!OpenDB(&db, dbid_lastseen))
{
Log(LOG_LEVEL_ERR, "Unable to open last seen db");
- return;
+ return false;
}
/* Update quality-of-connection entry */
@@ -127,7 +127,8 @@ void UpdateLastSawHost(const char *hostkey, const char *address,
};
KeyHostSeen q;
- if (ReadDB(db, quality_key, &q, sizeof(q)))
+ bool host_existed = ReadDB(db, quality_key, &q, sizeof(q));
+ if (host_existed)
{
newq.Q = QAverage(q.Q, newq.lastseen - q.lastseen, 0.4);
}
@@ -153,6 +154,7 @@ void UpdateLastSawHost(const char *hostkey, const char *address,
WriteDB(db, address_key, hostkey, strlen(hostkey) + 1);
CloseDB(db);
+ return !host_existed;
}
/*****************************************************************************/
diff --git a/libpromises/lastseen.h b/libpromises/lastseen.h
index 786c2cb5ed..68484a3559 100644
--- a/libpromises/lastseen.h
+++ b/libpromises/lastseen.h
@@ -44,8 +44,13 @@ typedef enum
bool Address2Hostkey(char *dst, size_t dst_size, const char *address);
char *HostkeyToAddress(const char *hostkey);
-void LastSaw1(const char *ipaddress, const char *hashstr, LastSeenRole role);
-void LastSaw(const char *ipaddress, const unsigned char *digest, LastSeenRole role);
+/**
+ * @brief Record a host connection in the lastseen database.
+ * @return true if this is the first time the host has been seen (new host),
+ * false if the host was already known.
+ */
+bool LastSaw1(const char *ipaddress, const char *hashstr, LastSeenRole role);
+bool LastSaw(const char *ipaddress, const unsigned char *digest, LastSeenRole role);
bool DeleteIpFromLastSeen(const char *ip, char *digest, size_t digest_size);
bool DeleteDigestFromLastSeen(const char *key, char *ip, size_t ip_size, bool a_entry_required);
diff --git a/tests/load/lastseen_load.c b/tests/load/lastseen_load.c
index 9d76edabd9..7738c21a58 100644
--- a/tests/load/lastseen_load.c
+++ b/tests/load/lastseen_load.c
@@ -21,7 +21,7 @@ static void tests_setup(void)
mkdir(GetStateDir(), (S_IRWXU | S_IRWXG | S_IRWXO));
}
-void UpdateLastSawHost(const char *hostkey, const char *address,
+bool UpdateLastSawHost(const char *hostkey, const char *address,
bool incoming, time_t timestamp);
int main()
diff --git a/tests/load/lastseen_threaded_load.c b/tests/load/lastseen_threaded_load.c
index 631c66c8bb..cf92a32276 100644
--- a/tests/load/lastseen_threaded_load.c
+++ b/tests/load/lastseen_threaded_load.c
@@ -35,7 +35,7 @@ pthread_mutex_t end_mtx = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
pthread_cond_t end_cond = PTHREAD_COND_INITIALIZER;
-void UpdateLastSawHost(const char *hostkey, const char *address,
+bool UpdateLastSawHost(const char *hostkey, const char *address,
bool incoming, time_t timestamp);
diff --git a/tests/unit/lastseen_test.c b/tests/unit/lastseen_test.c
index 4f710bd073..833a46c7ad 100644
--- a/tests/unit/lastseen_test.c
+++ b/tests/unit/lastseen_test.c
@@ -10,7 +10,7 @@
char CFWORKDIR[CF_BUFSIZE];
-void UpdateLastSawHost(const char *hostkey, const char *address,
+bool UpdateLastSawHost(const char *hostkey, const char *address,
bool incoming, time_t timestamp);
/* For abbreviation of tests. */