Browse Source

Support no-soa, no-dualstack-selection for bind flags

Nick Peng 6 years ago
parent
commit
4e11c13ec0
3 changed files with 157 additions and 54 deletions
  1. 10 0
      src/dns_conf.c
  2. 4 2
      src/dns_conf.h
  3. 143 52
      src/dns_server.c

+ 10 - 0
src/dns_conf.c

@@ -811,8 +811,10 @@ static int _config_bind_ip(int argc, char *argv[], DNS_BIND_TYPE type)
 		{"no-rule-nameserver", no_argument, NULL, 'N'},   
 		{"no-rule-ipset", no_argument, NULL, 'I'},   
 		{"no-rule-sni-proxy", no_argument, NULL, 'P'},   
+		{"no-rule-soa", no_argument, NULL, 'O'},
 		{"no-speed-check", no_argument, NULL, 'S'},  
 		{"no-cache", no_argument, NULL, 'C'},  
+		{"no-dualstack-selection", no_argument, NULL, 'D'},
 		{NULL, no_argument, NULL, 0}
 	};
 	/* clang-format on */
@@ -870,6 +872,14 @@ static int _config_bind_ip(int argc, char *argv[], DNS_BIND_TYPE type)
 			server_flag |= BIND_FLAG_NO_CACHE;
 			break;
 		}
+		case 'O': {
+			server_flag |= BIND_FLAG_NO_RULE_SOA;
+			break;
+		}
+		case 'D': {
+			server_flag |= BIND_FLAG_NO_DUALSTACK_SELECTION;
+			break;
+		}
 		default:
 			break;
 		}

+ 4 - 2
src/dns_conf.h

@@ -63,8 +63,10 @@ typedef enum {
 #define BIND_FLAG_NO_RULE_NAMESERVER (1 << 1)
 #define BIND_FLAG_NO_RULE_IPSET (1 << 2)
 #define BIND_FLAG_NO_RULE_SNIPROXY (1 << 3)
-#define BIND_FLAG_NO_SPEED_CHECK (1 << 4)
-#define BIND_FLAG_NO_CACHE (1 << 5)
+#define BIND_FLAG_NO_RULE_SOA (1 << 4)
+#define BIND_FLAG_NO_SPEED_CHECK (1 << 5)
+#define BIND_FLAG_NO_CACHE (1 << 6)
+#define BIND_FLAG_NO_DUALSTACK_SELECTION (1 << 7)
 
 struct dns_rule_flags {
 	unsigned int flags;

+ 143 - 52
src/dns_server.c

@@ -228,6 +228,49 @@ static int _dns_server_epoll_ctl(struct dns_server_conn_head *head, int op, uint
 	return 0;
 }
 
+static int _dns_server_is_dualstack_selection(struct dns_request *request)
+{
+	if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_DUALSTACK_SELECTION) == 0) {
+		return 0;
+	}
+
+	return dns_conf_dualstack_ip_selection;
+}
+
+static int _dns_server_is_return_soa(struct dns_request *request)
+{
+	struct dns_rule_flags *rule_flag = NULL;
+	unsigned int flags = 0;
+
+	if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_RULE_SOA) == 0) {
+		return 0;
+	}
+
+	if (dns_conf_force_AAAA_SOA == 1 && request->qtype == DNS_T_AAAA) {
+		return 1;
+	}
+
+	if (request->domain_rule) {
+		rule_flag = request->domain_rule->rules[DOMAIN_RULE_FLAGS];
+		if (rule_flag) {
+			flags = rule_flag->flags;
+			if (flags & DOMAIN_FLAG_ADDR_SOA) {
+				return 1;
+			} 
+
+			if ((flags & DOMAIN_FLAG_ADDR_IPV4_SOA) && (request->qtype == DNS_T_A)) {
+				return 1;
+			}
+
+			if ((flags & DOMAIN_FLAG_ADDR_IPV6_SOA) && (request->qtype == DNS_T_AAAA)) {
+				return 1;
+			}
+		}
+	}
+
+	return 0;
+}
+
 static void _dns_server_audit_log(struct dns_request *request)
 {
 	char req_host[MAX_IP_LEN];
@@ -604,85 +647,133 @@ static int _dns_setup_ipset(struct dns_request *request)
 	return ret;
 }
 
-static int _dns_server_request_complete(struct dns_request *request)
+static int _dns_server_request_complete_A(struct dns_request *request)
 {
 	char *cname = NULL;
 	int cname_ttl = 0;
 
-	if (atomic_inc_return(&request->notified) != 1) {
+	if (request->has_cname) {
+		cname = request->cname;
+		cname_ttl = request->ttl_cname;
+	}
+
+	if (request->has_ipv4 == 0) {
 		return 0;
 	}
 
-	/* if passthrouth, return */
-	if (request->passthrough) {
+	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;
+	}
+
+	if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_CACHE) == 0) {
 		return 0;
 	}
 
