Browse Source

Make the ipset working as expected when the domain passthrough

Kevin Zhou 5 years ago
parent
commit
cb73eadf01
1 changed files with 76 additions and 0 deletions
  1. 76 0
      src/dns_server.c

+ 76 - 0
src/dns_server.c

@@ -1712,6 +1712,14 @@ static int _dns_server_get_answer(struct dns_request *request, struct dns_packet
 static int _dns_server_reply_passthrouth(struct dns_request *request, struct dns_packet *packet,
 										 unsigned char *inpacket, int inpacket_len)
 {
+	int ttl;
+	char name[DNS_MAX_CNAME_LEN] = {0};
+	int rr_count;
+	int i = 0;
+	int j = 0;
+	struct dns_rrs *rrs = NULL;
+	struct dns_ipset_rule *ipset_rule = NULL;
+	struct dns_rule_flags *rule_flags = NULL;
 	int ret = 0;
 
 	if (atomic_inc_return(&request->notified) != 1) {
@@ -1731,6 +1739,74 @@ static int _dns_server_reply_passthrouth(struct dns_request *request, struct dns
 	dns_server_update_reply_packet_id(request, inpacket, inpacket_len);
 	ret = _dns_reply_inpacket(request, inpacket, inpacket_len);
 
+	if (packet->head.rcode != DNS_RC_NOERROR && packet->head.rcode != DNS_RC_NXDOMAIN) {
+		return ret;
+	}
+
+	if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_RULE_IPSET) == 0) {
+		return ret;
+	}
+
+	/* check ipset rule */
+	rule_flags = request->domain_rule.rules[DOMAIN_RULE_FLAGS];
+	if (rule_flags) {
+		if (rule_flags->flags & DOMAIN_FLAG_IPSET_IGNORE) {
+			return ret;
+		}
+	}
+
+	ipset_rule = request->domain_rule.rules[DOMAIN_RULE_IPSET];
+	if (ipset_rule == NULL) {
+		return ret;
+	}
+
+	for (j = 1; j < DNS_RRS_END; j++) {
+		rrs = dns_get_rrs_start(packet, j, &rr_count);
+		for (i = 0; i < rr_count && rrs; i++, rrs = dns_get_rrs_next(packet, rrs)) {
+			switch (rrs->type) {
+			case DNS_T_A: {
+				unsigned char addr[4];
+				if (request->qtype != DNS_T_A) {
+					/* ignore non-matched query type */
+					if (request->dualstack_selection == 0) {
+						break;
+					}
+				}
+				/* get A result */
+				dns_get_A(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr);
+
+				/* add IPV4 to ipset */
+				ipset_add(ipset_rule->ipsetname, addr, DNS_RR_A_LEN, request->ttl_v4 * 2);
+
+				tlog(TLOG_DEBUG, "IPSET-MATCH-PASSTHROUTH: domain: %s, ipset: %s, IP: %d.%d.%d.%d",
+					request->domain, ipset_rule->ipsetname, addr[0], addr[1], addr[2], addr[3]);
+			} break;
+			case DNS_T_AAAA: {
+				unsigned char addr[16];
+				if (request->qtype != DNS_T_AAAA) {
+					/* ignore non-matched query type */
+					break;
+				}
+				dns_get_AAAA(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr);
+
+				/* add IPV6 to ipset */
+				if (request->has_ipv6) {
+					if (request->has_ipv4) {
+						ipset_add(ipset_rule->ipsetname, addr, DNS_RR_A_LEN, request->ttl_v4 * 2);
+					}
+					ipset_add(ipset_rule->ipsetname, addr, DNS_RR_AAAA_LEN, request->ttl_v6 * 2);
+				}
+
+				tlog(TLOG_DEBUG, "IPSET-MATCH-PASSTHROUTH: 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]);
+			} break;
+			default:
+				break;
+			}
+		}
+	}
+
 	return ret;
 }