dns: fix crash issue

This commit is contained in:
Nick Peng
2023-04-22 19:06:44 +08:00
parent e38d5eaecc
commit 56d0332bf9
3 changed files with 108 additions and 27 deletions

View File

@@ -274,6 +274,10 @@ static int _dns_encode_domain(struct dns_context *context, const char *domain)
total_len++; total_len++;
if (dict_offset >= 0) { if (dict_offset >= 0) {
int offset = 0xc000 | dict_offset; int offset = 0xc000 | dict_offset;
if (_dns_left_len(context) < 2) {
return -1;
}
_dns_write_short(&ptr_num, offset); _dns_write_short(&ptr_num, offset);
context->ptr++; context->ptr++;
ptr_num = NULL; ptr_num = NULL;
@@ -295,6 +299,10 @@ static int _dns_encode_domain(struct dns_context *context, const char *domain)
domain++; domain++;
} }
if (_dns_left_len(context) < 1) {
return -1;
}
*ptr_num = num; *ptr_num = num;
if (total_len > 1) { if (total_len > 1) {
@@ -575,7 +583,7 @@ struct dns_rr_nested *dns_add_rr_nested_start(struct dns_rr_nested *rr_nested_bu
return rr_nested_buffer; return rr_nested_buffer;
} }
int dns_add_rr_nested_memcpy(struct dns_rr_nested *rr_nested, void *data, int data_len) int dns_add_rr_nested_memcpy(struct dns_rr_nested *rr_nested, const void *data, int data_len)
{ {
if (rr_nested == NULL || data == NULL || data_len <= 0) { if (rr_nested == NULL || data == NULL || data_len <= 0) {
return -1; return -1;
@@ -603,6 +611,12 @@ int dns_add_rr_nested_end(struct dns_rr_nested *rr_nested, dns_type_t rtype)
return -1; return -1;
} }
/* NO SVC keys, reset ptr */
if (len <= 14) {
rr_nested->context.ptr = rr_nested->rr_start;
return 0;
}
_dns_write_short(&ptr, len - rr_nested->rr_head_len); _dns_write_short(&ptr, len - rr_nested->rr_head_len);
return _dns_rr_add_end(rr_nested->context.packet, rr_nested->type, rtype, len); return _dns_rr_add_end(rr_nested->context.packet, rr_nested->type, rtype, len);
@@ -1076,7 +1090,12 @@ int dns_add_HTTPS_start(struct dns_rr_nested *svcparam_buffer, struct dns_packet
return -1; return -1;
} }
int target_len = strnlen(target, DNS_MAX_CNAME_LEN) + 1; int target_len = 0;
if (target == NULL) {
target = "";
}
target_len = strnlen(target, DNS_MAX_CNAME_LEN) + 1;
if (_dns_left_len(&svcparam_buffer->context) < 2 + target_len) { if (_dns_left_len(&svcparam_buffer->context) < 2 + target_len) {
return -1; return -1;
} }
@@ -1117,6 +1136,22 @@ int dns_HTTPS_add_port(struct dns_rr_nested *svcparam, unsigned short port)
return 0; return 0;
} }
int dns_HTTPS_add_alpn(struct dns_rr_nested *svcparam, const char *alpn, int alpn_len)
{
if (_dns_left_len(&svcparam->context) < 2 + 2 + alpn_len) {
return -1;
}
unsigned short value = DNS_HTTPS_T_ALPN;
dns_add_rr_nested_memcpy(svcparam, &value, 2);
value = alpn_len;
dns_add_rr_nested_memcpy(svcparam, &value, 2);
dns_add_rr_nested_memcpy(svcparam, alpn, alpn_len);
return 0;
}
int dns_HTTPS_add_ech(struct dns_rr_nested *svcparam, void *ech, int ech_len) int dns_HTTPS_add_ech(struct dns_rr_nested *svcparam, void *ech, int ech_len)
{ {
if (_dns_left_len(&svcparam->context) < 2 + 2 + ech_len) { if (_dns_left_len(&svcparam->context) < 2 + 2 + ech_len) {
@@ -1133,7 +1168,7 @@ int dns_HTTPS_add_ech(struct dns_rr_nested *svcparam, void *ech, int ech_len)
return 0; return 0;
} }
int dns_HTTPS_add_ipv4hint(struct dns_rr_nested *svcparam, unsigned char addr[][DNS_RR_A_LEN], int addr_num) int dns_HTTPS_add_ipv4hint(struct dns_rr_nested *svcparam, unsigned char *addr[], int addr_num)
{ {
if (_dns_left_len(&svcparam->context) < 4 + addr_num * DNS_RR_A_LEN) { if (_dns_left_len(&svcparam->context) < 4 + addr_num * DNS_RR_A_LEN) {
return -1; return -1;
@@ -1151,7 +1186,8 @@ int dns_HTTPS_add_ipv4hint(struct dns_rr_nested *svcparam, unsigned char addr[][
return 0; return 0;
} }
int dns_HTTPS_add_ipv6hint(struct dns_rr_nested *svcparam, unsigned char addr[][DNS_RR_AAAA_LEN], int addr_num)
int dns_HTTPS_add_ipv6hint(struct dns_rr_nested *svcparam, unsigned char *addr[], int addr_num)
{ {
if (_dns_left_len(&svcparam->context) < 4 + addr_num * DNS_RR_AAAA_LEN) { if (_dns_left_len(&svcparam->context) < 4 + addr_num * DNS_RR_AAAA_LEN) {
return -1; return -1;
@@ -1175,8 +1211,8 @@ int dns_add_HTTPS_end(struct dns_rr_nested *svcparam)
return dns_add_rr_nested_end(svcparam, DNS_T_HTTPS); return dns_add_rr_nested_end(svcparam, DNS_T_HTTPS);
} }
struct dns_https_param *dns_get_HTTPS_svcparm_start(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, int dns_get_HTTPS_svcparm_start(struct dns_rrs *rrs, struct dns_https_param **https_param, char *domain, int maxsize,
int *priority, char *target, int target_size) int *ttl, int *priority, char *target, int target_size)
{ {
int qtype = 0; int qtype = 0;
unsigned char *data = NULL; unsigned char *data = NULL;
@@ -1184,32 +1220,39 @@ struct dns_https_param *dns_get_HTTPS_svcparm_start(struct dns_rrs *rrs, char *d
data = dns_get_rr_nested_start(rrs, domain, maxsize, &qtype, ttl, &rr_len); data = dns_get_rr_nested_start(rrs, domain, maxsize, &qtype, ttl, &rr_len);
if (data == NULL) { if (data == NULL) {
return NULL; return -1;
} }
if (qtype != DNS_T_HTTPS) { if (qtype != DNS_T_HTTPS) {
return NULL; return -1;
} }
if (rr_len < 2) { if (rr_len < 2) {
return NULL; return -1;
} }
*priority = _dns_read_short(&data); *priority = _dns_read_short(&data);
rr_len -= 2; rr_len -= 2;
if (rr_len <= 0) { if (rr_len <= 0) {
return NULL; return -1;
} }
int len = strnlen((char *)data, rr_len); int len = strnlen((char *)data, rr_len);
safe_strncpy(target, (char *)data, target_size); safe_strncpy(target, (char *)data, target_size);
data += len + 1; data += len + 1;
rr_len -= len + 1; rr_len -= len + 1;
if (rr_len <= 0) { if (rr_len < 0) {
return NULL; return -1;
} }
return (struct dns_https_param *)data; if (rr_len == 0) {
*https_param = NULL;
return 0;
}
*https_param = (struct dns_https_param *)data;
return 0;
} }
struct dns_https_param *dns_get_HTTPS_svcparm_next(struct dns_rrs *rrs, struct dns_https_param *param) struct dns_https_param *dns_get_HTTPS_svcparm_next(struct dns_rrs *rrs, struct dns_https_param *param)
@@ -1925,12 +1968,16 @@ static int _dns_encode_HTTPS(struct dns_context *context, struct dns_rrs *rrs)
int priority = 0; int priority = 0;
struct dns_https_param *param = NULL; struct dns_https_param *param = NULL;
param = dns_get_HTTPS_svcparm_start(rrs, domain, DNS_MAX_CNAME_LEN, &ttl, &priority, target, DNS_MAX_CNAME_LEN); ret =
if (param == NULL) { dns_get_HTTPS_svcparm_start(rrs, &param, domain, DNS_MAX_CNAME_LEN, &ttl, &priority, target, DNS_MAX_CNAME_LEN);
tlog(TLOG_ERROR, "get https param failed."); if (ret < 0) {
return -1; tlog(TLOG_DEBUG, "get https param failed.");
return 0;
} }
qtype = DNS_T_HTTPS;
qclass = DNS_C_IN;
ret = _dns_encode_rr_head(context, domain, qtype, qclass, ttl, 0, &rr_len_ptr); ret = _dns_encode_rr_head(context, domain, qtype, qclass, ttl, 0, &rr_len_ptr);
if (ret < 0) { if (ret < 0) {
return -1; return -1;
@@ -1954,6 +2001,10 @@ static int _dns_encode_HTTPS(struct dns_context *context, struct dns_rrs *rrs)
return -1; return -1;
} }
if (param->len + 4 > _dns_left_len(context)) {
return -1;
}
_dns_write_short(&context->ptr, param->key); _dns_write_short(&context->ptr, param->key);
_dns_write_short(&context->ptr, param->len); _dns_write_short(&context->ptr, param->len);
switch (param->key) { switch (param->key) {
@@ -1974,6 +2025,10 @@ static int _dns_encode_HTTPS(struct dns_context *context, struct dns_rrs *rrs)
} }
} }
if (_dns_left_len(context) < 2) {
return -1;
}
_dns_write_short(&rr_len_ptr, context->ptr - rr_start); _dns_write_short(&rr_len_ptr, context->ptr - rr_start);
return 0; return 0;

View File

@@ -30,6 +30,8 @@ extern "C" {
#define DNS_IN_PACKSIZE (512 * 8) #define DNS_IN_PACKSIZE (512 * 8)
#define DNS_PACKSIZE (512 * 12) #define DNS_PACKSIZE (512 * 12)
#define DNS_DEFAULT_PACKET_SIZE 512 #define DNS_DEFAULT_PACKET_SIZE 512
#define DNS_MAX_ALPN_LEN 32
#define DNS_MAX_ECH_LEN 256
#define DNS_ADDR_FAMILY_IP 1 #define DNS_ADDR_FAMILY_IP 1
#define DNS_ADDR_FAMILY_IPV6 2 #define DNS_ADDR_FAMILY_IPV6 2
@@ -236,7 +238,7 @@ struct dns_rrs *dns_get_rrs_start(struct dns_packet *packet, dns_rr_type type, i
struct dns_rr_nested *dns_add_rr_nested_start(struct dns_rr_nested *rr_nested_buffer, struct dns_packet *packet, struct dns_rr_nested *dns_add_rr_nested_start(struct dns_rr_nested *rr_nested_buffer, struct dns_packet *packet,
dns_rr_type type, dns_type_t rtype, const char *domain, int ttl); dns_rr_type type, dns_type_t rtype, const char *domain, int ttl);
int dns_add_rr_nested_end(struct dns_rr_nested *rr_nested, dns_type_t rtype); int dns_add_rr_nested_end(struct dns_rr_nested *rr_nested, dns_type_t rtype);
int dns_add_rr_nested_memcpy(struct dns_rr_nested *rr_nested, void *data, int data_len); int dns_add_rr_nested_memcpy(struct dns_rr_nested *rr_nested, const void *data, int data_len);
void *dns_get_rr_nested_start(struct dns_rrs *rrs, char *domain, int maxsize, int *qtype, int *ttl, int *rr_len); void *dns_get_rr_nested_start(struct dns_rrs *rrs, char *domain, int maxsize, int *qtype, int *ttl, int *rr_len);
void *dns_get_rr_nested_next(struct dns_rrs *rrs, void *rr_nested, int rr_nested_len); void *dns_get_rr_nested_next(struct dns_rrs *rrs, void *rr_nested, int rr_nested_len);
@@ -280,19 +282,26 @@ int dns_add_OPT_TCP_KEEPALIVE(struct dns_packet *packet, unsigned short timeout)
int dns_get_OPT_TCP_KEEPALIVE(struct dns_rrs *rrs, unsigned short *opt_code, unsigned short *opt_len, int dns_get_OPT_TCP_KEEPALIVE(struct dns_rrs *rrs, unsigned short *opt_code, unsigned short *opt_len,
unsigned short *timeout); unsigned short *timeout);
/* the key must be added in orders, or dig will report FORMERR */
int dns_add_HTTPS_start(struct dns_rr_nested *svcparam_buffer, struct dns_packet *packet, dns_rr_type type, int dns_add_HTTPS_start(struct dns_rr_nested *svcparam_buffer, struct dns_packet *packet, dns_rr_type type,
const char *domain, int ttl, int priority, const char *target); const char *domain, int ttl, int priority, const char *target);
int dns_HTTPS_add_raw(struct dns_rr_nested *svcparam, unsigned short key, unsigned char *value, unsigned short len); int dns_HTTPS_add_raw(struct dns_rr_nested *svcparam, unsigned short key, unsigned char *value, unsigned short len);
int dns_HTTPS_add_port(struct dns_rr_nested *svcparam, unsigned short port); /* key 1, alph */
int dns_HTTPS_add_alpn(struct dns_rr_nested *svcparam, const char *alpn); int dns_HTTPS_add_alpn(struct dns_rr_nested *svcparam, const char *alpn, int alpn_len);
/* key 2, no default alph */
int dns_HTTPS_add_no_default_alpn(struct dns_rr_nested *svcparam); int dns_HTTPS_add_no_default_alpn(struct dns_rr_nested *svcparam);
int dns_HTTPS_add_ipv4hint(struct dns_rr_nested *svcparam, unsigned char addr[][DNS_RR_A_LEN], int addr_num); /* key 3, port */
int dns_HTTPS_add_ipv6hint(struct dns_rr_nested *svcparam, unsigned char addr[][DNS_RR_AAAA_LEN], int addr_num); int dns_HTTPS_add_port(struct dns_rr_nested *svcparam, unsigned short port);
/* key 4, ipv4 */
int dns_HTTPS_add_ipv4hint(struct dns_rr_nested *svcparam, unsigned char *addr[], int addr_num);
/* key 5, ech */
int dns_HTTPS_add_ech(struct dns_rr_nested *svcparam, void *ech, int ech_len); int dns_HTTPS_add_ech(struct dns_rr_nested *svcparam, void *ech, int ech_len);
/* key 6, ipv6*/
int dns_HTTPS_add_ipv6hint(struct dns_rr_nested *svcparam, unsigned char *addr[], int addr_num);
int dns_add_HTTPS_end(struct dns_rr_nested *svcparam); int dns_add_HTTPS_end(struct dns_rr_nested *svcparam);
struct dns_https_param *dns_get_HTTPS_svcparm_start(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, int dns_get_HTTPS_svcparm_start(struct dns_rrs *rrs, struct dns_https_param **https_param, char *domain, int maxsize,
int *priority, char *target, int target_size); int *ttl, int *priority, char *target, int target_size);
struct dns_https_param *dns_get_HTTPS_svcparm_next(struct dns_rrs *rrs, struct dns_https_param *parm); struct dns_https_param *dns_get_HTTPS_svcparm_next(struct dns_rrs *rrs, struct dns_https_param *parm);
/* /*

View File

@@ -1601,10 +1601,11 @@ static int _dns_debug_display(struct dns_packet *packet)
char target[DNS_MAX_CNAME_LEN] = {0}; char target[DNS_MAX_CNAME_LEN] = {0};
struct dns_https_param *p = NULL; struct dns_https_param *p = NULL;
int priority = 0; int priority = 0;
int ret = 0;
p = dns_get_HTTPS_svcparm_start(rrs, name, DNS_MAX_CNAME_LEN, &ttl, &priority, target, ret = dns_get_HTTPS_svcparm_start(rrs, &p, name, DNS_MAX_CNAME_LEN, &ttl, &priority, target,
DNS_MAX_CNAME_LEN); DNS_MAX_CNAME_LEN);
if (p == NULL) { if (ret != 0) {
printf("get HTTPS svcparm failed\n"); printf("get HTTPS svcparm failed\n");
break; break;
} }
@@ -1617,7 +1618,23 @@ static int _dns_debug_display(struct dns_packet *packet)
printf(" HTTPS: mandatory: %s\n", p->value); printf(" HTTPS: mandatory: %s\n", p->value);
} break; } break;
case DNS_HTTPS_T_ALPN: { case DNS_HTTPS_T_ALPN: {
printf(" HTTPS: alpn: %s\n", p->value); char alph[64] = {0};
int total_alph_len = 0;
char *ptr = (char *)p->value;
do {
int alphlen = *ptr;
memcpy(alph + total_alph_len, ptr + 1, alphlen);
total_alph_len += alphlen;
ptr += alphlen + 1;
alph[total_alph_len] = ',';
total_alph_len++;
alph[total_alph_len] = ' ';
total_alph_len++;
} while (ptr - (char *)p->value < p->len);
if (total_alph_len > 2) {
alph[total_alph_len - 2] = '\0';
}
printf(" HTTPS: alpn: %s\n", alph);
} break; } break;
case DNS_HTTPS_T_NO_DEFAULT_ALPN: { case DNS_HTTPS_T_NO_DEFAULT_ALPN: {
printf(" HTTPS: no_default_alpn: %s\n", p->value); printf(" HTTPS: no_default_alpn: %s\n", p->value);