diff options
Diffstat (limited to 'functions.c')
-rw-r--r-- | functions.c | 124 |
1 files changed, 121 insertions, 3 deletions
diff --git a/functions.c b/functions.c index 8ef2b21..35be8e4 100644 --- a/functions.c +++ b/functions.c @@ -1596,7 +1596,7 @@ int isnickinanychannel(struct channel *channels, int maxchannelcount, char *nick return 0; } -// Populate our channels struct with all nicks in a RPL_NAMREPLY +// Populate our channels struct with all nicks in a 353 RPL_NAMREPLY // Returns 1 on success or 0 on failure int addnamereplytochannel(char *namereply, struct channel *channels, int maxchannelcount) { //:irc.tghost.co.uk 353 blabounce = #blabouncer :blabounce bbnick ~@l_bratch @l_blabnc Hughbla Bratchbot ars @@ -1609,10 +1609,12 @@ int addnamereplytochannel(char *namereply, struct channel *channels, int maxchan // Strip the leading ':' stripprefix(strcopy, 1); - // Find the start of the channel name, which comes after the first '=' followed by a space + // Find the start of the channel name, which comes after the first '=', '*', or '@', followed by a space + // From RFC 2812: + // "@" is used for secret channels, "*" for private channels, and "=" for others (public channels). int channelpos = -1; for (size_t i = 0; i < strlen(strcopy) - 2; i++) { - if (strcopy[i] == '=' && strcopy[i + 1] == ' ' && strcopy[i + 2] != '\0') { + if ((strcopy[i] == '=' || strcopy[i] == '*' || strcopy[i] == '@') && strcopy[i + 1] == ' ' && strcopy[i + 2] != '\0') { // Name found channelpos = i + 2; break; @@ -1708,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; + } +} |