+	/* if doing prefetch, update cache only */
+	if (request->prefetch) {
+		dns_cache_replace(request->domain, cname, cname_ttl, request->ttl_v4, DNS_T_A, request->ipv4_addr, DNS_RR_A_LEN, request->ping_ttl_v4);
+	} else {
+		/* insert result to cache */
+		dns_cache_insert(request->domain, cname, cname_ttl, request->ttl_v4, DNS_T_A, request->ipv4_addr, DNS_RR_A_LEN, request->ping_ttl_v4);
+	}
+
+	return 0;
+}
+
+static int _dns_server_request_complete_AAAA(struct dns_request *request)
+{
+	char *cname = NULL;
+	int cname_ttl = 0;
+
 	if (request->has_cname) {
 		cname = request->cname;
 		cname_ttl = request->ttl_cname;
 	}
 
-	if (request->qtype == DNS_T_A) {
-		if (request->has_ipv4) {
-			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_ping_result == 0 && request->ttl_v4 > DNS_SERVER_TMOUT_TTL) {
-				request->ttl_v4 = DNS_SERVER_TMOUT_TTL;
-			}
+	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", request->domain, request->rcode,
+			 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]);
 
-			/* if doing prefetch, update cache only */
-			if (request->prefetch) {
-				dns_cache_replace(request->domain, cname, cname_ttl, request->ttl_v4, DNS_T_A, request->ipv4_addr, DNS_RR_A_LEN, request->ping_ttl_v4);
-			} else {
-				/* insert result to cache */
-				dns_cache_insert(request->domain, cname, cname_ttl, request->ttl_v4, DNS_T_A, request->ipv4_addr, DNS_RR_A_LEN, request->ping_ttl_v4);
-			}
-
-			request->has_soa = 0;
+		if (request->has_ping_result == 0 && request->ttl_v6 > DNS_SERVER_TMOUT_TTL) {
+			request->ttl_v6 = DNS_SERVER_TMOUT_TTL;
 		}
 
-	} else if (request->qtype == DNS_T_AAAA) {
-		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", request->domain, request->rcode,
-				 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]);
-
-			if (request->has_ping_result == 0 && request->ttl_v6 > DNS_SERVER_TMOUT_TTL) {
-				request->ttl_v6 = DNS_SERVER_TMOUT_TTL;
-			}
-
-			/* if doing prefetch, update cache only */
+		/* if doing prefetch, update cache only */
+		if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_CACHE) != 0) {
 			if (request->prefetch) {
 				dns_cache_replace(request->domain, cname, cname_ttl, request->ttl_v6, DNS_T_AAAA, request->ipv6_addr, DNS_RR_AAAA_LEN, request->ping_ttl_v6);
 			} else {
 				/* insert result to cache */
 				dns_cache_insert(request->domain, cname, cname_ttl, request->ttl_v6, DNS_T_AAAA, request->ipv6_addr, DNS_RR_AAAA_LEN, request->ping_ttl_v6);
 			}
-
-			request->has_soa = 0;
 		}
 
-		if (request->has_ipv4 && (request->ping_ttl_v4 > 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 ipv4 is fasting than ipv6, add ipv4 to cache, and return SOA for AAAA request */
-			if ((request->ping_ttl_v4 + (dns_conf_dualstack_ip_selection_threshold * 10)) < request->ping_ttl_v6 || request->ping_ttl_v6 < 0) {
-				tlog(TLOG_DEBUG, "Force IPV4 perfered.");
+	if (request->has_ipv4 && (request->ping_ttl_v4 > 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]);
+
+		/* if ipv4 is fasting than ipv6, add ipv4 to cache, and return SOA for AAAA request */
+		if ((request->ping_ttl_v4 + (dns_conf_dualstack_ip_selection_threshold * 10)) < request->ping_ttl_v6 || request->ping_ttl_v6 < 0) {
+			tlog(TLOG_DEBUG, "Force IPV4 perfered.");
+			if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_CACHE) != 0) {
 				if (request->prefetch) {
 					dns_cache_replace(request->domain, cname, cname_ttl, request->ttl_v4, DNS_T_A, request->ipv4_addr, DNS_RR_A_LEN, request->ping_ttl_v4);
 				} else {
 					dns_cache_insert(request->domain, cname, cname_ttl, request->ttl_v4, DNS_T_A, request->ipv4_addr, DNS_RR_A_LEN, request->ping_ttl_v4);
 				}
+			}
 
-				return _dns_server_reply_SOA(DNS_RC_NOERROR, request);
+			if (_dns_server_is_dualstack_selection(request)) {
+				if (_dns_server_reply_SOA(DNS_RC_NOERROR, request) != 0) {
+					return -1;
+				}
+
+				return 1;
 			}
 		}
+	}
+
+	request->has_ipv4 = 0;
 
