diff --git a/etc/smartdns/smartdns.conf b/etc/smartdns/smartdns.conf index 6514b9148a..7f9f740ec6 100644 --- a/etc/smartdns/smartdns.conf +++ b/etc/smartdns/smartdns.conf @@ -348,3 +348,4 @@ log-level info # ip-set -name ip-list -file /etc/smartdns/ip-list.conf # bogus-nxdomain ip-set:ip-list # ip-alias ip-set:ip-list 1.2.3.4 +# ip-alias ip-set:ip-list ip-set:ip-map-list diff --git a/package/openwrt/files/etc/init.d/smartdns b/package/openwrt/files/etc/init.d/smartdns index afc4aa453a..a8eabf3d56 100644 --- a/package/openwrt/files/etc/init.d/smartdns +++ b/package/openwrt/files/etc/init.d/smartdns @@ -296,6 +296,7 @@ load_domain_rules() config_get forwarding_domain_set_file "$section" "forwarding_domain_set_file" "" [ ! -z "$forwarding_domain_set_file" ] && { + [ ! -e "$forwarding_domain_set_file" ] && touch $forwarding_domain_set_file conf_append "domain-set" "-name ${domain_set_name}-forwarding-file -file '$forwarding_domain_set_file'" conf_append "domain-rules" "/domain-set:${domain_set_name}-forwarding-file/ $domain_set_args" } @@ -307,6 +308,7 @@ load_domain_rules() config_get block_domain_set_file "$section" "block_domain_set_file" [ ! -z "$block_domain_set_file" ] && { + [ ! -e "$block_domain_set_file" ] && touch $block_domain_set_file conf_append "domain-set" "-name ${domain_set_name}-block-file -file '$block_domain_set_file'" conf_append "domain-rules" "/domain-set:${domain_set_name}-block-file/ --address #" } @@ -355,6 +357,7 @@ load_domain_rule_list() [ ! -z "$addition_flag" ] && domain_set_args="$domain_set_args $addition_flag" [ -z "$domain_set_args" ] && return + [ ! -e "$domain_list_file" ] && touch $domain_list_file conf_append "domain-set" "-name domain-rule-list-${domain_set_name} -file '$domain_list_file'" conf_append "domain-rules" "/domain-set:domain-rule-list-${domain_set_name}/ $domain_set_args" } diff --git a/src/dns_conf.c b/src/dns_conf.c index 34fbb70167..6dda14c366 100644 --- a/src/dns_conf.c +++ b/src/dns_conf.c @@ -794,8 +794,8 @@ static int _config_set_rule_each_from_list(const char *file, set_rule_add_func c fp = fopen(file, "r"); if (fp == NULL) { - tlog(TLOG_WARN, "open file %s error, %s", file, strerror(errno)); - return 0; + tlog(TLOG_ERROR, "open file %s error, %s", file, strerror(errno)); + return -1; } line_no = 0; @@ -845,7 +845,9 @@ static int _config_domain_rule_set_each(const char *domain_set, set_rule_add_fun { switch (set_name_item->type) { case DNS_DOMAIN_SET_LIST: - _config_set_rule_each_from_list(set_name_item->file, callback, priv); + if (_config_set_rule_each_from_list(set_name_item->file, callback, priv) != 0) { + return -1; + } break; case DNS_DOMAIN_SET_GEOSITE: break; @@ -2858,7 +2860,9 @@ static int _config_ip_rule_set_each(const char *ip_set, set_rule_add_func callba { switch (set_name_item->type) { case DNS_IP_SET_LIST: - _config_set_rule_each_from_list(set_name_item->file, callback, priv); + if (_config_set_rule_each_from_list(set_name_item->file, callback, priv) != 0) { + return -1; + } break; default: tlog(TLOG_WARN, "ip set %s type %d not support.", set_name_list->name, set_name_item->type); @@ -3020,10 +3024,58 @@ static int _config_ip_rule_add(const char *ip_cidr, enum ip_rule type, void *rul return -1; } +static int _config_ip_rule_alias_add_ip(const char *ip, struct ip_rule_alias *ip_alias) +{ + struct sockaddr_storage addr; + socklen_t addr_len = sizeof(addr); + unsigned char *paddr = NULL; + int ret = 0; + + ret = getaddr_by_host(ip, (struct sockaddr *)&addr, &addr_len); + if (ret != 0) { + tlog(TLOG_ERROR, "ip is invalid: %s", ip); + goto errout; + } + + switch (addr.ss_family) { + case AF_INET: { + struct sockaddr_in *addr_in = NULL; + addr_in = (struct sockaddr_in *)&addr; + paddr = (unsigned char *)&(addr_in->sin_addr.s_addr); + _dns_iplist_ip_address_add(&ip_alias->ip_alias, paddr, DNS_RR_A_LEN); + } break; + case AF_INET6: { + struct sockaddr_in6 *addr_in6 = NULL; + addr_in6 = (struct sockaddr_in6 *)&addr; + if (IN6_IS_ADDR_V4MAPPED(&addr_in6->sin6_addr)) { + paddr = addr_in6->sin6_addr.s6_addr + 12; + _dns_iplist_ip_address_add(&ip_alias->ip_alias, paddr, DNS_RR_A_LEN); + } else { + paddr = addr_in6->sin6_addr.s6_addr; + _dns_iplist_ip_address_add(&ip_alias->ip_alias, paddr, DNS_RR_AAAA_LEN); + } + } break; + default: + goto errout; + break; + } + + return 0; + +errout: + return -1; +} + +static int _config_ip_alias_add_ip_callback(const char *ip_cidr, void *priv) +{ + return _config_ip_rule_alias_add_ip(ip_cidr, (struct ip_rule_alias *)priv); +} + static int _config_ip_alias(const char *ip_cidr, const char *ips) { struct ip_rule_alias *ip_alias = NULL; char *target_ips = NULL; + int ret = 0; if (ip_cidr == NULL || ips == NULL) { goto errout; @@ -3034,43 +3086,21 @@ static int _config_ip_alias(const char *ip_cidr, const char *ips) goto errout; } - target_ips = strdup(ips); - if (target_ips == NULL) { - goto errout; - } - - for (char *tok = strtok(target_ips, ","); tok != NULL; tok = strtok(NULL, ",")) { - struct sockaddr_storage addr; - socklen_t addr_len = sizeof(addr); - unsigned char *paddr = NULL; - int ret = 0; - - ret = getaddr_by_host(tok, (struct sockaddr *)&addr, &addr_len); - if (ret != 0) { + if (strncmp(ips, "ip-set:", sizeof("ip-set:") - 1) == 0) { + if (_config_ip_rule_set_each(ips + sizeof("ip-set:") - 1, _config_ip_alias_add_ip_callback, ip_alias) != 0) { + goto errout; + } + } else { + target_ips = strdup(ips); + if (target_ips == NULL) { goto errout; } - switch (addr.ss_family) { - case AF_INET: { - struct sockaddr_in *addr_in = NULL; - addr_in = (struct sockaddr_in *)&addr; - paddr = (unsigned char *)&(addr_in->sin_addr.s_addr); - _dns_iplist_ip_address_add(&ip_alias->ip_alias, paddr, DNS_RR_A_LEN); - } break; - case AF_INET6: { - struct sockaddr_in6 *addr_in6 = NULL; - addr_in6 = (struct sockaddr_in6 *)&addr; - if (IN6_IS_ADDR_V4MAPPED(&addr_in6->sin6_addr)) { - paddr = addr_in6->sin6_addr.s6_addr + 12; - _dns_iplist_ip_address_add(&ip_alias->ip_alias, paddr, DNS_RR_A_LEN); - } else { - paddr = addr_in6->sin6_addr.s6_addr; - _dns_iplist_ip_address_add(&ip_alias->ip_alias, paddr, DNS_RR_AAAA_LEN); + for (char *tok = strtok(target_ips, ","); tok != NULL; tok = strtok(NULL, ",")) { + ret = _config_ip_rule_alias_add_ip(tok, ip_alias); + if (ret != 0) { + goto errout; } - } break; - default: - goto errout; - break; } } @@ -3079,7 +3109,9 @@ static int _config_ip_alias(const char *ip_cidr, const char *ips) } _dns_ip_rule_put(&ip_alias->head); - free(target_ips); + if (target_ips) { + free(target_ips); + } return 0; errout: @@ -3302,6 +3334,10 @@ static int _conf_ip_set(void *data, int argc, char *argv[]) if (ip_set) { free(ip_set); } + + if (ip_set_name_list != NULL) { + free(ip_set_name_list); + } return -1; } diff --git a/test/cases/test-ip-rule.cc b/test/cases/test-ip-rule.cc index 742f44f1c0..550b7f02b4 100644 --- a/test/cases/test-ip-rule.cc +++ b/test/cases/test-ip-rule.cc @@ -210,3 +210,72 @@ cache-persist no)"""); EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com"); EXPECT_EQ(client.GetAnswer()[0].GetData(), "7.8.9.10"); } + +TEST_F(IPRule, ip_alias_ip_set) +{ + smartdns::MockServer server_upstream; + smartdns::MockServer server_upstream2; + smartdns::Server server; + std::string file = "/tmp/smartdns_test_ip_set.list" + smartdns::GenerateRandomString(5); + std::string file_ip = "/tmp/smartdns_test_ip_set_ip.list" + smartdns::GenerateRandomString(5); + std::ofstream ofs(file); + std::ofstream ofs_ip(file_ip); + ASSERT_TRUE(ofs.is_open()); + ASSERT_TRUE(ofs_ip.is_open()); + Defer + { + ofs.close(); + unlink(file.c_str()); + ofs_ip.close(); + unlink(file_ip.c_str()); + }; + + server_upstream.Start("udp://0.0.0.0:61053", [](struct smartdns::ServerRequestContext *request) { + if (request->qtype != DNS_T_A) { + return smartdns::SERVER_REQUEST_SOA; + } + + smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4", 611); + smartdns::MockServer::AddIP(request, request->domain.c_str(), "4.5.6.7", 611); + smartdns::MockServer::AddIP(request, request->domain.c_str(), "7.8.9.10", 611); + return smartdns::SERVER_REQUEST_OK; + }); + + server.MockPing(PING_TYPE_ICMP, "1.2.3.4", 60, 10); + server.MockPing(PING_TYPE_ICMP, "4.5.6.7", 60, 90); + server.MockPing(PING_TYPE_ICMP, "7.8.9.10", 60, 40); + + std::string ipset_list = R"""( +1.2.3.0/24 +4.5.6.0/24 +7.8.9.0/24 +)"""; + ofs.write(ipset_list.c_str(), ipset_list.length()); + ofs.flush(); + + std::string ipset_list_ip = R"""( +1.1.1.1 +)"""; + ofs_ip.write(ipset_list_ip.c_str(), ipset_list_ip.length()); + ofs_ip.flush(); + + server.Start(R"""(bind [::]:60053 +server udp://127.0.0.1:61053 -blacklist-ip +ip-set -name ip-list -file )""" + + file + R"""( +ip-set -name ip-list-ip -file )""" + + file_ip + R"""( +ip-alias ip-set:ip-list ip-set:ip-list-ip +log-num 0 +speed-check-mode none +log-console yes +log-level debug +cache-persist no)"""); + smartdns::Client client; + ASSERT_TRUE(client.Query("a.com", 60053)); + std::cout << client.GetResult() << std::endl; + ASSERT_EQ(client.GetAnswerNum(), 1); + EXPECT_EQ(client.GetStatus(), "NOERROR"); + EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com"); + EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.1.1.1"); +}