From cd06fa6674c97516c7a73065239015344aac6488 Mon Sep 17 00:00:00 2001 From: infosec-it-init Date: Thu, 29 Apr 2021 17:55:29 +0200 Subject: [PATCH 1/4] support list of dedicated resolvers/nameservers in domains file --- src/main.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++----- src/massdns.h | 2 ++ src/string.h | 51 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 6 deletions(-) diff --git a/src/main.c b/src/main.c index 6110884..9c833c7 100644 --- a/src/main.c +++ b/src/main.c @@ -388,6 +388,52 @@ buffer_t massdns_resolvers_from_file(char *filename) single_list_free_with_elements(list); return resolvers; } +buffer_t resolvers_from_line(char *line, char **qname) +{ + buffer_t resolvers; + resolvers.len = 0; + resolvers.data = NULL; + char** parts; + char* line_copy = strmcpy(line); + parts = str_split(line_copy, ' '); + char* domain = strmcpy(*parts); + *qname = domain; + // check if there are dedicated resolvers specified in the line + if (*(parts + 1)) + { + single_list_t *list = single_list_new(); + size_t i = 1; + while (*(parts + i)) + { + resolver_t *resolver = safe_calloc(sizeof(*resolver)); + struct sockaddr_storage *addr = &resolver->address; + if (str_to_addr(*(parts + i), 53, addr)) + { + if((addr->ss_family == AF_INET && context.sockets.interfaces4.len > 0) + || (addr->ss_family == AF_INET6 && context.sockets.interfaces6.len > 0)) + { + single_list_push_back(list, resolver); + } + else + { + log_msg("No query socket for dedicated resolver \"%s\" found.\n", *(parts + i)); + } + } + else + { + log_msg("\"%s\" is not a valid resolver. Skipped.\n", *(parts + i)); + } + i++; + } + resolvers = single_list_to_array_copy(list, sizeof(resolver_t)); + single_list_free_with_elements(list); + } + free(line_copy); + free(*parts); + free(parts); + return resolvers; +} + void set_sndbuf(int fd) { @@ -480,9 +526,9 @@ void query_sockets_setup() } } -bool next_query(char **qname) +bool next_query(char **qname, buffer_t *dedicated_resolvers) { - static char line[512]; + static char line[4048]; static size_t line_index = 0; while (fgets(line, sizeof(line), context.domainfile)) @@ -500,8 +546,7 @@ bool next_query(char **qname) { continue; } - *qname = line; - + *dedicated_resolvers = resolvers_from_line(line, qname); return true; } return false; @@ -604,7 +649,12 @@ void send_query(lookup_t *lookup) // Pool of resolvers cannot be empty due to check after parsing resolvers. if(!context.cmd_args.sticky || lookup->resolver == NULL) { - if(context.cmd_args.predictable_resolver) + if(lookup->dedicated_resolvers.len > 0 && lookup->dedicated_resolver_index + 1 < lookup->dedicated_resolvers.len) + { + lookup->resolver = ((resolver_t *) lookup->dedicated_resolvers.data) + lookup->dedicated_resolver_index; + lookup->dedicated_resolver_index++; + } + else if(context.cmd_args.predictable_resolver) { lookup->resolver = ((resolver_t *) context.resolvers.data) + context.lookup_index % context.resolvers.len; } @@ -902,11 +952,12 @@ void done() void can_send() { char *qname; + buffer_t dedicated_resolvers; bool new; while (hashmapSize(context.map) < context.cmd_args.hashmap_size && context.state <= STATE_QUERYING) { - if(!next_query(&qname)) + if(!next_query(&qname, &dedicated_resolvers)) { if(hashmapSize(context.map) <= 0) { @@ -918,6 +969,7 @@ void can_send() } context.stats.numdomains++; lookup_t *lookup = new_lookup(qname, context.cmd_args.record_type, &new); + lookup->dedicated_resolvers = dedicated_resolvers; if(!new) { continue; diff --git a/src/massdns.h b/src/massdns.h index fa74024..b7858a9 100644 --- a/src/massdns.h +++ b/src/massdns.h @@ -85,6 +85,8 @@ typedef struct uint16_t transaction; void **ring_entry; // pointer to the entry within the timed ring for entry invalidation resolver_t *resolver; + buffer_t dedicated_resolvers; + size_t dedicated_resolver_index; lookup_key_t *key; socket_info_t *socket; } lookup_t; diff --git a/src/string.h b/src/string.h index ea6abfe..fdbe5ca 100644 --- a/src/string.h +++ b/src/string.h @@ -178,3 +178,54 @@ size_t json_escape(char *dst, size_t dst_len, const uint8_t *src, size_t src_len #undef json_escape_body #endif + +char** str_split(char* a_str, const char a_delim) +{ + char** result = 0; + size_t count = 0; + char* tmp = a_str; + char* last_comma = 0; + char delim[2]; + delim[0] = a_delim; + delim[1] = 0; + + /* Count how many elements will be extracted. */ + while (*tmp) + { + if (a_delim == *tmp) + { + // count multiple delimiters in a row only once + if (last_comma + 1 < tmp) + { + count++; + } + last_comma = tmp; + } + tmp++; + } + + /* Add space for trailing token. */ + count += last_comma < (a_str + strlen(a_str) - 1); + + /* Add space for terminating null string so caller + knows where the list of returned strings ends. */ + count++; + + result = malloc(sizeof(char*) * count); + + if (result) + { + size_t idx = 0; + char* token = strtok(a_str, delim); + while (token) + { + assert(idx < count); + *(result + idx++) = strmcpy(token); + token = strtok(0, delim); + } + assert(idx == count - 1); + *(result + idx) = 0; + } + + return result; +} From 1b0c09824dc28b41177d3ced8e9e88e9681fd31f Mon Sep 17 00:00:00 2001 From: infosec-it-init Date: Fri, 30 Apr 2021 13:39:11 +0200 Subject: [PATCH 2/4] add dedicated resolvers to hashmap to verify ip --- src/main.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main.c b/src/main.c index 9c833c7..773c55a 100644 --- a/src/main.c +++ b/src/main.c @@ -413,6 +413,16 @@ buffer_t resolvers_from_line(char *line, char **qname) || (addr->ss_family == AF_INET6 && context.sockets.interfaces6.len > 0)) { single_list_push_back(list, resolver); + if (context.cmd_args.verify_ip) + { + errno = 0; + hashmapPut(context.resolver_map, &resolver->address, resolver); + if (errno != 0) + { + log_msg("Error putting resolver into hashmap: %s\n", strerror(errno)); + abort(); + } + } } else { From d01aba1a9687ea4dbfc6214d59e5ca4d21442b96 Mon Sep 17 00:00:00 2001 From: infosec-it-init Date: Fri, 4 Jun 2021 09:01:39 +0200 Subject: [PATCH 3/4] fix resolver index check to not skip last dedicated resolver --- src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index 773c55a..ecb42cc 100644 --- a/src/main.c +++ b/src/main.c @@ -659,7 +659,7 @@ void send_query(lookup_t *lookup) // Pool of resolvers cannot be empty due to check after parsing resolvers. if(!context.cmd_args.sticky || lookup->resolver == NULL) { - if(lookup->dedicated_resolvers.len > 0 && lookup->dedicated_resolver_index + 1 < lookup->dedicated_resolvers.len) + if(lookup->dedicated_resolvers.len > 0 && lookup->dedicated_resolver_index < lookup->dedicated_resolvers.len) { lookup->resolver = ((resolver_t *) lookup->dedicated_resolvers.data) + lookup->dedicated_resolver_index; lookup->dedicated_resolver_index++; From f18a462ae7fc1cad8fe499014c161f3e0bd6602a Mon Sep 17 00:00:00 2001 From: infosec-it-init Date: Wed, 9 Jun 2021 13:59:57 +0200 Subject: [PATCH 4/4] fix: check for null lookup before setting resolvers per entry --- src/main.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index ecb42cc..2f1ad58 100644 --- a/src/main.c +++ b/src/main.c @@ -979,7 +979,10 @@ void can_send() } context.stats.numdomains++; lookup_t *lookup = new_lookup(qname, context.cmd_args.record_type, &new); - lookup->dedicated_resolvers = dedicated_resolvers; + if (lookup != NULL) + { + lookup->dedicated_resolvers = dedicated_resolvers; + } if(!new) { continue;