summaryrefslogtreecommitdiff
path: root/functions.c
diff options
context:
space:
mode:
authorLuke Bratch <luke@bratch.co.uk>2025-08-11 23:02:08 +0100
committerLuke Bratch <luke@bratch.co.uk>2025-08-11 23:02:08 +0100
commit2a1d4b2e958de1581e9bda7b07b705b963e394a6 (patch)
treedb66b6cd7f3441a244469c57b35dcab65b3f5353 /functions.c
parent0e7f232b3d5ecb484d9d91bdd7e4b6d4e7791585 (diff)
Implement update checking using the command "BLABOUNCER UPDATECHECK", or optionally (enabled by default, toggled with configuration option "checkupdates") at startup and successful client authentication.HEADmaster
This is implemented using a DNS TXT record check to the domain "version.blabouncer.blatech.net".
Diffstat (limited to 'functions.c')
-rw-r--r--functions.c116
1 files changed, 116 insertions, 0 deletions
diff --git a/functions.c b/functions.c
index 54e2663..35be8e4 100644
--- a/functions.c
+++ b/functions.c
@@ -1710,3 +1710,119 @@ void strlower(char *string) {
string[i] = tolower(string[i]);
}
}
+
+// Gets a single TXT record from DNS for "dnsname" and stores the result in "record"
+// Returns 1 on success or 0 on failure
+// TODO: If this is ever used for more than just version checks, then it needs to do more than a single record.
+int gettxtrecordsingle(char *dnsname, char *record) {
+ debugprint(DEBUG_FULL, "gettxtrecordsingle(): given '%s'.\n", dnsname);
+
+ unsigned char buffer[8000] = {0};
+ char result[MAXDNSTXTLEN] = {0};
+ const unsigned char *presult = NULL;
+ struct __res_state resState = {0};
+ ns_msg nsMsg = {0};
+ ns_rr rr;
+
+ int type = 0;
+ int ret = 0;
+ int size = 0;
+ int count = 0;
+ long unsigned int len = 0;
+ int res_init = 0;
+
+ ret = res_ninit(&resState);
+
+ if (ret) {
+ debugprint(DEBUG_CRIT, "gettxtrecordsingle(): res_ninit() returned failure (it returned %d)! Returning 0.\n", ret);
+ return 0;
+ } else {
+ res_init = 1;
+ }
+
+ memset(buffer, 0, sizeof (buffer));
+ size = res_nquery(&resState, dnsname, C_IN, T_TXT, buffer, sizeof(buffer) - 1);
+
+ if (size < 1) {
+ res_nclose(&resState);
+ debugprint(DEBUG_CRIT, "gettxtrecordsingle(): res_nquery() returned zero-length or failure (it returend %d)! Returning 0.\n", size);
+ return 0;
+ }
+
+ ret = ns_initparse(buffer, size, &nsMsg);
+
+ if (ret) {
+ res_nclose(&resState);
+ debugprint(DEBUG_CRIT, "gettxtrecordsingle(): ns_initparse() returned failure (failed to parse the buffer buffer?) (it returned %d)! Returning 0.\n", ret);
+ return 0;
+ }
+
+ count = ns_msg_count(nsMsg, ns_s_an);
+
+ for (int i = 0; i < count; i++) {
+ ret = ns_parserr(&nsMsg, ns_s_an, i , &rr);
+
+ if (ret) {
+ res_nclose(&resState);
+ return 0;
+ }
+
+ type = ns_rr_type(rr);
+ if (ns_t_txt == type) {
+ len = ns_rr_rdlen(rr);
+ presult = ns_rr_rdata(rr);
+
+ if ((len > 1) && (len < sizeof(result))) {
+ len--;
+ memcpy (result, presult+1, len);
+ result[len] = '\0';
+ debugprint(DEBUG_FULL, "gettxtrecordsingle(): record '%d' from DNS is '%s'.\n", i, result);
+
+ // Only using the first result
+ if (i == 0) {
+ strncpy(record, result, sizeof(result) - 1);
+ }
+ }
+ }
+ }
+
+ debugprint(DEBUG_FULL, "gettxtrecordsingle(): using record '%s'.\n", result);
+
+ if (res_init) {
+ res_nclose (&resState);
+ }
+
+ return 1;
+}
+
+// Gets the latest blabouncer version string from DNS and stores it in "version"
+// Ignores the Git version portion (everything after the first '-') of VERSION, if present
+// Returns 1 if local VERSION is current, -1 if local VERSION is not current, or 0 on failure
+int checkversion(char *version) {
+ if (!gettxtrecordsingle(VERSIONTXTNAME, version)) {
+ debugprint(DEBUG_CRIT, "checkversion(): gettxtrecordsingle() failure and the buffer contains '%s', returning 0.\n", version);
+ return 0;
+ } else {
+ debugprint(DEBUG_FULL, "checkversion(): gettxtrecordsingle() success and the returned record is '%s'.\n", version);
+ }
+
+ // Ignore the Git version portion (everything after the first '-') of VERSION, if present
+ char localversion[MAXDNSTXTLEN];
+ strncpy(localversion, VERSION, sizeof(localversion) - 1);
+
+ for (size_t i = 0; i < strlen(localversion); i++) {
+ if (localversion[i] == '-') {
+ localversion[i] = '\0';
+ debugprint(DEBUG_FULL, "checkversion(): Trimmed local VERSION string to '%s'.\n", localversion);
+ break;
+ }
+ }
+
+ if (strncmp(localversion, version, sizeof(localversion))) {
+ debugprint(DEBUG_SOME, "checkversion(): Returned version '%s' doesn't match expected '%s', returning -1.\n", version, localversion);
+ return -1;
+ } else {
+ debugprint(DEBUG_FULL, "checkversion(): Returned version '%s' matches expected '%s', returning 1.\n", version, localversion);
+ return 1;
+ }
+}