-		request->has_ipv4 = 0;
+	return 0;
+}
+
+static int _dns_server_request_complete(struct dns_request *request)
+{
+	int ret = 0;
+
+	if (atomic_inc_return(&request->notified) != 1) {
+		return 0;
+	}
+
+	/* if passthrouth, return */
+	if (request->passthrough) {
+		return 0;
+	}
+
+	if (request->qtype == DNS_T_A) {
+		if (_dns_server_request_complete_A(request) != 0) {
+			tlog(TLOG_ERROR, "complete DNS A failed.");
+			return -1;
+		}
+	} else if (request->qtype == DNS_T_AAAA) {
+		ret = _dns_server_request_complete_AAAA(request);
+		if (ret != 0) {
+			if (ret == 1) {
+				return 0;
+			}
+			tlog(TLOG_ERROR, "complete DNS A failed.");
+			return -1;
+		}
 	}
 
 	if (request->has_soa) {
@@ -893,7 +984,7 @@ static void _dns_server_ping_result(struct ping_host_struct *ping_host, const ch
 			memcpy(request->ipv4_addr, &addr_in->sin_addr.s_addr, 4);
 		}
 
-		if (request->qtype == DNS_T_AAAA && dns_conf_dualstack_ip_selection == 1) {
+		if (request->qtype == DNS_T_AAAA && _dns_server_is_dualstack_selection(request)) {
 			if (request->ping_ttl_v6 < 0 && request->has_soa == 0) {
 				return;
 			}
@@ -1140,7 +1231,7 @@ static int _dns_server_process_answer_A(struct dns_rrs *rrs, struct dns_request
 
 	if (request->qtype != DNS_T_A) {
 		/* ignore non-matched query type */
-		if (dns_conf_dualstack_ip_selection == 0) {
+		if (_dns_server_is_dualstack_selection(request) == 0) {
 			return 0;
 		}
 	}
@@ -1399,7 +1490,7 @@ static int _dns_server_passthrough_rule_check(struct dns_request *request, char
 				unsigned char addr[4];
 				if (request->qtype != DNS_T_A) {
 					/* ignore non-matched query type */
-					if (dns_conf_dualstack_ip_selection == 0) {
+					if (_dns_server_is_dualstack_selection(request) == 0) {
 						break;
 					}
 				}
@@ -1663,7 +1754,7 @@ static int _dns_server_pre_process_rule_flags(struct dns_request *request)
 		goto errout;
 	}
 
-	if (flags & DOMAIN_FLAG_ADDR_SOA) {
+	if (_dns_server_is_return_soa(request)) {
 		/* return SOA */
 		_dns_server_reply_SOA(DNS_RC_NOERROR, request);
 		return 0;
@@ -1677,7 +1768,7 @@ static int _dns_server_pre_process_rule_flags(struct dns_request *request)
 			goto errout;
 		}
 
-		if (flags & DOMAIN_FLAG_ADDR_IPV4_SOA) {
+		if (_dns_server_is_return_soa(request)) {
 			/* return SOA for A request */
 			_dns_server_reply_SOA(DNS_RC_NOERROR, request);
 			return 0;
@@ -1689,7 +1780,7 @@ static int _dns_server_pre_process_rule_flags(struct dns_request *request)
 			goto errout;
 		}
 
-		if (flags & DOMAIN_FLAG_ADDR_IPV6_SOA) {
+		if (_dns_server_is_return_soa(request)) {
 			/* return SOA for A request */
 			_dns_server_reply_SOA(DNS_RC_NOERROR, request);
 			return 0;
@@ -1768,7 +1859,7 @@ static int _dns_server_process_cache(struct dns_request *request)
 		goto errout;
 	}
 
-	if (dns_conf_dualstack_ip_selection && request->qtype == DNS_T_AAAA) {
+	if (_dns_server_is_dualstack_selection(request) && request->qtype == DNS_T_AAAA) {
 		dns_cache_A = dns_cache_lookup(request->domain, DNS_T_A);
 		if (dns_cache_A && (dns_cache_A->speed > 0)) {
 			if ((dns_cache_A->speed + (dns_conf_dualstack_ip_selection_threshold * 10)) < dns_cache->speed || dns_cache->speed < 0) {
@@ -1891,7 +1982,7 @@ static int _dns_server_process_special_query(struct dns_request *request)
 		break;
 	case DNS_T_AAAA:
 		/* force return SOA */
-		if (dns_conf_force_AAAA_SOA == 1) {
+		if (_dns_server_is_return_soa(request)) {
 			_dns_server_reply_SOA(DNS_RC_NOERROR, request);
 			goto clean_exit;
 		}
@@ -1975,7 +2066,7 @@ static int _dns_server_do_query(struct dns_request *request, const char *domain,
 	request->send_tick = get_tick_count();
 
 	/* When the dual stack ip preference is enabled, both A and AAAA records are requested. */
-	if (qtype == DNS_T_AAAA && dns_conf_dualstack_ip_selection) {
+	if (qtype == DNS_T_AAAA && _dns_server_is_dualstack_selection(request)) {
 		_dns_server_request_get(request);
 		request->request_wait++;
 		if (dns_client_query(request->domain, DNS_T_A, dns_server_resolve_callback, request, group_name) != 0) {