Browse Source

DoH3: fix http3 parser issue, and fix DoH3 memory leak issue.

Nick Peng 6 months ago
parent
commit
8612d0a46d
4 changed files with 33 additions and 14 deletions
  1. 2 2
      ReadMe.md
  2. 2 2
      ReadMe_en.md
  3. 11 6
      src/dns_client.c
  4. 18 4
      src/http_parse.c

+ 2 - 2
ReadMe.md

@@ -4,7 +4,7 @@
 
 ![SmartDNS](doc/smartdns-banner.png)
 SmartDNS 是一个运行在本地的 DNS 服务器,它接受来自本地客户端的 DNS 查询请求,然后从多个上游 DNS 服务器获取 DNS 查询结果,并将访问速度最快的结果返回给客户端,以此提高网络访问速度。
-SmartDNS 同时支持指定特定域名 IP 地址,并高性匹配,可达到过滤广告的效果; 支持DOT(DNS over TLS)和DOH(DNS over HTTPS),更好的保护隐私。  
+SmartDNS 同时支持指定特定域名 IP 地址,并高性匹配,可达到过滤广告的效果; 支持DOT,DOH,DOQ,DOH3,更好的保护隐私。  
 
 与 DNSmasq 的 all-servers 不同,SmartDNS 返回的是访问速度最快的解析结果。
 
@@ -95,7 +95,7 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms
    支持从域名所属 IP 地址列表中查找到访问速度最快的 IP 地址,并返回给客户端,提高网络访问速度。
 
 1. **支持多种查询协议**  
-   支持 UDP、TCP、DOT 和 DOH 查询及服务,以及非 53 端口查询;支持通过socks5,HTTP代理查询;
+   支持 UDP、TCP、DOT、DOH、DOQ 和 DOH3 查询及服务,以及非 53 端口查询;支持通过socks5,HTTP代理查询;
 
 1. **特定域名 IP 地址指定**  
    支持指定域名的 IP 地址,达到广告过滤效果、避免恶意网站的效果。

+ 2 - 2
ReadMe_en.md

@@ -1,7 +1,7 @@
 # SmartDNS
 
 ![SmartDNS](doc/smartdns-banner.png)  
-SmartDNS is a local DNS server. SmartDNS accepts DNS query requests from local clients, obtains DNS query results from multiple upstream DNS servers, and returns the fastest access results to clients. supports secure DNS protocols like DoT (DNS over TLS), DoH (DNS over HTTPS), better protect privacy,  
+SmartDNS is a local DNS server. SmartDNS accepts DNS query requests from local clients, obtains DNS query results from multiple upstream DNS servers, and returns the fastest access results to clients. supports secure DNS protocols like DoT, DoH, DoQ, DoH3, better protect privacy,  
 Avoiding DNS pollution and improving network access speed, supports high-performance ad filtering.
 
 Unlike dnsmasq's all-servers, smartdns returns the fastest access resolution.
@@ -94,7 +94,7 @@ From the comparison, smartdns found the fastest IP address to visit www.baidu.co
    Support 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.
 
 1. **Support for multiple query protocols**  
-   Support UDP, TCP, DOT(DNS over TLS), DOH(DNS over HTTPS) queries and service, and non-53 port queries, effectively avoiding DNS pollution and protect privacy, and support query DNS over socks5, http proxy.
+   Support UDP, TCP, DOT(DNS over TLS), DOH(DNS over HTTPS), DOQ(DNS over Quic), DOH3(DNS over HTTP3) queries and service, and non-53 port queries, effectively avoiding DNS pollution and protect privacy, and support query DNS over socks5, http proxy.
 
 1. **Domain IP address specification**  
    Support configuring IP address of specific domain to achieve the effect of advertising filtering, and avoid malicious websites.

+ 11 - 6
src/dns_client.c

