From 94b84cd32c2e7de46082354209c4eead1e6d73ba Mon Sep 17 00:00:00 2001 From: Nick Peng Date: Sat, 21 May 2022 02:18:44 +0800 Subject: [PATCH] dns_server: support query smartdns server ip --- ReadMe.md | 21 ++--- ReadMe_en.md | 18 ++-- src/dns_conf.c | 35 ++++++++ src/dns_conf.h | 1 + src/dns_server.c | 211 ++++++++++++++++++++++++++++++++++++++++++----- 5 files changed, 238 insertions(+), 48 deletions(-) diff --git a/ReadMe.md b/ReadMe.md index feb6633..04f1c6f 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -311,8 +311,6 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms * **检测上游服务是否配置成功** - * 方法一 - 执行 ```shell @@ -329,22 +327,15 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms Non-authoritative answer: smartdns name = smartdns. ``` - - * 方法二 - - 使用 `nslookup` 查询域名(例如 `www.baidu.com`),查看结果中 IP 地址是否**只有一个**,如有多个 IP 地址返回,则表示未生效,请多尝试几个域名检查。 - + + 或执行 ```shell - $ nslookup www.baidu.com 192.168.1.1 - Server: 192.168.1.1 - Address: 192.168.1.1#53 - - Non-authoritative answer: - www.baidu.com canonical name = www.a.shifen.com. - Name: www.a.shifen.com - Address: 14.215.177.38 + $ nslookup smartdns ``` + 查看命令结果是否有解析出路由器的IP地址,如果是则表示生效。 + + 4. 启动服务 勾选配置页面中的 `Enable(启用)`来启动 SmartDNS。 diff --git a/ReadMe_en.md b/ReadMe_en.md index 4149e71..49177f4 100755 --- a/ReadMe_en.md +++ b/ReadMe_en.md @@ -281,7 +281,7 @@ https://github.com/pymumu/smartdns/releases * **Check if the service is configured successfully** - * Method 1: Query domain name with `nslookup -querytype=ptr 0.0.0.1` + * Query domain name with `nslookup -querytype=ptr 0.0.0.1` See if the `name` item in the command result is displayed as `smartdns` or `hostname`, such as `smartdns` ```shell @@ -293,18 +293,12 @@ https://github.com/pymumu/smartdns/releases smartdns name = smartdns. ``` - * Method 2: Use `nslookup` to query the `www.baidu.com` domain name to see if the IP address of Baidu in the result is `only one. If there are multiple IP addresses returned, it means that it is not valid. Please try to check several domain names. + * or Query doman name `smartdns `with `nslookup smartdns` + ```shell + $ nslookup smartdns + ``` - ```shell - pi@raspberrypi:~ $ nslookup www.baidu.com 192.168.1.1 - Server: 192.168.1.1 - Address: 192.168.1.1#53 - - Non-authoritative answer: - www.baidu.com canonical name = www.a.shifen.com. - Name: www.a.shifen.com - Address: 14.215.177.38 - ``` + Check whether the command result resolves the IP address of the router, if so, it means it is working. 1. Start Service diff --git a/src/dns_conf.c b/src/dns_conf.c index 2ea870b..01a59c9 100644 --- a/src/dns_conf.c +++ b/src/dns_conf.c @@ -1749,6 +1749,10 @@ int dns_server_check_update_hosts(void) struct stat statbuf; time_t now; + if (dns_conf_dnsmasq_lease_file[0] == '\0') { + return -1; + } + if (stat(dns_conf_dnsmasq_lease_file, &statbuf) != 0) { return -1; } @@ -1798,6 +1802,35 @@ static int _config_log_level(void *data, int argc, char *argv[]) return 0; } +static void _config_setup_smartdns_domain(void) +{ + char hostname[DNS_MAX_CNAME_LEN]; + /* get local host name */ + if (getdomainname(hostname, DNS_MAX_CNAME_LEN) != 0) { + gethostname(hostname, DNS_MAX_CNAME_LEN); + } + + /* get host name again */ + if (strncmp(hostname, "(none)", DNS_MAX_CNAME_LEN) == 0) { + gethostname(hostname, DNS_MAX_CNAME_LEN); + } + + /* if hostname is (none), return smartdns */ + if (strncmp(hostname, "(none)", DNS_MAX_CNAME_LEN) == 0) { + safe_strncpy(hostname, "smartdns", DNS_MAX_CNAME_LEN); + } + + if (hostname[0] != '\0') { + _config_domain_rule_flag_set(hostname, DOMAIN_FLAG_SMARTDNS_DOMAIN, 0); + } + + if (dns_conf_server_name[0] != '\0') { + _config_domain_rule_flag_set(dns_conf_server_name, DOMAIN_FLAG_SMARTDNS_DOMAIN, 0); + } + + _config_domain_rule_flag_set("smartdns", DOMAIN_FLAG_SMARTDNS_DOMAIN, 0); +} + static struct config_item _config_item[] = { CONF_STRING("server-name", (char *)dns_conf_server_name, DNS_MAX_SERVER_NAME_LEN), CONF_CUSTOM("bind", _config_bind_ip_udp, NULL), @@ -1918,6 +1951,8 @@ static int _dns_server_load_conf_init(void) hash_init(dns_hosts_table.hosts); hash_init(dns_ptr_table.ptr); + _config_setup_smartdns_domain(); + return 0; } diff --git a/src/dns_conf.h b/src/dns_conf.h index 6874ab3..dc66f12 100644 --- a/src/dns_conf.h +++ b/src/dns_conf.h @@ -86,6 +86,7 @@ typedef enum { #define DOMAIN_FLAG_IPSET_IPV6_IGN (1 << 8) #define DOMAIN_FLAG_NAMESERVER_IGNORE (1 << 9) #define DOMAIN_FLAG_DUALSTACK_SELECT (1 << 10) +#define DOMAIN_FLAG_SMARTDNS_DOMAIN (1 << 11) #define SERVER_FLAG_EXCLUDE_DEFAULT (1 << 0) diff --git a/src/dns_server.c b/src/dns_server.c index 767bd1c..c12bbfe 100644 --- a/src/dns_server.c +++ b/src/dns_server.c @@ -665,11 +665,11 @@ static int _dns_add_rrs(struct dns_server_post_context *context) tlog(TLOG_INFO, "result: %s, rcode: %d, index: %d, rtt: %d, " "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x", - request->domain, request->rcode, context->ip_num, request->ping_ttl_v6, request->ipv6_addr[0], request->ipv6_addr[1], - request->ipv6_addr[2], request->ipv6_addr[3], request->ipv6_addr[4], request->ipv6_addr[5], - request->ipv6_addr[6], request->ipv6_addr[7], request->ipv6_addr[8], request->ipv6_addr[9], - request->ipv6_addr[10], request->ipv6_addr[11], request->ipv6_addr[12], request->ipv6_addr[13], - request->ipv6_addr[14], request->ipv6_addr[15]); + request->domain, request->rcode, context->ip_num, request->ping_ttl_v6, request->ipv6_addr[0], + request->ipv6_addr[1], request->ipv6_addr[2], request->ipv6_addr[3], request->ipv6_addr[4], + request->ipv6_addr[5], request->ipv6_addr[6], request->ipv6_addr[7], request->ipv6_addr[8], + request->ipv6_addr[9], request->ipv6_addr[10], request->ipv6_addr[11], request->ipv6_addr[12], + request->ipv6_addr[13], request->ipv6_addr[14], request->ipv6_addr[15]); } ret |= _dns_rrs_add_all_best_ip(context); @@ -1328,7 +1328,8 @@ out: return _dns_server_reply_all_pending_list(request, &context); } -static int _dns_ip_address_check_add(struct dns_request *request, char *cname, unsigned char *addr, dns_type_t addr_type) +static int _dns_ip_address_check_add(struct dns_request *request, char *cname, unsigned char *addr, + dns_type_t addr_type) { uint32_t key = 0; struct dns_ip_address *addr_map = NULL; @@ -1684,7 +1685,8 @@ static void _dns_server_ping_result(struct ping_host_struct *ping_host, const ch if (is_ipv6_ready) { if (error == EADDRNOTAVAIL || errno == EACCES) { is_ipv6_ready = 0; - tlog(TLOG_ERROR, "IPV6 is not ready, disable all ipv6 feature, recheck after %ds", IPV6_READY_CHECK_TIME); + tlog(TLOG_ERROR, "IPV6 is not ready, disable all ipv6 feature, recheck after %ds", + IPV6_READY_CHECK_TIME); } } return; @@ -1753,8 +1755,7 @@ static void _dns_server_ping_result(struct ping_host_struct *ping_host, const ch request->has_ping_result = 1; } } else { - addr_map = _dns_ip_address_get(request, addr_in6->sin6_addr.s6_addr, - DNS_T_AAAA); + addr_map = _dns_ip_address_get(request, addr_in6->sin6_addr.s6_addr, DNS_T_AAAA); if (addr_map) { addr_map->ping_ttl = rtt; } @@ -1766,8 +1767,7 @@ static void _dns_server_ping_result(struct ping_host_struct *ping_host, const ch memcpy(request->ipv6_addr, addr_in6->sin6_addr.s6_addr, 16); if (addr_map && addr_map->cname[0] != 0) { request->has_cname = 1; - safe_strncpy(request->cname, addr_map->cname, - DNS_MAX_CNAME_LEN); + safe_strncpy(request->cname, addr_map->cname, DNS_MAX_CNAME_LEN); } else { request->has_cname = 0; } @@ -2414,7 +2414,7 @@ static int dns_server_resolve_callback(char *domain, dns_result_type rtype, unsi } ttl = _dns_server_get_conf_ttl(ttl); - if ( ttl > dns_conf_rr_ttl_reply_max && dns_conf_rr_ttl_reply_max > 0) { + if (ttl > dns_conf_rr_ttl_reply_max && dns_conf_rr_ttl_reply_max > 0) { ttl = dns_conf_rr_ttl_reply_max; } @@ -2454,6 +2454,153 @@ static int dns_server_resolve_callback(char *domain, dns_result_type rtype, unsi return 0; } +static int _dns_server_get_inet_by_addr(struct sockaddr_storage *localaddr, struct sockaddr_storage *addr, int family) +{ + struct ifaddrs *ifaddr = NULL; + struct ifaddrs *ifa = NULL; + char ethname[16] = {0}; + + if (getifaddrs(&ifaddr) == -1) { + return -1; + } + + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == NULL) { + continue; + } + + if (localaddr->ss_family != ifa->ifa_addr->sa_family) { + continue; + } + + switch (ifa->ifa_addr->sa_family) { + case AF_INET: { + struct sockaddr_in *addr_in_1; + struct sockaddr_in *addr_in_2; + addr_in_1 = (struct sockaddr_in *)ifa->ifa_addr; + addr_in_2 = (struct sockaddr_in *)localaddr; + if (memcmp(&(addr_in_1->sin_addr.s_addr), &(addr_in_2->sin_addr.s_addr), 4) != 0) { + continue; + } + } break; + case AF_INET6: { + struct sockaddr_in6 *addr_in6_1; + struct sockaddr_in6 *addr_in6_2; + addr_in6_1 = (struct sockaddr_in6 *)ifa->ifa_addr; + addr_in6_2 = (struct sockaddr_in6 *)localaddr; + if (IN6_IS_ADDR_V4MAPPED(&addr_in6_1->sin6_addr)) { + unsigned char *addr1 = addr_in6_1->sin6_addr.s6_addr + 12; + unsigned char *addr2 = addr_in6_2->sin6_addr.s6_addr + 12; + if (memcmp(addr1, addr2, 4) != 0) { + continue; + } + } else { + unsigned char *addr1 = addr_in6_1->sin6_addr.s6_addr; + unsigned char *addr2 = addr_in6_2->sin6_addr.s6_addr; + if (memcmp(addr1, addr2, 16) != 0) { + continue; + } + } + } break; + default: + continue; + break; + } + + safe_strncpy(ethname, ifa->ifa_name, sizeof(ethname)); + break; + } + + if (ethname[0] == '\0') { + goto errout; + } + + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == NULL) { + continue; + } + + if (ifa->ifa_addr->sa_family != family) { + continue; + } + + if (strncmp(ethname, ifa->ifa_name, sizeof(ethname)) != 0) { + continue; + } + + if (family == AF_INET) { + memcpy(addr, ifa->ifa_addr, sizeof(struct sockaddr_in)); + } else if (family == AF_INET6) { + memcpy(addr, ifa->ifa_addr, sizeof(struct sockaddr_in6)); + } + + break; + } + + freeifaddrs(ifaddr); + return 0; +errout: + if (ifaddr) { + freeifaddrs(ifaddr); + } + + return -1; +} + +static int _dns_server_reply_request_eth_ip(struct dns_request *request) +{ + struct sockaddr_in *addr_in = NULL; + struct sockaddr_in6 *addr_in6 = NULL; + struct sockaddr_storage *localaddr; + struct sockaddr_storage localaddr_buff; + + localaddr = &request->localaddr; + + /* address /domain/ rule */ + switch (request->qtype) { + case DNS_T_A: + if (localaddr->ss_family != AF_INET) { + if (_dns_server_get_inet_by_addr(localaddr, &localaddr_buff, AF_INET) != 0) { + _dns_server_reply_SOA(DNS_RC_NOERROR, request); + return 0; + } + + localaddr = &localaddr_buff; + } + addr_in = (struct sockaddr_in *)localaddr; + memcpy(request->ipv4_addr, &addr_in->sin_addr.s_addr, DNS_RR_A_LEN); + request->ttl_v4 = 600; + request->has_ipv4 = 1; + break; + case DNS_T_AAAA: + if (localaddr->ss_family != AF_INET6) { + if (_dns_server_get_inet_by_addr(localaddr, &localaddr_buff, AF_INET6) != 0) { + _dns_server_reply_SOA(DNS_RC_NOERROR, request); + return 0; + } + + localaddr = &localaddr_buff; + } + addr_in6 = (struct sockaddr_in6 *)localaddr; + memcpy(request->ipv6_addr, &addr_in6->sin6_addr.s6_addr, DNS_RR_AAAA_LEN); + request->ttl_v6 = 600; + request->has_ipv6 = 1; + break; + default: + goto out; + break; + } + + request->rcode = DNS_RC_NOERROR; + struct dns_server_post_context context; + _dns_server_post_context_init(&context, request); + context.do_reply = 1; + _dns_request_post(&context); + + return 0; +out: + return -1; +} static int _dns_server_process_ptrs(struct dns_request *request) { @@ -2462,7 +2609,7 @@ static int _dns_server_process_ptrs(struct dns_request *request) struct dns_ptr *ptr_tmp = NULL; key = hash_string(request->domain); hash_for_each_possible(dns_ptr_table.ptr, ptr_tmp, node, key) - { + { if (strncmp(ptr_tmp->ptr_domain, request->domain, DNS_MAX_CNAME_LEN) != 0) { continue; } @@ -2482,7 +2629,7 @@ errout: return -1; } -static int _dns_server_process_local_ptr(struct dns_request *request) +static int _dns_server_process_local_ptr(struct dns_request *request) { struct ifaddrs *ifaddr = NULL; struct ifaddrs *ifa = NULL; @@ -2541,14 +2688,12 @@ static int _dns_server_process_local_ptr(struct dns_request *request) } /* Determine if the smartdns service is in effect. */ - if (strncmp(request->domain, "0.0.0.0.in-addr.arpa", DNS_MAX_CNAME_LEN) == - 0) { + if (strncmp(request->domain, "0.0.0.0.in-addr.arpa", DNS_MAX_CNAME_LEN) == 0) { found = 1; } /* Determine if the smartdns service is in effect. */ - if (found == 0 && - strncmp(request->domain, "smartdns", sizeof("smartdns")) == 0) { + if (found == 0 && strncmp(request->domain, "smartdns", sizeof("smartdns")) == 0) { found = 1; } @@ -3176,10 +3321,33 @@ static void _dns_server_request_set_callback(struct dns_request *request, dns_re request->user_ptr = user_ptr; } +static int _dns_server_process_smartdns_domain(struct dns_request *request) +{ + struct dns_rule_flags *rule_flag = NULL; + unsigned int flags = 0; + + /* get domain rule flag */ + rule_flag = request->domain_rule.rules[DOMAIN_RULE_FLAGS]; + if (rule_flag == NULL) { + return -1; + } + + flags = rule_flag->flags; + if (!(flags & DOMAIN_FLAG_SMARTDNS_DOMAIN)) { + return -1; + } + + return _dns_server_reply_request_eth_ip(request); +} + static int _dns_server_process_special_query(struct dns_request *request) { int ret = 0; + if (_dns_server_process_smartdns_domain(request) == 0) { + goto clean_exit; + } + switch (request->qtype) { case DNS_T_PTR: /* return PTR record */ @@ -3266,7 +3434,7 @@ static int _dns_server_process_host(struct dns_request *request) if (host_tmp->dns_type != dns_type) { continue; } - + if (strncmp(host_tmp->domain, hostname_lower, DNS_MAX_CNAME_LEN) != 0) { continue; } @@ -3283,7 +3451,7 @@ static int _dns_server_process_host(struct dns_request *request) request->has_soa = 1; return _dns_server_reply_SOA(DNS_RC_NOERROR, request); } - + switch (request->qtype) { case DNS_T_A: memcpy(request->ipv4_addr, host->ipv4_addr, DNS_RR_A_LEN); @@ -4446,7 +4614,8 @@ int dns_server_init(void) } _dns_server_check_ipv6_ready(); - tlog(TLOG_INFO, "%s", (is_ipv6_ready) ? "IPV6 is ready, enable IPV6 features" : "IPV6 is not ready, disable IPV6 features"); + tlog(TLOG_INFO, "%s", + (is_ipv6_ready) ? "IPV6 is ready, enable IPV6 features" : "IPV6 is not ready, disable IPV6 features"); return 0; errout: