Skip to content

Commit

Permalink
feature: add group-match option.
Browse files Browse the repository at this point in the history
  • Loading branch information
pymumu committed Jan 10, 2024
1 parent 4d396ff commit a75495b
Show file tree
Hide file tree
Showing 5 changed files with 399 additions and 42 deletions.
5 changes: 5 additions & 0 deletions etc/smartdns/smartdns.conf
Original file line number Diff line number Diff line change
Expand Up @@ -387,3 +387,8 @@ log-level info
# 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 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-end
132 changes: 128 additions & 4 deletions src/dns_conf.c
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,8 @@ struct dns_edns_client_subnet dns_conf_ipv6_ecs;

char dns_conf_sni_proxy_ip[DNS_MAX_IPLEN];

static int _conf_domain_rule_nameserver(char *domain, const char *group_name);
static int _conf_domain_rule_nameserver(const char *domain, const char *group_name);
static int _conf_domain_rule_group(const char *domain, const char *group_name);
static int _conf_ptr_add(const char *hostname, const char *ip, int is_dynamic);
static int _conf_client_subnet(char *subnet, struct dns_edns_client_subnet *ipv4_ecs,
struct dns_edns_client_subnet *ipv6_ecs);
Expand All @@ -205,6 +206,8 @@ static struct dns_conf_group *_config_rule_group_new(const char *group_name);
static struct dns_conf_group *_config_current_rule_group(void);
static void _config_ip_iter_free(radix_node_t *node, void *cbctx);
static int _config_nftset_setvalue(struct dns_nftset_names *nftsets, const char *nftsetvalue);
static int _config_client_rule_flag_set(const char *ip_cidr, unsigned int flag, unsigned int is_clear);
static int _config_client_rule_group_add(const char *client, const char *group_name);

static void *_new_dns_rule_ext(enum domain_rule domain_rule, int ext_size)
{
Expand Down Expand Up @@ -237,6 +240,9 @@ static void *_new_dns_rule_ext(enum domain_rule domain_rule, int ext_size)
case DOMAIN_RULE_NAMESERVER:
size = sizeof(struct dns_nameserver_rule);
break;
case DOMAIN_RULE_GROUP:
size = sizeof(struct dns_group_rule);
break;
case DOMAIN_RULE_CHECKSPEED:
size = sizeof(struct dns_domain_check_orders);
break;
Expand Down Expand Up @@ -623,6 +629,81 @@ static int _config_group_end(void *data, int argc, char *argv[])
return 0;
}

static int _config_group_match(void *data, int argc, char *argv[])
{
int opt = 0;
struct dns_conf_group_info *saved_group_info = dns_conf_current_group_info;
const char *group_name = saved_group_info->group_name;
char group_name_buf[DNS_MAX_CONF_CNAME_LEN];

/* clang-format off */
static struct option long_options[] = {
{"domain", required_argument, NULL, 'd'},
{"client-ip", required_argument, NULL, 'c'},
{"group", required_argument, NULL, 'g'},
{NULL, no_argument, NULL, 0}
};
/* clang-format on */

if (argc <= 1 || group_name == NULL) {
tlog(TLOG_ERROR, "invalid parameter.");
goto errout;
}

dns_conf_current_group_info = dns_conf_default_group_info;

for (int i = 1; i < argc - 1; i++) {
if (strncmp(argv[i], "-g", sizeof("-g")) == 0 || strncmp(argv[i], "--group", sizeof("--group")) == 0 ||
strncmp(argv[i], "-group", sizeof("-group")) == 0) {
safe_strncpy(group_name_buf, argv[i + 1], DNS_MAX_CONF_CNAME_LEN);
group_name = group_name_buf;
break;
}
}

while (1) {
opt = getopt_long_only(argc, argv, "g:", long_options, NULL);
if (opt == -1) {
break;
}

switch (opt) {
case 'g': {
group_name = optarg;
break;
}
case 'd': {
const char *domain = optarg;

if (_conf_domain_rule_group(domain, group_name) != 0) {
tlog(TLOG_ERROR, "set group match for domain %s failed.", optarg);
goto errout;
}
break;
}
case 'c': {
char *client_ip = optarg;
if (_config_client_rule_group_add(client_ip, group_name) != 0) {
tlog(TLOG_ERROR, "add group rule failed.");
goto errout;
}
break;
}
default:
tlog(TLOG_WARN, "unknown group-match option: %s at '%s:%d'.", argv[optind - 1], conf_get_conf_file(),
conf_get_current_lineno());
break;
}
}

dns_conf_current_group_info = saved_group_info;

return 0;
errout:
dns_conf_current_group_info = saved_group_info;
return -1;
}

/* create and get dns server group */
static struct dns_proxy_names *_dns_conf_get_proxy(const char *proxy_name)
{
Expand Down Expand Up @@ -2854,7 +2935,7 @@ static int _config_server_https(void *data, int argc, char *argv[])
return ret;
}

