Skip to content

Commit

Permalink
feature: add ip-alias option.
Browse files Browse the repository at this point in the history
  • Loading branch information
pymumu committed Aug 16, 2023
1 parent c19a39a commit 1054229
Show file tree
Hide file tree
Showing 10 changed files with 636 additions and 94 deletions.
4 changes: 4 additions & 0 deletions etc/smartdns/smartdns.conf
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ bind [::]:53
# List of IPs that will be ignored
# ignore-ip [ip/subnet]

# alias of IPs
# ip-alias [ip/subnet] [ip1[,ip2]...]
# ip-alias 192.168.0.1/24 10.9.0.1,10.9.0.2

# speed check mode
# speed-check-mode [ping|tcp:port|none|,]
# example:
Expand Down
149 changes: 140 additions & 9 deletions src/dns_conf.c
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,38 @@ 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));
if (iplist->ipaddr == NULL) {
return;
}
memset(&iplist->ipaddr[iplist->ipaddr_num], 0, sizeof(struct dns_iplist_ip_address));
iplist->ipaddr[iplist->ipaddr_num].addr_len = addr_len;
memcpy(iplist->ipaddr[iplist->ipaddr_num].addr, addr, addr_len);
iplist->ipaddr_num++;
}

static int _get_domain(char *value, char *domain, int max_domain_size, char **ptr_after_domain)
{
char *begin = NULL;
Expand Down Expand Up @@ -768,6 +800,7 @@ static void _config_domain_destroy(void)

static void _config_address_destroy(radix_node_t *node, void *cbctx)
{
struct dns_ip_address_rule *address_rule = NULL;
if (node == NULL) {
return;
}
Expand All @@ -776,6 +809,12 @@ static void _config_address_destroy(radix_node_t *node, void *cbctx)
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;
}
Expand Down Expand Up @@ -2461,20 +2500,20 @@ static radix_node_t *_create_addr_node(char *addr)
return node;
}

static int _config_iplist_rule(char *subnet, enum address_rule rule)
static struct dns_ip_address_rule *_config_iplist_rule(char *subnet, enum address_rule rule)
{
radix_node_t *node = NULL;
struct dns_ip_address_rule *ip_rule = NULL;

node = _create_addr_node(subnet);
if (node == NULL) {
return -1;
return NULL;
}

if (node->data == NULL) {
ip_rule = malloc(sizeof(*ip_rule));
if (ip_rule == NULL) {
return -1;
return NULL;
}

node->data = ip_rule;
Expand All @@ -2496,11 +2535,15 @@ static int _config_iplist_rule(char *subnet, enum address_rule rule)
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 -1;
return NULL;
}

return 0;
return ip_rule;
}

static int _config_qtype_soa(void *data, int argc, char *argv[])
Expand Down Expand Up @@ -2582,7 +2625,11 @@ static int _config_blacklist_ip(void *data, int argc, char *argv[])
return -1;
}

return _config_iplist_rule(argv[1], ADDRESS_RULE_BLACKLIST);
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[])
Expand All @@ -2591,7 +2638,11 @@ static int _conf_bogus_nxdomain(void *data, int argc, char *argv[])
return -1;
}

return _config_iplist_rule(argv[1], ADDRESS_RULE_BOGUS);
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[])
Expand All @@ -2600,7 +2651,11 @@ static int _conf_ip_ignore(void *data, int argc, char *argv[])
return -1;
}

return _config_iplist_rule(argv[1], ADDRESS_RULE_IP_IGNORE);
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[])
Expand All @@ -2609,7 +2664,82 @@ static int _conf_whitelist_ip(void *data, int argc, char *argv[])
return -1;
}

return _config_iplist_rule(argv[1], ADDRESS_RULE_WHITELIST);
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;
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,
Expand Down Expand Up @@ -3591,6 +3721,7 @@ static struct config_item _config_item[] = {
CONF_CUSTOM("force-qtype-SOA", _config_qtype_soa, NULL),
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("bogus-nxdomain", _conf_bogus_nxdomain, NULL),
CONF_CUSTOM("ignore-ip", _conf_ip_ignore, NULL),
CONF_CUSTOM("edns-client-subnet", _conf_edns_client_subnet, NULL),
Expand Down
18 changes: 18 additions & 0 deletions src/dns_conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -355,13 +355,31 @@ enum address_rule {
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 {
unsigned char ipv4_addr[DNS_RR_A_LEN];
unsigned char ipv6_addr[DNS_RR_AAAA_LEN];
unsigned char addr[0];
};
};

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 {
Expand Down
Loading

0 comments on commit 1054229

Please sign in to comment.