feature: add ip-rules and ip-set options

This commit is contained in:
Nick Peng
2023-09-06 23:25:13 +08:00
parent c39a7b9b41
commit 1b12709451
5 changed files with 723 additions and 256 deletions

View File

@@ -47,6 +47,8 @@ uint8_t *dns_qtype_soa_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 */
struct dns_group_table dns_group_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)
{
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);
}
static void _config_address_destroy(radix_node_t *node, void *cbctx)
{
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)
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)
{
FILE *fp = NULL;
char line[MAX_LINE_LEN];
char domain[DNS_MAX_CNAME_LEN];
char value[DNS_MAX_CNAME_LEN];
int ret = 0;
int line_no = 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;
while (fgets(line, MAX_LINE_LEN, fp)) {
line_no++;
filed_num = sscanf(line, "%255s", domain);
filed_num = sscanf(line, "%255s", value);
if (filed_num <= 0) {
continue;
}
if (domain[0] == '#' || domain[0] == '\n') {
if (value[0] == '#' || value[0] == '\n') {
continue;
}
ret = callback(domain, priv);
ret = callback(value, priv);
if (ret != 0) {
tlog(TLOG_WARN, "process file %s failed at line %d.", file, line_no);
continue;
@@ -858,7 +819,7 @@ static int _config_domain_rule_each_from_list(const char *file, domain_set_rule_
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 *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) {
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;
case DNS_DOMAIN_SET_GEOSITE:
break;
@@ -2474,7 +2435,7 @@ errout:
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;
void *p = NULL;
@@ -2500,50 +2461,59 @@ static radix_node_t *_create_addr_node(char *addr)
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_address_rule *ip_rule = NULL;
struct dns_ip_rule *rule;
int size = 0;
node = _create_addr_node(subnet);
if (node == NULL) {
if (ip_rule >= IP_RULE_MAX) {
return NULL;
}
if (node->data == NULL) {
ip_rule = malloc(sizeof(*ip_rule));
if (ip_rule == NULL) {
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;
switch (ip_rule) {
case IP_RULE_FLAGS:
size = sizeof(struct ip_rule_flags);
break;
case ADDRESS_RULE_WHITELIST:
ip_rule->whitelist = 1;
case IP_RULE_ALIAS:
size = sizeof(struct ip_rule_alias);
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:
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[])
@@ -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,
struct dns_edns_client_subnet *ipv6_ecs)
{
@@ -2971,6 +2818,514 @@ errout:
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[])
{
if (argc <= 1) {
@@ -3736,6 +4091,8 @@ static struct config_item _config_item[] = {
CONF_CUSTOM("blacklist-ip", _config_blacklist_ip, NULL),
CONF_CUSTOM("whitelist-ip", _conf_whitelist_ip, 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("ignore-ip", _conf_ip_ignore, 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_ptr_table.ptr);
hash_init(dns_domain_set_name_table.names);
hash_init(dns_ip_set_name_table.names);
return 0;
}
@@ -3874,11 +4232,16 @@ static void dns_server_bind_destroy(void)
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)
{
_config_domain_destroy();
Destroy_Radix(dns_conf_address_rule.ipv4, _config_address_destroy, NULL);
Destroy_Radix(dns_conf_address_rule.ipv6, _config_address_destroy, NULL);
_config_ip_rules_destroy();
_config_ipset_table_destroy();
_config_nftset_table_destroy();
_config_group_table_destroy();
@@ -4019,6 +4382,8 @@ static int _dns_conf_load_post(void)
_config_domain_set_name_table_destroy();
_config_ip_set_name_table_destroy();
_config_update_bootstrap_dns_rule();
_config_add_default_server_if_needed();

View File

@@ -85,6 +85,12 @@ enum domain_rule {
DOMAIN_RULE_MAX,
};
enum ip_rule {
IP_RULE_FLAGS = 0,
IP_RULE_ALIAS = 1,
IP_RULE_MAX,
};
typedef enum {
DNS_BIND_TYPE_UDP,
DNS_BIND_TYPE_TCP,
@@ -119,6 +125,11 @@ typedef enum {
#define DOMAIN_FLAG_NO_CACHE (1 << 17)
#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_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 {
int addr_len;
union {
@@ -369,20 +372,10 @@ struct dns_iplist_ip_address {
};
struct dns_iplist_ip_addresses {
atomic_t refcnt;
int ipaddr_num;
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 {
radix_tree_t *ipv4;
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;
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 {
enum domain_rule type;
int type;
void *rule;
};

View File

@@ -2733,12 +2733,12 @@ static int _dns_server_check_speed(struct dns_request *request, char *ip)
return -1;
}
static struct dns_ip_address_rule *_dns_server_ip_rule_get(struct dns_request *request, unsigned char *addr,
int addr_len, dns_type_t addr_type)
static struct dns_ip_rules *_dns_server_ip_rule_get(struct dns_request *request, unsigned char *addr, int addr_len,
dns_type_t addr_type)
{
prefix_t prefix;
radix_node_t *node = NULL;
struct dns_ip_address_rule *rule = NULL;
struct dns_ip_rules *rule = NULL;
/* Match IP address rules */
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;
}
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;
}
if (rule->bogus) {
request->rcode = DNS_RC_NXDOMAIN;
request->has_soa = 1;
request->force_soa = 1;
_dns_server_setup_soa(request);
goto nxdomain;
}
rule_flags = container_of(ip_rules->rules[IP_RULE_FLAGS], struct ip_rule_flags, head);
if (rule_flags != NULL) {
if (rule_flags->flags & IP_RULE_FLAG_BOGUS) {
request->rcode = DNS_RC_NXDOMAIN;
request->has_soa = 1;
request->force_soa = 1;
_dns_server_setup_soa(request);
goto nxdomain;
}
/* blacklist-ip */
if (rule->blacklist) {
if (result_flag & DNSSERVER_FLAG_BLACKLIST_IP) {
goto match;
/* blacklist-ip */
if (rule_flags->flags & IP_RULE_FLAG_BLACKLIST) {
if (result_flag & DNSSERVER_FLAG_BLACKLIST_IP) {
goto match;
}
}
/* ignore-ip */
if (rule_flags->flags & IP_RULE_FLAG_IP_IGNORE) {
goto skip;
}
}
/* ignore-ip */
if (rule->ip_ignore) {
goto skip;
}
if (rule->ip_alias_enable) {
if (ip_rules->rules[IP_RULE_ALIAS] != NULL) {
goto match;
}
rule_not_found:
if (result_flag & DNSSERVER_FLAG_WHITELIST_IP) {
if (rule == NULL) {
if (rule_flags == NULL) {
goto skip;
}
if (!rule->whitelist) {
if (!(rule_flags->flags & IP_RULE_FLAG_WHITELIST)) {
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,
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;
rule = _dns_server_ip_rule_get(request, addr, addr_len, addr_type);
ret = _dns_server_ip_rule_check(request, rule, result_flag);
ip_rules = _dns_server_ip_rule_get(request, addr, addr_len, addr_type);
ret = _dns_server_ip_rule_check(request, ip_rules, result_flag);
if (ret != 0) {
return ret;
}
if (rule->ip_alias_enable && alias != NULL) {
if (ip_rules->rules[IP_RULE_ALIAS] && alias != NULL) {
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) {
return 0;
}

View File

@@ -363,6 +363,7 @@ static int load_conf_file(const char *file, struct config_item *items, conf_erro
int read_len = 0;
int is_last_line_wrap = 0;
int current_line_wrap = 0;
int is_func_found = 0;
const char *last_file = NULL;
if (handler == NULL) {
@@ -431,6 +432,8 @@ static int load_conf_file(const char *file, struct config_item *items, conf_erro
goto errout;
}
is_func_found = 0;
for (i = last_item_index;; i++) {
if (i < 0) {
continue;
@@ -471,8 +474,13 @@ static int load_conf_file(const char *file, struct config_item *items, conf_erro
}
last_item_index = i;
is_func_found = 1;
break;
}
if (is_func_found == 0) {
handler(file, line_no, CONF_RET_NOENT);
}
}
fclose(fp);