Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Differentiate upstream servers by address AND port #923

Merged
merged 2 commits into from
Nov 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/FTL.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@
#define calloc(p1,p2) FTLcalloc(p1,p2, __FILE__, __FUNCTION__, __LINE__)
#define realloc(p1,p2) FTLrealloc(p1,p2, __FILE__, __FUNCTION__, __LINE__)

// Preprocessor help functions
#define str(x) # x
#define xstr(x) str(x)

extern pthread_t telnet_listenthreadv4;
extern pthread_t telnet_listenthreadv6;
extern pthread_t socket_listenthread;
Expand Down
67 changes: 54 additions & 13 deletions src/api/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,7 @@ void getUpstreamDestinations(const char *client_message, const int *sock)
{
float percentage = 0.0f;
const char* ip, *name;
in_port_t upstream_port = 0;

if(i == -2)
{
Expand All @@ -533,26 +534,30 @@ void getUpstreamDestinations(const char *client_message, const int *sock)
}
else
{
// Regular forward destionation
// Regular upstream destination
// Get sorted indices
int upstreamID;
if(sort)
upstreamID = temparray[i][0];
else
upstreamID = i;

// Get forward pointer
const upstreamsData* forward = getUpstream(upstreamID, true);
if(forward == NULL)
// Get upstream pointer
const upstreamsData* upstream = getUpstream(upstreamID, true);
if(upstream == NULL)
continue;

// Get IP and host name of forward destination if available
ip = getstr(forward->ippos);
name = getstr(forward->namepos);
// Get IP and host name of upstream destination if available
ip = getstr(upstream->ippos);
if(upstream->namepos != 0)
name = getstr(upstream->namepos);
else
name = getstr(upstream->ippos);
upstream_port = upstream->port;

// Get percentage
if(totalqueries > 0)
percentage = 1e2f * forward->count / totalqueries;
percentage = 1e2f * upstream->count / totalqueries;
}

// Send data:
Expand All @@ -561,7 +566,11 @@ void getUpstreamDestinations(const char *client_message, const int *sock)
if(percentage > 0.0f || i < 0)
{
if(istelnet[*sock])
ssend(*sock, "%i %.2f %s %s\n", i, percentage, ip, name);
if(upstream_port != 0)
ssend(*sock, "%i %.2f %s#%u %s#%u\n", i, percentage,
ip, upstream_port, name, upstream_port);
else
ssend(*sock, "%i %.2f %s %s\n", i, percentage, ip, name);
else
{
if(!pack_str32(*sock, name) || !pack_str32(*sock, ip))
Expand Down Expand Up @@ -690,6 +699,15 @@ void getAllQueries(const char *client_message, const int *sock)
forwarddestid = -2;
else
{
// Extract address/name and port
char serv_addr[INET6_ADDRSTRLEN] = { 0 };
unsigned int serv_port = 53;
// We limit the number of bytes written into the serv_addr buffer
// to prevent buffer overflows. If there is no port available in
// the database, we skip extracting them and use the default port
sscanf(forwarddest, "%"xstr(INET6_ADDRSTRLEN)"[^#]#%u", serv_addr, &serv_port);
serv_addr[INET6_ADDRSTRLEN-1] = '\0';

// Iterate through all known forward destinations
forwarddestid = -3;
for(int i = 0; i < counters->upstreams; i++)
Expand All @@ -701,9 +719,9 @@ void getAllQueries(const char *client_message, const int *sock)

// Try to match the requested string against their IP addresses and
// (if available) their host names
if(strcmp(getstr(forward->ippos), forwarddest) == 0 ||
if((strcmp(getstr(forward->ippos), serv_addr) == 0 ||
(forward->namepos != 0 &&
strcmp(getstr(forward->namepos), forwarddest) == 0))
strcmp(getstr(forward->namepos), serv_addr) == 0)) && forward->port == serv_port)
{
forwarddestid = i;
break;
Expand Down Expand Up @@ -943,9 +961,28 @@ void getAllQueries(const char *client_message, const int *sock)
regex_idx = dns_cache->black_regex_idx;
}

// Get IP of upstream destination, if applicable
in_port_t upstream_port = 0;
const char *upstream_name = "N/A";
if(query->status == QUERY_FORWARDED)
{
const upstreamsData *upstream = getUpstream(query->upstreamID, true);
if(upstream != NULL)
{
if(upstream->namepos != 0)
// Get upstream destination name if possible
upstream_name = getstr(upstream->namepos);
else
// If we have no name, get the IP address
upstream_name = getstr(upstream->ippos);

upstream_port = upstream->port;
}
}

if(istelnet[*sock])
{
ssend(*sock,"%lli %s %s %s %i %i %i %lu %s %i",
ssend(*sock,"%lli %s %s %s %i %i %i %lu %s %i %s",
(long long)query->timestamp,
qtype,
domain,
Expand All @@ -955,7 +992,11 @@ void getAllQueries(const char *client_message, const int *sock)
query->reply,
delay,
CNAME_domain,
regex_idx);
regex_idx,
upstream_name);
if(upstream_port != 0)
ssend(*sock, "#%u", upstream_port);

if(config.debug & DEBUG_API)
ssend(*sock, " %i", queryID);
ssend(*sock, "\n");
Expand Down
22 changes: 20 additions & 2 deletions src/database/query-table.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
#include "../config.h"
// getstr()
#include "../shmem.h"
// free()
#include "../memory.h"

static bool saving_failed_before = false;

Expand Down Expand Up @@ -143,7 +145,14 @@ void DB_save_queries(void)
{
// Get forward pointer
const upstreamsData* upstream = getUpstream(query->upstreamID, true);
sqlite3_bind_text(stmt, 6, getstr(upstream->ippos), -1, SQLITE_STATIC);
char *buffer = NULL;
if(asprintf(&buffer, "%s#%u", getstr(upstream->ippos), upstream->port) > 0)
sqlite3_bind_text(stmt, 6, buffer, -1, SQLITE_TRANSIENT);
else
sqlite3_bind_null(stmt, 6);

if(buffer != NULL)
free(buffer);
}
else
{
Expand Down Expand Up @@ -389,7 +398,16 @@ void DB_read_queries(void)
(long long)queryTimeStamp);
continue;
}
upstreamID = findUpstreamID(upstream, true);

// Get IP address and port of upstream destination
char serv_addr[INET6_ADDRSTRLEN] = { 0 };
unsigned int serv_port = 53;
// We limit the number of bytes written into the serv_addr buffer
// to prevent buffer overflows. If there is no port available in
// the database, we skip extracting them and use the default port
sscanf(upstream, "%"xstr(INET6_ADDRSTRLEN)"[^#]#%u", serv_addr, &serv_port);
serv_addr[INET6_ADDRSTRLEN-1] = '\0';
upstreamID = findUpstreamID(serv_addr, (in_port_t)serv_port, true);
}

// Obtain IDs only after filtering which queries we want to keep
Expand Down
8 changes: 5 additions & 3 deletions src/datastructure.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ int findQueryID(const int id)
return -1;
}

int findUpstreamID(const char * upstreamString, const bool count)
int findUpstreamID(const char * upstreamString, const in_port_t port, const bool count)
{
// Go through already knows upstream servers and see if we used one of those
for(int upstreamID=0; upstreamID < counters->upstreams; upstreamID++)
Expand All @@ -75,7 +75,7 @@ int findUpstreamID(const char * upstreamString, const bool count)
if(upstream == NULL)
continue;

if(strcmp(getstr(upstream->ippos), upstreamString) == 0)
if(strcmp(getstr(upstream->ippos), upstreamString) == 0 && upstream->port == port)
{
if(count)
{
Expand All @@ -88,7 +88,7 @@ int findUpstreamID(const char * upstreamString, const bool count)
// This upstream server is not known
// Store ID
const int upstreamID = counters->upstreams;
logg("New upstream server: %s (%i/%u)", upstreamString, upstreamID, counters->upstreams_MAX);
logg("New upstream server: %s:%u (%i/%u)", upstreamString, port, upstreamID, counters->upstreams_MAX);

// Check struct size
memory_check(UPSTREAMS);
Expand Down Expand Up @@ -119,6 +119,8 @@ int findUpstreamID(const char * upstreamString, const bool count)
upstream->namepos = 0; // 0 -> string with length zero
// This is a new upstream server
upstream->lastQuery = time(NULL);
// Store port
upstream->port = port;
// Increase counter by one
counters->upstreams++;

Expand Down
3 changes: 2 additions & 1 deletion src/datastructure.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ typedef struct {
typedef struct {
unsigned char magic;
bool new;
in_addr_t port;
int count;
int failed;
size_t ippos;
Expand Down Expand Up @@ -86,7 +87,7 @@ typedef struct {

void strtolower(char *str);
int findQueryID(const int id);
int findUpstreamID(const char * upstream, const bool count);
int findUpstreamID(const char * upstream, const in_port_t port, const bool count);
int findDomainID(const char *domain, const bool count);
int findClientID(const char *client, const bool count);
int findCacheID(int domainID, int clientID, enum query_types query_type);
Expand Down
8 changes: 4 additions & 4 deletions src/dnsmasq/forward.c
Original file line number Diff line number Diff line change
Expand Up @@ -547,14 +547,14 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
(union all_addr *)&start->addr.in.sin_addr, NULL);
FTL_forwarded(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
(union all_addr *)&start->addr.in.sin_addr, daemon->log_display_id);
start, daemon->log_display_id);
}
else
{
log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
(union all_addr *)&start->addr.in6.sin6_addr, NULL);
FTL_forwarded(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
(union all_addr *)&start->addr.in6.sin6_addr, daemon->log_display_id);
start, daemon->log_display_id);
}
start->queries++;
forwarded = 1;
Expand Down Expand Up @@ -2179,14 +2179,14 @@ unsigned char *tcp_request(int confd, time_t now,
log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
(union all_addr *)&last_server->addr.in.sin_addr, NULL);
FTL_forwarded(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
(union all_addr *)&last_server->addr.in.sin_addr, daemon->log_display_id);
last_server, daemon->log_display_id);
}
else
{
log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
(union all_addr *)&last_server->addr.in6.sin6_addr, NULL);
FTL_forwarded(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
(union all_addr *)&last_server->addr.in6.sin6_addr, daemon->log_display_id);
last_server, daemon->log_display_id);
}

