Skip to content

Commit

Permalink
feature: client-rule support mac address.
Browse files Browse the repository at this point in the history
  • Loading branch information
pymumu committed Jan 11, 2024
1 parent 422f982 commit 9c4b3d0
Show file tree
Hide file tree
Showing 8 changed files with 510 additions and 32 deletions.
3 changes: 3 additions & 0 deletions ReadMe.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms
1. **多 DNS 上游服务器**
支持配置多个上游 DNS 服务器,并同时进行查询,即使其中有 DNS 服务器异常,也不会影响查询。

1. **支持每个客户端独立控制**
支持基于MAC,IP地址控制客户端使用不同查询规则,可实现家长控制等功能。

1. **返回最快 IP 地址**
支持从域名所属 IP 地址列表中查找到访问速度最快的 IP 地址,并返回给客户端,提高网络访问速度。

Expand Down
3 changes: 3 additions & 0 deletions ReadMe_en.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ From the comparison, smartdns found the fastest IP address to visit www.baidu.co
1. **Multiple upstream DNS servers**
Support configuring multiple upstream DNS servers and query at the same time.the query will not be affected, Even if there is a DNS server exception.

1. **Support per-client query control**
Support controlling clients using different query rules based on MAC and IP addresses, enabling features such as parental control.

1. **Return the fastest IP address**
Supports finding the fastest access IP address from the IP address list of the domain name and returning it to the client to avoid DNS pollution and improve network access speed.

Expand Down
4 changes: 2 additions & 2 deletions etc/smartdns/smartdns.conf
Original file line number Diff line number Diff line change
Expand Up @@ -385,10 +385,10 @@ log-level info
# ip-alias ip-set:ip-list ip-set:ip-map-list

# set client rules
# client-rules ip-cidr [-group [group]] [-no-rule-addr] [-no-rule-nameserver] [-no-rule-ipset] [-no-speed-check] [-no-cache] [-no-rule-soa] [-no-dualstack-selection]
# client-rules [ip-cidr|mac|ip-set] [-group [group]] [-no-rule-addr] [-no-rule-nameserver] [-no-rule-ipset] [-no-speed-check] [-no-cache] [-no-rule-soa] [-no-dualstack-selection]
# client-rules option is same as bind option, please see bind option for detail.

# set group rules
# group-begin [group-name]
# group-match [-g|group group-name] [-domain domain] [-client-ip client]
# group-match [-g|group group-name] [-domain domain] [-client-ip [ip-cidr|mac|ip-set]]
# group-end
155 changes: 127 additions & 28 deletions src/dns_conf.c
Original file line number Diff line number Diff line change
Expand Up @@ -3329,6 +3329,51 @@ static int _config_client_rules_free(struct dns_client_rules *client_rules)
return 0;
}

static struct client_roue_group_mac *_config_client_rule_group_mac_new(uint8_t mac[6])
{
struct client_roue_group_mac *group_mac = NULL;
uint32_t key;

group_mac = malloc(sizeof(*group_mac));
if (group_mac == NULL) {
return NULL;
}
memset(group_mac, 0, sizeof(*group_mac));
memcpy(group_mac->mac, mac, 6);

key = jhash(mac, 6, 0);
hash_add(dns_conf_client_rule.mac, &group_mac->node, key);
dns_conf_client_rule.mac_num++;

return group_mac;
}

struct client_roue_group_mac *dns_server_rule_group_mac_get(const uint8_t mac[6])
{
struct client_roue_group_mac *group_mac = NULL;
uint32_t key;

key = jhash(mac, 6, 0);
hash_for_each_possible(dns_conf_client_rule.mac, group_mac, node, key)
{
if (memcmp(group_mac->mac, mac, 6) == 0) {
return group_mac;
}
}

return NULL;
}

static struct client_roue_group_mac *_config_client_rule_group_mac_get_or_add(uint8_t mac[6])
{
struct client_roue_group_mac *group_mac = dns_server_rule_group_mac_get(mac);
if (group_mac == NULL) {
group_mac = _config_client_rule_group_mac_new(mac);
}

return group_mac;
}

static int _config_client_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;
Expand All @@ -3340,31 +3385,50 @@ static int _config_client_rule_flag_set(const char *ip_cidr, unsigned int flag,
struct dns_client_rules *client_rules = NULL;
struct dns_client_rules *add_client_rules = NULL;
struct client_rule_flags *client_rule_flags = NULL;
struct client_roue_group_mac *group_mac = NULL;
radix_node_t *node = NULL;
uint8_t mac[6];
int is_mac_address = 0;

is_mac_address = parser_mac_address(ip_cidr, mac);
if (is_mac_address == 0) {
group_mac = _config_client_rule_group_mac_get_or_add(mac);
if (group_mac == NULL) {
tlog(TLOG_ERROR, "get or add mac %s failed", ip_cidr);
goto errout;
}

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_client_rule_flag_callback, &args);
}
client_rules = group_mac->rules;
} else {
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_client_rule_flag_callback, &args);
}

