diff --git a/ReadMe.md b/ReadMe.md index 29f1769..fae8d6a 100755 --- a/ReadMe.md +++ b/ReadMe.md @@ -395,6 +395,7 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use |server-tls|Upstream TLS DNS server|None|[IP][:port] [-blacklist-ip][-check-edns], Repeatable, blacklist-ip parameter represents filtering the result of IPs with blacklist-ip configuration.| server-tls 8.8.8.8:853 |address|Domain IP address|None|address /domain/[ip\|-\|-4\|-6\|#\|#4\|#6], `-` for ignore, `#` for return SOA, `4` for IPV4, `6` for IPV6| address /www.example.com/1.2.3.4 |ipset|Domain IPSet|None|ipset /domain/[ipset\|-], `-` for ignore|ipset /www.example.com/pass +|ipset-timeout|ipset timeout enable|auto|[yes]|ipset-timeout yes |bogus-nxdomain|bogus IP address|None|[IP/subnet], Repeatable| bogus-nxdomain 1.2.3.4/16 |ignore-ip|ignore ip address|None|[ip/subnet], Repeatable| ignore-ip 1.2.3.4/16 |blacklist-ip|ip blacklist|None|[ip/subnet], Repeatable,When the filtering server responds IPs in the IP blacklist, The result will be discarded directly| blacklist-ip 1.2.3.4/16 diff --git a/ReadMe_zh-CN.md b/ReadMe_zh-CN.md index 3372d18..9cbb3c0 100644 --- a/ReadMe_zh-CN.md +++ b/ReadMe_zh-CN.md @@ -395,6 +395,7 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms |server-tls|上游TLS DNS|无|[IP][:port] [-blacklist-ip][-check-edns],可重复,blacklist-ip参数指定使用blacklist-ip配置IP过滤结果| server-tls 8.8.8.8:853 |address|指定域名IP地址|无|address /domain/[ip\|-\|-4\|-6\|#\|#4\|#6], `-`表示忽略, `#`表示返回SOA, `4`表示IPV4, `6`表示IPV6| address /www.example.com/1.2.3.4 |ipset|域名IPSET|None|ipset /domain/[ipset\|-], `-`表示忽略|ipset /www.example.com/pass +|ipset-timeout|设置IPSET超时功能启用|auto|[yes]|ipset-timeout yes |bogus-nxdomain|假冒IP地址过滤|无|[ip/subnet],可重复| bogus-nxdomain 1.2.3.4/16 |ignore-ip|忽略IP地址|无|[ip/subnet],可重复| ignore-ip 1.2.3.4/16 |blacklist-ip|黑名单IP地址|无|[ip/subnet],可重复| blacklist-ip 1.2.3.4/16 diff --git a/etc/smartdns/smartdns.conf b/etc/smartdns/smartdns.conf index b1b0ae5..3363e03 100644 --- a/etc/smartdns/smartdns.conf +++ b/etc/smartdns/smartdns.conf @@ -102,6 +102,9 @@ log-level info # address /www.example.com/-, ignore address, query from upstream, suffix 4, for ipv4, 6 for ipv6, none for all # address /www.example.com/#, return SOA to client, suffix 4, for ipv4, 6 for ipv6, none for all +# enable ipset timeout by ttl feature +# ipset-timeout [yes] + # specific ipset to domain # ipset /domain/[ipset|-] # ipset /www.example.com/block, set ipset with ipset name of block diff --git a/src/dns_cache.c b/src/dns_cache.c index 5ff4d73..cdfaadc 100644 --- a/src/dns_cache.c +++ b/src/dns_cache.c @@ -147,7 +147,7 @@ int dns_cache_insert(char *domain, char *cname, int cname_ttl, int ttl, dns_type dns_cache->cname[0] = 0; dns_cache->qtype = qtype; dns_cache->ttl = ttl; - dns_cache->hitnum = 6; + dns_cache->hitnum = 2; atomic_set(&dns_cache->ref, 1); time(&dns_cache->insert_time); if (qtype == DNS_T_A) { diff --git a/src/dns_conf.c b/src/dns_conf.c index 20fd222..92428f9 100644 --- a/src/dns_conf.c +++ b/src/dns_conf.c @@ -45,6 +45,8 @@ int dns_conf_rr_ttl_min; int dns_conf_rr_ttl_max; int dns_conf_force_AAAA_SOA; +int dns_conf_ipset_timeout_enable; + struct dns_edns_client_subnet dns_conf_ipv4_ecs; struct dns_edns_client_subnet dns_conf_ipv6_ecs; @@ -706,6 +708,7 @@ struct config_item config_item[] = { CONF_CUSTOM("server-tcp", config_server_tcp, NULL), CONF_CUSTOM("server-tls", config_server_tls, NULL), CONF_CUSTOM("address", config_address, NULL), + CONF_YESNO("ipset-timeout", &dns_conf_ipset_timeout_enable), CONF_CUSTOM("ipset", config_ipset, NULL), CONF_INT("tcp-idle-time", &dns_conf_tcp_idle_time, 0, 3600), CONF_INT("cache-size", &dns_conf_cachesize, 0, CONF_INT_MAX), diff --git a/src/dns_conf.h b/src/dns_conf.h index cadacc6..19be534 100644 --- a/src/dns_conf.h +++ b/src/dns_conf.h @@ -133,6 +133,7 @@ extern int dns_conf_rr_ttl; extern int dns_conf_rr_ttl_min; extern int dns_conf_rr_ttl_max; extern int dns_conf_force_AAAA_SOA; +extern int dns_conf_ipset_timeout_enable; extern struct dns_edns_client_subnet dns_conf_ipv4_ecs; extern struct dns_edns_client_subnet dns_conf_ipv6_ecs; diff --git a/src/dns_server.c b/src/dns_server.c index 32f2f3c..18c2813 100644 --- a/src/dns_server.c +++ b/src/dns_server.c @@ -408,6 +408,10 @@ static int _dns_reply(struct dns_request *request) int ret = 0; int encode_len = 0; + if (request->client == NULL) { + return 0; + } + _dns_server_audit_log(request); memset(&head, 0, sizeof(head)); @@ -490,14 +494,14 @@ static int _dns_setup_ipset(struct dns_request *request) } if (request->has_ipv4 && request->qtype == DNS_T_A) { - ret |= ipset_add(ipset_rule->ipsetname, request->ipv4_addr, DNS_RR_A_LEN); + ret |= ipset_add(ipset_rule->ipsetname, request->ipv4_addr, DNS_RR_A_LEN, request->ttl_v4 * 2); } if (request->has_ipv6 && request->qtype == DNS_T_AAAA) { if (request->has_ipv4) { - ret |= ipset_add(ipset_rule->ipsetname, request->ipv4_addr, DNS_RR_A_LEN); + ret |= ipset_add(ipset_rule->ipsetname, request->ipv4_addr, DNS_RR_A_LEN, request->ttl_v4 * 2); } - ret |= ipset_add(ipset_rule->ipsetname, request->ipv6_addr, DNS_RR_AAAA_LEN); + ret |= ipset_add(ipset_rule->ipsetname, request->ipv6_addr, DNS_RR_AAAA_LEN, request->ttl_v6 * 2); } tlog(TLOG_DEBUG, "IPSET-MATCH: domain:%s, ipset:%s, result: %d", request->domain, ipset_rule->ipsetname, ret); @@ -548,7 +552,12 @@ int _dns_server_request_complete(struct dns_request *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."); - dns_cache_insert(request->domain, cname, cname_ttl, request->ttl_v4, DNS_T_A, request->ipv4_addr, DNS_RR_A_LEN); + if (request->prefetch) { + dns_cache_replace(request->domain, cname, cname_ttl, request->ttl_v4, DNS_T_A, request->ipv4_addr, DNS_RR_A_LEN); + } else { + dns_cache_insert(request->domain, cname, cname_ttl, request->ttl_v4, DNS_T_A, request->ipv4_addr, DNS_RR_A_LEN); + } + return _dns_server_reply_SOA(DNS_RC_NOERROR, request, NULL); } @@ -575,15 +584,16 @@ int _dns_server_request_complete(struct dns_request *request) } } - if (request->prefetch) { - return 0; - } - if (request->has_soa) { tlog(TLOG_INFO, "result: %s, qtype: %d, SOA", request->domain, request->qtype); } _dns_setup_ipset(request); + + if (request->prefetch) { + return 0; + } + _dns_reply(request); return 0; @@ -1594,6 +1604,8 @@ static int _dns_server_prefetch_request(char *domain, dns_type_t qtype) hash_init(request->ip_map); strncpy(request->domain, domain, DNS_MAX_CNAME_LEN); + request->domain_rule = _dns_server_get_domain_rule(request->domain); + tlog(TLOG_INFO, "prefetch domain %s, qtype = %d\n", request->domain, qtype); _dns_server_request_get(request); diff --git a/src/util.c b/src/util.c index 834fa73..5a5af66 100644 --- a/src/util.c +++ b/src/util.c @@ -1,4 +1,5 @@ #include "util.h" +#include "dns_conf.h" #include #include #include @@ -19,6 +20,7 @@ #define IPSET_ATTR_IPADDR_IPV6 2 #define IPSET_ATTR_PROTOCOL 1 #define IPSET_ATTR_SETNAME 2 +#define IPSET_ATTR_TIMEOUT 6 #define IPSET_ADD 9 #define IPSET_DEL 10 #define IPSET_MAXNAMELEN 32 @@ -246,11 +248,20 @@ static int _ipset_socket_init(void) return 0; } -static int _ipset_operate(const char *ipsetname, const unsigned char addr[], int addr_len, int operate) +static int _ipset_support_timeout(const char *ipsetname) +{ + if (dns_conf_ipset_timeout_enable) { + return 0; + } + + return -1; +} + +static int _ipset_operate(const char *ipsetname, const unsigned char addr[], int addr_len, unsigned long timeout, int operate) { struct nlmsghdr *netlink_head; struct ipset_netlink_msg *netlink_msg; - struct ipset_netlink_attr *nested[2]; + struct ipset_netlink_attr *nested[3]; char buffer[BUFF_SZ]; uint8_t proto; ssize_t rc; @@ -285,7 +296,7 @@ static int _ipset_operate(const char *ipsetname, const unsigned char addr[], int netlink_head = (struct nlmsghdr *)buffer; netlink_head->nlmsg_len = NETLINK_ALIGN(sizeof(struct nlmsghdr)); netlink_head->nlmsg_type = operate | (NFNL_SUBSYS_IPSET << 8); - netlink_head->nlmsg_flags = NLM_F_REQUEST; + netlink_head->nlmsg_flags = NLM_F_REQUEST | NLM_F_REPLACE; netlink_msg = (struct ipset_netlink_msg *)(buffer + netlink_head->nlmsg_len); netlink_head->nlmsg_len += NETLINK_ALIGN(sizeof(struct ipset_netlink_msg)); @@ -303,9 +314,15 @@ static int _ipset_operate(const char *ipsetname, const unsigned char addr[], int nested[1] = (struct ipset_netlink_attr *)(buffer + NETLINK_ALIGN(netlink_head->nlmsg_len)); netlink_head->nlmsg_len += NETLINK_ALIGN(sizeof(struct ipset_netlink_attr)); nested[1]->type = NLA_F_NESTED | IPSET_ATTR_IP; - _ipset_add_attr(netlink_head, (af == AF_INET ? IPSET_ATTR_IPADDR_IPV4 : IPSET_ATTR_IPADDR_IPV6) | NLA_F_NET_BYTEORDER, addr_len, addr); + _ipset_add_attr(netlink_head, (af == AF_INET ? IPSET_ATTR_IPADDR_IPV4 : IPSET_ATTR_IPADDR_IPV6) | NLA_F_NET_BYTEORDER, addr_len, addr); nested[1]->len = (void *)buffer + NETLINK_ALIGN(netlink_head->nlmsg_len) - (void *)nested[1]; + + if (timeout > 0 && _ipset_support_timeout(ipsetname) == 0) { + timeout = htonl(timeout); + _ipset_add_attr(netlink_head, IPSET_ATTR_TIMEOUT | NLA_F_NET_BYTEORDER, sizeof(timeout), &timeout); + } + nested[0]->len = (void *)buffer + NETLINK_ALIGN(netlink_head->nlmsg_len) - (void *)nested[0]; for (;;) { @@ -326,17 +343,16 @@ static int _ipset_operate(const char *ipsetname, const unsigned char addr[], int return rc; } -int ipset_add(const char *ipsetname, const unsigned char addr[], int addr_len) +int ipset_add(const char *ipsetname, const unsigned char addr[], int addr_len, unsigned long timeout) { - return _ipset_operate(ipsetname, addr, addr_len, IPSET_ADD); + return _ipset_operate(ipsetname, addr, addr_len, timeout, IPSET_ADD); } int ipset_del(const char *ipsetname, const unsigned char addr[], int addr_len) { - return _ipset_operate(ipsetname, addr, addr_len, IPSET_DEL); + return _ipset_operate(ipsetname, addr, addr_len, 0, IPSET_DEL); } - #define THREAD_STACK_SIZE (16*1024) static pthread_mutex_t *lock_cs; static long *lock_count; diff --git a/src/util.h b/src/util.h index 624ff64..7bcaf13 100644 --- a/src/util.h +++ b/src/util.h @@ -22,7 +22,7 @@ char *reverse_string(char *output, char *input, int len); void print_stack(void); -int ipset_add(const char *ipsetname, const unsigned char addr[], int addr_len); +int ipset_add(const char *ipsetname, const unsigned char addr[], int addr_len, unsigned long timeout); int ipset_del(const char *ipsetname, const unsigned char addr[], int addr_len);