feature: add ip-rules and ip-set options
This commit is contained in:
781
src/dns_conf.c
781
src/dns_conf.c
@@ -47,6 +47,8 @@ uint8_t *dns_qtype_soa_table;
|
|||||||
|
|
||||||
struct dns_domain_set_name_table dns_domain_set_name_table;
|
struct dns_domain_set_name_table dns_domain_set_name_table;
|
||||||
|
|
||||||
|
struct dns_ip_set_name_table dns_ip_set_name_table;
|
||||||
|
|
||||||
/* dns groups */
|
/* dns groups */
|
||||||
struct dns_group_table dns_group_table;
|
struct dns_group_table dns_group_table;
|
||||||
struct dns_proxy_table dns_proxy_table;
|
struct dns_proxy_table dns_proxy_table;
|
||||||
@@ -252,26 +254,6 @@ static void _dns_rule_put(struct dns_rule *rule)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct dns_iplist_ip_addresses *_new_dns_iplist_ip_addresses(void)
|
|
||||||
{
|
|
||||||
struct dns_iplist_ip_addresses *iplist;
|
|
||||||
|
|
||||||
iplist = malloc(sizeof(struct dns_iplist_ip_addresses));
|
|
||||||
if (!iplist) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
memset(iplist, 0, sizeof(struct dns_iplist_ip_addresses));
|
|
||||||
atomic_set(&iplist->refcnt, 1);
|
|
||||||
return iplist;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _dns_iplist_ip_addresses_put(struct dns_iplist_ip_addresses *iplist)
|
|
||||||
{
|
|
||||||
if (atomic_dec_and_test(&iplist->refcnt)) {
|
|
||||||
free(iplist);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _dns_iplist_ip_address_add(struct dns_iplist_ip_addresses *iplist, unsigned char addr[], int addr_len)
|
static void _dns_iplist_ip_address_add(struct dns_iplist_ip_addresses *iplist, unsigned char addr[], int addr_len)
|
||||||
{
|
{
|
||||||
iplist->ipaddr = realloc(iplist->ipaddr, (iplist->ipaddr_num + 1) * sizeof(struct dns_iplist_ip_address));
|
iplist->ipaddr = realloc(iplist->ipaddr, (iplist->ipaddr_num + 1) * sizeof(struct dns_iplist_ip_address));
|
||||||
@@ -798,33 +780,12 @@ static void _config_domain_destroy(void)
|
|||||||
art_tree_destroy(&dns_conf_domain_rule);
|
art_tree_destroy(&dns_conf_domain_rule);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _config_address_destroy(radix_node_t *node, void *cbctx)
|
typedef int (*set_rule_add_func)(const char *value, void *priv);
|
||||||
{
|
static int _config_set_rule_each_from_list(const char *file, set_rule_add_func callback, void *priv)
|
||||||
struct dns_ip_address_rule *address_rule = NULL;
|
|
||||||
if (node == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node->data == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
address_rule = node->data;
|
|
||||||
if (address_rule->ip_alias) {
|
|
||||||
_dns_iplist_ip_addresses_put(address_rule->ip_alias);
|
|
||||||
address_rule->ip_alias = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(node->data);
|
|
||||||
node->data = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef int (*domain_set_rule_add_func)(const char *domain, void *priv);
|
|
||||||
static int _config_domain_rule_each_from_list(const char *file, domain_set_rule_add_func callback, void *priv)
|
|
||||||
{
|
{
|
||||||
FILE *fp = NULL;
|
FILE *fp = NULL;
|
||||||
char line[MAX_LINE_LEN];
|
char line[MAX_LINE_LEN];
|
||||||
char domain[DNS_MAX_CNAME_LEN];
|
char value[DNS_MAX_CNAME_LEN];
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int line_no = 0;
|
int line_no = 0;
|
||||||
int filed_num = 0;
|
int filed_num = 0;
|
||||||
@@ -838,16 +799,16 @@ static int _config_domain_rule_each_from_list(const char *file, domain_set_rule_
|
|||||||
line_no = 0;
|
line_no = 0;
|
||||||
while (fgets(line, MAX_LINE_LEN, fp)) {
|
while (fgets(line, MAX_LINE_LEN, fp)) {
|
||||||
line_no++;
|
line_no++;
|
||||||
filed_num = sscanf(line, "%255s", domain);
|
filed_num = sscanf(line, "%255s", value);
|
||||||
if (filed_num <= 0) {
|
if (filed_num <= 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (domain[0] == '#' || domain[0] == '\n') {
|
if (value[0] == '#' || value[0] == '\n') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = callback(domain, priv);
|
ret = callback(value, priv);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
tlog(TLOG_WARN, "process file %s failed at line %d.", file, line_no);
|
tlog(TLOG_WARN, "process file %s failed at line %d.", file, line_no);
|
||||||
continue;
|
continue;
|
||||||
@@ -858,7 +819,7 @@ static int _config_domain_rule_each_from_list(const char *file, domain_set_rule_
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _config_domain_rule_set_each(const char *domain_set, domain_set_rule_add_func callback, void *priv)
|
static int _config_domain_rule_set_each(const char *domain_set, set_rule_add_func callback, void *priv)
|
||||||
{
|
{
|
||||||
struct dns_domain_set_name_list *set_name_list = NULL;
|
struct dns_domain_set_name_list *set_name_list = NULL;
|
||||||
struct dns_domain_set_name *set_name_item = NULL;
|
struct dns_domain_set_name *set_name_item = NULL;
|
||||||
@@ -882,7 +843,7 @@ static int _config_domain_rule_set_each(const char *domain_set, domain_set_rule_
|
|||||||
{
|
{
|
||||||
switch (set_name_item->type) {
|
switch (set_name_item->type) {
|
||||||
case DNS_DOMAIN_SET_LIST:
|
case DNS_DOMAIN_SET_LIST:
|
||||||
_config_domain_rule_each_from_list(set_name_item->file, callback, priv);
|
_config_set_rule_each_from_list(set_name_item->file, callback, priv);
|
||||||
break;
|
break;
|
||||||
case DNS_DOMAIN_SET_GEOSITE:
|
case DNS_DOMAIN_SET_GEOSITE:
|
||||||
break;
|
break;
|
||||||
@@ -2474,7 +2435,7 @@ errout:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static radix_node_t *_create_addr_node(char *addr)
|
static radix_node_t *_create_addr_node(const char *addr)
|
||||||
{
|
{
|
||||||
radix_node_t *node = NULL;
|
radix_node_t *node = NULL;
|
||||||
void *p = NULL;
|
void *p = NULL;
|
||||||
@@ -2500,50 +2461,59 @@ static radix_node_t *_create_addr_node(char *addr)
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct dns_ip_address_rule *_config_iplist_rule(char *subnet, enum address_rule rule)
|
static void *_new_dns_ip_rule_ext(enum ip_rule ip_rule, int ext_size)
|
||||||
{
|
{
|
||||||
radix_node_t *node = NULL;
|
struct dns_ip_rule *rule;
|
||||||
struct dns_ip_address_rule *ip_rule = NULL;
|
int size = 0;
|
||||||
|
|
||||||
node = _create_addr_node(subnet);
|
if (ip_rule >= IP_RULE_MAX) {
|
||||||
if (node == NULL) {
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node->data == NULL) {
|
switch (ip_rule) {
|
||||||
ip_rule = malloc(sizeof(*ip_rule));
|
case IP_RULE_FLAGS:
|
||||||
if (ip_rule == NULL) {
|
size = sizeof(struct ip_rule_flags);
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
node->data = ip_rule;
|
|
||||||
memset(ip_rule, 0, sizeof(*ip_rule));
|
|
||||||
}
|
|
||||||
|
|
||||||
ip_rule = node->data;
|
|
||||||
|
|
||||||
switch (rule) {
|
|
||||||
case ADDRESS_RULE_BLACKLIST:
|
|
||||||
ip_rule->blacklist = 1;
|
|
||||||
break;
|
break;
|
||||||
case ADDRESS_RULE_WHITELIST:
|
case IP_RULE_ALIAS:
|
||||||
ip_rule->whitelist = 1;
|
size = sizeof(struct ip_rule_alias);
|
||||||
break;
|
break;
|
||||||
case ADDRESS_RULE_BOGUS:
|
|
||||||
ip_rule->bogus = 1;
|
|
||||||
break;
|
|
||||||
case ADDRESS_RULE_IP_IGNORE:
|
|
||||||
ip_rule->ip_ignore = 1;
|
|
||||||
break;
|
|
||||||
case ADDRESS_RULE_IP_ALIAS: {
|
|
||||||
ip_rule->ip_alias = _new_dns_iplist_ip_addresses();
|
|
||||||
ip_rule->ip_alias_enable = 1;
|
|
||||||
} break;
|
|
||||||
default:
|
default:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ip_rule;
|
size += ext_size;
|
||||||
|
rule = malloc(size);
|
||||||
|
if (!rule) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memset(rule, 0, size);
|
||||||
|
rule->rule = ip_rule;
|
||||||
|
atomic_set(&rule->refcnt, 1);
|
||||||
|
return rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *_new_dns_ip_rule(enum ip_rule ip_rule)
|
||||||
|
{
|
||||||
|
return _new_dns_ip_rule_ext(ip_rule, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _dns_ip_rule_get(struct dns_ip_rule *rule)
|
||||||
|
{
|
||||||
|
atomic_inc(&rule->refcnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _dns_ip_rule_put(struct dns_ip_rule *rule)
|
||||||
|
{
|
||||||
|
if (atomic_dec_and_test(&rule->refcnt)) {
|
||||||
|
if (rule->rule == IP_RULE_ALIAS) {
|
||||||
|
struct ip_rule_alias *alias = container_of(rule, struct ip_rule_alias, head);
|
||||||
|
if (alias->ip_alias.ipaddr) {
|
||||||
|
free(alias->ip_alias.ipaddr);
|
||||||
|
alias->ip_alias.ipaddr_num = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(rule);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _config_qtype_soa(void *data, int argc, char *argv[])
|
static int _config_qtype_soa(void *data, int argc, char *argv[])
|
||||||
@@ -2619,129 +2589,6 @@ static void _config_domain_set_name_table_destroy(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _config_blacklist_ip(void *data, int argc, char *argv[])
|
|
||||||
{
|
|
||||||
if (argc <= 1) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_config_iplist_rule(argv[1], ADDRESS_RULE_BLACKLIST) == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _conf_bogus_nxdomain(void *data, int argc, char *argv[])
|
|
||||||
{
|
|
||||||
if (argc <= 1) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_config_iplist_rule(argv[1], ADDRESS_RULE_BOGUS) == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _conf_ip_ignore(void *data, int argc, char *argv[])
|
|
||||||
{
|
|
||||||
if (argc <= 1) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_config_iplist_rule(argv[1], ADDRESS_RULE_IP_IGNORE) == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _conf_whitelist_ip(void *data, int argc, char *argv[])
|
|
||||||
{
|
|
||||||
if (argc <= 1) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_config_iplist_rule(argv[1], ADDRESS_RULE_WHITELIST) == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _conf_ip_alias(void *data, int argc, char *argv[])
|
|
||||||
{
|
|
||||||
struct dns_ip_address_rule *ip_rule = NULL;
|
|
||||||
struct dns_iplist_ip_addresses *ip_alias = NULL;
|
|
||||||
char *target_ips = NULL;
|
|
||||||
|
|
||||||
if (argc <= 2) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ip_rule = _config_iplist_rule(argv[1], ADDRESS_RULE_IP_ALIAS);
|
|
||||||
if (ip_rule == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ip_alias = ip_rule->ip_alias;
|
|
||||||
if (ip_alias == NULL) {
|
|
||||||
tlog(TLOG_ERROR, "cannot malloc memory");
|
|
||||||
goto errout;
|
|
||||||
}
|
|
||||||
|
|
||||||
target_ips = strdup(argv[2]);
|
|
||||||
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) {
|
|
||||||
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, 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, paddr, DNS_RR_A_LEN);
|
|
||||||
} else {
|
|
||||||
paddr = addr_in6->sin6_addr.s6_addr;
|
|
||||||
_dns_iplist_ip_address_add(ip_alias, paddr, DNS_RR_AAAA_LEN);
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
default:
|
|
||||||
goto errout;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(target_ips);
|
|
||||||
return 0;
|
|
||||||
errout:
|
|
||||||
if (target_ips) {
|
|
||||||
free(target_ips);
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _conf_client_subnet(char *subnet, struct dns_edns_client_subnet *ipv4_ecs,
|
static int _conf_client_subnet(char *subnet, struct dns_edns_client_subnet *ipv4_ecs,
|
||||||
struct dns_edns_client_subnet *ipv6_ecs)
|
struct dns_edns_client_subnet *ipv6_ecs)
|
||||||
{
|
{
|
||||||
@@ -2971,6 +2818,514 @@ errout:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _config_ip_rule_set_each(const char *ip_set, set_rule_add_func callback, void *priv)
|
||||||
|
{
|
||||||
|
struct dns_ip_set_name_list *set_name_list = NULL;
|
||||||
|
struct dns_ip_set_name *set_name_item = NULL;
|
||||||
|
|
||||||
|
uint32_t key = 0;
|
||||||
|
|
||||||
|
key = hash_string(ip_set);
|
||||||
|
hash_for_each_possible(dns_ip_set_name_table.names, set_name_list, node, key)
|
||||||
|
{
|
||||||
|
if (strcmp(set_name_list->name, ip_set) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (set_name_list == NULL) {
|
||||||
|
tlog(TLOG_WARN, "ip set %s not found.", ip_set);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_for_each_entry(set_name_item, &set_name_list->set_name_list, list)
|
||||||
|
{
|
||||||
|
switch (set_name_item->type) {
|
||||||
|
case DNS_IP_SET_LIST:
|
||||||
|
_config_set_rule_each_from_list(set_name_item->file, callback, priv);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
tlog(TLOG_WARN, "ip set %s type %d not support.", set_name_list->name, set_name_item->type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _config_ip_rules_free(struct dns_ip_rules *ip_rules)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
if (ip_rules == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < DOMAIN_RULE_MAX; i++) {
|
||||||
|
if (ip_rules->rules[i] == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
_dns_ip_rule_put(ip_rules->rules[i]);
|
||||||
|
ip_rules->rules[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(ip_rules);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _config_ip_rule_flag_set(const char *ip_cidr, unsigned int flag, unsigned int is_clear);
|
||||||
|
static int _config_ip_rule_flag_callback(const char *ip_cidr, void *priv)
|
||||||
|
{
|
||||||
|
struct dns_set_rule_flags_callback_args *args = (struct dns_set_rule_flags_callback_args *)priv;
|
||||||
|
return _config_ip_rule_flag_set(ip_cidr, args->flags, args->is_clear_flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _config_ip_rule_flag_set(const char *ip_cidr, unsigned int flag, unsigned int is_clear)
|
||||||
|
{
|
||||||
|
struct dns_ip_rules *ip_rules = NULL;
|
||||||
|
struct dns_ip_rules *add_ip_rules = NULL;
|
||||||
|
struct ip_rule_flags *ip_rule_flags = NULL;
|
||||||
|
radix_node_t *node = NULL;
|
||||||
|
|
||||||
|
if (strncmp(ip_cidr, "ip-set:", sizeof("ip-set:") - 1) == 0) {
|
||||||
|
struct dns_set_rule_flags_callback_args args;
|
||||||
|
args.flags = flag;
|
||||||
|
args.is_clear_flag = is_clear;
|
||||||
|
return _config_ip_rule_set_each(ip_cidr + sizeof("ip-set:") - 1, _config_ip_rule_flag_callback, &args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get existing or create domain rule */
|
||||||
|
node = _create_addr_node(ip_cidr);
|
||||||
|
if (node == NULL) {
|
||||||
|
tlog(TLOG_ERROR, "create addr node failed.");
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_rules = node->data;
|
||||||
|
if (ip_rules == NULL) {
|
||||||
|
add_ip_rules = malloc(sizeof(*add_ip_rules));
|
||||||
|
if (add_ip_rules == NULL) {
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
memset(add_ip_rules, 0, sizeof(*add_ip_rules));
|
||||||
|
ip_rules = add_ip_rules;
|
||||||
|
node->data = ip_rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add new rule to domain */
|
||||||
|
if (ip_rules->rules[IP_RULE_FLAGS] == NULL) {
|
||||||
|
ip_rule_flags = _new_dns_ip_rule(IP_RULE_FLAGS);
|
||||||
|
ip_rule_flags->flags = 0;
|
||||||
|
ip_rules->rules[IP_RULE_FLAGS] = &ip_rule_flags->head;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_rule_flags = container_of(ip_rules->rules[IP_RULE_FLAGS], struct ip_rule_flags, head);
|
||||||
|
if (is_clear == false) {
|
||||||
|
ip_rule_flags->flags |= flag;
|
||||||
|
} else {
|
||||||
|
ip_rule_flags->flags &= ~flag;
|
||||||
|
}
|
||||||
|
ip_rule_flags->is_flag_set |= flag;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
errout:
|
||||||
|
if (add_ip_rules) {
|
||||||
|
free(add_ip_rules);
|
||||||
|
}
|
||||||
|
|
||||||
|
tlog(TLOG_ERROR, "set ip %s flags failed", ip_cidr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _config_ip_rule_add(const char *ip_cidr, enum ip_rule type, void *rule);
|
||||||
|
static int _config_ip_rule_add_callback(const char *ip_cidr, void *priv)
|
||||||
|
{
|
||||||
|
struct dns_set_rule_add_callback_args *args = (struct dns_set_rule_add_callback_args *)priv;
|
||||||
|
return _config_ip_rule_add(ip_cidr, args->type, args->rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _config_ip_rule_add(const char *ip_cidr, enum ip_rule type, void *rule)
|
||||||
|
{
|
||||||
|
struct dns_ip_rules *ip_rules = NULL;
|
||||||
|
struct dns_ip_rules *add_ip_rules = NULL;
|
||||||
|
radix_node_t *node = NULL;
|
||||||
|
|
||||||
|
if (ip_cidr == NULL) {
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type >= IP_RULE_MAX) {
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncmp(ip_cidr, "ip-set:", sizeof("ip-set:") - 1) == 0) {
|
||||||
|
struct dns_set_rule_add_callback_args args;
|
||||||
|
args.type = type;
|
||||||
|
args.rule = rule;
|
||||||
|
return _config_ip_rule_set_each(ip_cidr + sizeof("ip-set:") - 1, _config_ip_rule_add_callback, &args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get existing or create domain rule */
|
||||||
|
node = _create_addr_node(ip_cidr);
|
||||||
|
if (node == NULL) {
|
||||||
|
tlog(TLOG_ERROR, "create addr node failed.");
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_rules = node->data;
|
||||||
|
if (ip_rules == NULL) {
|
||||||
|
add_ip_rules = malloc(sizeof(*add_ip_rules));
|
||||||
|
if (add_ip_rules == NULL) {
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
memset(add_ip_rules, 0, sizeof(*add_ip_rules));
|
||||||
|
ip_rules = add_ip_rules;
|
||||||
|
node->data = ip_rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add new rule to domain */
|
||||||
|
if (ip_rules->rules[type]) {
|
||||||
|
_dns_ip_rule_put(ip_rules->rules[type]);
|
||||||
|
ip_rules->rules[type] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_rules->rules[type] = rule;
|
||||||
|
_dns_ip_rule_get(rule);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
errout:
|
||||||
|
if (add_ip_rules) {
|
||||||
|
free(add_ip_rules);
|
||||||
|
}
|
||||||
|
|
||||||
|
tlog(TLOG_ERROR, "add ip %s rule failed", ip_cidr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _config_ip_alias(const char *ip_cidr, const char *ips)
|
||||||
|
{
|
||||||
|
struct ip_rule_alias *ip_alias = NULL;
|
||||||
|
char *target_ips = NULL;
|
||||||
|
|
||||||
|
if (ip_cidr == NULL || ips == NULL) {
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_alias = _new_dns_ip_rule(IP_RULE_ALIAS);
|
||||||
|
if (ip_alias == NULL) {
|
||||||
|
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) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_config_ip_rule_add(ip_cidr, IP_RULE_ALIAS, ip_alias) != 0) {
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
_dns_ip_rule_put(&ip_alias->head);
|
||||||
|
free(target_ips);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
errout:
|
||||||
|
|
||||||
|
if (ip_alias) {
|
||||||
|
_dns_ip_rule_put(&ip_alias->head);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target_ips) {
|
||||||
|
free(target_ips);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _config_blacklist_ip(void *data, int argc, char *argv[])
|
||||||
|
{
|
||||||
|
if (argc <= 1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _config_ip_rule_flag_set(argv[1], IP_RULE_FLAG_BLACKLIST, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _conf_bogus_nxdomain(void *data, int argc, char *argv[])
|
||||||
|
{
|
||||||
|
if (argc <= 1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _config_ip_rule_flag_set(argv[1], IP_RULE_FLAG_BOGUS, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _conf_ip_ignore(void *data, int argc, char *argv[])
|
||||||
|
{
|
||||||
|
if (argc <= 1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _config_ip_rule_flag_set(argv[1], IP_RULE_FLAG_IP_IGNORE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _conf_whitelist_ip(void *data, int argc, char *argv[])
|
||||||
|
{
|
||||||
|
if (argc <= 1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _config_ip_rule_flag_set(argv[1], IP_RULE_FLAG_WHITELIST, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _conf_ip_alias(void *data, int argc, char *argv[])
|
||||||
|
{
|
||||||
|
if (argc <= 2) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _config_ip_alias(argv[1], argv[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _conf_ip_rules(void *data, int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int opt = 0;
|
||||||
|
char *ip_cidr = argv[1];
|
||||||
|
|
||||||
|
/* clang-format off */
|
||||||
|
static struct option long_options[] = {
|
||||||
|
{"blacklist-ip", no_argument, NULL, 'b'},
|
||||||
|
{"whitelist-ip", no_argument, NULL, 'w'},
|
||||||
|
{"bogus-nxdomain", no_argument, NULL, 'n'},
|
||||||
|
{"ignore-ip", no_argument, NULL, 'i'},
|
||||||
|
{"ip-alias", required_argument, NULL, 'a'},
|
||||||
|
{NULL, no_argument, NULL, 0}
|
||||||
|
};
|
||||||
|
/* clang-format on */
|
||||||
|
|
||||||
|
if (argc <= 1) {
|
||||||
|
tlog(TLOG_ERROR, "invalid parameter.");
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* process extra options */
|
||||||
|
optind = 1;
|
||||||
|
while (1) {
|
||||||
|
opt = getopt_long_only(argc, argv, "", long_options, NULL);
|
||||||
|
if (opt == -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (opt) {
|
||||||
|
case 'b': {
|
||||||
|
if (_config_ip_rule_flag_set(ip_cidr, IP_RULE_FLAG_BLACKLIST, 0) != 0) {
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'w': {
|
||||||
|
if (_config_ip_rule_flag_set(ip_cidr, IP_RULE_FLAG_WHITELIST, 0) != 0) {
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'n': {
|
||||||
|
if (_config_ip_rule_flag_set(ip_cidr, IP_RULE_FLAG_BOGUS, 0) != 0) {
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'i': {
|
||||||
|
if (_config_ip_rule_flag_set(ip_cidr, IP_RULE_FLAG_IP_IGNORE, 0) != 0) {
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'a': {
|
||||||
|
|
||||||
|
if (_config_ip_alias(ip_cidr, optarg) != 0) {
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
errout:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _conf_ip_set(void *data, int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int opt = 0;
|
||||||
|
uint32_t key = 0;
|
||||||
|
struct dns_ip_set_name *ip_set = NULL;
|
||||||
|
struct dns_ip_set_name_list *ip_set_name_list = NULL;
|
||||||
|
char set_name[DNS_MAX_CNAME_LEN] = {0};
|
||||||
|
|
||||||
|
/* clang-format off */
|
||||||
|
static struct option long_options[] = {
|
||||||
|
{"name", required_argument, NULL, 'n'},
|
||||||
|
{"type", required_argument, NULL, 't'},
|
||||||
|
{"file", required_argument, NULL, 'f'},
|
||||||
|
{NULL, 0, NULL, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (argc <= 1) {
|
||||||
|
tlog(TLOG_ERROR, "invalid parameter.");
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_set = malloc(sizeof(*ip_set));
|
||||||
|
if (ip_set == NULL) {
|
||||||
|
tlog(TLOG_ERROR, "cannot malloc memory.");
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
memset(ip_set, 0, sizeof(*ip_set));
|
||||||
|
INIT_LIST_HEAD(&ip_set->list);
|
||||||
|
|
||||||
|
optind = 1;
|
||||||
|
while (1) {
|
||||||
|
opt = getopt_long_only(argc, argv, "n:t:f:", long_options, NULL);
|
||||||
|
if (opt == -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (opt) {
|
||||||
|
case 'n':
|
||||||
|
safe_strncpy(set_name, optarg, DNS_MAX_CNAME_LEN);
|
||||||
|
break;
|
||||||
|
case 't': {
|
||||||
|
const char *type = optarg;
|
||||||
|
if (strncmp(type, "list", 5) == 0) {
|
||||||
|
ip_set->type = DNS_IP_SET_LIST;
|
||||||
|
} else {
|
||||||
|
tlog(TLOG_ERROR, "invalid domain set type.");
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'f':
|
||||||
|
conf_get_conf_fullpath(optarg, ip_set->file, DNS_MAX_PATH);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* clang-format on */
|
||||||
|
|
||||||
|
if (set_name[0] == 0 || ip_set->file[0] == 0) {
|
||||||
|
tlog(TLOG_ERROR, "invalid parameter.");
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
key = hash_string(set_name);
|
||||||
|
hash_for_each_possible(dns_ip_set_name_table.names, ip_set_name_list, node, key)
|
||||||
|
{
|
||||||
|
if (strcmp(ip_set_name_list->name, set_name) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ip_set_name_list == NULL) {
|
||||||
|
ip_set_name_list = malloc(sizeof(*ip_set_name_list));
|
||||||
|
if (ip_set_name_list == NULL) {
|
||||||
|
tlog(TLOG_ERROR, "cannot malloc memory.");
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
memset(ip_set_name_list, 0, sizeof(*ip_set_name_list));
|
||||||
|
INIT_LIST_HEAD(&ip_set_name_list->set_name_list);
|
||||||
|
safe_strncpy(ip_set_name_list->name, set_name, DNS_MAX_CNAME_LEN);
|
||||||
|
hash_add(dns_ip_set_name_table.names, &ip_set_name_list->node, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
list_add_tail(&ip_set->list, &ip_set_name_list->set_name_list);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
errout:
|
||||||
|
if (ip_set) {
|
||||||
|
free(ip_set);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _config_ip_iter_free(radix_node_t *node, void *cbctx)
|
||||||
|
{
|
||||||
|
struct dns_ip_rules *ip_rules = NULL;
|
||||||
|
if (node == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->data == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_rules = node->data;
|
||||||
|
_config_ip_rules_free(ip_rules);
|
||||||
|
node->data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _config_ip_set_name_table_destroy(void)
|
||||||
|
{
|
||||||
|
struct dns_ip_set_name_list *set_name_list = NULL;
|
||||||
|
struct hlist_node *tmp = NULL;
|
||||||
|
struct dns_ip_set_name *set_name = NULL;
|
||||||
|
struct dns_ip_set_name *tmp1 = NULL;
|
||||||
|
unsigned long i = 0;
|
||||||
|
|
||||||
|
hash_for_each_safe(dns_ip_set_name_table.names, i, tmp, set_name_list, node)
|
||||||
|
{
|
||||||
|
hlist_del_init(&set_name_list->node);
|
||||||
|
list_for_each_entry_safe(set_name, tmp1, &set_name_list->set_name_list, list)
|
||||||
|
{
|
||||||
|
list_del(&set_name->list);
|
||||||
|
free(set_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(set_name_list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int _conf_ddns_domain(void *data, int argc, char *argv[])
|
static int _conf_ddns_domain(void *data, int argc, char *argv[])
|
||||||
{
|
{
|
||||||
if (argc <= 1) {
|
if (argc <= 1) {
|
||||||
@@ -3736,6 +4091,8 @@ static struct config_item _config_item[] = {
|
|||||||
CONF_CUSTOM("blacklist-ip", _config_blacklist_ip, NULL),
|
CONF_CUSTOM("blacklist-ip", _config_blacklist_ip, NULL),
|
||||||
CONF_CUSTOM("whitelist-ip", _conf_whitelist_ip, NULL),
|
CONF_CUSTOM("whitelist-ip", _conf_whitelist_ip, NULL),
|
||||||
CONF_CUSTOM("ip-alias", _conf_ip_alias, NULL),
|
CONF_CUSTOM("ip-alias", _conf_ip_alias, NULL),
|
||||||
|
CONF_CUSTOM("ip-rules", _conf_ip_rules, NULL),
|
||||||
|
CONF_CUSTOM("ip-set", _conf_ip_set, NULL),
|
||||||
CONF_CUSTOM("bogus-nxdomain", _conf_bogus_nxdomain, NULL),
|
CONF_CUSTOM("bogus-nxdomain", _conf_bogus_nxdomain, NULL),
|
||||||
CONF_CUSTOM("ignore-ip", _conf_ip_ignore, NULL),
|
CONF_CUSTOM("ignore-ip", _conf_ip_ignore, NULL),
|
||||||
CONF_CUSTOM("edns-client-subnet", _conf_edns_client_subnet, NULL),
|
CONF_CUSTOM("edns-client-subnet", _conf_edns_client_subnet, NULL),
|
||||||
@@ -3841,6 +4198,7 @@ static int _dns_server_load_conf_init(void)
|
|||||||
hash_init(dns_hosts_table.hosts);
|
hash_init(dns_hosts_table.hosts);
|
||||||
hash_init(dns_ptr_table.ptr);
|
hash_init(dns_ptr_table.ptr);
|
||||||
hash_init(dns_domain_set_name_table.names);
|
hash_init(dns_domain_set_name_table.names);
|
||||||
|
hash_init(dns_ip_set_name_table.names);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -3874,11 +4232,16 @@ static void dns_server_bind_destroy(void)
|
|||||||
dns_conf_bind_ip_num = 0;
|
dns_conf_bind_ip_num = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _config_ip_rules_destroy(void)
|
||||||
|
{
|
||||||
|
Destroy_Radix(dns_conf_address_rule.ipv4, _config_ip_iter_free, NULL);
|
||||||
|
Destroy_Radix(dns_conf_address_rule.ipv6, _config_ip_iter_free, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
void dns_server_load_exit(void)
|
void dns_server_load_exit(void)
|
||||||
{
|
{
|
||||||
_config_domain_destroy();
|
_config_domain_destroy();
|
||||||
Destroy_Radix(dns_conf_address_rule.ipv4, _config_address_destroy, NULL);
|
_config_ip_rules_destroy();
|
||||||
Destroy_Radix(dns_conf_address_rule.ipv6, _config_address_destroy, NULL);
|
|
||||||
_config_ipset_table_destroy();
|
_config_ipset_table_destroy();
|
||||||
_config_nftset_table_destroy();
|
_config_nftset_table_destroy();
|
||||||
_config_group_table_destroy();
|
_config_group_table_destroy();
|
||||||
@@ -4019,6 +4382,8 @@ static int _dns_conf_load_post(void)
|
|||||||
|
|
||||||
_config_domain_set_name_table_destroy();
|
_config_domain_set_name_table_destroy();
|
||||||
|
|
||||||
|
_config_ip_set_name_table_destroy();
|
||||||
|
|
||||||
_config_update_bootstrap_dns_rule();
|
_config_update_bootstrap_dns_rule();
|
||||||
|
|
||||||
_config_add_default_server_if_needed();
|
_config_add_default_server_if_needed();
|
||||||
|
|||||||
@@ -85,6 +85,12 @@ enum domain_rule {
|
|||||||
DOMAIN_RULE_MAX,
|
DOMAIN_RULE_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum ip_rule {
|
||||||
|
IP_RULE_FLAGS = 0,
|
||||||
|
IP_RULE_ALIAS = 1,
|
||||||
|
IP_RULE_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
DNS_BIND_TYPE_UDP,
|
DNS_BIND_TYPE_UDP,
|
||||||
DNS_BIND_TYPE_TCP,
|
DNS_BIND_TYPE_TCP,
|
||||||
@@ -119,6 +125,11 @@ typedef enum {
|
|||||||
#define DOMAIN_FLAG_NO_CACHE (1 << 17)
|
#define DOMAIN_FLAG_NO_CACHE (1 << 17)
|
||||||
#define DOMAIN_FLAG_NO_IPALIAS (1 << 18)
|
#define DOMAIN_FLAG_NO_IPALIAS (1 << 18)
|
||||||
|
|
||||||
|
#define IP_RULE_FLAG_BLACKLIST (1 << 0)
|
||||||
|
#define IP_RULE_FLAG_WHITELIST (1 << 1)
|
||||||
|
#define IP_RULE_FLAG_BOGUS (1 << 2)
|
||||||
|
#define IP_RULE_FLAG_IP_IGNORE (1 << 3)
|
||||||
|
|
||||||
#define SERVER_FLAG_EXCLUDE_DEFAULT (1 << 0)
|
#define SERVER_FLAG_EXCLUDE_DEFAULT (1 << 0)
|
||||||
#define SERVER_FLAG_HITCHHIKING (1 << 1)
|
#define SERVER_FLAG_HITCHHIKING (1 << 1)
|
||||||
|
|
||||||
@@ -351,14 +362,6 @@ struct dns_bogus_ip_address {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
enum address_rule {
|
|
||||||
ADDRESS_RULE_BLACKLIST = 1,
|
|
||||||
ADDRESS_RULE_WHITELIST = 2,
|
|
||||||
ADDRESS_RULE_BOGUS = 3,
|
|
||||||
ADDRESS_RULE_IP_IGNORE = 4,
|
|
||||||
ADDRESS_RULE_IP_ALIAS = 5,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct dns_iplist_ip_address {
|
struct dns_iplist_ip_address {
|
||||||
int addr_len;
|
int addr_len;
|
||||||
union {
|
union {
|
||||||
@@ -369,20 +372,10 @@ struct dns_iplist_ip_address {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct dns_iplist_ip_addresses {
|
struct dns_iplist_ip_addresses {
|
||||||
atomic_t refcnt;
|
|
||||||
int ipaddr_num;
|
int ipaddr_num;
|
||||||
struct dns_iplist_ip_address *ipaddr;
|
struct dns_iplist_ip_address *ipaddr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dns_ip_address_rule {
|
|
||||||
unsigned int blacklist : 1;
|
|
||||||
unsigned int whitelist : 1;
|
|
||||||
unsigned int bogus : 1;
|
|
||||||
unsigned int ip_ignore : 1;
|
|
||||||
unsigned int ip_alias_enable : 1;
|
|
||||||
struct dns_iplist_ip_addresses *ip_alias;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct dns_conf_address_rule {
|
struct dns_conf_address_rule {
|
||||||
radix_tree_t *ipv4;
|
radix_tree_t *ipv4;
|
||||||
radix_tree_t *ipv6;
|
radix_tree_t *ipv6;
|
||||||
@@ -438,8 +431,48 @@ struct dns_domain_set_name_table {
|
|||||||
};
|
};
|
||||||
extern struct dns_domain_set_name_table dns_domain_set_name_table;
|
extern struct dns_domain_set_name_table dns_domain_set_name_table;
|
||||||
|
|
||||||
|
struct dns_ip_rule {
|
||||||
|
atomic_t refcnt;
|
||||||
|
enum ip_rule rule;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum dns_ip_set_type {
|
||||||
|
DNS_IP_SET_LIST = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dns_ip_rules {
|
||||||
|
struct dns_ip_rule *rules[IP_RULE_MAX];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ip_rule_flags {
|
||||||
|
struct dns_ip_rule head;
|
||||||
|
unsigned int flags;
|
||||||
|
unsigned int is_flag_set;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ip_rule_alias {
|
||||||
|
struct dns_ip_rule head;
|
||||||
|
struct dns_iplist_ip_addresses ip_alias;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dns_ip_set_name {
|
||||||
|
struct list_head list;
|
||||||
|
enum dns_ip_set_type type;
|
||||||
|
char file[DNS_MAX_PATH];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dns_ip_set_name_list {
|
||||||
|
struct hlist_node node;
|
||||||
|
char name[DNS_MAX_CNAME_LEN];
|
||||||
|
struct list_head set_name_list;
|
||||||
|
};
|
||||||
|
struct dns_ip_set_name_table {
|
||||||
|
DECLARE_HASHTABLE(names, 4);
|
||||||
|
};
|
||||||
|
extern struct dns_ip_set_name_table dns_ip_set_name_table;
|
||||||
|
|
||||||
struct dns_set_rule_add_callback_args {
|
struct dns_set_rule_add_callback_args {
|
||||||
enum domain_rule type;
|
int type;
|
||||||
void *rule;
|
void *rule;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2733,12 +2733,12 @@ static int _dns_server_check_speed(struct dns_request *request, char *ip)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct dns_ip_address_rule *_dns_server_ip_rule_get(struct dns_request *request, unsigned char *addr,
|
static struct dns_ip_rules *_dns_server_ip_rule_get(struct dns_request *request, unsigned char *addr, int addr_len,
|
||||||
int addr_len, dns_type_t addr_type)
|
dns_type_t addr_type)
|
||||||
{
|
{
|
||||||
prefix_t prefix;
|
prefix_t prefix;
|
||||||
radix_node_t *node = NULL;
|
radix_node_t *node = NULL;
|
||||||
struct dns_ip_address_rule *rule = NULL;
|
struct dns_ip_rules *rule = NULL;
|
||||||
|
|
||||||
/* Match IP address rules */
|
/* Match IP address rules */
|
||||||
if (prefix_from_blob(addr, addr_len, addr_len * 8, &prefix) == NULL) {
|
if (prefix_from_blob(addr, addr_len, addr_len * 8, &prefix) == NULL) {
|
||||||
@@ -2769,43 +2769,47 @@ static struct dns_ip_address_rule *_dns_server_ip_rule_get(struct dns_request *r
|
|||||||
return rule;
|
return rule;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _dns_server_ip_rule_check(struct dns_request *request, struct dns_ip_address_rule *rule, int result_flag)
|
static int _dns_server_ip_rule_check(struct dns_request *request, struct dns_ip_rules *ip_rules, int result_flag)
|
||||||
{
|
{
|
||||||
if (rule == NULL) {
|
struct ip_rule_flags *rule_flags = NULL;
|
||||||
|
if (ip_rules == NULL) {
|
||||||
goto rule_not_found;
|
goto rule_not_found;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rule->bogus) {
|
rule_flags = container_of(ip_rules->rules[IP_RULE_FLAGS], struct ip_rule_flags, head);
|
||||||
request->rcode = DNS_RC_NXDOMAIN;
|
if (rule_flags != NULL) {
|
||||||
request->has_soa = 1;
|
if (rule_flags->flags & IP_RULE_FLAG_BOGUS) {
|
||||||
request->force_soa = 1;
|
request->rcode = DNS_RC_NXDOMAIN;
|
||||||
_dns_server_setup_soa(request);
|
request->has_soa = 1;
|
||||||
goto nxdomain;
|
request->force_soa = 1;
|
||||||
}
|
_dns_server_setup_soa(request);
|
||||||
|
goto nxdomain;
|
||||||
|
}
|
||||||
|
|
||||||
/* blacklist-ip */
|
/* blacklist-ip */
|
||||||
if (rule->blacklist) {
|
if (rule_flags->flags & IP_RULE_FLAG_BLACKLIST) {
|
||||||
if (result_flag & DNSSERVER_FLAG_BLACKLIST_IP) {
|
if (result_flag & DNSSERVER_FLAG_BLACKLIST_IP) {
|
||||||
goto match;
|
goto match;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ignore-ip */
|
||||||
|
if (rule_flags->flags & IP_RULE_FLAG_IP_IGNORE) {
|
||||||
|
goto skip;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ignore-ip */
|
if (ip_rules->rules[IP_RULE_ALIAS] != NULL) {
|
||||||
if (rule->ip_ignore) {
|
|
||||||
goto skip;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rule->ip_alias_enable) {
|
|
||||||
goto match;
|
goto match;
|
||||||
}
|
}
|
||||||
|
|
||||||
rule_not_found:
|
rule_not_found:
|
||||||
if (result_flag & DNSSERVER_FLAG_WHITELIST_IP) {
|
if (result_flag & DNSSERVER_FLAG_WHITELIST_IP) {
|
||||||
if (rule == NULL) {
|
if (rule_flags == NULL) {
|
||||||
goto skip;
|
goto skip;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rule->whitelist) {
|
if (!(rule_flags->flags & IP_RULE_FLAG_WHITELIST)) {
|
||||||
goto skip;
|
goto skip;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2853,18 +2857,19 @@ static int _dns_server_process_ip_alias(struct dns_request *request, struct dns_
|
|||||||
static int _dns_server_process_ip_rule(struct dns_request *request, unsigned char *addr, int addr_len,
|
static int _dns_server_process_ip_rule(struct dns_request *request, unsigned char *addr, int addr_len,
|
||||||
dns_type_t addr_type, int result_flag, struct dns_iplist_ip_addresses **alias)
|
dns_type_t addr_type, int result_flag, struct dns_iplist_ip_addresses **alias)
|
||||||
{
|
{
|
||||||
struct dns_ip_address_rule *rule = NULL;
|
struct dns_ip_rules *ip_rules = NULL;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
rule = _dns_server_ip_rule_get(request, addr, addr_len, addr_type);
|
ip_rules = _dns_server_ip_rule_get(request, addr, addr_len, addr_type);
|
||||||
ret = _dns_server_ip_rule_check(request, rule, result_flag);
|
ret = _dns_server_ip_rule_check(request, ip_rules, result_flag);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rule->ip_alias_enable && alias != NULL) {
|
if (ip_rules->rules[IP_RULE_ALIAS] && alias != NULL) {
|
||||||
if (request->no_ipalias == 0) {
|
if (request->no_ipalias == 0) {
|
||||||
*alias = rule->ip_alias;
|
struct ip_rule_alias *rule = container_of(ip_rules->rules[IP_RULE_ALIAS], struct ip_rule_alias, head);
|
||||||
|
*alias = &rule->ip_alias;
|
||||||
if (alias == NULL) {
|
if (alias == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -363,6 +363,7 @@ static int load_conf_file(const char *file, struct config_item *items, conf_erro
|
|||||||
int read_len = 0;
|
int read_len = 0;
|
||||||
int is_last_line_wrap = 0;
|
int is_last_line_wrap = 0;
|
||||||
int current_line_wrap = 0;
|
int current_line_wrap = 0;
|
||||||
|
int is_func_found = 0;
|
||||||
const char *last_file = NULL;
|
const char *last_file = NULL;
|
||||||
|
|
||||||
if (handler == NULL) {
|
if (handler == NULL) {
|
||||||
@@ -431,6 +432,8 @@ static int load_conf_file(const char *file, struct config_item *items, conf_erro
|
|||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is_func_found = 0;
|
||||||
|
|
||||||
for (i = last_item_index;; i++) {
|
for (i = last_item_index;; i++) {
|
||||||
if (i < 0) {
|
if (i < 0) {
|
||||||
continue;
|
continue;
|
||||||
@@ -471,8 +474,13 @@ static int load_conf_file(const char *file, struct config_item *items, conf_erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
last_item_index = i;
|
last_item_index = i;
|
||||||
|
is_func_found = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_func_found == 0) {
|
||||||
|
handler(file, line_no, CONF_RET_NOENT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|||||||
@@ -154,3 +154,59 @@ cache-persist no)""");
|
|||||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
|
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
|
||||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "7.8.9.10");
|
EXPECT_EQ(client.GetAnswer()[0].GetData(), "7.8.9.10");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(IPRule, ignore_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::ofstream ofs(file);
|
||||||
|
ASSERT_TRUE(ofs.is_open());
|
||||||
|
Defer
|
||||||
|
{
|
||||||
|
ofs.close();
|
||||||
|
unlink(file.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;
|
||||||
|
});
|
||||||
|
|
||||||
|
/* this ip will be discard, but is reachable */
|
||||||
|
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
|
||||||
|
)""";
|
||||||
|
ofs.write(ipset_list.c_str(), ipset_list.length());
|
||||||
|
ofs.flush();
|
||||||
|
|
||||||
|
server.Start(R"""(bind [::]:60053
|
||||||
|
server udp://127.0.0.1:61053 -blacklist-ip
|
||||||
|
ip-set -name ip-list -file )""" +
|
||||||
|
file + R"""(
|
||||||
|
ignore-ip ip-set:ip-list
|
||||||
|
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(), "7.8.9.10");
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user