Compare commits
1 Commits
quic
...
https-svcb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
27c1aedd3b |
484
src/dns_server.c
484
src/dns_server.c
@@ -224,6 +224,18 @@ struct dns_request_domain_rule {
|
||||
typedef DNS_CHILD_POST_RESULT (*child_request_callback)(struct dns_request *request, struct dns_request *child_request,
|
||||
int is_first_resp);
|
||||
|
||||
struct dns_request_https {
|
||||
char domain[DNS_MAX_CNAME_LEN];
|
||||
char target[DNS_MAX_CNAME_LEN];
|
||||
int ttl;
|
||||
int priority;
|
||||
char alpn[DNS_MAX_ALPN_LEN];
|
||||
int alpn_len;
|
||||
int port;
|
||||
int ech[DNS_MAX_ECH_LEN];
|
||||
int ech_len;
|
||||
};
|
||||
|
||||
struct dns_request {
|
||||
atomic_t refcnt;
|
||||
|
||||
@@ -258,6 +270,7 @@ struct dns_request {
|
||||
struct sockaddr_storage localaddr;
|
||||
int has_ecs;
|
||||
struct dns_opt_ecs ecs;
|
||||
struct dns_request_https *https_svcb;
|
||||
|
||||
dns_result_callback result_callback;
|
||||
void *user_ptr;
|
||||
@@ -275,6 +288,7 @@ struct dns_request {
|
||||
int ping_time;
|
||||
int ip_ttl;
|
||||
unsigned char ip_addr[DNS_RR_AAAA_LEN];
|
||||
int ip_addr_type;
|
||||
|
||||
struct dns_soa soa;
|
||||
int has_soa;
|
||||
@@ -945,6 +959,64 @@ static void _dns_server_setup_soa(struct dns_request *request)
|
||||
soa->minimum = 86400;
|
||||
}
|
||||
|
||||
static int _dns_add_rrs_HTTPS(struct dns_server_post_context *context)
|
||||
{
|
||||
struct dns_request *request = context->request;
|
||||
struct dns_request_https *https_svcb = request->https_svcb;
|
||||
int ret = 0;
|
||||
struct dns_rr_nested param;
|
||||
|
||||
if (https_svcb == NULL || request->qtype != DNS_T_HTTPS) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = dns_add_HTTPS_start(¶m, context->packet, DNS_RRS_AN, https_svcb->domain, https_svcb->ttl,
|
||||
https_svcb->priority, https_svcb->target);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (https_svcb->alpn[0] != '\0' && https_svcb->alpn_len > 0) {
|
||||
ret = dns_HTTPS_add_alpn(¶m, https_svcb->alpn, https_svcb->alpn_len);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (https_svcb->port != 0) {
|
||||
ret = dns_HTTPS_add_port(¶m, https_svcb->port);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (request->has_ip) {
|
||||
unsigned char *addr[1];
|
||||
addr[0] = request->ip_addr;
|
||||
if (request->ip_addr_type == DNS_T_A) {
|
||||
ret = dns_HTTPS_add_ipv4hint(¶m, addr, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (https_svcb->ech[0] != 0 && https_svcb->ech_len > 0) {
|
||||
ret = dns_HTTPS_add_ech(¶m, https_svcb->ech, https_svcb->ech_len);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (request->has_ip) {
|
||||
unsigned char *addr[1];
|
||||
addr[0] = request->ip_addr;
|
||||
if (request->ip_addr_type == DNS_T_AAAA) {
|
||||
ret = dns_HTTPS_add_ipv6hint(¶m, addr, 1);
|
||||
}
|
||||
}
|
||||
|
||||
dns_add_HTTPS_end(¶m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_add_rrs(struct dns_server_post_context *context)
|
||||
{
|
||||
struct dns_request *request = context->request;
|
||||
@@ -962,6 +1034,10 @@ static int _dns_add_rrs(struct dns_server_post_context *context)
|
||||
domain = request->cname;
|
||||
}
|
||||
|
||||
if (request->https_svcb != NULL) {
|
||||
ret = _dns_add_rrs_HTTPS(context);
|
||||
}
|
||||
|
||||
/* add A record */
|
||||
if (request->has_ip && context->do_force_soa == 0) {
|
||||
_dns_server_context_add_ip(context, request->ip_addr);
|
||||
@@ -1306,7 +1382,7 @@ static int _dns_server_request_update_cache(struct dns_request *request, dns_typ
|
||||
int ttl = 0;
|
||||
int speed = 0;
|
||||
|
||||
if (qtype != DNS_T_A && qtype != DNS_T_AAAA) {
|
||||
if (qtype != DNS_T_A && qtype != DNS_T_AAAA && qtype != DNS_T_HTTPS) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
@@ -1631,7 +1707,7 @@ static int _dns_cache_reply_packet(struct dns_server_post_context *context)
|
||||
return _dns_cache_packet(context);
|
||||
}
|
||||
|
||||
if (context->qtype != DNS_T_AAAA && context->qtype != DNS_T_A) {
|
||||
if (context->qtype != DNS_T_AAAA && context->qtype != DNS_T_A && context->qtype != DNS_T_HTTPS) {
|
||||
return _dns_cache_specify_packet(context);
|
||||
}
|
||||
|
||||
@@ -1657,6 +1733,47 @@ static int _dns_cache_reply_packet(struct dns_server_post_context *context)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _dns_server_add_ipset_nftset(struct dns_request *request, struct dns_ipset_rule *ipset_rule,
|
||||
struct dns_nftset_rule *nftset_rule, const unsigned char addr[], int addr_len,
|
||||
int timeout_value)
|
||||
{
|
||||
if (ipset_rule != NULL) {
|
||||
/* add IPV4 to ipset */
|
||||
if (addr_len == DNS_RR_A_LEN) {
|
||||
tlog(TLOG_DEBUG, "IPSET-MATCH: domain: %s, ipset: %s, IP: %d.%d.%d.%d", request->domain,
|
||||
ipset_rule->ipsetname, addr[0], addr[1], addr[2], addr[3]);
|
||||
ipset_add(ipset_rule->ipsetname, addr, DNS_RR_A_LEN, timeout_value);
|
||||
} else if (addr_len == DNS_RR_AAAA_LEN) {
|
||||
tlog(TLOG_DEBUG,
|
||||
"IPSET-MATCH: domain: %s, ipset: %s, IP: "
|
||||
"%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x",
|
||||
request->domain, ipset_rule->ipsetname, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6],
|
||||
addr[7], addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]);
|
||||
ipset_add(ipset_rule->ipsetname, addr, DNS_RR_AAAA_LEN, timeout_value);
|
||||
}
|
||||
}
|
||||
|
||||
if (nftset_rule != NULL) {
|
||||
/* add IPV4 to ipset */
|
||||
if (addr_len == DNS_RR_A_LEN) {
|
||||
tlog(TLOG_DEBUG, "NFTSET-MATCH: domain: %s, nftset: %s %s %s, IP: %d.%d.%d.%d", request->domain,
|
||||
nftset_rule->familyname, nftset_rule->nfttablename, nftset_rule->nftsetname, addr[0], addr[1], addr[2],
|
||||
addr[3]);
|
||||
nftset_add(nftset_rule->familyname, nftset_rule->nfttablename, nftset_rule->nftsetname, addr, DNS_RR_A_LEN,
|
||||
timeout_value);
|
||||
} else if (addr_len == DNS_RR_AAAA_LEN) {
|
||||
tlog(TLOG_DEBUG,
|
||||
"NFTSET-MATCH: domain: %s, nftset: %s %s %s, IP: "
|
||||
"%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x",
|
||||
request->domain, nftset_rule->familyname, nftset_rule->nfttablename, nftset_rule->nftsetname, addr[0],
|
||||
addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7], addr[8], addr[9], addr[10], addr[11],
|
||||
addr[12], addr[13], addr[14], addr[15]);
|
||||
nftset_add(nftset_rule->familyname, nftset_rule->nfttablename, nftset_rule->nftsetname, addr,
|
||||
DNS_RR_AAAA_LEN, timeout_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int _dns_server_setup_ipset_nftset_packet(struct dns_server_post_context *context)
|
||||
{
|
||||
int ttl = 0;
|
||||
@@ -1768,21 +1885,7 @@ static int _dns_server_setup_ipset_nftset_packet(struct dns_server_post_context
|
||||
dns_get_A(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr);
|
||||
|
||||
rule = ipset_rule_v4 ? ipset_rule_v4 : ipset_rule;
|
||||
if (rule != NULL) {
|
||||
/* add IPV4 to ipset */
|
||||
tlog(TLOG_DEBUG, "IPSET-MATCH: domain: %s, ipset: %s, IP: %d.%d.%d.%d", request->domain,
|
||||
rule->ipsetname, addr[0], addr[1], addr[2], addr[3]);
|
||||
ipset_add(rule->ipsetname, addr, DNS_RR_A_LEN, timeout_value);
|
||||
}
|
||||
|
||||
if (nftset_ip != NULL) {
|
||||
/* add IPV4 to ipset */
|
||||
tlog(TLOG_DEBUG, "NFTSET-MATCH: domain: %s, nftset: %s %s %s, IP: %d.%d.%d.%d", request->domain,
|
||||
nftset_ip->familyname, nftset_ip->nfttablename, nftset_ip->nftsetname, addr[0], addr[1],
|
||||
addr[2], addr[3]);
|
||||
nftset_add(nftset_ip->familyname, nftset_ip->nfttablename, nftset_ip->nftsetname, addr,
|
||||
DNS_RR_A_LEN, timeout_value);
|
||||
}
|
||||
_dns_server_add_ipset_nftset(request, rule, nftset_ip, addr, DNS_RR_A_LEN, timeout_value);
|
||||
} break;
|
||||
case DNS_T_AAAA: {
|
||||
unsigned char addr[16];
|
||||
@@ -1793,26 +1896,42 @@ static int _dns_server_setup_ipset_nftset_packet(struct dns_server_post_context
|
||||
dns_get_AAAA(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr);
|
||||
|
||||
rule = ipset_rule_v6 ? ipset_rule_v6 : ipset_rule;
|
||||
if (rule != NULL) {
|
||||
tlog(TLOG_DEBUG,
|
||||
"IPSET-MATCH: domain: %s, ipset: %s, IP: "
|
||||
"%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x",
|
||||
request->domain, rule->ipsetname, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5],
|
||||
addr[6], addr[7], addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14],
|
||||
addr[15]);
|
||||
ipset_add(rule->ipsetname, addr, DNS_RR_AAAA_LEN, timeout_value);
|
||||
_dns_server_add_ipset_nftset(request, rule, nftset_ip6, addr, DNS_RR_AAAA_LEN, timeout_value);
|
||||
} break;
|
||||
case DNS_T_HTTPS: {
|
||||
char target[DNS_MAX_CNAME_LEN] = {0};
|
||||
struct dns_https_param *p = NULL;
|
||||
int priority = 0;
|
||||
|
||||
int ret = dns_get_HTTPS_svcparm_start(rrs, &p, name, DNS_MAX_CNAME_LEN, &ttl, &priority, target,
|
||||
DNS_MAX_CNAME_LEN);
|
||||
if (ret != 0) {
|
||||
tlog(TLOG_WARN, "get HTTPS svcparm failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (nftset_ip6 != NULL) {
|
||||
/* add IPV6 to ipset */
|
||||
tlog(TLOG_DEBUG,
|
||||
"NFTSET-MATCH: domain: %s, nftset: %s %s %s, IP: "
|
||||
"%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x",
|
||||
request->domain, nftset_ip6->familyname, nftset_ip6->nfttablename, nftset_ip6->nftsetname,
|
||||
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7], addr[8], addr[9],
|
||||
addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]);
|
||||
nftset_add(nftset_ip6->familyname, nftset_ip6->nfttablename, nftset_ip6->nftsetname, addr,
|
||||
DNS_RR_AAAA_LEN, timeout_value);
|
||||
for (; p; p = dns_get_HTTPS_svcparm_next(rrs, p)) {
|
||||
switch (p->key) {
|
||||
case DNS_HTTPS_T_IPV4HINT: {
|
||||
unsigned char *addr;
|
||||
for (int k = 0; k < p->len / 4; k++) {
|
||||
addr = p->value + k * 4;
|
||||
rule = ipset_rule_v4 ? ipset_rule_v4 : ipset_rule;
|
||||
_dns_server_add_ipset_nftset(request, rule, nftset_ip, addr, DNS_RR_A_LEN, timeout_value);
|
||||
}
|
||||
} break;
|
||||
case DNS_HTTPS_T_IPV6HINT: {
|
||||
unsigned char *addr;
|
||||
for (int k = 0; k < p->len / 16; k++) {
|
||||
addr = p->value + k * 16;
|
||||
rule = ipset_rule_v6 ? ipset_rule_v6 : ipset_rule;
|
||||
_dns_server_add_ipset_nftset(request, rule, nftset_ip6, addr, DNS_RR_AAAA_LEN,
|
||||
timeout_value);
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
@@ -2310,7 +2429,8 @@ static void _dns_server_select_possible_ipaddress(struct dns_request *request)
|
||||
}
|
||||
|
||||
/* Return the most likely correct IP address */
|
||||
/* Returns the IP with the most hits, or the last returned record is considered to be the most likely correct. */
|
||||
/* Returns the IP with the most hits, or the last returned record is considered to be the most likely
|
||||
* correct. */
|
||||
pthread_mutex_lock(&request->ip_map_lock);
|
||||
hash_for_each_safe(request->ip_map, bucket, tmp, addr_map, node)
|
||||
{
|
||||
@@ -2375,6 +2495,9 @@ static void _dns_server_delete_request(struct dns_request *request)
|
||||
_dns_server_conn_release(request->conn);
|
||||
}
|
||||
pthread_mutex_destroy(&request->ip_map_lock);
|
||||
if (request->https_svcb) {
|
||||
free(request->https_svcb);
|
||||
}
|
||||
memset(request, 0, sizeof(*request));
|
||||
free(request);
|
||||
}
|
||||
@@ -2629,6 +2752,7 @@ static void _dns_server_ping_result(struct ping_host_struct *ping_host, const ch
|
||||
|
||||
if (request->ping_time > rtt || request->ping_time == -1) {
|
||||
memcpy(request->ip_addr, &addr_in->sin_addr.s_addr, 4);
|
||||
request->ip_addr_type = DNS_T_A;
|
||||
request->ping_time = rtt;
|
||||
request->has_cname = 0;
|
||||
request->has_ip = 1;
|
||||
@@ -2646,7 +2770,7 @@ static void _dns_server_ping_result(struct ping_host_struct *ping_host, const ch
|
||||
}
|
||||
}
|
||||
|
||||
if (request->qtype == DNS_T_A) {
|
||||
if (request->qtype == DNS_T_A || request->qtype == DNS_T_HTTPS) {
|
||||
request->has_ping_result = 1;
|
||||
}
|
||||
} break;
|
||||
@@ -2664,6 +2788,7 @@ static void _dns_server_ping_result(struct ping_host_struct *ping_host, const ch
|
||||
request->has_cname = 0;
|
||||
request->has_ip = 1;
|
||||
memcpy(request->ip_addr, addr_in6->sin6_addr.s6_addr + 12, 4);
|
||||
request->ip_addr_type = DNS_T_A;
|
||||
if (addr_map && addr_map->cname[0] != 0) {
|
||||
request->has_cname = 1;
|
||||
safe_strncpy(request->cname, addr_map->cname, DNS_MAX_CNAME_LEN);
|
||||
@@ -2672,7 +2797,7 @@ static void _dns_server_ping_result(struct ping_host_struct *ping_host, const ch
|
||||
}
|
||||
}
|
||||
|
||||
if (request->qtype == DNS_T_A) {
|
||||
if (request->qtype == DNS_T_A || request->qtype == DNS_T_HTTPS) {
|
||||
request->has_ping_result = 1;
|
||||
}
|
||||
} else {
|
||||
@@ -2686,6 +2811,7 @@ static void _dns_server_ping_result(struct ping_host_struct *ping_host, const ch
|
||||
request->has_cname = 0;
|
||||
request->has_ip = 1;
|
||||
memcpy(request->ip_addr, addr_in6->sin6_addr.s6_addr, 16);
|
||||
request->ip_addr_type = DNS_T_AAAA;
|
||||
if (addr_map && addr_map->cname[0] != 0) {
|
||||
request->has_cname = 1;
|
||||
safe_strncpy(request->cname, addr_map->cname, DNS_MAX_CNAME_LEN);
|
||||
@@ -2694,7 +2820,7 @@ static void _dns_server_ping_result(struct ping_host_struct *ping_host, const ch
|
||||
}
|
||||
}
|
||||
|
||||
if (request->qtype == DNS_T_AAAA) {
|
||||
if (request->qtype == DNS_T_AAAA || request->qtype == DNS_T_HTTPS) {
|
||||
request->has_ping_result = 1;
|
||||
}
|
||||
}
|
||||
@@ -2941,37 +3067,18 @@ static int _dns_server_is_adblock_ipv6(const unsigned char addr[16])
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _dns_server_process_answer_A(struct dns_rrs *rrs, struct dns_request *request, const char *domain,
|
||||
char *cname, unsigned int result_flag)
|
||||
static int _dns_server_process_answer_A_IP(struct dns_request *request, char *cname, unsigned char addr[4], int ttl,
|
||||
unsigned int result_flag)
|
||||
{
|
||||
int ttl = 0;
|
||||
char ip[DNS_MAX_CNAME_LEN] = {0};
|
||||
int ip_check_result = 0;
|
||||
unsigned char addr[4];
|
||||
unsigned char *paddrs[MAX_IP_NUM];
|
||||
int paddr_num = 0;
|
||||
char name[DNS_MAX_CNAME_LEN] = {0};
|
||||
char ip[DNS_MAX_CNAME_LEN] = {0};
|
||||
struct dns_iplist_ip_addresses *alias = NULL;
|
||||
|
||||
if (request->qtype != DNS_T_A) {
|
||||
/* ignore non-matched query type */
|
||||
if (request->dualstack_selection == 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* get A result */
|
||||
dns_get_A(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr);
|
||||
paddrs[paddr_num] = addr;
|
||||
paddr_num = 1;
|
||||
|
||||
tlog(TLOG_DEBUG, "domain: %s TTL: %d IP: %d.%d.%d.%d", name, ttl, addr[0], addr[1], addr[2], addr[3]);
|
||||
|
||||
/* if domain is not match */
|
||||
if (strncmp(name, domain, DNS_MAX_CNAME_LEN) != 0 && strncmp(cname, name, DNS_MAX_CNAME_LEN) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ip rule check */
|
||||
ip_check_result = _dns_server_process_ip_rule(request, addr, 4, DNS_T_A, result_flag, &alias);
|
||||
if (ip_check_result == 0) {
|
||||
@@ -2991,6 +3098,7 @@ static int _dns_server_process_answer_A(struct dns_rrs *rrs, struct dns_request
|
||||
unsigned char *paddr = paddrs[i];
|
||||
if (atomic_read(&request->ip_map_num) == 0) {
|
||||
request->has_ip = 1;
|
||||
request->ip_addr_type = DNS_T_A;
|
||||
memcpy(request->ip_addr, paddr, DNS_RR_A_LEN);
|
||||
request->ip_ttl = _dns_server_get_conf_ttl(request, ttl);
|
||||
if (cname[0] != 0 && request->has_cname == 0 && dns_conf_force_no_cname == 0) {
|
||||
@@ -3029,36 +3137,18 @@ static int _dns_server_process_answer_A(struct dns_rrs *rrs, struct dns_request
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_server_process_answer_AAAA(struct dns_rrs *rrs, struct dns_request *request, const char *domain,
|
||||
char *cname, unsigned int result_flag)
|
||||
static int _dns_server_process_answer_AAAA_IP(struct dns_request *request, char *cname, unsigned char addr[16], int ttl,
|
||||
unsigned int result_flag)
|
||||
{
|
||||
unsigned char addr[16];
|
||||
unsigned char *paddrs[MAX_IP_NUM];
|
||||
int paddr_num = 0;
|
||||
char name[DNS_MAX_CNAME_LEN] = {0};
|
||||
char ip[DNS_MAX_CNAME_LEN] = {0};
|
||||
int ttl = 0;
|
||||
int ip_check_result = 0;
|
||||
unsigned char *paddrs[MAX_IP_NUM];
|
||||
struct dns_iplist_ip_addresses *alias = NULL;
|
||||
int paddr_num = 0;
|
||||
|
||||
if (request->qtype != DNS_T_AAAA) {
|
||||
/* ignore non-matched query type */
|
||||
return -1;
|
||||
}
|
||||
|
||||
dns_get_AAAA(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr);
|
||||
paddrs[paddr_num] = addr;
|
||||
paddr_num = 1;
|
||||
|
||||
tlog(TLOG_DEBUG, "domain: %s TTL: %d IP: %.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x",
|
||||
name, ttl, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7], addr[8], addr[9], addr[10],
|
||||
addr[11], addr[12], addr[13], addr[14], addr[15]);
|
||||
|
||||
/* if domain is not match */
|
||||
if (strncmp(name, domain, DNS_MAX_CNAME_LEN) != 0 && strncmp(cname, name, DNS_MAX_CNAME_LEN) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ip_check_result = _dns_server_process_ip_rule(request, addr, 16, DNS_T_AAAA, result_flag, &alias);
|
||||
if (ip_check_result == 0) {
|
||||
/* match */
|
||||
@@ -3077,6 +3167,7 @@ static int _dns_server_process_answer_AAAA(struct dns_rrs *rrs, struct dns_reque
|
||||
unsigned char *paddr = paddrs[i];
|
||||
if (atomic_read(&request->ip_map_num) == 0) {
|
||||
request->has_ip = 1;
|
||||
request->ip_addr_type = DNS_T_AAAA;
|
||||
memcpy(request->ip_addr, paddr, DNS_RR_AAAA_LEN);
|
||||
request->ip_ttl = _dns_server_get_conf_ttl(request, ttl);
|
||||
if (cname[0] != 0 && request->has_cname == 0 && dns_conf_force_no_cname == 0) {
|
||||
@@ -3117,6 +3208,176 @@ static int _dns_server_process_answer_AAAA(struct dns_rrs *rrs, struct dns_reque
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_server_process_answer_A(struct dns_rrs *rrs, struct dns_request *request, const char *domain,
|
||||
char *cname, unsigned int result_flag)
|
||||
{
|
||||
int ttl = 0;
|
||||
unsigned char addr[4];
|
||||
char name[DNS_MAX_CNAME_LEN] = {0};
|
||||
|
||||
if (request->qtype != DNS_T_A) {
|
||||
/* ignore non-matched query type */
|
||||
if (request->dualstack_selection == 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* get A result */
|
||||
dns_get_A(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr);
|
||||
|
||||
tlog(TLOG_DEBUG, "domain: %s TTL: %d IP: %d.%d.%d.%d", name, ttl, addr[0], addr[1], addr[2], addr[3]);
|
||||
|
||||
/* if domain is not match */
|
||||
if (strncmp(name, domain, DNS_MAX_CNAME_LEN) != 0 && strncmp(cname, name, DNS_MAX_CNAME_LEN) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
_dns_server_request_get(request);
|
||||
int ret = _dns_server_process_answer_A_IP(request, cname, addr, ttl, result_flag);
|
||||
_dns_server_request_release(request);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _dns_server_process_answer_AAAA(struct dns_rrs *rrs, struct dns_request *request, const char *domain,
|
||||
char *cname, unsigned int result_flag)
|
||||
{
|
||||
unsigned char addr[16];
|
||||
|
||||
char name[DNS_MAX_CNAME_LEN] = {0};
|
||||
|
||||
int ttl = 0;
|
||||
|
||||
if (request->qtype != DNS_T_AAAA) {
|
||||
/* ignore non-matched query type */
|
||||
return -1;
|
||||
}
|
||||
|
||||
dns_get_AAAA(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr);
|
||||
|
||||
tlog(TLOG_DEBUG, "domain: %s TTL: %d IP: %.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x",
|
||||
name, ttl, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7], addr[8], addr[9], addr[10],
|
||||
addr[11], addr[12], addr[13], addr[14], addr[15]);
|
||||
|
||||
/* if domain is not match */
|
||||
if (strncmp(name, domain, DNS_MAX_CNAME_LEN) != 0 && strncmp(cname, name, DNS_MAX_CNAME_LEN) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
_dns_server_request_get(request);
|
||||
int ret = _dns_server_process_answer_AAAA_IP(request, cname, addr, ttl, result_flag);
|
||||
_dns_server_request_release(request);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _dns_server_process_answer_HTTPS(struct dns_rrs *rrs, struct dns_request *request, const char *domain,
|
||||
char *cname, unsigned int result_flag)
|
||||
{
|
||||
int ttl = 0;
|
||||
int ret = -1;
|
||||
char name[DNS_MAX_CNAME_LEN] = {0};
|
||||
char target[DNS_MAX_CNAME_LEN] = {0};
|
||||
struct dns_https_param *p = NULL;
|
||||
int priority = 0;
|
||||
struct dns_request_https *https_svcb;
|
||||
|
||||
ret = dns_get_HTTPS_svcparm_start(rrs, &p, name, DNS_MAX_CNAME_LEN, &ttl, &priority, target, DNS_MAX_CNAME_LEN);
|
||||
if (ret != 0) {
|
||||
tlog(TLOG_WARN, "get HTTPS svcparm failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
https_svcb = request->https_svcb;
|
||||
if (https_svcb == 0) {
|
||||
/* ignore non-matched query type */
|
||||
tlog(TLOG_WARN, "https svcb not set");
|
||||
return -1;
|
||||
}
|
||||
|
||||
tlog(TLOG_DEBUG, "domain: %s HTTPS: %s TTL: %d priority: %d", name, target, ttl, priority);
|
||||
https_svcb->ttl = ttl;
|
||||
https_svcb->priority = priority;
|
||||
safe_strncpy(https_svcb->target, target, sizeof(https_svcb->target));
|
||||
safe_strncpy(https_svcb->domain, name, sizeof(https_svcb->domain));
|
||||
request->ip_ttl = ttl;
|
||||
|
||||
_dns_server_request_get(request);
|
||||
for (; p; p = dns_get_HTTPS_svcparm_next(rrs, p)) {
|
||||
switch (p->key) {
|
||||
case DNS_HTTPS_T_MANDATORY: {
|
||||
} break;
|
||||
case DNS_HTTPS_T_ALPN: {
|
||||
memcpy(https_svcb->alpn, p->value, sizeof(https_svcb->alpn));
|
||||
https_svcb->alpn_len = p->len;
|
||||
} break;
|
||||
case DNS_HTTPS_T_NO_DEFAULT_ALPN: {
|
||||
} break;
|
||||
case DNS_HTTPS_T_PORT: {
|
||||
int port = *(unsigned short *)(p->value);
|
||||
https_svcb->port = ntohs(port);
|
||||
} break;
|
||||
case DNS_HTTPS_T_IPV4HINT: {
|
||||
struct dns_rule_address_IPV4 *address_ipv4 = NULL;
|
||||
if (_dns_server_is_return_soa_qtype(request, DNS_T_A)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_RULE_ADDR) == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
address_ipv4 = _dns_server_get_dns_rule(request, DOMAIN_RULE_ADDRESS_IPV4);
|
||||
if (address_ipv4 != NULL) {
|
||||
memcpy(request->ip_addr, address_ipv4->ipv4_addr, DNS_RR_A_LEN);
|
||||
request->has_ip = 1;
|
||||
request->ip_addr_type = DNS_T_A;
|
||||
break;
|
||||
}
|
||||
|
||||
for (int k = 0; k < p->len / 4; k++) {
|
||||
_dns_server_process_answer_A_IP(request, cname, p->value + k * 4, ttl, result_flag);
|
||||
}
|
||||
} break;
|
||||
case DNS_HTTPS_T_ECH: {
|
||||
if (p->len > sizeof(https_svcb->ech)) {
|
||||
tlog(TLOG_WARN, "ech too long");
|
||||
break;
|
||||
}
|
||||
memcpy(https_svcb->ech, p->value, p->len);
|
||||
https_svcb->ech_len = p->len;
|
||||
} break;
|
||||
case DNS_HTTPS_T_IPV6HINT: {
|
||||
struct dns_rule_address_IPV6 *address_ipv6 = NULL;
|
||||
|
||||
if (_dns_server_is_return_soa_qtype(request, DNS_T_AAAA)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_RULE_ADDR) == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
address_ipv6 = _dns_server_get_dns_rule(request, DOMAIN_RULE_ADDRESS_IPV6);
|
||||
if (address_ipv6 != NULL) {
|
||||
memcpy(request->ip_addr, address_ipv6->ipv6_addr, DNS_RR_AAAA_LEN);
|
||||
request->has_ip = 1;
|
||||
request->ip_addr_type = DNS_T_AAAA;
|
||||
break;
|
||||
}
|
||||
|
||||
for (int k = 0; k < p->len / 16; k++) {
|
||||
_dns_server_process_answer_AAAA_IP(request, cname, p->value + k * 16, ttl, result_flag);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
_dns_server_request_release(request);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_server_process_answer(struct dns_request *request, const char *domain, struct dns_packet *packet,
|
||||
unsigned int result_flag)
|
||||
{
|
||||
@@ -3187,6 +3448,15 @@ static int _dns_server_process_answer(struct dns_request *request, const char *d
|
||||
request->ttl_cname = _dns_server_get_conf_ttl(request, ttl);
|
||||
tlog(TLOG_DEBUG, "name: %s ttl: %d cname: %s\n", domain_name, ttl, cname);
|
||||
} break;
|
||||
case DNS_T_HTTPS: {
|
||||
ret = _dns_server_process_answer_HTTPS(rrs, request, domain, cname, result_flag);
|
||||
if (ret == -1) {
|
||||
break;
|
||||
} else if (ret == -2) {
|
||||
continue;
|
||||
}
|
||||
request->rcode = packet->head.rcode;
|
||||
} break;
|
||||
case DNS_T_SOA: {
|
||||
/* if DNS64 enabled, skip check SOA. */
|
||||
if (_dns_server_is_dns64_request(request)) {
|
||||
@@ -3199,7 +3469,8 @@ static int _dns_server_process_answer(struct dns_request *request, const char *d
|
||||
}
|
||||
dns_get_SOA(rrs, name, 128, &ttl, &request->soa);
|
||||
tlog(TLOG_DEBUG,
|
||||
"domain: %s, qtype: %d, SOA: mname: %s, rname: %s, serial: %d, refresh: %d, retry: %d, expire: "
|
||||
"domain: %s, qtype: %d, SOA: mname: %s, rname: %s, serial: %d, refresh: %d, retry: %d, "
|
||||
"expire: "
|
||||
"%d, minimum: %d",
|
||||
domain, request->qtype, request->soa.mname, request->soa.rname, request->soa.serial,
|
||||
request->soa.refresh, request->soa.retry, request->soa.expire, request->soa.minimum);
|
||||
@@ -3311,7 +3582,8 @@ static int _dns_server_passthrough_rule_check(struct dns_request *request, const
|
||||
}
|
||||
|
||||
tlog(TLOG_DEBUG,
|
||||
"domain: %s TTL: %d IP: %.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x",
|
||||
"domain: %s TTL: %d IP: "
|
||||
"%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x",
|
||||
name, ttl_tmp, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7], addr[8],
|
||||
addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]);
|
||||
|
||||
@@ -3466,7 +3738,8 @@ static int _dns_server_get_answer(struct dns_server_post_context *context)
|
||||
}
|
||||
dns_get_SOA(rrs, name, 128, &ttl, &request->soa);
|
||||
tlog(TLOG_DEBUG,
|
||||
"domain: %s, qtype: %d, SOA: mname: %s, rname: %s, serial: %d, refresh: %d, retry: %d, expire: "
|
||||
"domain: %s, qtype: %d, SOA: mname: %s, rname: %s, serial: %d, refresh: %d, retry: %d, "
|
||||
"expire: "
|
||||
"%d, minimum: %d",
|
||||
request->domain, request->qtype, request->soa.mname, request->soa.rname, request->soa.serial,
|
||||
request->soa.refresh, request->soa.retry, request->soa.expire, request->soa.minimum);
|
||||
@@ -3901,7 +4174,8 @@ static int _dns_server_process_local_ptr(struct dns_request *request)
|
||||
} else {
|
||||
addr = addr_in6->sin6_addr.s6_addr;
|
||||
snprintf(reverse_addr, sizeof(reverse_addr),
|
||||
"%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
|
||||
"%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%"
|
||||
"x.%x.%x."
|
||||
"%x.ip6.arpa",
|
||||
addr[15] & 0xF, (addr[15] >> 4) & 0xF, addr[14] & 0xF, (addr[14] >> 4) & 0xF, addr[13] & 0xF,
|
||||
(addr[13] >> 4) & 0xF, addr[12] & 0xF, (addr[12] >> 4) & 0xF, addr[11] & 0xF,
|
||||
@@ -4268,6 +4542,13 @@ static int _dns_server_pre_process_rule_flags(struct dns_request *request)
|
||||
request->dualstack_selection = 0;
|
||||
}
|
||||
break;
|
||||
case DNS_T_HTTPS:
|
||||
if (_dns_server_is_return_soa_qtype(request, DNS_T_A) && _dns_server_is_return_soa_qtype(request, DNS_T_AAAA)) {
|
||||
/* return SOA for HTTPS request */
|
||||
rcode = DNS_RC_NXDOMAIN;
|
||||
goto soa;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto out;
|
||||
break;
|
||||
@@ -4796,6 +5077,19 @@ errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _dns_server_process_https_svcb(struct dns_request *request)
|
||||
{
|
||||
if (request->https_svcb == NULL) {
|
||||
request->https_svcb = malloc(sizeof(*request->https_svcb));
|
||||
if (request->https_svcb == NULL) {
|
||||
return -1;
|
||||
}
|
||||
memset(request->https_svcb, 0, sizeof(*request->https_svcb));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_server_qtype_soa(struct dns_request *request)
|
||||
{
|
||||
if (request->skip_qtype_soa || dns_qtype_soa_table == NULL) {
|
||||
@@ -5002,6 +5296,10 @@ static int _dns_server_process_cache(struct dns_request *request)
|
||||
goto reply_cache;
|
||||
}
|
||||
|
||||
if (request->qtype == DNS_T_HTTPS) {
|
||||
goto reply_cache;
|
||||
}
|
||||
|
||||
if (request->dualstack_selection) {
|
||||
int dualstack_qtype = 0;
|
||||
if (request->qtype == DNS_T_A) {
|
||||
@@ -5234,11 +5532,11 @@ static int _dns_server_process_special_query(struct dns_request *request)
|
||||
/* pass to upstream server */
|
||||
request->passthrough = 1;
|
||||
}
|
||||
case DNS_T_HTTPS:
|
||||
break;
|
||||
case DNS_T_A:
|
||||
break;
|
||||
case DNS_T_AAAA:
|
||||
|
||||
break;
|
||||
default:
|
||||
tlog(TLOG_DEBUG, "unsupported qtype: %d, domain: %s", request->qtype, request->domain);
|
||||
@@ -5285,7 +5583,8 @@ static void _dns_server_check_set_passthrough(struct dns_request *request)
|
||||
request->dualstack_selection = 0;
|
||||
}
|
||||
|
||||
if (request->passthrough == 1 && (request->qtype == DNS_T_A || request->qtype == DNS_T_AAAA)) {
|
||||
if (request->passthrough == 1 &&
|
||||
(request->qtype == DNS_T_A || request->qtype == DNS_T_AAAA || request->qtype == DNS_T_HTTPS)) {
|
||||
request->passthrough = 2;
|
||||
}
|
||||
}
|
||||
@@ -5506,6 +5805,10 @@ static int _dns_server_do_query(struct dns_request *request, int skip_notify_eve
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
if (_dns_server_process_https_svcb(request) != 0) {
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
// setup options
|
||||
_dns_server_setup_query_option(request, &options);
|
||||
|
||||
@@ -5638,7 +5941,8 @@ static int _dns_server_recv(struct dns_server_conn_head *conn, unsigned char *in
|
||||
}
|
||||
|
||||
tlog(TLOG_DEBUG,
|
||||
"request qdcount = %d, ancount = %d, nscount = %d, nrcount = %d, len = %d, id = %d, tc = %d, rd = %d, ra = "
|
||||
"request qdcount = %d, ancount = %d, nscount = %d, nrcount = %d, len = %d, id = %d, tc = %d, rd = %d, "
|
||||
"ra = "
|
||||
"%d, rcode = %d\n",
|
||||
packet->head.qdcount, packet->head.ancount, packet->head.nscount, packet->head.nrcount, inpacket_len,
|
||||
packet->head.id, packet->head.tc, packet->head.rd, packet->head.ra, packet->head.rcode);
|
||||
|
||||
266
test/cases/test-https.cc
Normal file
266
test/cases/test-https.cc
Normal file
@@ -0,0 +1,266 @@
|
||||
/*************************************************************************
|
||||
*
|
||||
* Copyright (C) 2018-2023 Ruilin Peng (Nick) <pymumu@gmail.com>.
|
||||
*
|
||||
* smartdns is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* smartdns is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "client.h"
|
||||
#include "dns.h"
|
||||
#include "include/utils.h"
|
||||
#include "server.h"
|
||||
#include "util.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include <fstream>
|
||||
|
||||
class HTTPS : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
virtual void SetUp() {}
|
||||
virtual void TearDown() {}
|
||||
};
|
||||
|
||||
TEST_F(HTTPS, ipv4_speed_prefer)
|
||||
{
|
||||
smartdns::MockServer server_upstream;
|
||||
smartdns::Server server;
|
||||
|
||||
server_upstream.Start("udp://0.0.0.0:61053", [&](struct smartdns::ServerRequestContext *request) {
|
||||
if (request->qtype != DNS_T_HTTPS) {
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
}
|
||||
|
||||
struct dns_packet *packet = request->response_packet;
|
||||
struct dns_rr_nested svcparam_buffer;
|
||||
|
||||
dns_add_HTTPS_start(&svcparam_buffer, packet, DNS_RRS_AN, request->domain.c_str(), 3, 1, "b.com");
|
||||
const char alph[] = "\x02h2\x05h3-19";
|
||||
int alph_len = sizeof(alph) - 1;
|
||||
dns_HTTPS_add_alpn(&svcparam_buffer, alph, alph_len);
|
||||
dns_HTTPS_add_port(&svcparam_buffer, 443);
|
||||
unsigned char add_v4[] = {1, 2, 3, 4};
|
||||
unsigned char *addr[1] = {add_v4};
|
||||
dns_HTTPS_add_ipv4hint(&svcparam_buffer, addr, 1);
|
||||
unsigned char ech[] = {0x00, 0x45, 0xfe, 0x0d, 0x00};
|
||||
dns_HTTPS_add_ech(&svcparam_buffer, (void *)ech, sizeof(ech));
|
||||
unsigned char add_v6[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
|
||||
addr[0] = add_v6;
|
||||
dns_HTTPS_add_ipv6hint(&svcparam_buffer, addr, 1);
|
||||
dns_add_HTTPS_end(&svcparam_buffer);
|
||||
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
});
|
||||
|
||||
server.MockPing(PING_TYPE_ICMP, "1.2.3.4", 60, 10);
|
||||
server.Start(R"""(bind [::]:60053
|
||||
server 127.0.0.1:61053
|
||||
log-console yes
|
||||
dualstack-ip-selection no
|
||||
log-level debug
|
||||
cache-persist no)""");
|
||||
smartdns::Client client;
|
||||
ASSERT_TRUE(client.Query("a.com HTTPS", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 3);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetType(), "HTTPS");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "1 b.com. alpn=\"h2,h3-19\" port=443 ipv4hint=1.2.3.4 ech=AEX+DQA=");
|
||||
}
|
||||
|
||||
TEST_F(HTTPS, ipv6_speed_prefer)
|
||||
{
|
||||
smartdns::MockServer server_upstream;
|
||||
smartdns::Server server;
|
||||
|
||||
server_upstream.Start("udp://0.0.0.0:61053", [&](struct smartdns::ServerRequestContext *request) {
|
||||
if (request->qtype != DNS_T_HTTPS) {
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
}
|
||||
|
||||
struct dns_packet *packet = request->response_packet;
|
||||
struct dns_rr_nested svcparam_buffer;
|
||||
|
||||
dns_add_HTTPS_start(&svcparam_buffer, packet, DNS_RRS_AN, request->domain.c_str(), 3, 1, "b.com");
|
||||
const char alph[] = "\x02h2\x05h3-19";
|
||||
int alph_len = sizeof(alph) - 1;
|
||||
dns_HTTPS_add_alpn(&svcparam_buffer, alph, alph_len);
|
||||
dns_HTTPS_add_port(&svcparam_buffer, 443);
|
||||
unsigned char add_v4[] = {1, 2, 3, 4};
|
||||
unsigned char *addr[1] = {add_v4};
|
||||
dns_HTTPS_add_ipv4hint(&svcparam_buffer, addr, 1);
|
||||
unsigned char ech[] = {0x00, 0x45, 0xfe, 0x0d, 0x00};
|
||||
dns_HTTPS_add_ech(&svcparam_buffer, (void *)ech, sizeof(ech));
|
||||
unsigned char add_v6[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
|
||||
addr[0] = add_v6;
|
||||
dns_HTTPS_add_ipv6hint(&svcparam_buffer, addr, 1);
|
||||
dns_add_HTTPS_end(&svcparam_buffer);
|
||||
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
});
|
||||
|
||||
server.MockPing(PING_TYPE_ICMP, "102:304:506:708:90a:b0c:d0e:f10", 60, 10);
|
||||
server.Start(R"""(bind [::]:60053
|
||||
server 127.0.0.1:61053
|
||||
log-console yes
|
||||
dualstack-ip-selection no
|
||||
log-level debug
|
||||
cache-persist no)""");
|
||||
smartdns::Client client;
|
||||
ASSERT_TRUE(client.Query("a.com HTTPS", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 3);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetType(), "HTTPS");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(),
|
||||
"1 b.com. alpn=\"h2,h3-19\" port=443 ech=AEX+DQA= ipv6hint=102:304:506:708:90a:b0c:d0e:f10");
|
||||
}
|
||||
|
||||
TEST_F(HTTPS, ipv4_SOA)
|
||||
{
|
||||
smartdns::MockServer server_upstream;
|
||||
smartdns::Server server;
|
||||
|
||||
server_upstream.Start("udp://0.0.0.0:61053", [&](struct smartdns::ServerRequestContext *request) {
|
||||
if (request->qtype != DNS_T_HTTPS) {
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
}
|
||||
|
||||
struct dns_packet *packet = request->response_packet;
|
||||
struct dns_rr_nested svcparam_buffer;
|
||||
|
||||
dns_add_HTTPS_start(&svcparam_buffer, packet, DNS_RRS_AN, request->domain.c_str(), 3, 1, "a.com");
|
||||
const char alph[] = "\x02h2\x05h3-19";
|
||||
int alph_len = sizeof(alph) - 1;
|
||||
dns_HTTPS_add_alpn(&svcparam_buffer, alph, alph_len);
|
||||
dns_HTTPS_add_port(&svcparam_buffer, 443);
|
||||
unsigned char add_v4[] = {1, 2, 3, 4};
|
||||
unsigned char *addr[1] = {add_v4};
|
||||
dns_HTTPS_add_ipv4hint(&svcparam_buffer, addr, 1);
|
||||
unsigned char ech[] = {0x00, 0x45, 0xfe, 0x0d, 0x00};
|
||||
dns_HTTPS_add_ech(&svcparam_buffer, (void *)ech, sizeof(ech));
|
||||
unsigned char add_v6[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
|
||||
addr[0] = add_v6;
|
||||
dns_HTTPS_add_ipv6hint(&svcparam_buffer, addr, 1);
|
||||
dns_add_HTTPS_end(&svcparam_buffer);
|
||||
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
});
|
||||
|
||||
server.Start(R"""(bind [::]:60053
|
||||
server 127.0.0.1:61053
|
||||
log-console yes
|
||||
dualstack-ip-selection no
|
||||
address /a.com/#4
|
||||
log-level debug
|
||||
cache-persist no)""");
|
||||
smartdns::Client client;
|
||||
ASSERT_TRUE(client.Query("a.com HTTPS", 61053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
auto result_check = client.GetAnswer()[0].GetData();
|
||||
|
||||
ASSERT_TRUE(client.Query("a.com HTTPS", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 3);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetType(), "HTTPS");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(),
|
||||
"1 a.com. alpn=\"h2,h3-19\" port=443 ech=AEX+DQA= ipv6hint=102:304:506:708:90a:b0c:d0e:f10");
|
||||
}
|
||||
|
||||
TEST_F(HTTPS, ipv6_SOA)
|
||||
{
|
||||
smartdns::MockServer server_upstream;
|
||||
smartdns::Server server;
|
||||
|
||||
server_upstream.Start("udp://0.0.0.0:61053", [&](struct smartdns::ServerRequestContext *request) {
|
||||
if (request->qtype != DNS_T_HTTPS) {
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
}
|
||||
|
||||
struct dns_packet *packet = request->response_packet;
|
||||
struct dns_rr_nested svcparam_buffer;
|
||||
|
||||
dns_add_HTTPS_start(&svcparam_buffer, packet, DNS_RRS_AN, request->domain.c_str(), 3, 1, "a.com");
|
||||
const char alph[] = "\x02h2\x05h3-19";
|
||||
int alph_len = sizeof(alph) - 1;
|
||||
dns_HTTPS_add_alpn(&svcparam_buffer, alph, alph_len);
|
||||
dns_HTTPS_add_port(&svcparam_buffer, 443);
|
||||
unsigned char add_v4[] = {1, 2, 3, 4};
|
||||
unsigned char *addr[1] = {add_v4};
|
||||
dns_HTTPS_add_ipv4hint(&svcparam_buffer, addr, 1);
|
||||
unsigned char ech[] = {0x00, 0x45, 0xfe, 0x0d, 0x00};
|
||||
dns_HTTPS_add_ech(&svcparam_buffer, (void *)ech, sizeof(ech));
|
||||
unsigned char add_v6[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
|
||||
addr[0] = add_v6;
|
||||
dns_HTTPS_add_ipv6hint(&svcparam_buffer, addr, 1);
|
||||
dns_add_HTTPS_end(&svcparam_buffer);
|
||||
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
});
|
||||
|
||||
server.Start(R"""(bind [::]:60053
|
||||
server 127.0.0.1:61053
|
||||
log-console yes
|
||||
dualstack-ip-selection no
|
||||
address /a.com/#6
|
||||
log-level debug
|
||||
cache-persist no)""");
|
||||
smartdns::Client client;
|
||||
ASSERT_TRUE(client.Query("a.com HTTPS", 61053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
auto result_check = client.GetAnswer()[0].GetData();
|
||||
|
||||
ASSERT_TRUE(client.Query("a.com HTTPS", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 3);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetType(), "HTTPS");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "1 a.com. alpn=\"h2,h3-19\" port=443 ipv4hint=1.2.3.4 ech=AEX+DQA=");
|
||||
}
|
||||
|
||||
TEST_F(HTTPS, SOA)
|
||||
{
|
||||
smartdns::MockServer server_upstream;
|
||||
smartdns::Server server;
|
||||
|
||||
server_upstream.Start("udp://0.0.0.0:61053", [&](struct smartdns::ServerRequestContext *request) {
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
});
|
||||
|
||||
server.Start(R"""(bind [::]:60053
|
||||
server 127.0.0.1:61053
|
||||
log-console yes
|
||||
dualstack-ip-selection no
|
||||
address /a.com/#6
|
||||
log-level debug
|
||||
cache-persist no)""");
|
||||
smartdns::Client client;
|
||||
ASSERT_TRUE(client.Query("a.com HTTPS", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAuthorityNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NXDOMAIN");
|
||||
EXPECT_EQ(client.GetAuthority()[0].GetName(), "a.com");
|
||||
EXPECT_EQ(client.GetAuthority()[0].GetTTL(), 60);
|
||||
EXPECT_EQ(client.GetAuthority()[0].GetType(), "SOA");
|
||||
}
|
||||
@@ -255,3 +255,55 @@ cache-persist no)""");
|
||||
EXPECT_EQ(client.GetAuthority()[0].GetTTL(), 30);
|
||||
EXPECT_EQ(client.GetAuthority()[0].GetType(), "SOA");
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST_F(QtypeSOA, HTTPS_SOA)
|
||||
{
|
||||
smartdns::MockServer server_upstream;
|
||||
smartdns::Server server;
|
||||
std::map<int, int> qid_map;
|
||||
|
||||
server_upstream.Start("udp://0.0.0.0:61053", [&](struct smartdns::ServerRequestContext *request) {
|
||||
if (request->qtype != DNS_T_HTTPS) {
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
}
|
||||
|
||||
struct dns_packet *packet = request->response_packet;
|
||||
struct dns_rr_nested svcparam_buffer;
|
||||
|
||||
dns_add_HTTPS_start(&svcparam_buffer, packet, DNS_RRS_AN, request->domain.c_str(), 3, 1, "a.com");
|
||||
const char alph[] = "\x02h2\x05h3-19";
|
||||
int alph_len = sizeof(alph) - 1;
|
||||
dns_HTTPS_add_alpn(&svcparam_buffer, alph, alph_len);
|
||||
dns_HTTPS_add_port(&svcparam_buffer, 443);
|
||||
unsigned char add_v4[] = {1, 2, 3, 4};
|
||||
unsigned char *addr[1] = {add_v4};
|
||||
dns_HTTPS_add_ipv4hint(&svcparam_buffer, addr, 1);
|
||||
unsigned char ech[] = {0x00, 0x45, 0xfe, 0x0d, 0x00};
|
||||
dns_HTTPS_add_ech(&svcparam_buffer, (void *)ech, sizeof(ech));
|
||||
unsigned char add_v6[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
|
||||
addr[0] = add_v6;
|
||||
dns_HTTPS_add_ipv6hint(&svcparam_buffer, addr, 1);
|
||||
dns_add_HTTPS_end(&svcparam_buffer);
|
||||
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
});
|
||||
|
||||
server.Start(R"""(bind [::]:60053
|
||||
server 127.0.0.1:61053
|
||||
log-console yes
|
||||
dualstack-ip-selection no
|
||||
speed-check-mode none
|
||||
address /a.com/#
|
||||
log-level debug
|
||||
cache-persist no)""");
|
||||
smartdns::Client client;
|
||||
ASSERT_TRUE(client.Query("a.com HTTPS", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAuthorityNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NXDOMAIN");
|
||||
EXPECT_EQ(client.GetAuthority()[0].GetName(), "a.com");
|
||||
EXPECT_EQ(client.GetAuthority()[0].GetTTL(), 30);
|
||||
EXPECT_EQ(client.GetAuthority()[0].GetType(), "SOA");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user