Bläddra i källkod

dns_server: support query smartdns server ip

Nick Peng 3 år sedan
förälder
incheckning
94b84cd32c
5 ändrade filer med 238 tillägg och 48 borttagningar
  1. 6 15
      ReadMe.md
  2. 6 12
      ReadMe_en.md
  3. 35 0
      src/dns_conf.c
  4. 1 0
      src/dns_conf.h
  5. 190 21
      src/dns_server.c

+ 6 - 15
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。

+ 6 - 12
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
 

+ 35 - 0
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;
 }
 

+ 1 - 0
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)
 

+ 190 - 21
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: