make locally resolved DNS domains configurable through host_domain pref (multi allowed); also match exact domain

This commit is contained in:
rakslice 2020-11-14 02:23:42 -08:00
parent a453ae105a
commit a1ef6be18a
7 changed files with 121 additions and 24 deletions

View File

@ -48,6 +48,7 @@ extern void PrefsReplaceBool(const char *name, bool b);
extern void PrefsReplaceInt32(const char *name, int32 val); extern void PrefsReplaceInt32(const char *name, int32 val);
extern const char *PrefsFindString(const char *name, int index = 0); extern const char *PrefsFindString(const char *name, int index = 0);
extern "C" const char *PrefsFindStringC(const char *name, int index = 0);
extern bool PrefsFindBool(const char *name); extern bool PrefsFindBool(const char *name);
extern int32 PrefsFindInt32(const char *name); extern int32 PrefsFindInt32(const char *name);

View File

@ -328,6 +328,11 @@ const char *PrefsFindString(const char *name, int index)
return NULL; return NULL;
} }
extern "C" const char *PrefsFindStringC(const char *name, int index)
{
return PrefsFindString(name, index);
}
bool PrefsFindBool(const char *name) bool PrefsFindBool(const char *name)
{ {
prefs_node *p = find_node(name, TYPE_BOOLEAN, 0); prefs_node *p = find_node(name, TYPE_BOOLEAN, 0);

View File

@ -81,6 +81,7 @@ prefs_desc common_prefs_items[] = {
{"gammaramp", TYPE_STRING, false, "gamma ramp (on, off or fullscreen)"}, {"gammaramp", TYPE_STRING, false, "gamma ramp (on, off or fullscreen)"},
{"swap_opt_cmd", TYPE_BOOLEAN, false, "swap option and command key"}, {"swap_opt_cmd", TYPE_BOOLEAN, false, "swap option and command key"},
{"ignoresegv", TYPE_BOOLEAN, false, "ignore illegal memory accesses"}, {"ignoresegv", TYPE_BOOLEAN, false, "ignore illegal memory accesses"},
{"host_domain", TYPE_STRING, true, "handle DNS requests for this domain on the host (slirp only)"},
{NULL, TYPE_END, false, NULL} // End of list {NULL, TYPE_END, false, NULL} // End of list
}; };

View File

@ -127,6 +127,7 @@ static int get_dns_addr(struct in_addr *pdns_addr)
void slirp_cleanup(void) void slirp_cleanup(void)
{ {
WSACleanup(); WSACleanup();
unload_host_domains();
} }
#endif #endif
@ -134,6 +135,8 @@ int slirp_init(void)
{ {
// debug_init("/tmp/slirp.log", DEBUG_DEFAULT); // debug_init("/tmp/slirp.log", DEBUG_DEFAULT);
load_host_domains();
#ifdef _WIN32 #ifdef _WIN32
{ {
WSADATA Data; WSADATA Data;

View File

@ -370,6 +370,9 @@ int tcp_emu _P((struct socket *, struct mbuf *));
int tcp_ctl _P((struct socket *)); int tcp_ctl _P((struct socket *));
struct tcpcb *tcp_drop(struct tcpcb *tp, int err); struct tcpcb *tcp_drop(struct tcpcb *tp, int err);
void load_host_domains();
void unload_host_domains();
#ifdef USE_PPP #ifdef USE_PPP
#define MIN_MRU MINMRU #define MIN_MRU MINMRU
#define MAX_MRU MAXMRU #define MAX_MRU MAXMRU

View File

@ -13,6 +13,8 @@
#ifdef __sun__ #ifdef __sun__
#include <sys/filio.h> #include <sys/filio.h>
#endif #endif
#include <assert.h>
#include <stdbool.h>
#define DEBUG_HOST_RESOLVED_DNS 0 #define DEBUG_HOST_RESOLVED_DNS 0
@ -21,12 +23,9 @@
* looked up on the host to allow for host-supported DNS alternatives * looked up on the host to allow for host-supported DNS alternatives
* (e.g. MDNS, hosts file, etc.) * (e.g. MDNS, hosts file, etc.)
**/ **/
static const char * host_resolved_domain_suffixes[] = { static const char ** host_resolved_domain_suffixes = NULL;
".local.",
NULL // list ending
};
#define DOT_LOCAL_TTL 60 // In seconds. Keep this short as data is very dynamic and requerying is cheap #define HOST_DOMAIN_TTL 60 // In seconds.
#if DEBUG_HOST_RESOLVED_DNS #if DEBUG_HOST_RESOLVED_DNS
#define D(...) printf(__VA_ARGS__); fflush(stdout); #define D(...) printf(__VA_ARGS__); fflush(stdout);
@ -34,6 +33,81 @@ static const char * host_resolved_domain_suffixes[] = {
#define D(...) #define D(...)
#endif #endif
const char *PrefsFindStringC(const char *name, int index);
int prepare_host_domain_suffixes(char * buf) {
/**
* Set up the list of domain suffixes to match from the host_domain prefs.
* Call first with buf NULL to figure out the size of buffer needed.
**/
int pos = 0;
const char ** host_resolved_domain_suffixes_pos = NULL;
if (buf) {
D("Setting up slirp host domain suffixes for matching:\n");
host_resolved_domain_suffixes_pos = (const char **) buf;
}
// find out how many values there are
int host_domain_count = 0;
while (PrefsFindStringC("host_domain", host_domain_count) != NULL) {
host_domain_count ++;
}
// leave space for the top array
pos += (host_domain_count + 1) * sizeof(const char *);
const char *str;
int host_domain_num = 0;
while ((str = PrefsFindStringC("host_domain", host_domain_num++)) != NULL) {
if (str[0] == '\0') continue;
if (buf) {
const char * cur_entry = (const char *) (buf + pos);
*host_resolved_domain_suffixes_pos = cur_entry;
host_resolved_domain_suffixes_pos++;
}
// this is a suffix to match so it must have a leading dot
if (str[0] != '.') {
if (buf) buf[pos] = '.';
pos++;
}
if (buf) strcpy(buf + pos, str);
pos += strlen(str);
// domain to be checked will be FQDN so suffix must have a trailing dot
if (str[strlen(str) - 1] != '.') {
if (buf) buf[pos] = '.';
pos++;
}
if (buf) {
buf[pos] = '\0';
D(" %d. %s\n", host_domain_num, *(host_resolved_domain_suffixes_pos-1));
}
pos++;
}
// end of list marker
if (buf) *host_resolved_domain_suffixes_pos = NULL;
return pos;
}
void load_host_domains() {
const int size = prepare_host_domain_suffixes(NULL);
char * buf = malloc(size);
if (buf) {
prepare_host_domain_suffixes(buf);
host_resolved_domain_suffixes = (const char **) buf;
}
}
void unload_host_domains() {
if (host_resolved_domain_suffixes) {
free((char *) host_resolved_domain_suffixes);
host_resolved_domain_suffixes = NULL;
}
}
void void
so_init() so_init()
{ {
@ -602,17 +676,17 @@ static char * decode_dns_name(char * data) {
} }
/** Take a look at a UDP DNS request the client has made and see if we want to resolve it internally. /** Take a look at a UDP DNS request the client has made and see if we want to resolve it internally.
* Returns TRUE if the request has been internally and can be dropped, * Returns true if the request has been internally and can be dropped,
* FALSE otherwise * false otherwise
**/ **/
static BOOL resolve_dns_request(struct socket * so, struct sockaddr_in addr, caddr_t data, int len) { static bool resolve_dns_request(struct socket * so, struct sockaddr_in addr, caddr_t data, int len) {
BOOL drop_dns_request = FALSE; bool drop_dns_request = false;
D("Checking outgoing DNS UDP packet\n"); D("Checking outgoing DNS UDP packet\n");
if (len < sizeof(struct DNS_HEADER)) { if (len < sizeof(struct DNS_HEADER)) {
D("Packet too short for DNS header\n"); D("Packet too short for DNS header\n");
return FALSE; return false;
} }
const caddr_t packet = data; const caddr_t packet = data;
@ -622,40 +696,40 @@ static BOOL resolve_dns_request(struct socket * so, struct sockaddr_in addr, cad
if (h.qr != 0) { if (h.qr != 0) {
D("DNS packet is not a request\n"); D("DNS packet is not a request\n");
return FALSE; return false;
} }
if (ntohs(h.q_count) == 0) { if (ntohs(h.q_count) == 0) {
D("DNS request has no queries\n"); D("DNS request has no queries\n");
return FALSE; return false;
} }
if (ntohs(h.q_count) > 1) { if (ntohs(h.q_count) > 1) {
D("DNS request has multiple queries (not supported)\n"); D("DNS request has multiple queries (not supported)\n");
return FALSE; return false;
} }
if (ntohs(h.ans_count != 0) || ntohs(h.auth_count != 0) || ntohs(h.add_count != 0)) { if (ntohs(h.ans_count != 0) || ntohs(h.auth_count != 0) || ntohs(h.add_count != 0)) {
D("DNS request has unsupported extra contents\n"); D("DNS request has unsupported extra contents\n");
return FALSE; return false;
} }
if (len == 0) { if (len == 0) {
D("Packet too short for DNS query string\n"); D("Packet too short for DNS query string\n");
return FALSE; return false;
} }
char * original_query_str = data; char * original_query_str = data;
int query_str_len = strnlen(data, len); int query_str_len = strnlen(data, len);
if (query_str_len == len) { // went off end of packet if (query_str_len == len) { // went off end of packet
D("Unterminated DNS query string\n"); D("Unterminated DNS query string\n");
return FALSE; return false;
} }
char * decoded_name_str = decode_dns_name(original_query_str); char * decoded_name_str = decode_dns_name(original_query_str);
if (decoded_name_str == NULL) { if (decoded_name_str == NULL) {
D("Error while decoding DNS query string"); D("Error while decoding DNS query string");
return FALSE; return false;
} }
D("DNS host query for %s\n", decoded_name_str); D("DNS host query for %s\n", decoded_name_str);
@ -665,10 +739,10 @@ static BOOL resolve_dns_request(struct socket * so, struct sockaddr_in addr, cad
POP_STRUCT(struct QUESTION, qinfo, data, len); POP_STRUCT(struct QUESTION, qinfo, data, len);
if (ntohs(qinfo.qtype) != 1 || ntohs(qinfo.qclass) != 1) { if (ntohs(qinfo.qtype) != 1 /* type A */ || ntohs(qinfo.qclass) != 1 /* class IN */ ) {
D("DNS host query for %s: Request isn't the supported type (INET A query)\n", decoded_name_str); D("DNS host query for %s: Request isn't the supported type (INET A query)\n", decoded_name_str);
free(decoded_name_str); free(decoded_name_str);
return FALSE; return false;
} }
D("DNS host query for %s: Request is eligible to check for host resolution suffix\n", decoded_name_str); D("DNS host query for %s: Request is eligible to check for host resolution suffix\n", decoded_name_str);
@ -678,21 +752,28 @@ static BOOL resolve_dns_request(struct socket * so, struct sockaddr_in addr, cad
for (const char ** suffix_ptr = host_resolved_domain_suffixes; *suffix_ptr != NULL; suffix_ptr++) { for (const char ** suffix_ptr = host_resolved_domain_suffixes; *suffix_ptr != NULL; suffix_ptr++) {
const char * suffix = *suffix_ptr; const char * suffix = *suffix_ptr;
// ends with suffix?
int suffix_pos = strlen(decoded_name_str) - strlen(suffix); int suffix_pos = strlen(decoded_name_str) - strlen(suffix);
if (suffix_pos > 0 && strcmp(decoded_name_str + suffix_pos, suffix) == 0) { if (suffix_pos > 0 && strcmp(decoded_name_str + suffix_pos, suffix) == 0) {
matched_suffix = suffix; matched_suffix = suffix;
break; break;
} }
// also check if the domain exactly matched the one the suffix is for
if (strcmp(decoded_name_str, suffix + 1) == 0) {
matched_suffix = suffix;
break;
}
} }
if (matched_suffix == NULL) { if (matched_suffix == NULL) {
D("DNS host query for %s: No suffix matched\n", decoded_name_str); D("DNS host query for %s: No suffix matched\n", decoded_name_str);
} else { } else {
D("DNS host query for %s: Suffix matched: %s\n", decoded_name_str, matched_suffix); D("DNS host query for %s: Matched for suffix: %s\n", decoded_name_str, matched_suffix);
// we are going to take this request and resolve it on the host // we are going to take this request and resolve it on the host
drop_dns_request = TRUE; drop_dns_request = true;
D("DNS host query for %s: Doing lookup on host\n", decoded_name_str); D("DNS host query for %s: Doing lookup on host\n", decoded_name_str);
@ -739,7 +820,7 @@ static BOOL resolve_dns_request(struct socket * so, struct sockaddr_in addr, cad
struct R_DATA resource; struct R_DATA resource;
resource.type = htons(1); resource.type = htons(1);
resource._class = htons(1); resource._class = htons(1);
resource.ttl = htonl(DOT_LOCAL_TTL); resource.ttl = htonl(HOST_DOMAIN_TTL);
resource.data_len = htons(sizeof(struct in_addr)); resource.data_len = htons(sizeof(struct in_addr));
memcpy(response_packet + response_pos, &resource, sizeof(struct R_DATA)); memcpy(response_packet + response_pos, &resource, sizeof(struct R_DATA));
@ -787,8 +868,10 @@ sosendto(so, m)
switch(ntohl(so->so_faddr.s_addr) & 0xff) { switch(ntohl(so->so_faddr.s_addr) & 0xff) {
case CTL_DNS: case CTL_DNS:
addr.sin_addr = dns_addr; addr.sin_addr = dns_addr;
if (host_resolved_domain_suffixes != NULL) {
if (resolve_dns_request(so, addr, m->m_data, m->m_len)) if (resolve_dns_request(so, addr, m->m_data, m->m_len))
return 0; return 0;
}
break; break;
case CTL_ALIAS: case CTL_ALIAS:
default: default:

View File

@ -68,6 +68,7 @@ prefs_desc common_prefs_items[] = {
{"mag_rate", TYPE_INT32, 0, "rate of magnification"}, {"mag_rate", TYPE_INT32, 0, "rate of magnification"},
{"gammaramp", TYPE_STRING, false, "gamma ramp (on, off or fullscreen)"}, {"gammaramp", TYPE_STRING, false, "gamma ramp (on, off or fullscreen)"},
{"swap_opt_cmd", TYPE_BOOLEAN, false, "swap option and command key"}, {"swap_opt_cmd", TYPE_BOOLEAN, false, "swap option and command key"},
{"host_domain", TYPE_STRING, true, "handle DNS requests for this domain on the host (slirp only)"},
{NULL, TYPE_END, false, NULL} // End of list {NULL, TYPE_END, false, NULL} // End of list
}; };