@@ -4835,6 +4835,7 @@ static int _dns_client_send_http3(struct dns_query_struct *query, struct dns_ser
 #ifdef OSSL_QUIC1_VERSION
 	int send_len = 0;
 	int http_len = 0;
+	int ret = 0;
 	unsigned char inpacket_data[DNS_IN_PACKSIZE];
 	unsigned char *inpacket = inpacket_data;
 	struct client_dns_server_flag_https *https_flag = NULL;
@@ -4887,7 +4888,8 @@ static int _dns_client_send_http3(struct dns_query_struct *query, struct dns_ser
 	INIT_LIST_HEAD(&stream->list);
 
 	if (server_info->status != DNS_SERVER_STATUS_CONNECTED) {
-		return _dns_client_quic_pending_data(stream, server_info, inpacket, http_len);
+		ret = _dns_client_quic_pending_data(stream, server_info, inpacket, http_len);
+		goto out;
 	}
 
 	/* run hand shake */
@@ -4896,7 +4898,8 @@ static int _dns_client_send_http3(struct dns_query_struct *query, struct dns_ser
 	SSL *quic_stream = SSL_new_stream(server_info->ssl, 0);
 	if (quic_stream == NULL) {
 		_dns_client_shutdown_socket(server_info);
-		return _dns_client_quic_pending_data(stream, server_info, inpacket, http_len);
+		ret = _dns_client_quic_pending_data(stream, server_info, inpacket, http_len);
+		goto out;
 	}
 
 	pthread_mutex_lock(&server_info->lock);
@@ -4911,18 +4914,20 @@ static int _dns_client_send_http3(struct dns_query_struct *query, struct dns_ser
 	if (send_len <= 0) {
 		if (errno == EAGAIN || errno == EPIPE || server_info->ssl == NULL) {
 			/* save data to buffer, and retry when EPOLLOUT is available */
-			return _dns_client_quic_pending_data(stream, server_info, inpacket, http_len);
+			ret = _dns_client_quic_pending_data(stream, server_info, inpacket, http_len);
+			goto out;
 		} else if (server_info->ssl && errno != ENOMEM) {
 			_dns_client_shutdown_socket(server_info);
 		}
 		return -1;
 	} else if (send_len < len) {
 		/* save remain data to buffer, and retry when EPOLLOUT is available */
-		return _dns_client_quic_pending_data(stream, server_info, inpacket + send_len, http_len - send_len);
+		ret = _dns_client_quic_pending_data(stream, server_info, inpacket + send_len, http_len - send_len);
+		goto out;
 	}
-
+out:
 	http_head_destroy(http_head);
-	return 0;
+	return ret;
 errout:
 	if (http_head) {
 		http_head_destroy(http_head);

+ 18 - 4
src/http_parse.c

@@ -1373,6 +1373,7 @@ static int _http_head_parse_http3_0(struct http_head *http_head, const uint8_t *
 	int offset = 0;
 	int offset_ret = 0;
 
+	http_head->data_len = 0;
 	while (offset < data_len) {
 		offset_ret = _quicvarint_decode((uint8_t *)data + offset, data_len - offset, &frame_type);
 		if (offset_ret < 0) {
@@ -1411,12 +1412,25 @@ static int _http_head_parse_http3_0(struct http_head *http_head, const uint8_t *
 				memcpy(http_head->buff + http_head->buff_len, data + offset, frame_len);
 				http_head->code_msg = (const char *)(http_head->buff + http_head->buff_len);
 				http_head->buff_len += frame_len;
-			} else {
-				http_head->data = data + offset;
-				http_head->data_len = frame_len;
+			} else if (frame_len > 0) {
+				if (http_head->data == NULL) {
+					http_head->data = _http_head_buffer_get_end(http_head);
+				}
+
+				if (_http_head_buffer_append(http_head, data + offset, frame_len) == NULL) {
+					http_head->code_msg = "Receive Buffer Insufficient";
+					http_head->code = 500;
+					http_head->data_len = 0;
+					http_head->buff_len = 0;
+					return -2;
+				}
+				memcpy(http_head->buff + http_head->buff_len, data + offset, frame_len);
+				http_head->data_len += frame_len;
 			}
 		} else {
-			return -2;
+			/* skip unknown frame. e.g. GREASE  */
+			offset += frame_len;
+			continue;
 		}
 		offset += frame_len;
 	}