/* Get existing or create domain rule */
node = _create_client_rules_node(ip_cidr);
if (node == NULL) {
tlog(TLOG_ERROR, "create addr node failed.");
goto errout;
/* Get existing or create domain rule */
node = _create_client_rules_node(ip_cidr);
if (node == NULL) {
tlog(TLOG_ERROR, "create addr node failed.");
goto errout;
}

client_rules = node->data;
}

client_rules = node->data;
if (client_rules == NULL) {
add_client_rules = malloc(sizeof(*add_client_rules));
if (add_client_rules == NULL) {
goto errout;
}
memset(add_client_rules, 0, sizeof(*add_client_rules));
client_rules = add_client_rules;
node->data = client_rules;
if (is_mac_address == 0) {
group_mac->rules = client_rules;
} else {
node->data = client_rules;
}
}

/* add new rule to domain */
Expand All @@ -3390,7 +3454,7 @@ static int _config_client_rule_flag_set(const char *ip_cidr, unsigned int flag,

tlog(TLOG_ERROR, "set ip %s flags failed", ip_cidr);

return 0;
return -1;
}

static int _config_client_rule_add(const char *ip_cidr, enum client_rule type, void *rule);
Expand All @@ -3404,6 +3468,7 @@ static int _config_client_rule_add(const char *ip_cidr, enum client_rule type, v
{
struct dns_client_rules *client_rules = NULL;
struct dns_client_rules *add_client_rules = NULL;
struct client_roue_group_mac *group_mac = NULL;
radix_node_t *node = NULL;

if (ip_cidr == NULL) {
Expand All @@ -3414,29 +3479,48 @@ static int _config_client_rule_add(const char *ip_cidr, enum client_rule type, v
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_client_rule_add_callback, &args);
}
uint8_t mac[6];
int is_mac_address = 0;

/* Get existing or create domain rule */
node = _create_client_rules_node(ip_cidr);
if (node == NULL) {
tlog(TLOG_ERROR, "create addr node failed.");
goto errout;
is_mac_address = parser_mac_address(ip_cidr, mac);
if (is_mac_address == 0) {
group_mac = _config_client_rule_group_mac_get_or_add(mac);
if (group_mac == NULL) {
tlog(TLOG_ERROR, "get or add mac %s failed", ip_cidr);
goto errout;
}

client_rules = group_mac->rules;
} else {
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_client_rule_add_callback, &args);
}

/* Get existing or create domain rule */
node = _create_client_rules_node(ip_cidr);
if (node == NULL) {
tlog(TLOG_ERROR, "create addr node failed.");
goto errout;
}

client_rules = node->data;
}

client_rules = node->data;
if (client_rules == NULL) {
add_client_rules = malloc(sizeof(*add_client_rules));
if (add_client_rules == NULL) {
goto errout;
}
memset(add_client_rules, 0, sizeof(*add_client_rules));
client_rules = add_client_rules;
node->data = client_rules;
if (is_mac_address == 0) {
group_mac->rules = client_rules;
} else {
node->data = client_rules;
}
}

/* add new rule to domain */
Expand Down Expand Up @@ -5656,7 +5740,7 @@ static int _dns_server_load_conf_init(void)
tlog(TLOG_WARN, "init client rule radix tree failed.");
return -1;
}

hash_init(dns_conf_client_rule.mac);
hash_init(dns_conf_rule.group);
dns_conf_rule.default_conf = _config_rule_group_new("");
if (dns_conf_rule.default_conf == NULL) {
Expand Down Expand Up @@ -5707,9 +5791,24 @@ static void dns_server_bind_destroy(void)
dns_conf_bind_ip_num = 0;
}

static void _config_client_rule_destroy_mac(void)
{
struct hlist_node *tmp = NULL;
unsigned int i;
struct client_roue_group_mac *group_mac = NULL;

hash_for_each_safe(dns_conf_client_rule.mac, i, tmp, group_mac, node)
{
hlist_del_init(&group_mac->node);
_config_client_rules_free(group_mac->rules);
free(group_mac);
}
}

static void _config_client_rule_destroy(void)
{
Destroy_Radix(dns_conf_client_rule.rule, _config_client_rule_iter_free_cb, NULL);
_config_client_rule_destroy_mac();
}

void dns_server_load_exit(void)
Expand Down
10 changes: 10 additions & 0 deletions src/dns_conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -458,8 +458,16 @@ struct dns_client_rules {
struct dns_client_rule *rules[CLIENT_RULE_MAX];
};

struct client_roue_group_mac {
struct hlist_node node;
uint8_t mac[6];
struct dns_client_rules *rules;
};

struct dns_conf_client_rule {
radix_tree_t *rule;
DECLARE_HASHTABLE(mac, 6);
int mac_num;
};

struct nftset_ipset_rules {
Expand Down Expand Up @@ -690,6 +698,8 @@ struct dns_conf_group *dns_server_get_rule_group(const char *group_name);

struct dns_conf_group *dns_server_get_default_rule_group(void);

struct client_roue_group_mac *dns_server_rule_group_mac_get(const uint8_t mac[6]);

extern int config_additional_file(void *data, int argc, char *argv[]);

const char *dns_conf_get_cache_dir(void);
Expand Down
Loading

0 comments on commit 9c4b3d0

Please sign in to comment.