diff --git a/ReadMe.md b/ReadMe.md index fede399..ee8387b 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -528,7 +528,7 @@ https://github.com/pymumu/smartdns/releases |nameserver|指定域名使用server组解析|无|nameserver /domain/[group\|-], `group`为组名,`-`表示忽略此规则,配套server中的`-group`参数使用| nameserver /www.example.com/office |ipset|域名IPSET|None|ipset /domain/[ipset\|-], `-`表示忽略|ipset /www.example.com/pass |ipset-timeout|设置IPSET超时功能启用|auto|[yes]|ipset-timeout yes -|domain-rules|设置域名规则|无|domain-rules /domain/ [-rules...]
`[-speed-check-mode]`: 测速模式,参考`speed-check-mode`配置
`[-address]`: 参考`address`配置
`[-nameserver]`: 参考`nameserver`配置
`[-ipset]`:参考`ipset`配置|domain-rules /www.example.com/ -speed-check-mode none +|domain-rules|设置域名规则|无|domain-rules /domain/ [-rules...]
`[-c\|-speed-check-mode]`: 测速模式,参考`speed-check-mode`配置
`[-a\|-address]`: 参考`address`配置
`[-n\|-nameserver]`: 参考`nameserver`配置
`[-p\|-ipset]`:参考`ipset`配置
`[-d\|-dualstack-ip-selection]`: 参考`dualstack-ip-selection`|domain-rules /www.example.com/ -speed-check-mode none |bogus-nxdomain|假冒IP地址过滤|无|[ip/subnet],可重复| bogus-nxdomain 1.2.3.4/16 |ignore-ip|忽略IP地址|无|[ip/subnet],可重复| ignore-ip 1.2.3.4/16 |whitelist-ip|白名单IP地址|无|[ip/subnet],可重复| whitelist-ip 1.2.3.4/16 diff --git a/ReadMe_en.md b/ReadMe_en.md index 5b06593..5d02375 100755 --- a/ReadMe_en.md +++ b/ReadMe_en.md @@ -522,7 +522,7 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use |nameserver|To query domain with specific server group|None|nameserver /domain/[group\|-], `group` is the group name, `-` means ignore this rule, use the `-group` parameter in the related server|nameserver /www.example.com/office |ipset|Domain IPSet|None|ipset /domain/[ipset\|-], `-` for ignore|ipset /www.example.com/pass |ipset-timeout|ipset timeout enable|auto|[yes]|ipset-timeout yes -|domain-rules|set domain rules|None|domain-rules /domain/ [-rules...]
`[-speed-check-mode]`: set speed check mode,same as parameter `speed-check-mode`
`[-address]`: same as parameter `address`
`[-nameserver]`: same as parameter `nameserver`
`[-ipset]`: same as parameter `ipset`|domain-rules /www.example.com/ -speed-check-mode none +|domain-rules|set domain rules|None|domain-rules /domain/ [-rules...]
`[-c\|-speed-check-mode]`: set speed check mode,same as parameter `speed-check-mode`
`[-a\|-address]`: same as parameter `address`
`[-n\|-nameserver]`: same as parameter `nameserver`
`[-p\|-ipset]`: same as parameter `ipset`
`[-d\|-dualstack-ip-selection]`: same as parameter `dualstack-ip-selection`|domain-rules /www.example.com/ -speed-check-mode none |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 |whitelist-ip|ip whitelist|None|[ip/subnet], Repeatable,When the filtering server responds IPs in the IP whitelist, only result in whitelist will be accepted| whitelist-ip 1.2.3.4/16 diff --git a/etc/smartdns/smartdns.conf b/etc/smartdns/smartdns.conf index 018a3f9..355cfe3 100644 --- a/etc/smartdns/smartdns.conf +++ b/etc/smartdns/smartdns.conf @@ -189,8 +189,9 @@ log-level info # set domain rules # domain-rules /domain/ [-speed-check-mode [...]] # rules: -# -speed-check-mode [mode]: speed check mode +# [-c] -speed-check-mode [mode]: speed check mode # speed-check-mode [ping|tcp:port|none|,] -# -address [address|-]: same as address option -# -nameserver [group|-]: same as nameserver option -# -ipset [ipset|-]: same as ipset option +# [-a] -address [address|-]: same as address option +# [-n] -nameserver [group|-]: same as nameserver option +# [-p] -ipset [ipset|-]: same as ipset option +# [-d] -dualstack-ip-selection [yes|no]: same as dualstack-ip-selection option diff --git a/src/dns_conf.c b/src/dns_conf.c index 8f9f408..83b4cc8 100644 --- a/src/dns_conf.c +++ b/src/dns_conf.c @@ -482,7 +482,7 @@ errout: return -1; } -static int _config_domain_rule_flag_set(char *domain, unsigned int flag) +static int _config_domain_rule_flag_set(char *domain, unsigned int flag, unsigned int is_clear) { struct dns_domain_rule *domain_rule = NULL; struct dns_domain_rule *old_domain_rule = NULL; @@ -521,7 +521,12 @@ static int _config_domain_rule_flag_set(char *domain, unsigned int flag) } rule_flags = domain_rule->rules[DOMAIN_RULE_FLAGS]; - rule_flags->flags |= flag; + if (is_clear == false) { + rule_flags->flags |= flag; + } else { + rule_flags->flags &= ~flag; + } + rule_flags->is_flag_set |= flag; /* update domain rule */ if (add_domain_rule) { @@ -606,7 +611,7 @@ static int _conf_domain_rule_ipset(char *domain, const char *ipsetname) ipset_rule->ipsetname = ipset; } else { /* ignore this domain */ - if (_config_domain_rule_flag_set(domain, DOMAIN_FLAG_IPSET_IGNORE) != 0) { + if (_config_domain_rule_flag_set(domain, DOMAIN_FLAG_IPSET_IGNORE, 0) != 0) { goto errout; } @@ -670,7 +675,7 @@ static int _conf_domain_rule_address(char *domain, const char *domain_address) } /* add SOA rule */ - if (_config_domain_rule_flag_set(domain, flag) != 0) { + if (_config_domain_rule_flag_set(domain, flag, 0) != 0) { goto errout; } @@ -687,7 +692,7 @@ static int _conf_domain_rule_address(char *domain, const char *domain_address) } /* ignore rule */ - if (_config_domain_rule_flag_set(domain, flag) != 0) { + if (_config_domain_rule_flag_set(domain, flag, 0) != 0) { goto errout; } @@ -1008,7 +1013,7 @@ static int _conf_domain_rule_nameserver(char *domain, const char *group_name) nameserver_rule->group_name = group; } else { /* ignore this domain */ - if (_config_domain_rule_flag_set(domain, DOMAIN_FLAG_NAMESERVER_IGNORE) != 0) { + if (_config_domain_rule_flag_set(domain, DOMAIN_FLAG_NAMESERVER_IGNORE, 0) != 0) { goto errout; } @@ -1029,6 +1034,26 @@ errout: return 0; } +static int _conf_domain_rule_dualstack_selection(char *domain, const char *yesno) +{ + if (strncmp(yesno, "yes", sizeof("yes")) == 0 || strncmp(yesno, "Yes", sizeof("Yes")) == 0) { + if (_config_domain_rule_flag_set(domain, DOMAIN_FLAG_DUALSTACK_SELECT, 0) != 0) { + goto errout; + } + } else { + /* ignore this domain */ + if (_config_domain_rule_flag_set(domain, DOMAIN_FLAG_DUALSTACK_SELECT, 1) != 0) { + goto errout; + } + } + + return 0; + +errout: + tlog(TLOG_ERROR, "set dualstack for %s failed. ", domain); + return 1; +} + static int _config_nameserver(void *data, int argc, char *argv[]) { char domain[DNS_MAX_CONF_CNAME_LEN]; @@ -1239,6 +1264,7 @@ static int _conf_domain_rules(void *data, int argc, char *argv[]) {"address", required_argument, NULL, 'a'}, {"ipset", required_argument, NULL, 'p'}, {"nameserver", required_argument, NULL, 'n'}, + {"dualstack-ip-selection", required_argument, NULL, 'd'}, {NULL, no_argument, NULL, 0} }; /* clang-format on */ @@ -1255,7 +1281,7 @@ static int _conf_domain_rules(void *data, int argc, char *argv[]) /* process extra options */ optind = 1; while (1) { - opt = getopt_long_only(argc, argv, "", long_options, NULL); + opt = getopt_long_only(argc, argv, "c:a:p:n:d:", long_options, NULL); if (opt == -1) { break; } @@ -1313,6 +1339,15 @@ static int _conf_domain_rules(void *data, int argc, char *argv[]) break; } + case 'd': { + const char *yesno = optarg; + if (_conf_domain_rule_dualstack_selection(domain, yesno) != 0) { + tlog(TLOG_ERROR, "set dualstack selection rule failed."); + goto errout; + } + + break; + } default: break; } diff --git a/src/dns_conf.h b/src/dns_conf.h index 95aaa78..78e6f19 100644 --- a/src/dns_conf.h +++ b/src/dns_conf.h @@ -80,6 +80,7 @@ typedef enum { #define DOMAIN_FLAG_ADDR_IPV6_IGN (1 << 5) #define DOMAIN_FLAG_IPSET_IGNORE (1 << 6) #define DOMAIN_FLAG_NAMESERVER_IGNORE (1 << 7) +#define DOMAIN_FLAG_DUALSTACK_SELECT (1 << 8) #define SERVER_FLAG_EXCLUDE_DEFAULT (1 << 0) @@ -95,6 +96,7 @@ typedef enum { struct dns_rule_flags { unsigned int flags; + unsigned int is_flag_set; }; struct dns_address_IPV4 { diff --git a/src/dns_server.c b/src/dns_server.c index 884601a..9b0ed65 100644 --- a/src/dns_server.c +++ b/src/dns_server.c @@ -258,6 +258,21 @@ static int _dns_server_epoll_ctl(struct dns_server_conn_head *head, int op, uint static void _dns_server_set_dualstack_selection(struct dns_request *request) { + struct dns_rule_flags *rule_flag = NULL; + + rule_flag = request->domain_rule.rules[DOMAIN_RULE_FLAGS]; + if (rule_flag) { + if (rule_flag->flags & DOMAIN_FLAG_DUALSTACK_SELECT) { + request->dualstack_selection = 1; + return; + } + + if (rule_flag->is_flag_set & DOMAIN_FLAG_DUALSTACK_SELECT) { + request->dualstack_selection = 0; + return; + } + } + if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_DUALSTACK_SELECTION) == 0) { request->dualstack_selection = 0; return; @@ -2591,6 +2606,10 @@ static int _dns_server_do_query(struct dns_request *request, const char *domain, group_name = dns_group; } + _dns_server_set_dualstack_selection(request); + + tlog(TLOG_DEBUG, "dualstack selection %d", request->dualstack_selection); + if (_dns_server_process_special_query(request) == 0) { goto clean_exit; } @@ -2717,7 +2736,6 @@ static int _dns_server_recv(struct dns_server_conn_head *conn, unsigned char *in _dns_server_request_set_client(request, conn); _dns_server_request_set_client_addr(request, from, from_len); _dns_server_request_set_id(request, packet->head.id); - _dns_server_set_dualstack_selection(request); ret = _dns_server_do_query(request, domain, qtype); if (ret != 0) { tlog(TLOG_ERROR, "do query %s failed.\n", domain);