feature: support set ttl, ttl-min, ttl-max to domain.
This commit is contained in:
35
src/dns.c
35
src/dns.c
@@ -42,6 +42,8 @@
|
||||
(void)(expr); \
|
||||
} while (0)
|
||||
|
||||
#define member_size(type, member) sizeof(((type *)0)->member)
|
||||
|
||||
/* read short and move pointer */
|
||||
static unsigned short _dns_read_short(unsigned char **buffer)
|
||||
{
|
||||
@@ -111,7 +113,7 @@ static int _dns_get_domain_from_packet(unsigned char *packet, int packet_size, u
|
||||
|
||||
/*[len]string[len]string...[0]0 */
|
||||
while (1) {
|
||||
if (ptr >= packet + packet_size || ptr < packet || output_len >= size - 1 || ptr_jump > 4) {
|
||||
if (ptr >= packet + packet_size || ptr < packet || output_len >= size - 1 || ptr_jump > 32) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1639,12 +1641,12 @@ static int _dns_encode_SOA(struct dns_context *context, struct dns_rrs *rrs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_decode_opt_ecs(struct dns_context *context, struct dns_opt_ecs *ecs)
|
||||
static int _dns_decode_opt_ecs(struct dns_context *context, struct dns_opt_ecs *ecs, int opt_len)
|
||||
{
|
||||
// TODO
|
||||
|
||||
int len = 0;
|
||||
if (_dns_left_len(context) < 4) {
|
||||
if (opt_len < 4) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1668,25 +1670,24 @@ static int _dns_decode_opt_ecs(struct dns_context *context, struct dns_opt_ecs *
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_decode_opt_cookie(struct dns_context *context, struct dns_opt_cookie *cookie)
|
||||
static int _dns_decode_opt_cookie(struct dns_context *context, struct dns_opt_cookie *cookie, int opt_len)
|
||||
{
|
||||
// TODO
|
||||
int len = _dns_left_len(context);
|
||||
if (len < 8) {
|
||||
if (opt_len < (int)member_size(struct dns_opt_cookie, client_cookie)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = 8;
|
||||
int len = 8;
|
||||
memcpy(cookie->client_cookie, context->ptr, len);
|
||||
context->ptr += len;
|
||||
|
||||
len = _dns_left_len(context);
|
||||
if (len == 0) {
|
||||
opt_len -= len;
|
||||
if (opt_len <= 0) {
|
||||
cookie->server_cookie_len = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (len < 8) {
|
||||
if (opt_len < (int)member_size(struct dns_opt_cookie, server_cookie)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1881,7 +1882,7 @@ static int _dns_decode_opt(struct dns_context *context, dns_rr_type type, unsign
|
||||
switch (opt_code) {
|
||||
case DNS_OPT_T_ECS: {
|
||||
struct dns_opt_ecs ecs;
|
||||
ret = _dns_decode_opt_ecs(context, &ecs);
|
||||
ret = _dns_decode_opt_ecs(context, &ecs, opt_len);
|
||||
if (ret != 0) {
|
||||
tlog(TLOG_ERROR, "decode ecs failed.");
|
||||
return -1;
|
||||
@@ -1895,7 +1896,7 @@ static int _dns_decode_opt(struct dns_context *context, dns_rr_type type, unsign
|
||||
} break;
|
||||
case DNS_OPT_T_COOKIE: {
|
||||
struct dns_opt_cookie cookie;
|
||||
ret = _dns_decode_opt_cookie(context, &cookie);
|
||||
ret = _dns_decode_opt_cookie(context, &cookie, opt_len);
|
||||
if (ret != 0) {
|
||||
tlog(TLOG_ERROR, "decode cookie failed.");
|
||||
return -1;
|
||||
@@ -2254,6 +2255,16 @@ static int _dns_encode_qd(struct dns_context *context, struct dns_rrs *rrs)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (domain[0] == '-') {
|
||||
/* for google and cloudflare */
|
||||
unsigned char *ptr = context->ptr - 7;
|
||||
memcpy(ptr, "\xC0\x12", 2);
|
||||
ptr += 2;
|
||||
_dns_write_short(&ptr, qtype);
|
||||
_dns_write_short(&ptr, qclass);
|
||||
context->ptr = ptr;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -194,6 +194,9 @@ static void *_new_dns_rule(enum domain_rule domain_rule)
|
||||
case DOMAIN_RULE_CNAME:
|
||||
size = sizeof(struct dns_cname_rule);
|
||||
break;
|
||||
case DOMAIN_RULE_TTL:
|
||||
size = sizeof(struct dns_ttl_rule);
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
@@ -2363,6 +2366,39 @@ errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _conf_domain_rule_rr_ttl(const char *domain, int ttl, int ttl_min, int ttl_max)
|
||||
{
|
||||
struct dns_ttl_rule *rr_ttl = NULL;
|
||||
|
||||
if (ttl < 0 || ttl_min < 0 || ttl_max < 0) {
|
||||
tlog(TLOG_ERROR, "invalid ttl value.");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
rr_ttl = _new_dns_rule(DOMAIN_RULE_TTL);
|
||||
if (rr_ttl == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
rr_ttl->ttl = ttl;
|
||||
rr_ttl->ttl_min = ttl_min;
|
||||
rr_ttl->ttl_max = ttl_max;
|
||||
|
||||
if (_config_domain_rule_add(domain, DOMAIN_RULE_TTL, rr_ttl) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
_dns_rule_put(&rr_ttl->head);
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
if (rr_ttl != NULL) {
|
||||
_dns_rule_put(&rr_ttl->head);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _conf_domain_rule_no_serve_expired(const char *domain)
|
||||
{
|
||||
return _config_domain_rule_flag_set(domain, DOMAIN_FLAG_NO_SERVE_EXPIRED, 0);
|
||||
@@ -2378,6 +2414,9 @@ static int _conf_domain_rules(void *data, int argc, char *argv[])
|
||||
int opt = 0;
|
||||
char domain[DNS_MAX_CONF_CNAME_LEN];
|
||||
char *value = argv[1];
|
||||
int rr_ttl = 0;
|
||||
int rr_ttl_min = 0;
|
||||
int rr_ttl_max = 0;
|
||||
|
||||
/* clang-format off */
|
||||
static struct option long_options[] = {
|
||||
@@ -2388,6 +2427,9 @@ static int _conf_domain_rules(void *data, int argc, char *argv[])
|
||||
{"nameserver", required_argument, NULL, 'n'},
|
||||
{"dualstack-ip-selection", required_argument, NULL, 'd'},
|
||||
{"cname", required_argument, NULL, 'A'},
|
||||
{"rr-ttl", required_argument, NULL, 251},
|
||||
{"rr-ttl-min", required_argument, NULL, 252},
|
||||
{"rr-ttl-max", required_argument, NULL, 253},
|
||||
{"no-serve-expired", no_argument, NULL, 254},
|
||||
{"delete", no_argument, NULL, 255},
|
||||
{NULL, no_argument, NULL, 0}
|
||||
@@ -2496,6 +2538,18 @@ static int _conf_domain_rules(void *data, int argc, char *argv[])
|
||||
|
||||
break;
|
||||
}
|
||||
case 251: {
|
||||
rr_ttl = atoi(optarg);
|
||||
break;
|
||||
}
|
||||
case 252: {
|
||||
rr_ttl_min = atoi(optarg);
|
||||
break;
|
||||
}
|
||||
case 253: {
|
||||
rr_ttl_max = atoi(optarg);
|
||||
break;
|
||||
}
|
||||
case 254: {
|
||||
if (_conf_domain_rule_no_serve_expired(domain) != 0) {
|
||||
tlog(TLOG_ERROR, "set no-serve-expired rule failed.");
|
||||
@@ -2517,6 +2571,13 @@ static int _conf_domain_rules(void *data, int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
if (rr_ttl > 0 || rr_ttl_min > 0 || rr_ttl_max > 0) {
|
||||
if (_conf_domain_rule_rr_ttl(domain, rr_ttl, rr_ttl_min, rr_ttl_max) != 0) {
|
||||
tlog(TLOG_ERROR, "set rr-ttl rule failed.");
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
return -1;
|
||||
|
||||
@@ -75,6 +75,7 @@ enum domain_rule {
|
||||
DOMAIN_RULE_NAMESERVER,
|
||||
DOMAIN_RULE_CHECKSPEED,
|
||||
DOMAIN_RULE_CNAME,
|
||||
DOMAIN_RULE_TTL,
|
||||
DOMAIN_RULE_MAX,
|
||||
};
|
||||
|
||||
@@ -164,6 +165,13 @@ struct dns_cname_rule {
|
||||
char cname[DNS_MAX_CNAME_LEN];
|
||||
};
|
||||
|
||||
struct dns_ttl_rule {
|
||||
struct dns_rule head;
|
||||
int ttl;
|
||||
int ttl_max;
|
||||
int ttl_min;
|
||||
};
|
||||
|
||||
struct dns_nftset_name {
|
||||
struct hlist_node node;
|
||||
char nftfamilyname[DNS_MAX_NFTSET_FAMILYLEN];
|
||||
|
||||
@@ -290,6 +290,7 @@ static int _dns_server_reply_passthrough(struct dns_server_post_context *context
|
||||
static int _dns_server_do_query(struct dns_request *request, int skip_notify_event);
|
||||
static int _dns_request_post(struct dns_server_post_context *context);
|
||||
static int _dns_server_reply_all_pending_list(struct dns_request *request, struct dns_server_post_context *context);
|
||||
static void *_dns_server_get_dns_rule(struct dns_request *request, enum domain_rule rule);
|
||||
|
||||
static void _dns_server_wakeup_thread(void)
|
||||
{
|
||||
@@ -313,17 +314,37 @@ static int _dns_server_has_bind_flag(struct dns_request *request, uint32_t flag)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _dns_server_get_conf_ttl(int ttl)
|
||||
static int _dns_server_get_conf_ttl(struct dns_request *request, int ttl)
|
||||
{
|
||||
if (dns_conf_rr_ttl > 0) {
|
||||
return dns_conf_rr_ttl;
|
||||
int rr_ttl = dns_conf_rr_ttl;
|
||||
int rr_ttl_min = dns_conf_rr_ttl_min;
|
||||
int rr_ttl_max = dns_conf_rr_ttl_max;
|
||||
|
||||
struct dns_ttl_rule *ttl_rule = _dns_server_get_dns_rule(request, DOMAIN_RULE_TTL);
|
||||
if (ttl_rule != NULL) {
|
||||
if (ttl_rule->ttl > 0) {
|
||||
rr_ttl = ttl_rule->ttl;
|
||||
}
|
||||
|
||||
if (ttl_rule->ttl_min > 0) {
|
||||
rr_ttl_min = ttl_rule->ttl_min;
|
||||
}
|
||||
|
||||
if (ttl_rule->ttl_max > 0) {
|
||||
rr_ttl_max = ttl_rule->ttl_max;
|
||||
}
|
||||
}
|
||||
|
||||
if (dns_conf_rr_ttl_max > 0 && ttl > dns_conf_rr_ttl_max) {
|
||||
ttl = dns_conf_rr_ttl_max;
|
||||
} else if (dns_conf_rr_ttl_min > 0 && ttl < dns_conf_rr_ttl_min) {
|
||||
ttl = dns_conf_rr_ttl_min;
|
||||
if (rr_ttl > 0) {
|
||||
return rr_ttl;
|
||||
}
|
||||
|
||||
if (rr_ttl_min > 0 && ttl > rr_ttl_min) {
|
||||
ttl = rr_ttl_min;
|
||||
} else if (rr_ttl_max > 0 && ttl < rr_ttl_max) {
|
||||
ttl = rr_ttl_max;
|
||||
}
|
||||
|
||||
return ttl;
|
||||
}
|
||||
|
||||
@@ -1058,13 +1079,13 @@ static int _dns_server_request_update_cache(struct dns_request *request, dns_typ
|
||||
if (cache_ttl > 0) {
|
||||
ttl = cache_ttl;
|
||||
} else {
|
||||
ttl = _dns_server_get_conf_ttl(request->ip_ttl);
|
||||
ttl = _dns_server_get_conf_ttl(request, request->ip_ttl);
|
||||
}
|
||||
speed = request->ping_time;
|
||||
|
||||
if (has_soa) {
|
||||
if (request->dualstack_selection && request->has_ip && request->qtype == DNS_T_AAAA) {
|
||||
ttl = _dns_server_get_conf_ttl(request->ip_ttl);
|
||||
ttl = _dns_server_get_conf_ttl(request, request->ip_ttl);
|
||||
} else {
|
||||
ttl = dns_conf_rr_ttl;
|
||||
if (ttl == 0) {
|
||||
@@ -1220,7 +1241,7 @@ static int _dns_cache_cname_packet(struct dns_server_post_context *context)
|
||||
return -1;
|
||||
}
|
||||
|
||||
ttl = _dns_server_get_conf_ttl(request->ip_ttl);
|
||||
ttl = _dns_server_get_conf_ttl(request, request->ip_ttl);
|
||||
speed = request->ping_time;
|
||||
|
||||
tlog(TLOG_DEBUG, "Cache CNAME: %s, qtype: %d, speed: %d", request->cname, request->qtype, speed);
|
||||
@@ -2573,14 +2594,14 @@ static int _dns_server_process_answer_A(struct dns_rrs *rrs, struct dns_request
|
||||
if (request->has_ip == 0) {
|
||||
request->has_ip = 1;
|
||||
memcpy(request->ip_addr, addr, DNS_RR_A_LEN);
|
||||
request->ip_ttl = _dns_server_get_conf_ttl(ttl);
|
||||
request->ip_ttl = _dns_server_get_conf_ttl(request, ttl);
|
||||
if (cname[0] != 0 && request->has_cname == 0 && dns_conf_force_no_cname == 0) {
|
||||
request->has_cname = 1;
|
||||
safe_strncpy(request->cname, cname, DNS_MAX_CNAME_LEN);
|
||||
}
|
||||
} else {
|
||||
if (ttl < request->ip_ttl) {
|
||||
request->ip_ttl = _dns_server_get_conf_ttl(ttl);
|
||||
request->ip_ttl = _dns_server_get_conf_ttl(request, ttl);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2650,14 +2671,14 @@ static int _dns_server_process_answer_AAAA(struct dns_rrs *rrs, struct dns_reque
|
||||
if (request->has_ip == 0) {
|
||||
request->has_ip = 1;
|
||||
memcpy(request->ip_addr, addr, DNS_RR_AAAA_LEN);
|
||||
request->ip_ttl = _dns_server_get_conf_ttl(ttl);
|
||||
request->ip_ttl = _dns_server_get_conf_ttl(request, ttl);
|
||||
if (cname[0] != 0 && request->has_cname == 0 && dns_conf_force_no_cname == 0) {
|
||||
request->has_cname = 1;
|
||||
safe_strncpy(request->cname, cname, DNS_MAX_CNAME_LEN);
|
||||
}
|
||||
} else {
|
||||
if (ttl < request->ip_ttl) {
|
||||
request->ip_ttl = _dns_server_get_conf_ttl(ttl);
|
||||
request->ip_ttl = _dns_server_get_conf_ttl(request, ttl);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2752,7 +2773,7 @@ static int _dns_server_process_answer(struct dns_request *request, const char *d
|
||||
continue;
|
||||
}
|
||||
safe_strncpy(cname, domain_cname, DNS_MAX_CNAME_LEN);
|
||||
request->ttl_cname = _dns_server_get_conf_ttl(ttl);
|
||||
request->ttl_cname = _dns_server_get_conf_ttl(request, ttl);
|
||||
tlog(TLOG_DEBUG, "name: %s ttl: %d cname: %s\n", name, ttl, cname);
|
||||
} break;
|
||||
case DNS_T_SOA: {
|
||||
@@ -2960,7 +2981,7 @@ static int _dns_server_get_answer(struct dns_server_post_context *context)
|
||||
|
||||
memcpy(request->ip_addr, addr, DNS_RR_A_LEN);
|
||||
/* add this ip to request */
|
||||
request->ip_ttl = _dns_server_get_conf_ttl(ttl);
|
||||
request->ip_ttl = _dns_server_get_conf_ttl(request, ttl);
|
||||
request->has_ip = 1;
|
||||
request->rcode = packet->head.rcode;
|
||||
} break;
|
||||
@@ -2990,7 +3011,7 @@ static int _dns_server_get_answer(struct dns_server_post_context *context)
|
||||
}
|
||||
|
||||
memcpy(request->ip_addr, addr, DNS_RR_AAAA_LEN);
|
||||
request->ip_ttl = _dns_server_get_conf_ttl(ttl);
|
||||
request->ip_ttl = _dns_server_get_conf_ttl(request, ttl);
|
||||
request->has_ip = 1;
|
||||
request->rcode = packet->head.rcode;
|
||||
} break;
|
||||
@@ -3015,7 +3036,7 @@ static int _dns_server_get_answer(struct dns_server_post_context *context)
|
||||
}
|
||||
|
||||
safe_strncpy(request->cname, cname, DNS_MAX_CNAME_LEN);
|
||||
request->ttl_cname = _dns_server_get_conf_ttl(ttl);
|
||||
request->ttl_cname = _dns_server_get_conf_ttl(request, ttl);
|
||||
request->has_cname = 1;
|
||||
} break;
|
||||
case DNS_T_SOA: {
|
||||
@@ -3188,7 +3209,7 @@ static int dns_server_resolve_callback(const char *domain, dns_result_type rtype
|
||||
return 0;
|
||||
}
|
||||
|
||||
ttl = _dns_server_get_conf_ttl(ttl);
|
||||
ttl = _dns_server_get_conf_ttl(request, ttl);
|
||||
if (ttl > dns_conf_rr_ttl_reply_max && dns_conf_rr_ttl_reply_max > 0) {
|
||||
ttl = dns_conf_rr_ttl_reply_max;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user