From 11cf7b614c2ad42acf12cf4843daa1b67696763b Mon Sep 17 00:00:00 2001 From: Nick Peng Date: Sun, 24 Jan 2021 14:16:35 +0800 Subject: [PATCH] dualstack: cache SOA record for speed. --- src/dns_cache.c | 71 +++++++++++++++++++++++++++++++++++------- src/dns_cache.h | 13 ++++++-- src/dns_server.c | 81 ++++++++++++++++++++++++++++++------------------ 3 files changed, 119 insertions(+), 46 deletions(-) diff --git a/src/dns_cache.c b/src/dns_cache.c index 2bd4b35..7df2abf 100644 --- a/src/dns_cache.c +++ b/src/dns_cache.c @@ -142,8 +142,7 @@ void dns_cache_data_free(struct dns_cache_data *data) free(data); } -struct dns_cache_data *dns_cache_new_data_addr(uint32_t cache_flag, char *cname, int cname_ttl, unsigned char *addr, - int addr_len) +struct dns_cache_data *dns_cache_new_data(void) { struct dns_cache_addr *cache_addr = malloc(sizeof(struct dns_cache_addr)); memset(cache_addr, 0, sizeof(struct dns_cache_addr)); @@ -151,6 +150,50 @@ struct dns_cache_data *dns_cache_new_data_addr(uint32_t cache_flag, char *cname, return NULL; } + cache_addr->head.cache_type = CACHE_TYPE_NONE; + cache_addr->head.size = sizeof(struct dns_cache_addr) - sizeof(struct dns_cache_data_head); + + return (struct dns_cache_data *)cache_addr; +} + +void dns_cache_set_data_soa(struct dns_cache_data *dns_cache, int32_t cache_flag, char *cname, int cname_ttl) +{ + if (dns_cache == NULL) { + goto errout; + } + + struct dns_cache_addr *cache_addr = (struct dns_cache_addr *)dns_cache; + if (cache_addr == NULL) { + goto errout; + } + + memset(cache_addr->addr_data.addr, 0, sizeof(cache_addr->addr_data.addr)); + + if (cname) { + safe_strncpy(cache_addr->addr_data.cname, cname, DNS_MAX_CNAME_LEN); + cache_addr->addr_data.cname_ttl = cname_ttl; + } + + cache_addr->head.cache_flag = cache_flag; + cache_addr->addr_data.soa = 1; + cache_addr->head.cache_type = CACHE_TYPE_ADDR; + cache_addr->head.size = sizeof(struct dns_cache_addr) - sizeof(struct dns_cache_data_head); +errout: + return; +} + +void dns_cache_set_data_addr(struct dns_cache_data *dns_cache, uint32_t cache_flag, char *cname, int cname_ttl, + unsigned char *addr, int addr_len) +{ + if (dns_cache == NULL) { + goto errout; + } + + struct dns_cache_addr *cache_addr = (struct dns_cache_addr *)dns_cache; + if (cache_addr == NULL) { + goto errout; + } + if (addr_len == DNS_RR_A_LEN) { memcpy(cache_addr->addr_data.addr, addr, DNS_RR_A_LEN); } else if (addr_len != DNS_RR_AAAA_LEN) { @@ -167,16 +210,8 @@ struct dns_cache_data *dns_cache_new_data_addr(uint32_t cache_flag, char *cname, cache_addr->head.cache_flag = cache_flag; cache_addr->head.cache_type = CACHE_TYPE_ADDR; cache_addr->head.size = sizeof(struct dns_cache_addr) - sizeof(struct dns_cache_data_head); - - return (struct dns_cache_data *)cache_addr; - errout: - if (cache_addr) { - free(cache_addr); - cache_addr = NULL; - } - - return NULL; + return; } struct dns_cache_data *dns_cache_new_data_packet(uint32_t cache_flag, void *packet, size_t packet_len) @@ -377,6 +412,18 @@ int dns_cache_get_ttl(struct dns_cache *dns_cache) return ttl; } +int dns_cache_is_soa(struct dns_cache *dns_cache) { + if (dns_cache == NULL) { + return 0; + } + + struct dns_cache_addr *cache_addr = (struct dns_cache_addr *)dns_cache_get_data(dns_cache); + if (cache_addr->addr_data.soa) { + return 1; + } + return 0; +} + struct dns_cache_data *dns_cache_get_data(struct dns_cache *dns_cache) { return dns_cache->cache_data; @@ -468,7 +515,7 @@ void dns_cache_invalidate(dns_cache_preinvalid_callback callback, int ttl_pre) } if (ttl < 0) { - if (dns_cache_head.enable_inactive) { + if (dns_cache_head.enable_inactive && (dns_cache_is_soa(dns_cache) == 0)) { _dns_cache_move_inactive(dns_cache); } else { _dns_cache_remove(dns_cache); diff --git a/src/dns_cache.h b/src/dns_cache.h index 519cb68..f8a6873 100644 --- a/src/dns_cache.h +++ b/src/dns_cache.h @@ -63,6 +63,7 @@ struct dns_cache_addr { struct dns_cache_addr_data { unsigned int cname_ttl; char cname[DNS_MAX_CNAME_LEN]; + char soa; union { unsigned char ipv4_addr[DNS_RR_A_LEN]; unsigned char ipv6_addr[DNS_RR_AAAA_LEN]; @@ -116,9 +117,6 @@ uint32_t dns_cache_get_cache_flag(struct dns_cache_data *cache_data); void dns_cache_data_free(struct dns_cache_data *data); -struct dns_cache_data *dns_cache_new_data_addr(uint32_t cache_flag, char *cname, int cname_ttl, unsigned char *addr, - int addr_len); - struct dns_cache_data *dns_cache_new_data_packet(uint32_t cache_flag, void *packet, size_t packet_len); int dns_cache_init(int size, int enable_inactive, int inactive_list_expired); @@ -145,8 +143,17 @@ void dns_cache_invalidate(dns_cache_preinvalid_callback callback, int ttl_pre); int dns_cache_get_ttl(struct dns_cache *dns_cache); +int dns_cache_is_soa(struct dns_cache *dns_cache); + +struct dns_cache_data *dns_cache_new_data(void); + struct dns_cache_data *dns_cache_get_data(struct dns_cache *dns_cache); +void dns_cache_set_data_addr(struct dns_cache_data *dns_cache, uint32_t cache_flag, char *cname, int cname_ttl, + unsigned char *addr, int addr_len); + +void dns_cache_set_data_soa(struct dns_cache_data *dns_cache, int32_t cache_flag, char *cname, int cname_ttl); + void dns_cache_destroy(void); int dns_cache_load(const char *file); diff --git a/src/dns_server.c b/src/dns_server.c index 3dcf9a6..dd8afb3 100644 --- a/src/dns_server.c +++ b/src/dns_server.c @@ -736,6 +736,10 @@ static int _dns_server_request_update_cache(struct dns_request *request, dns_typ goto errout; } + if (request->has_soa) { + ttl = dns_conf_rr_ttl; + } + /* if doing prefetch, update cache only */ if (request->prefetch) { if (dns_cache_replace(request->domain, ttl, qtype, speed, cache_data) != 0) { @@ -759,7 +763,7 @@ errout: static int _dns_server_request_complete_A(struct dns_request *request) { char *cname = NULL; - int cname_ttl = 0; + int cname_ttl = dns_conf_rr_ttl; struct dns_cache_data *cache_data = NULL; if (request->has_cname) { @@ -767,27 +771,29 @@ static int _dns_server_request_complete_A(struct dns_request *request) cname_ttl = request->ttl_cname; } - if (request->has_ipv4 == 0) { - return 0; + cache_data = dns_cache_new_data(); + if (cache_data == NULL) { + goto errout; } - tlog(TLOG_INFO, "result: %s, rcode: %d, %d.%d.%d.%d\n", request->domain, request->rcode, request->ipv4_addr[0], - request->ipv4_addr[1], request->ipv4_addr[2], request->ipv4_addr[3]); + if (request->has_ipv4 != 0) { + tlog(TLOG_INFO, "result: %s, rcode: %d, %d.%d.%d.%d\n", request->domain, request->rcode, request->ipv4_addr[0], + request->ipv4_addr[1], request->ipv4_addr[2], request->ipv4_addr[3]); - request->has_soa = 0; - if (request->has_ping_result == 0 && request->ttl_v4 > DNS_SERVER_TMOUT_TTL) { - request->ttl_v4 = DNS_SERVER_TMOUT_TTL; + request->has_soa = 0; + if (request->has_ping_result == 0 && request->ttl_v4 > DNS_SERVER_TMOUT_TTL) { + request->ttl_v4 = DNS_SERVER_TMOUT_TTL; + } + dns_cache_set_data_addr(cache_data, request->server_flags, cname, cname_ttl, request->ipv4_addr, DNS_RR_A_LEN); + } else { + dns_cache_set_data_soa(cache_data, request->server_flags, cname, cname_ttl); } if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_CACHE) == 0) { + dns_cache_data_free(cache_data); return 0; } - cache_data = dns_cache_new_data_addr(request->server_flags, cname, cname_ttl, request->ipv4_addr, DNS_RR_A_LEN); - if (cache_data == NULL) { - goto errout; - } - if (_dns_server_request_update_cache(request, DNS_T_A, cache_data) != 0) { goto errout; } @@ -807,7 +813,7 @@ static int _dns_server_request_complete_AAAA(struct dns_request *request) { int ret = -1; char *cname = NULL; - int cname_ttl = 0; + int cname_ttl = dns_conf_rr_ttl; struct dns_cache_data *cache_data = NULL; if (request->has_cname) { @@ -815,6 +821,11 @@ static int _dns_server_request_complete_AAAA(struct dns_request *request) cname_ttl = request->ttl_cname; } + cache_data = dns_cache_new_data(); + if (cache_data == NULL) { + goto errout; + } + if (request->has_ipv6) { tlog(TLOG_INFO, "result: %s, rcode: %d, %.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x", @@ -829,20 +840,22 @@ static int _dns_server_request_complete_AAAA(struct dns_request *request) } /* if doing prefetch, update cache only */ - if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_CACHE) != 0) { - cache_data = - dns_cache_new_data_addr(request->server_flags, cname, cname_ttl, request->ipv6_addr, DNS_T_AAAA); - if (cache_data == NULL) { - goto errout; - } - - if (_dns_server_request_update_cache(request, DNS_T_AAAA, cache_data) != 0) { - goto errout; - } - cache_data = NULL; - } + dns_cache_set_data_addr(cache_data, request->server_flags, cname, cname_ttl, request->ipv6_addr, + DNS_T_AAAA); request->has_soa = 0; + } else { + dns_cache_set_data_soa(cache_data, request->server_flags, cname, cname_ttl); + } + + if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_CACHE) != 0) { + if (_dns_server_request_update_cache(request, DNS_T_AAAA, cache_data) != 0) { + goto errout; + } + cache_data = NULL; + } else { + dns_cache_data_free(cache_data); + cache_data = NULL; } if (request->has_ipv4 && (request->ping_ttl_v4 > 0)) { @@ -854,12 +867,13 @@ static int _dns_server_request_complete_AAAA(struct dns_request *request) request->ping_ttl_v6 < 0) { tlog(TLOG_DEBUG, "Force IPV4 perfered."); if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_CACHE) != 0) { - cache_data = - dns_cache_new_data_addr(request->server_flags, cname, cname_ttl, request->ipv4_addr, DNS_T_A); + cache_data = dns_cache_new_data(); if (cache_data == NULL) { goto errout; } + dns_cache_set_data_addr(cache_data, request->server_flags, cname, cname_ttl, request->ipv4_addr, + DNS_T_A); if (_dns_server_request_update_cache(request, DNS_T_A, cache_data) != 0) { goto errout; } @@ -2417,7 +2431,7 @@ static int _dns_server_process_cache(struct dns_request *request) if (dns_cache == NULL) { if (request->dualstack_selection && request->qtype == DNS_T_AAAA) { dns_cache_A = dns_cache_lookup(request->domain, DNS_T_A); - if (dns_cache_A) { + if (dns_cache_A && dns_cache_is_soa(dns_cache_A) == 0 && dns_cache_is_soa(dns_cache)) { tlog(TLOG_DEBUG, "No IPV6 Found, Force IPV4 perfered."); if (dns_cache_get_ttl(dns_cache_A) == 0) { uint32_t server_flags = request->server_flags; @@ -2437,6 +2451,13 @@ static int _dns_server_process_cache(struct dns_request *request) goto out; } + if (request->qtype == DNS_T_A) { + if (dns_cache_is_soa(dns_cache)) { + ret = _dns_server_reply_SOA(DNS_RC_NOERROR, request); + goto out; + } + } + if (request->dualstack_selection && request->qtype == DNS_T_AAAA) { dns_cache_A = dns_cache_lookup(request->domain, DNS_T_A); if (dns_cache_A && (dns_cache_A->info.speed > 0)) { @@ -2610,8 +2631,6 @@ static int _dns_server_do_query(struct dns_request *request, const char *domain, _dns_server_set_dualstack_selection(request); - tlog(TLOG_DEBUG, "dualstack selection %d", request->dualstack_selection); - if (_dns_server_process_special_query(request) == 0) { goto clean_exit; }