diff --git a/src/args.c b/src/args.c
index 085b633a..c9bcbe15 100644
--- a/src/args.c
+++ b/src/args.c
@@ -555,7 +555,7 @@ void parse_args(int argc, char* argv[])
{
// Enable stdout printing
cli_mode = true;
- const bool match = verify_self_hash(true);
+ const bool match = verify_FTL(true);
if(match)
printf("%s SHA256 checksum matches\n", cli_tick());
else
diff --git a/src/database/message-table.c b/src/database/message-table.c
index 409d151b..a563a939 100644
--- a/src/database/message-table.c
+++ b/src/database/message-table.c
@@ -31,6 +31,8 @@
#include "database/query-table.h"
// escape_html()
#include "webserver/http-common.h"
+// GIT_HASH, FTL_ARCH
+#include "version.h"
// Number of arguments in a variadic macro
// Credit: https://stackoverflow.com/a/35693080/2087442
@@ -99,6 +101,8 @@ static const char *get_message_type_str(const enum message_type type)
return "CONNECTION_ERROR";
case NTP_MESSAGE:
return "NTP";
+ case VERIFY_MESSAGE:
+ return "VERIFY";
case MAX_MESSAGE:
default:
return "UNKNOWN";
@@ -135,6 +139,8 @@ static enum message_type get_message_type_from_string(const char *typestr)
return CONNECTION_ERROR_MESSAGE;
else if (strcmp(typestr, "NTP") == 0)
return NTP_MESSAGE;
+ else if (strcmp(typestr, "VERIFY") == 0)
+ return VERIFY_MESSAGE;
else
return MAX_MESSAGE;
}
@@ -242,6 +248,14 @@ static unsigned char message_blob_types[MAX_MESSAGE][5] =
SQLITE_NULL, // not used
SQLITE_NULL, // not used
SQLITE_NULL // not used
+ },
+ {
+ // VERIFY_MESSAGE: The message column contains the error
+ SQLITE_TEXT, // expected checksum
+ SQLITE_TEXT, // actual checksum
+ SQLITE_TEXT, // FTL commit hash
+ SQLITE_TEXT, // FTL architecture
+ SQLITE_NULL // not used
}
};
// Create message table in the database
@@ -928,6 +942,39 @@ static void format_ntp_message(char *plain, const int sizeof_plain, char *html,
log_warn("format_ntp_message(): Buffer too small to hold HTML message, warning truncated");
}
+static void format_verify_message(char *plain, const int sizeof_plain, char *html, const int sizeof_html,
+ const char *message, const char *expected, const char *actual,
+ const char *commit, const char *arch)
+{
+ if(snprintf(plain, sizeof_plain, "%s - expected \"%s\", but got \"%s\" - FTL commit is %s on %s",
+ message, expected, actual, commit, arch) > sizeof_plain)
+ log_warn("format_verify_message(): Buffer too small to hold plain message, warning truncated");
+
+ // Return early if HTML text is not required
+ if(sizeof_html < 1 || html == NULL)
+ return;
+
+ char *escaped_message = escape_html(message);
+ char *escaped_expected = escape_html(expected);
+ char *escaped_actual = escape_html(actual);
+ char *escaped_commit = escape_html(commit);
+ char *escaped_arch = escape_html(arch);
+
+ // Return early if memory allocation failed
+ if(escaped_message == NULL || escaped_expected == NULL || escaped_actual == NULL || escaped_commit == NULL || escaped_arch == NULL)
+ return;
+
+ if(snprintf(html, sizeof_html, "%s
Expected:
%s
%s
%s on %s",
+ escaped_message, escaped_expected, escaped_actual, escaped_commit, escaped_arch) > sizeof_html)
+ log_warn("format_verify_message(): Buffer too small to hold HTML message, warning truncated");
+
+ free(escaped_message);
+ free(escaped_expected);
+ free(escaped_actual);
+ free(escaped_commit);
+ free(escaped_arch);
+}
+
int count_messages(const bool filter_dnsmasq_warnings)
{
int count = 0;
@@ -1187,6 +1234,20 @@ bool format_messages(cJSON *array)
break;
}
+ case VERIFY_MESSAGE:
+ {
+ const char *message = (const char*)sqlite3_column_text(stmt, 3);
+ const char *expected = (const char*)sqlite3_column_text(stmt, 4);
+ const char *actual = (const char*)sqlite3_column_text(stmt, 5);
+ const char *hash = (const char*)sqlite3_column_text(stmt, 6);
+ const char *arch = (const char*)sqlite3_column_text(stmt, 7);
+
+ format_verify_message(plain, sizeof(plain), html, sizeof(html),
+ message, expected, actual, hash, arch);
+
+ break;
+ }
+
case MAX_MESSAGE: // Fall through
default:
log_warn("format_messages() - Unknown message type: %s", mtypestr);
@@ -1458,3 +1519,17 @@ void log_ntp_message(const bool error, const bool server, const char *message)
add_message(NTP_MESSAGE, message, level, who);
}
+
+void log_verify_message(const char *expected, const char *actual)
+{
+ // Create message
+ char buf[2048];
+ snprintf(buf, sizeof(buf), "Corrupt binary detected - this may lead to unexpected behaviour!");
+
+ // Log to FTL.log
+ log_crit("%s", buf);
+
+ // Log to database
+ add_message(VERIFY_MESSAGE, buf, expected, actual, GIT_HASH, FTL_ARCH);
+
+}
diff --git a/src/database/message-table.h b/src/database/message-table.h
index 5354af6f..d230f066 100644
--- a/src/database/message-table.h
+++ b/src/database/message-table.h
@@ -31,5 +31,6 @@ void logg_inaccessible_adlist(const int dbindex, const char *address);
void log_certificate_domain_mismatch(const char *certfile, const char *domain);
void log_connection_error(const char *server, const char *reason, const char *error);
void log_ntp_message(const bool error, const bool server, const char *message);
+void log_verify_message(const char *expected, const char *actual);
#endif //MESSAGETABLE_H
diff --git a/src/dnsmasq_interface.c b/src/dnsmasq_interface.c
index 362eb1bb..9eec8cda 100644
--- a/src/dnsmasq_interface.c
+++ b/src/dnsmasq_interface.c
@@ -3130,6 +3130,12 @@ void FTL_fork_and_bind_sockets(struct passwd *ent_pw, bool dnsmasq_start)
// Flush messages stored in the long-term database
flush_message_table();
+ // Verify checksum of this binary early on to ensure that the binary is
+ // not corrupted and that the binary is not tampered with. We can only
+ // do this here as we need the database to be properly initialized
+ // in case we need to store the verification result
+ verify_FTL(false);
+
// Initialize in-memory database starting index
update_disk_db_idx();
diff --git a/src/enums.h b/src/enums.h
index e748562c..1dd8c929 100644
--- a/src/enums.h
+++ b/src/enums.h
@@ -264,6 +264,7 @@ enum message_type {
CERTIFICATE_DOMAIN_MISMATCH_MESSAGE,
CONNECTION_ERROR_MESSAGE,
NTP_MESSAGE,
+ VERIFY_MESSAGE,
MAX_MESSAGE,
} __attribute__ ((packed));
diff --git a/src/files.c b/src/files.c
index 9e934b13..98834f19 100644
--- a/src/files.c
+++ b/src/files.c
@@ -15,6 +15,8 @@
#include "log.h"
// sha256_raw_to_hex()
#include "config/password.h"
+// log_verify_message()
+#include "database/message-table.h"
// opendir(), readdir()
#include