#ifdef HAVE_DNSSEC
Expand Down
51 changes: 38 additions & 13 deletions src/dnsmasq_interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,7 @@ bool _FTL_new_query(const unsigned int flags, const char *name,
// subnet (ECS) data), however, we do not rewrite the IPs ::1 and
// 127.0.0.1 to avoid queries originating from localhost of the
// *distant* machine as queries coming from the *local* machine
char clientIP[ADDRSTRLEN] = { 0 };
char clientIP[INET6_ADDRSTRLEN] = { 0 };
if(config.edns0_ecs && edns->client_set)
{
// Use ECS provided client
Expand Down Expand Up @@ -763,27 +763,41 @@ void _FTL_get_blocking_metadata(union all_addr **addrp, unsigned int *flags, con
}
}

void _FTL_forwarded(const unsigned int flags, const char *name, const union all_addr *addr, const int id,
void _FTL_forwarded(const unsigned int flags, const char *name, const struct server *serv, const int id,
const char* file, const int line)
{
// Save that this query got forwarded to an upstream server

// Lock shared memory
lock_shm();

// Get forward destination IP address
// Get forward destination IP address and port
in_port_t upstreamPort = 53;
char dest[ADDRSTRLEN];
// If addr == NULL, we will only duplicate an empty string instead of uninitialized memory
dest[0] = '\0';
if(addr != NULL)
inet_ntop((flags & F_IPV4) ? AF_INET : AF_INET6, addr, dest, ADDRSTRLEN);
if(serv != NULL)
{
if(serv->addr.sa.sa_family == AF_INET)
{
inet_ntop(AF_INET, &serv->addr.in.sin_addr, dest, ADDRSTRLEN);
upstreamPort = ntohs(serv->addr.in.sin_port);
}
else
{
inet_ntop(AF_INET6, &serv->addr.in6.sin6_addr, dest, ADDRSTRLEN);
upstreamPort = ntohs(serv->addr.in6.sin6_port);
}
}

// Convert upstreamIP to lower case
char *upstreamIP = strdup(dest);
strtolower(upstreamIP);

// Debug logging
if(config.debug & DEBUG_QUERIES) logg("**** forwarded %s to %s (ID %i, %s:%i)", name, upstreamIP, id, file, line);
if(config.debug & DEBUG_QUERIES)
logg("**** forwarded %s to %s#%u (ID %i, %s:%i)",
name, upstreamIP, upstreamPort, id, file, line);

// Save status and upstreamID in corresponding query identified by dnsmasq's ID
const int queryID = findQueryID(id);
Expand Down Expand Up @@ -815,7 +829,7 @@ void _FTL_forwarded(const unsigned int flags, const char *name, const union all_

// Get ID of upstream destination, create new upstream record
// if not found in current data structure
const int upstreamID = findUpstreamID(upstreamIP, true);
const int upstreamID = findUpstreamID(upstreamIP, upstreamPort, true);
query->upstreamID = upstreamID;

// Get time index for this query
Expand Down Expand Up @@ -1790,7 +1804,7 @@ void getCacheInformation(const int *sock)
// looked up for the longest time is evicted.
}

void FTL_forwarding_retried(const struct server *server, const int oldID, const int newID, const bool dnssec)
void FTL_forwarding_retried(const struct server *serv, const int oldID, const int newID, const bool dnssec)
{
// Forwarding to upstream server failed

Expand All @@ -1799,17 +1813,28 @@ void FTL_forwarding_retried(const struct server *server, const int oldID, const

// Try to obtain destination IP address if available
char dest[ADDRSTRLEN];
if(server->addr.sa.sa_family == AF_INET)
inet_ntop(AF_INET, &server->addr.in.sin_addr, dest, ADDRSTRLEN);
else
inet_ntop(AF_INET6, &server->addr.in6.sin6_addr, dest, ADDRSTRLEN);
in_port_t upstreamPort = 53;
dest[0] = '\0';
if(serv != NULL)
{
if(serv->addr.sa.sa_family == AF_INET)
{
inet_ntop(AF_INET, &serv->addr.in.sin_addr, dest, ADDRSTRLEN);
upstreamPort = ntohs(serv->addr.in.sin_port);
}
else
{
inet_ntop(AF_INET6, &serv->addr.in6.sin6_addr, dest, ADDRSTRLEN);
upstreamPort = ntohs(serv->addr.in6.sin6_port);
}
}

// Convert upstream to lower case
char *upstreamIP = strdup(dest);
strtolower(upstreamIP);

// Get upstream ID
const int upstreamID = findUpstreamID(upstreamIP, false);
const int upstreamID = findUpstreamID(upstreamIP, upstreamPort, false);

// Possible debugging information
if(config.debug & DEBUG_QUERIES)
Expand Down
4 changes: 2 additions & 2 deletions src/dnsmasq_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ void FTL_next_iface(const char *newiface);
#define FTL_new_query(flags, name, blockingreason, addr, types, qtype, id, edns, proto) _FTL_new_query(flags, name, blockingreason, addr, types, qtype, id, edns, proto, __FILE__, __LINE__)
bool _FTL_new_query(const unsigned int flags, const char *name, const char** blockingreason, const union all_addr *addr, const char *types, const unsigned short qtype, const int id, const struct edns_data *edns, enum protocol proto, const char* file, const int line);

#define FTL_forwarded(flags, name, addr, id) _FTL_forwarded(flags, name, addr, id, __FILE__, __LINE__)
void _FTL_forwarded(const unsigned int flags, const char *name, const union all_addr *addr, const int id, const char* file, const int line);
#define FTL_forwarded(flags, name, serv, id) _FTL_forwarded(flags, name, serv, id, __FILE__, __LINE__)
void _FTL_forwarded(const unsigned int flags, const char *name, const struct server *serv, const int id, const char* file, const int line);

#define FTL_reply(flags, name, addr, id) _FTL_reply(flags, name, addr, id, __FILE__, __LINE__)
void _FTL_reply(const unsigned int flags, const char *name, const union all_addr *addr, const int id, const char* file, const int line);
Expand Down