static int _conf_domain_rule_nameserver(char *domain, const char *group_name)
static int _conf_domain_rule_nameserver(const char *domain, const char *group_name)
{
struct dns_nameserver_rule *nameserver_rule = NULL;
const char *group = NULL;
Expand Down Expand Up @@ -2896,6 +2977,48 @@ static int _conf_domain_rule_nameserver(char *domain, const char *group_name)
return 0;
}

static int _conf_domain_rule_group(const char *domain, const char *group_name)
{
struct dns_group_rule *group_rule = NULL;
const char *group = NULL;

if (strncmp(group_name, "-", sizeof("-")) != 0) {
group = _dns_conf_get_group_name(group_name);
if (group == NULL) {
goto errout;
}

group_rule = _new_dns_rule(DOMAIN_RULE_GROUP);
if (group_rule == NULL) {
goto errout;
}

group_rule->group_name = group;
} else {
/* ignore this domain */
if (_config_domain_rule_flag_set(domain, DOMAIN_FLAG_GROUP_IGNORE, 0) != 0) {
goto errout;
}

return 0;
}

if (_config_domain_rule_add(domain, DOMAIN_RULE_GROUP, group_rule) != 0) {
goto errout;
}

_dns_rule_put(&group_rule->head);

return 0;
errout:
if (group_rule) {
_dns_rule_put(&group_rule->head);
}

tlog(TLOG_ERROR, "add group %s, %s failed", domain, group_name);
return 0;
}

static int _conf_domain_rule_dualstack_selection(char *domain, const char *yesno)
{
if (strncmp(yesno, "yes", sizeof("yes")) == 0 || strncmp(yesno, "Yes", sizeof("Yes")) == 0) {
Expand Down Expand Up @@ -3206,7 +3329,6 @@ static int _config_client_rules_free(struct dns_client_rules *client_rules)
return 0;
}

static int _config_client_rule_flag_set(const char *ip_cidr, unsigned int flag, unsigned int is_clear);
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 Down Expand Up @@ -4329,7 +4451,8 @@ static int _conf_domain_rules(void *data, int argc, char *argv[])
}

for (int i = 2; i < argc - 1; i++) {
if (strncmp(argv[i], "-g", sizeof("-g")) == 0 || strncmp(argv[i], "--group", sizeof("--group")) == 0) {
if (strncmp(argv[i], "-g", sizeof("-g")) == 0 || strncmp(argv[i], "--group", sizeof("--group")) == 0 ||
strncmp(argv[i], "-group", sizeof("-group")) == 0) {
safe_strncpy(group_name, argv[i + 1], DNS_MAX_CONF_CNAME_LEN);
group = group_name;
break;
Expand Down Expand Up @@ -5345,6 +5468,7 @@ static struct config_item _config_item[] = {
CONF_CUSTOM("hosts-file", _conf_hosts_file, NULL),
CONF_CUSTOM("group-begin", _config_group_begin, NULL),
CONF_CUSTOM("group-end", _config_group_end, NULL),
CONF_CUSTOM("group-match", _config_group_match, NULL),
CONF_CUSTOM("client-rules", _config_client_rules, NULL),
CONF_STRING("ca-file", (char *)&dns_conf_ca_file, DNS_MAX_PATH),
CONF_STRING("ca-path", (char *)&dns_conf_ca_path, DNS_MAX_PATH),
Expand Down
7 changes: 7 additions & 0 deletions src/dns_conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ enum domain_rule {
DOMAIN_RULE_NFTSET_IP,
DOMAIN_RULE_NFTSET_IP6,
DOMAIN_RULE_NAMESERVER,
DOMAIN_RULE_GROUP,
DOMAIN_RULE_CHECKSPEED,
DOMAIN_RULE_RESPONSE_MODE,
DOMAIN_RULE_CNAME,
Expand Down Expand Up @@ -133,6 +134,7 @@ typedef enum {
#define DOMAIN_FLAG_CNAME_IGN (1 << 16)
#define DOMAIN_FLAG_NO_CACHE (1 << 17)
#define DOMAIN_FLAG_NO_IPALIAS (1 << 18)
#define DOMAIN_FLAG_GROUP_IGNORE (1 << 19)

#define IP_RULE_FLAG_BLACKLIST (1 << 0)
#define IP_RULE_FLAG_WHITELIST (1 << 1)
Expand Down Expand Up @@ -258,6 +260,11 @@ struct dns_nameserver_rule {
const char *group_name;
};

struct dns_group_rule {
struct dns_rule head;
const char *group_name;
};

struct dns_server_groups {
struct hlist_node node;
char group_name[DNS_GROUP_NAME_LEN];
Expand Down
Loading

0 comments on commit a75495b

Please sign in to comment.