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_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();
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user