Support DNS Over HTTPS
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
|
||||
BIN=smartdns
|
||||
OBJS_LIB=lib/rbtree.o lib/art.o lib/bitops.o lib/radix.o lib/conf.o
|
||||
OBJS=smartdns.o fast_ping.o dns_client.o dns_server.o dns.o util.o tlog.o dns_conf.o dns_cache.o $(OBJS_LIB)
|
||||
OBJS=smartdns.o fast_ping.o dns_client.o dns_server.o dns.o util.o tlog.o dns_conf.o dns_cache.o http_parse.o $(OBJS_LIB)
|
||||
CFLAGS +=-O2 -g -Wall -Wstrict-prototypes -fno-omit-frame-pointer -Wstrict-aliasing
|
||||
CFLAGS +=-Iinclude
|
||||
CFLAGS += -DBASE_FILE_NAME=\"$(notdir $<)\"
|
||||
|
||||
290
src/dns_client.c
290
src/dns_client.c
@@ -22,6 +22,7 @@
|
||||
#include "dns_conf.h"
|
||||
#include "fast_ping.h"
|
||||
#include "hashtable.h"
|
||||
#include "http_parse.h"
|
||||
#include "list.h"
|
||||
#include "tlog.h"
|
||||
#include "util.h"
|
||||
@@ -96,9 +97,6 @@ struct dns_server_info {
|
||||
/* server type */
|
||||
dns_server_type_t type;
|
||||
|
||||
unsigned char *spki;
|
||||
int spki_len;
|
||||
|
||||
/* client socket */
|
||||
int fd;
|
||||
int ttl;
|
||||
@@ -107,7 +105,6 @@ struct dns_server_info {
|
||||
SSL_CTX *ssl_ctx;
|
||||
SSL_SESSION *ssl_session;
|
||||
dns_server_status status;
|
||||
unsigned int result_flag;
|
||||
|
||||
struct dns_server_buff send_buff;
|
||||
struct dns_server_buff recv_buff;
|
||||
@@ -124,6 +121,8 @@ struct dns_server_info {
|
||||
struct sockaddr_in6 in6;
|
||||
struct sockaddr addr;
|
||||
};
|
||||
|
||||
struct client_dns_server_flags flags;
|
||||
};
|
||||
|
||||
/* upstream server group member */
|
||||
@@ -298,8 +297,9 @@ static struct dns_server_info *_dns_client_get_server(char *server_ip, int port,
|
||||
case DNS_SERVER_UDP:
|
||||
sock_type = SOCK_DGRAM;
|
||||
break;
|
||||
case DNS_SERVER_TLS:
|
||||
case DNS_SERVER_TCP:
|
||||
case DNS_SERVER_TLS:
|
||||
case DNS_SERVER_HTTPS:
|
||||
sock_type = SOCK_STREAM;
|
||||
break;
|
||||
default:
|
||||
@@ -572,26 +572,88 @@ static void _dns_client_group_remove_all(void)
|
||||
}
|
||||
}
|
||||
|
||||
int dns_client_spki_decode(const char *spki, unsigned char *spki_data_out)
|
||||
{
|
||||
int spki_data_len = -1;
|
||||
|
||||
spki_data_len = SSL_base64_decode(spki, spki_data_out);
|
||||
|
||||
if (spki_data_len != SHA256_DIGEST_LENGTH) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return spki_data_len;
|
||||
}
|
||||
|
||||
static char *_dns_client_server_get_spki(struct dns_server_info *server_info, int *spki_len)
|
||||
{
|
||||
*spki_len = 0;
|
||||
char *spki = NULL;
|
||||
switch (server_info->type) {
|
||||
case DNS_SERVER_UDP: {
|
||||
} break;
|
||||
case DNS_SERVER_HTTPS: {
|
||||
struct client_dns_server_flag_https *flag_https = &server_info->flags.https;
|
||||
spki = flag_https->spki;
|
||||
*spki_len = flag_https->spi_len;
|
||||
} break;
|
||||
case DNS_SERVER_TLS: {
|
||||
struct client_dns_server_flag_tls *flag_tls = &server_info->flags.tls;
|
||||
spki = flag_tls->spki;
|
||||
*spki_len = flag_tls->spi_len;
|
||||
} break;
|
||||
break;
|
||||
case DNS_SERVER_TCP:
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (*spki_len <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return spki;
|
||||
}
|
||||
|
||||
/* add dns server information */
|
||||
static int _dns_client_server_add(char *server_ip, struct addrinfo *gai, dns_server_type_t server_type, unsigned int server_flag, unsigned int result_flag,
|
||||
int ttl, char *spki)
|
||||
static int _dns_client_server_add(char *server_ip, struct addrinfo *gai, dns_server_type_t server_type, struct client_dns_server_flags *flags)
|
||||
{
|
||||
struct dns_server_info *server_info = NULL;
|
||||
unsigned char *spki_data = NULL;
|
||||
int spki_data_len = 0;
|
||||
int ttl = 0;
|
||||
|
||||
/* read SPKI value, base64 sha256 value */
|
||||
if (spki && (strlen(spki) < DNS_MAX_SPKI_LEN)) {
|
||||
spki_data = malloc(DNS_MAX_SPKI_LEN);
|
||||
if (spki_data) {
|
||||
memset(spki_data, 0, DNS_MAX_SPKI_LEN);
|
||||
spki_data_len = SSL_base64_decode(spki, spki_data);
|
||||
if (spki_data_len != SHA256_DIGEST_LENGTH) {
|
||||
free(spki_data);
|
||||
spki_data = NULL;
|
||||
spki_data_len = 0;
|
||||
}
|
||||
switch (server_type) {
|
||||
case DNS_SERVER_UDP: {
|
||||
struct client_dns_server_flag_udp *flag_udp = &flags->udp;
|
||||
ttl = flag_udp->ttl;
|
||||
if (ttl > 255) {
|
||||
ttl = 255;
|
||||
} else if (ttl < -32) {
|
||||
ttl = -32;
|
||||
}
|
||||
} break;
|
||||
case DNS_SERVER_HTTPS: {
|
||||
struct client_dns_server_flag_https *flag_https = &flags->https;
|
||||
spki_data_len = flag_https->spi_len;
|
||||
} break;
|
||||
case DNS_SERVER_TLS: {
|
||||
struct client_dns_server_flag_tls *flag_tls = &flags->tls;
|
||||
spki_data_len = flag_tls->spi_len;
|
||||
} break;
|
||||
break;
|
||||
case DNS_SERVER_TCP:
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (spki_data_len > DNS_SERVER_SPKI_LEN) {
|
||||
tlog(TLOG_ERROR, "spki data length is invalid.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* if server exist, return */
|
||||
@@ -605,7 +667,7 @@ static int _dns_client_server_add(char *server_ip, struct addrinfo *gai, dns_ser
|
||||
}
|
||||
|
||||
if (server_type != DNS_SERVER_UDP) {
|
||||
result_flag &= (~DNSSERVER_FLAG_CHECK_TTL);
|
||||
flags->result_flag &= (~DNSSERVER_FLAG_CHECK_TTL);
|
||||
}
|
||||
|
||||
memset(server_info, 0, sizeof(*server_info));
|
||||
@@ -615,14 +677,12 @@ static int _dns_client_server_add(char *server_ip, struct addrinfo *gai, dns_ser
|
||||
server_info->type = server_type;
|
||||
server_info->fd = 0;
|
||||
server_info->status = DNS_SERVER_STATUS_INIT;
|
||||
server_info->result_flag = result_flag;
|
||||
server_info->ttl = ttl;
|
||||
server_info->ttl_range = 0;
|
||||
server_info->spki = spki_data;
|
||||
server_info->spki_len = spki_data_len;
|
||||
memcpy(&server_info->flags, flags, sizeof(server_info->flags));
|
||||
|
||||
/* exclude this server from default group */
|
||||
if ((server_flag & SERVER_FLAG_EXCLUDE_DEFAULT) == 0) {
|
||||
if ((server_info->flags.server_flag & SERVER_FLAG_EXCLUDE_DEFAULT) == 0) {
|
||||
if (_dns_client_add_to_group(DNS_SERVER_GROUP_DEFAULT, server_info) != 0) {
|
||||
tlog(TLOG_ERROR, "add server to default group failed.");
|
||||
goto errout;
|
||||
@@ -630,7 +690,7 @@ static int _dns_client_server_add(char *server_ip, struct addrinfo *gai, dns_ser
|
||||
}
|
||||
|
||||
/* if server type is TLS, create ssl context */
|
||||
if (server_type == DNS_SERVER_TLS) {
|
||||
if (server_type == DNS_SERVER_TLS || server_type == DNS_SERVER_HTTPS) {
|
||||
server_info->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
|
||||
if (server_info->ssl_ctx == NULL) {
|
||||
tlog(TLOG_ERROR, "init ssl failed.");
|
||||
@@ -646,15 +706,17 @@ static int _dns_client_server_add(char *server_ip, struct addrinfo *gai, dns_ser
|
||||
memcpy(&server_info->addr, gai->ai_addr, gai->ai_addrlen);
|
||||
|
||||
/* start ping task */
|
||||
if (ttl <= 0 && (result_flag & DNSSERVER_FLAG_CHECK_TTL)) {
|
||||
server_info->ping_host = fast_ping_start(PING_TYPE_DNS, server_ip, 0, 60000, 1000, _dns_client_server_update_ttl, server_info);
|
||||
if (server_info->ping_host == NULL) {
|
||||
tlog(TLOG_ERROR, "start ping failed.");
|
||||
goto errout;
|
||||
}
|
||||
if (server_type == DNS_SERVER_UDP) {
|
||||
if (ttl <= 0 && (server_info->flags.result_flag & DNSSERVER_FLAG_CHECK_TTL)) {
|
||||
server_info->ping_host = fast_ping_start(PING_TYPE_DNS, server_ip, 0, 60000, 1000, _dns_client_server_update_ttl, server_info);
|
||||
if (server_info->ping_host == NULL) {
|
||||
tlog(TLOG_ERROR, "start ping failed.");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (ttl < 0) {
|
||||
server_info->ttl_range = -ttl;
|
||||
if (ttl < 0) {
|
||||
server_info->ttl_range = -ttl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -741,10 +803,6 @@ static void _dns_client_server_remove_all(void)
|
||||
{
|
||||
list_del(&server_info->list);
|
||||
_dns_client_server_close(server_info);
|
||||
if (server_info->spki) {
|
||||
free(server_info->spki);
|
||||
server_info->spki = NULL;
|
||||
}
|
||||
free(server_info);
|
||||
}
|
||||
pthread_mutex_unlock(&client.server_list_lock);
|
||||
@@ -779,8 +837,7 @@ static int _dns_client_server_remove(char *server_ip, struct addrinfo *gai, dns_
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _dns_client_server_operate(char *server_ip, int port, dns_server_type_t server_type, unsigned int server_flag, unsigned int result_flag, int ttl,
|
||||
char *spki, int operate)
|
||||
static int _dns_client_server_operate(char *server_ip, int port, dns_server_type_t server_type, struct client_dns_server_flags *flags, int operate)
|
||||
{
|
||||
char port_s[8];
|
||||
int sock_type;
|
||||
@@ -796,8 +853,9 @@ static int _dns_client_server_operate(char *server_ip, int port, dns_server_type
|
||||
case DNS_SERVER_UDP:
|
||||
sock_type = SOCK_DGRAM;
|
||||
break;
|
||||
case DNS_SERVER_TLS:
|
||||
case DNS_SERVER_TCP:
|
||||
case DNS_SERVER_TLS:
|
||||
case DNS_SERVER_HTTPS:
|
||||
sock_type = SOCK_STREAM;
|
||||
break;
|
||||
default:
|
||||
@@ -815,7 +873,7 @@ static int _dns_client_server_operate(char *server_ip, int port, dns_server_type
|
||||
|
||||
if (operate == 0) {
|
||||
/* add server */
|
||||
ret = _dns_client_server_add(server_ip, gai, server_type, server_flag, result_flag, ttl, spki);
|
||||
ret = _dns_client_server_add(server_ip, gai, server_type, flags);
|
||||
if (ret != 0) {
|
||||
goto errout;
|
||||
}
|
||||
@@ -835,14 +893,14 @@ errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int dns_client_add_server(char *server_ip, int port, dns_server_type_t server_type, unsigned server_flag, unsigned int result_flag, int ttl, char *spki)
|
||||
int dns_client_add_server(char *server_ip, int port, dns_server_type_t server_type, struct client_dns_server_flags *flags)
|
||||
{
|
||||
return _dns_client_server_operate(server_ip, port, server_type, server_flag, result_flag, ttl, spki, 0);
|
||||
return _dns_client_server_operate(server_ip, port, server_type, flags, 0);
|
||||
}
|
||||
|
||||
int dns_client_remove_server(char *server_ip, int port, dns_server_type_t server_type)
|
||||
{
|
||||
return _dns_client_server_operate(server_ip, port, server_type, 0, 0, 0, NULL, 1);
|
||||
return _dns_client_server_operate(server_ip, port, server_type, NULL, 1);
|
||||
}
|
||||
|
||||
int dns_server_num(void)
|
||||
@@ -1101,7 +1159,7 @@ static int _dns_client_recv(struct dns_server_info *server_info, unsigned char *
|
||||
|
||||
/* get query reference */
|
||||
query = _dns_client_get_request(packet->head.id, domain);
|
||||
if (query == NULL || (query && has_opt == 0 && server_info->result_flag & DNSSERVER_FLAG_CHECK_EDNS)) {
|
||||
if (query == NULL || (query && has_opt == 0 && server_info->flags.result_flag & DNSSERVER_FLAG_CHECK_EDNS)) {
|
||||
if (query) {
|
||||
_dns_client_query_release(query);
|
||||
}
|
||||
@@ -1123,7 +1181,7 @@ static int _dns_client_recv(struct dns_server_info *server_info, unsigned char *
|
||||
|
||||
/* notify caller dns query result */
|
||||
if (query->callback) {
|
||||
ret = query->callback(query->domain, DNS_QUERY_RESULT, server_info->result_flag, packet, inpacket, inpacket_len, query->user_ptr);
|
||||
ret = query->callback(query->domain, DNS_QUERY_RESULT, server_info->flags.result_flag, packet, inpacket, inpacket_len, query->user_ptr);
|
||||
if (request_num == 0 || ret) {
|
||||
/* if all server replied, or done, stop query, release resource */
|
||||
_dns_client_query_remove(query);
|
||||
@@ -1326,7 +1384,7 @@ static int _dns_client_create_socket(struct dns_server_info *server_info)
|
||||
return _dns_client_create_socket_udp(server_info);
|
||||
} else if (server_info->type == DNS_SERVER_TCP) {
|
||||
return _DNS_client_create_socket_tcp(server_info);
|
||||
} else if (server_info->type == DNS_SERVER_TLS) {
|
||||
} else if (server_info->type == DNS_SERVER_TLS || server_info->type == DNS_SERVER_HTTPS) {
|
||||
return _DNS_client_create_socket_tls(server_info);
|
||||
} else {
|
||||
return -1;
|
||||
@@ -1382,7 +1440,7 @@ static int _dns_client_process_udp(struct dns_server_info *server_info, struct e
|
||||
|
||||
tlog(TLOG_DEBUG, "recv udp packet from %s, len: %d, ttl: %d", gethost_by_addr(from_host, sizeof(from_host), (struct sockaddr *)&from), len, ttl);
|
||||
|
||||
if ((ttl != server_info->ttl) && (server_info->ttl > 0) && (server_info->result_flag & DNSSERVER_FLAG_CHECK_TTL)) {
|
||||
if ((ttl != server_info->ttl) && (server_info->ttl > 0) && (server_info->flags.result_flag & DNSSERVER_FLAG_CHECK_TTL)) {
|
||||
/* If TTL check is enabled but the TTL is inconsistent, it is considered to be a fake dns packet */
|
||||
if ((ttl < server_info->ttl - server_info->ttl_range) || (ttl > server_info->ttl + server_info->ttl_range)) {
|
||||
/* tlog(TLOG_DEBUG, "TTL mismatch, from:%d, local %d, discard result", ttl, server_info->ttl); */
|
||||
@@ -1521,7 +1579,7 @@ static int _dns_client_socket_send(struct dns_server_info *server_info)
|
||||
return -1;
|
||||
} else if (server_info->type == DNS_SERVER_TCP) {
|
||||
return send(server_info->fd, server_info->send_buff.data, server_info->send_buff.len, MSG_NOSIGNAL);
|
||||
} else if (server_info->type == DNS_SERVER_TLS) {
|
||||
} else if (server_info->type == DNS_SERVER_TLS || server_info->type == DNS_SERVER_HTTPS) {
|
||||
return _dns_client_socket_ssl_send(server_info->ssl, server_info->send_buff.data, server_info->send_buff.len);
|
||||
} else {
|
||||
return -1;
|
||||
@@ -1534,7 +1592,7 @@ static int _dns_client_socket_recv(struct dns_server_info *server_info)
|
||||
return -1;
|
||||
} else if (server_info->type == DNS_SERVER_TCP) {
|
||||
return recv(server_info->fd, server_info->recv_buff.data + server_info->recv_buff.len, DNS_TCP_BUFFER - server_info->recv_buff.len, 0);
|
||||
} else if (server_info->type == DNS_SERVER_TLS) {
|
||||
} else if (server_info->type == DNS_SERVER_TLS || server_info->type == DNS_SERVER_HTTPS) {
|
||||
return _dns_client_socket_ssl_recv(server_info->ssl, server_info->recv_buff.data + server_info->recv_buff.len,
|
||||
DNS_TCP_BUFFER - server_info->recv_buff.len);
|
||||
} else {
|
||||
@@ -1545,7 +1603,9 @@ static int _dns_client_socket_recv(struct dns_server_info *server_info)
|
||||
static int _dns_client_process_tcp(struct dns_server_info *server_info, struct epoll_event *event, unsigned long now)
|
||||
{
|
||||
int len;
|
||||
int dns_packet_len = 0;
|
||||
int ret = -1;
|
||||
struct http_head *http_head = NULL;
|
||||
unsigned char *inpacket_data = NULL;
|
||||
|
||||
if (event->events & EPOLLIN) {
|
||||
@@ -1591,29 +1651,61 @@ static int _dns_client_process_tcp(struct dns_server_info *server_info, struct e
|
||||
}
|
||||
|
||||
while (1) {
|
||||
/* tcp result format
|
||||
* | len (short) | dns query result |
|
||||
*/
|
||||
inpacket_data = server_info->recv_buff.data;
|
||||
len = ntohs(*((unsigned short *)(inpacket_data)));
|
||||
if (len <= 0 || len >= DNS_IN_PACKSIZE) {
|
||||
/* data len is invalid */
|
||||
goto errout;
|
||||
}
|
||||
if (server_info->type == DNS_SERVER_HTTPS) {
|
||||
http_head = http_head_init(4096);
|
||||
if (http_head == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (len > server_info->recv_buff.len - 2) {
|
||||
/* len is not expceded, wait and recv */
|
||||
break;
|
||||
}
|
||||
len = http_head_parse(http_head, (char *)server_info->recv_buff.data, server_info->recv_buff.len);
|
||||
if (len < 0) {
|
||||
http_head_destroy(http_head);
|
||||
if (len == -1) {
|
||||
break;
|
||||
}
|
||||
goto errout;
|
||||
}
|
||||
|
||||
inpacket_data = server_info->recv_buff.data + 2;
|
||||
if (http_head_get_httpcode(http_head) != 200) {
|
||||
tlog(TLOG_WARN, "http server query failed, server return http code : %d, %s", http_head_get_httpcode(http_head),
|
||||
http_head_get_httpcode_msg(http_head));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
dns_packet_len = http_head_get_data_len(http_head);
|
||||
inpacket_data = (unsigned char *)http_head_get_data(http_head);
|
||||
} else {
|
||||
/* tcp result format
|
||||
* | len (short) | dns query result |
|
||||
*/
|
||||
inpacket_data = server_info->recv_buff.data;
|
||||
len = ntohs(*((unsigned short *)(inpacket_data)));
|
||||
if (len <= 0 || len >= DNS_IN_PACKSIZE) {
|
||||
/* data len is invalid */
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (len > server_info->recv_buff.len - 2) {
|
||||
/* len is not expceded, wait and recv */
|
||||
break;
|
||||
}
|
||||
|
||||
inpacket_data = server_info->recv_buff.data + 2;
|
||||
dns_packet_len = len;
|
||||
len += 2;
|
||||
}
|
||||
tlog(TLOG_DEBUG, "recv tcp packet from %s, len = %d", server_info->ip, len);
|
||||
|
||||
/* process result */
|
||||
if (_dns_client_recv(server_info, inpacket_data, len, &server_info->addr, server_info->ai_addrlen) != 0) {
|
||||
if (_dns_client_recv(server_info, inpacket_data, dns_packet_len, &server_info->addr, server_info->ai_addrlen) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
len += 2;
|
||||
|
||||
if (http_head) {
|
||||
http_head_destroy(http_head);
|
||||
http_head = NULL;
|
||||
}
|
||||
|
||||
server_info->recv_buff.len -= len;
|
||||
|
||||
/* move to next result */
|
||||
@@ -1677,6 +1769,10 @@ static int _dns_client_process_tcp(struct dns_server_info *server_info, struct e
|
||||
return 0;
|
||||
|
||||
errout:
|
||||
if (http_head) {
|
||||
http_head_destroy(http_head);
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&client.server_list_lock);
|
||||
server_info->recv_buff.len = 0;
|
||||
server_info->send_buff.len = 0;
|
||||
@@ -1705,6 +1801,8 @@ static int _dns_client_tls_verify(struct dns_server_info *server_info)
|
||||
unsigned char *key_data = NULL;
|
||||
unsigned char *key_data_tmp = NULL;
|
||||
unsigned char *key_sha256 = NULL;
|
||||
char *spki = NULL;
|
||||
int spki_len = 0;
|
||||
|
||||
cert = SSL_get_peer_certificate(server_info->ssl);
|
||||
if (cert == NULL) {
|
||||
@@ -1751,9 +1849,10 @@ static int _dns_client_tls_verify(struct dns_server_info *server_info)
|
||||
*ptr = 0;
|
||||
tlog(TLOG_DEBUG, "cert SPKI pin(%s): %s", "sha256", cert_fingerprint);
|
||||
|
||||
if (server_info->spki) {
|
||||
spki = _dns_client_server_get_spki(server_info, &spki_len);
|
||||
if (spki) {
|
||||
/* check SPKI */
|
||||
if (memcmp(server_info->spki, key_sha256, server_info->spki_len) != 0) {
|
||||
if (memcmp(spki, key_sha256, spki_len) != 0) {
|
||||
tlog(TLOG_INFO, "server %s cert spki is invalid", server_info->ip);
|
||||
goto errout;
|
||||
} else {
|
||||
@@ -1858,7 +1957,7 @@ static int _dns_client_process(struct dns_server_info *server_info, struct epoll
|
||||
} else if (server_info->type == DNS_SERVER_TCP) {
|
||||
/* receive from tcp */
|
||||
return _dns_client_process_tcp(server_info, event, now);
|
||||
} else if (server_info->type == DNS_SERVER_TLS) {
|
||||
} else if (server_info->type == DNS_SERVER_TLS || server_info->type == DNS_SERVER_HTTPS) {
|
||||
/* recive from tls */
|
||||
return _dns_client_process_tls(server_info, event, now);
|
||||
} else {
|
||||
@@ -1992,6 +2091,56 @@ static int _dns_client_send_tls(struct dns_server_info *server_info, void *packe
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_client_send_https(struct dns_server_info *server_info, void *packet, unsigned short len)
|
||||
{
|
||||
int send_len = 0;
|
||||
int http_len = 0;
|
||||
unsigned char inpacket_data[DNS_IN_PACKSIZE];
|
||||
unsigned char *inpacket = inpacket_data;
|
||||
struct client_dns_server_flag_https *https_flag = NULL;
|
||||
|
||||
if (len > sizeof(inpacket_data) - 2) {
|
||||
tlog(TLOG_ERROR, "packet size is invalid.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
https_flag = &server_info->flags.https;
|
||||
|
||||
http_len = snprintf((char *)inpacket, DNS_IN_PACKSIZE,
|
||||
"POST %s HTTP/1.1\r\n"
|
||||
"Host: %s\r\n"
|
||||
"content-type: application/dns-message\r\n"
|
||||
"Content-Length: %d\r\n"
|
||||
"\r\n",
|
||||
https_flag->path, https_flag->host, len);
|
||||
memcpy(inpacket + http_len, packet, len);
|
||||
http_len += len;
|
||||
|
||||
if (server_info->status != DNS_SERVER_STATUS_CONNECTED) {
|
||||
return _dns_client_send_data_to_buffer(server_info, inpacket, http_len);
|
||||
}
|
||||
|
||||
if (server_info->ssl == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
send_len = _dns_client_socket_ssl_send(server_info->ssl, inpacket, http_len);
|
||||
if (send_len < 0) {
|
||||
if (errno == EAGAIN || server_info->ssl == NULL) {
|
||||
/* save data to buffer, and retry when EPOLLOUT is available */
|
||||
return _dns_client_send_data_to_buffer(server_info, inpacket, http_len);
|
||||
} else if (server_info->ssl && errno != ENOMEM) {
|
||||
SSL_shutdown(server_info->ssl);
|
||||
}
|
||||
return -1;
|
||||
} else if (send_len < http_len) {
|
||||
/* save remain data to buffer, and retry when EPOLLOUT is available */
|
||||
return _dns_client_send_data_to_buffer(server_info, inpacket + send_len, http_len - send_len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_client_send_packet(struct dns_query_struct *query, void *packet, int len)
|
||||
{
|
||||
struct dns_server_info *server_info = NULL;
|
||||
@@ -2031,6 +2180,11 @@ static int _dns_client_send_packet(struct dns_query_struct *query, void *packet,
|
||||
ret = _dns_client_send_tls(server_info, packet, len);
|
||||
send_err = errno;
|
||||
break;
|
||||
case DNS_SERVER_HTTPS:
|
||||
/* https query */
|
||||
ret = _dns_client_send_https(server_info, packet, len);
|
||||
send_err = errno;
|
||||
break;
|
||||
default:
|
||||
/* unsupport query type */
|
||||
ret = -1;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define _SMART_DNS_CLIENT_H
|
||||
|
||||
#include "dns.h"
|
||||
#define DNS_SERVER_SPKI_LEN 64
|
||||
#define DNS_SERVER_GROUP_DEFAULT "default"
|
||||
|
||||
typedef enum {
|
||||
@@ -35,8 +36,39 @@ int dns_client_query(char *domain, int qtype, dns_client_callback callback, void
|
||||
|
||||
void dns_client_exit(void);
|
||||
|
||||
struct client_dns_server_flag_udp {
|
||||
int ttl;
|
||||
};
|
||||
|
||||
struct client_dns_server_flag_tls {
|
||||
char spki[DNS_SERVER_SPKI_LEN];
|
||||
int spi_len;
|
||||
char host[DNS_MAX_CNAME_LEN];
|
||||
};
|
||||
|
||||
struct client_dns_server_flag_https {
|
||||
char spki[DNS_SERVER_SPKI_LEN];
|
||||
int spi_len;
|
||||
char host[DNS_MAX_CNAME_LEN];
|
||||
char path[DNS_MAX_CNAME_LEN];
|
||||
};
|
||||
|
||||
struct client_dns_server_flags {
|
||||
dns_server_type_t type;
|
||||
unsigned int server_flag;
|
||||
unsigned int result_flag;
|
||||
|
||||
union {
|
||||
struct client_dns_server_flag_udp udp;
|
||||
struct client_dns_server_flag_tls tls;
|
||||
struct client_dns_server_flag_https https;
|
||||
};
|
||||
};
|
||||
|
||||
int dns_client_spki_decode(const char *spki, unsigned char *spki_data_out);
|
||||
|
||||
/* add remote dns server */
|
||||
int dns_client_add_server(char *server_ip, int port, dns_server_type_t server_type, unsigned int server_flag, unsigned int result_flag, int ttl, char *spki);
|
||||
int dns_client_add_server(char *server_ip, int port, dns_server_type_t server_type, struct client_dns_server_flags *flags);
|
||||
|
||||
/* remove remote dns server */
|
||||
int dns_client_remove_server(char *server_ip, int port, dns_server_type_t server_type);
|
||||
|
||||
@@ -68,6 +68,8 @@ int dns_conf_ipset_timeout_enable;
|
||||
struct dns_edns_client_subnet dns_conf_ipv4_ecs;
|
||||
struct dns_edns_client_subnet dns_conf_ipv6_ecs;
|
||||
|
||||
char dns_conf_sni_proxy_ip[DNS_MAX_IPLEN];
|
||||
|
||||
/* create and get dns server group */
|
||||
static struct dns_server_groups *_dns_conf_get_group(const char *group_name)
|
||||
{
|
||||
@@ -186,11 +188,24 @@ static int _config_server(int argc, char *argv[], dns_server_type_t type, int de
|
||||
|
||||
server = &dns_conf_servers[index];
|
||||
server->spki[0] = '\0';
|
||||
server->path[0] = '\0';
|
||||
server->hostname[0] = '\0';
|
||||
|
||||
ip = argv[1];
|
||||
|
||||
/* parse ip, port from ip */
|
||||
if (parse_ip(ip, server->server, &port) != 0) {
|
||||
return -1;
|
||||
if (type == DNS_SERVER_HTTPS) {
|
||||
if (parse_uri(ip, NULL, server->server, &port, server->path) != 0) {
|
||||
return -1;
|
||||
}
|
||||
strncpy(server->hostname, server->server, sizeof(server->hostname));
|
||||
if (server->path[0] == 0) {
|
||||
strcpy(server->path, "/");
|
||||
}
|
||||
} else {
|
||||
/* parse ip, port from ip */
|
||||
if (parse_ip(ip, server->server, &port) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* if port is not defined, set port to default 53 */
|
||||
@@ -706,6 +721,14 @@ static int _config_server_tls(void *data, int argc, char *argv[])
|
||||
return _config_server(argc, argv, DNS_SERVER_TLS, DEFAULT_DNS_TLS_PORT);
|
||||
}
|
||||
|
||||
static int _config_server_https(void *data, int argc, char *argv[])
|
||||
{
|
||||
int ret = 0;
|
||||
ret = _config_server(argc, argv, DNS_SERVER_HTTPS, DEFAULT_DNS_HTTPS_PORT);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _config_nameserver(void *data, int argc, char *argv[])
|
||||
{
|
||||
struct dns_nameserver_rule *nameserver_rule = NULL;
|
||||
@@ -954,6 +977,7 @@ static struct config_item _config_item[] = {
|
||||
CONF_CUSTOM("server", _config_server_udp, NULL),
|
||||
CONF_CUSTOM("server-tcp", _config_server_tcp, NULL),
|
||||
CONF_CUSTOM("server-tls", _config_server_tls, NULL),
|
||||
CONF_CUSTOM("server-https", _config_server_https, NULL),
|
||||
CONF_CUSTOM("nameserver", _config_nameserver, NULL),
|
||||
CONF_CUSTOM("address", _config_address, NULL),
|
||||
CONF_YESNO("ipset-timeout", &dns_conf_ipset_timeout_enable),
|
||||
|
||||
@@ -16,9 +16,11 @@
|
||||
#define DNS_NAX_GROUP_NUMBER 16
|
||||
#define DNS_MAX_IPLEN 64
|
||||
#define DNS_MAX_SPKI_LEN 64
|
||||
#define DNS_MAX_URL_LEN 256
|
||||
#define DNS_MAX_PATH 1024
|
||||
#define DEFAULT_DNS_PORT 53
|
||||
#define DEFAULT_DNS_TLS_PORT 853
|
||||
#define DEFAULT_DNS_HTTPS_PORT 443
|
||||
#define DNS_MAX_CONF_CNAME_LEN 128
|
||||
#define SMARTDNS_CONF_FILE "/etc/smartdns/smartdns.conf"
|
||||
#define SMARTDNS_LOG_FILE "/var/log/smartdns.log"
|
||||
@@ -93,6 +95,8 @@ struct dns_servers {
|
||||
int ttl;
|
||||
dns_server_type_t type;
|
||||
char spki[DNS_MAX_SPKI_LEN];
|
||||
char hostname[DNS_MAX_CNAME_LEN];
|
||||
char path[DNS_MAX_URL_LEN];
|
||||
};
|
||||
|
||||
/* ip address lists of domain */
|
||||
@@ -131,6 +135,7 @@ struct dns_conf_address_rule {
|
||||
|
||||
extern char dns_conf_server_ip[DNS_MAX_IPLEN];
|
||||
extern char dns_conf_server_tcp_ip[DNS_MAX_IPLEN];
|
||||
|
||||
extern int dns_conf_tcp_idle_time;
|
||||
extern int dns_conf_cachesize;
|
||||
extern int dns_conf_prefetch;
|
||||
@@ -166,6 +171,8 @@ extern int dns_conf_ipset_timeout_enable;
|
||||
extern struct dns_edns_client_subnet dns_conf_ipv4_ecs;
|
||||
extern struct dns_edns_client_subnet dns_conf_ipv6_ecs;
|
||||
|
||||
extern char dns_conf_sni_proxy_ip[DNS_MAX_IPLEN];
|
||||
|
||||
void dns_server_load_exit(void);
|
||||
|
||||
int dns_server_load_conf(const char *file);
|
||||
|
||||
114
src/dns_server.c
114
src/dns_server.c
@@ -119,6 +119,9 @@ struct dns_request {
|
||||
struct sockaddr addr;
|
||||
};
|
||||
|
||||
dns_result_callback result_callback;
|
||||
void *user_ptr;
|
||||
|
||||
int has_ping_result;
|
||||
int has_ping_tcp;
|
||||
int has_ptr;
|
||||
@@ -522,6 +525,45 @@ static int _dns_setup_ipset(struct dns_request *request)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _dns_result_callback(struct dns_request *request)
|
||||
{
|
||||
char ip[DNS_MAX_CNAME_LEN];
|
||||
|
||||
if (request->result_callback == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ip[0] = 0;
|
||||
if (request->qtype == DNS_T_A) {
|
||||
if (request->has_ipv4 == 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
sprintf(ip, "%d.%d.%d.%d", request->ipv4_addr[0], request->ipv4_addr[1], request->ipv4_addr[2], request->ipv4_addr[3]);
|
||||
|
||||
return request->result_callback(request->domain, request->rcode, request->qtype, ip, request->user_ptr);
|
||||
} else if (request->qtype == DNS_T_AAAA) {
|
||||
if (request->has_ipv6 == 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
sprintf(ip, "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x",
|
||||
request->ipv6_addr[0], request->ipv6_addr[1], request->ipv6_addr[2], request->ipv6_addr[3], request->ipv6_addr[4], request->ipv6_addr[5],
|
||||
request->ipv6_addr[6], request->ipv6_addr[7], request->ipv6_addr[8], request->ipv6_addr[9], request->ipv6_addr[10], request->ipv6_addr[11],
|
||||
request->ipv6_addr[12], request->ipv6_addr[13], request->ipv6_addr[14], request->ipv6_addr[15]);
|
||||
|
||||
return request->result_callback(request->domain, request->rcode, request->qtype, ip, request->user_ptr);
|
||||
}
|
||||
|
||||
request->result_callback(request->domain, DNS_RC_NXDOMAIN, request->qtype, ip, request->user_ptr);
|
||||
|
||||
return 0;
|
||||
out:
|
||||
|
||||
request->result_callback(request->domain, DNS_RC_NXDOMAIN, request->qtype, ip, request->user_ptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_server_request_complete(struct dns_request *request)
|
||||
{
|
||||
char *cname = NULL;
|
||||
@@ -610,6 +652,8 @@ static int _dns_server_request_complete(struct dns_request *request)
|
||||
/* update ipset */
|
||||
_dns_setup_ipset(request);
|
||||
|
||||
_dns_result_callback(request);
|
||||
|
||||
if (request->prefetch) {
|
||||
return 0;
|
||||
}
|
||||
@@ -1514,7 +1558,13 @@ static int _dns_server_process_cache(struct dns_request *request, struct dns_pac
|
||||
}
|
||||
|
||||
request->rcode = DNS_RC_NOERROR;
|
||||
_dns_reply(request);
|
||||
|
||||
_dns_result_callback(request);
|
||||
|
||||
if (request->prefetch == 0) {
|
||||
_dns_reply(request);
|
||||
}
|
||||
|
||||
dns_cache_update(dns_cache);
|
||||
dns_cache_release(dns_cache);
|
||||
|
||||
@@ -1781,6 +1831,68 @@ static int _dns_server_process_udp(struct dns_server_conn *dnsserver, struct epo
|
||||
return _dns_server_recv(dnsserver, inpacket, len, &from, from_len);
|
||||
}
|
||||
|
||||
int dns_server_query(char *domain, int qtype, dns_result_callback callback, void *user_ptr)
|
||||
{
|
||||
int ret = -1;
|
||||
struct dns_request *request = NULL;
|
||||
const char *group_name = NULL;
|
||||
|
||||
request = malloc(sizeof(*request));
|
||||
if (request == NULL) {
|
||||
tlog(TLOG_ERROR, "malloc failed.\n");
|
||||
goto errout;
|
||||
}
|
||||
memset(request, 0, sizeof(*request));
|
||||
pthread_mutex_init(&request->ip_map_lock, NULL);
|
||||
atomic_set(&request->adblock, 0);
|
||||
request->ping_ttl_v4 = -1;
|
||||
request->ping_ttl_v6 = -1;
|
||||
request->prefetch = 1;
|
||||
request->qtype = qtype;
|
||||
request->rcode = DNS_RC_SERVFAIL;
|
||||
request->result_callback = callback;
|
||||
request->user_ptr = user_ptr;
|
||||
|
||||
request->id = 0;
|
||||
hash_init(request->ip_map);
|
||||
strncpy(request->domain, domain, DNS_MAX_CNAME_LEN);
|
||||
|
||||
/* lookup domain rule */
|
||||
request->domain_rule = _dns_server_get_domain_rule(request->domain);
|
||||
|
||||
tlog(TLOG_INFO, "query domain %s, qtype = %d\n", request->domain, qtype);
|
||||
|
||||
/* process cache */
|
||||
if (_dns_server_process_cache(request, NULL) == 0) {
|
||||
ret = 0;
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
_dns_server_request_get(request);
|
||||
pthread_mutex_lock(&server.request_list_lock);
|
||||
list_add_tail(&request->list, &server.request_list);
|
||||
pthread_mutex_unlock(&server.request_list_lock);
|
||||
|
||||
_dns_server_request_get(request);
|
||||
request->send_tick = get_tick_count();
|
||||
request->request_wait++;
|
||||
|
||||
if (request->domain_rule) {
|
||||
/* get nameserver rule */
|
||||
if (request->domain_rule->rules[DOMAIN_RULE_NAMESERVER]) {
|
||||
struct dns_nameserver_rule *nameserver_rule = request->domain_rule->rules[DOMAIN_RULE_NAMESERVER];
|
||||
group_name = nameserver_rule->group_name;
|
||||
}
|
||||
}
|
||||
|
||||
/* send request */
|
||||
ret = dns_client_query(request->domain, qtype, dns_server_resolve_callback, request, group_name);
|
||||
clean_exit:
|
||||
return ret;
|
||||
errout:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void _dns_server_client_touch(struct dns_server_conn *client)
|
||||
{
|
||||
time(&client->last_request_time);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef _SMART_DNS_SERVER_H
|
||||
#define _SMART_DNS_SERVER_H
|
||||
|
||||
#include "dns.h"
|
||||
|
||||
#ifdef __cpluscplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -15,6 +17,12 @@ void dns_server_stop(void);
|
||||
|
||||
void dns_server_exit(void);
|
||||
|
||||
/* query result notify function */
|
||||
typedef int (*dns_result_callback)(char *domain, dns_rtcode_t rtcode, dns_type_t addr_type, char *ip, void *user_ptr);
|
||||
|
||||
/* query domain */
|
||||
int dns_server_query(char *domain, int qtype, dns_result_callback callback, void *user_ptr);
|
||||
|
||||
#ifdef __cpluscplus
|
||||
}
|
||||
#endif
|
||||
|
||||
445
src/http_parse.c
Normal file
445
src/http_parse.c
Normal file
@@ -0,0 +1,445 @@
|
||||
#include "http_parse.h"
|
||||
#include "hash.h"
|
||||
#include "hashtable.h"
|
||||
#include "jhash.h"
|
||||
#include "list.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
struct http_head_fields {
|
||||
struct hlist_node node;
|
||||
struct list_head list;
|
||||
|
||||
char *name;
|
||||
char *value;
|
||||
};
|
||||
|
||||
struct http_head {
|
||||
HTTP_HEAD_TYPE head_type;
|
||||
HTTP_METHOD method;
|
||||
char *url;
|
||||
char *version;
|
||||
int code;
|
||||
char *code_msg;
|
||||
int buff_size;
|
||||
int buff_len;
|
||||
char *buff;
|
||||
int head_ok;
|
||||
int head_len;
|
||||
char *data;
|
||||
int data_len;
|
||||
int expect_data_len;
|
||||
struct http_head_fields field_head;
|
||||
DECLARE_HASHTABLE(field_map, 4);
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns:
|
||||
* >=0 - success http data len
|
||||
* -1 - Incomplete request
|
||||
* -2 - parse failed
|
||||
*/
|
||||
struct http_head *http_head_init(int buffsize)
|
||||
{
|
||||
struct http_head *http_head = NULL;
|
||||
char *buffer = NULL;
|
||||
|
||||
http_head = malloc(sizeof(*http_head));
|
||||
if (http_head == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
memset(http_head, 0, sizeof(*http_head));
|
||||
INIT_LIST_HEAD(&http_head->field_head.list);
|
||||
hash_init(http_head->field_map);
|
||||
|
||||
buffer = malloc(buffsize);
|
||||
if (buffer == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
http_head->buff = buffer;
|
||||
http_head->buff_size = buffsize;
|
||||
|
||||
return http_head;
|
||||
|
||||
errout:
|
||||
if (buffer) {
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
if (http_head) {
|
||||
free(http_head);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct http_head_fields *http_head_first_fields(struct http_head *http_head)
|
||||
{
|
||||
struct http_head_fields *first = NULL;
|
||||
first = list_first_entry(&http_head->field_head.list, struct http_head_fields, list);
|
||||
|
||||
if (first->name == NULL && first->value == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return first;
|
||||
}
|
||||
|
||||
const char *http_head_get_fields_value(struct http_head *http_head, const char *name)
|
||||
{
|
||||
unsigned long key;
|
||||
struct http_head_fields *filed;
|
||||
|
||||
key = hash_string(name);
|
||||
hash_for_each_possible(http_head->field_map, filed, node, key)
|
||||
{
|
||||
if (strncmp(filed->name, name, 128) == 0) {
|
||||
return filed->value;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct http_head_fields *http_head_next_fields(struct http_head_fields *fields)
|
||||
{
|
||||
struct http_head_fields *next = NULL;
|
||||
next = list_next_entry(fields, list);
|
||||
|
||||
if (next->name == NULL && next->value == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
int http_head_lookup_fields(struct http_head_fields *fields, const char **name, const char **value)
|
||||
{
|
||||
if (fields == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (name) {
|
||||
*name = fields->name;
|
||||
}
|
||||
|
||||
if (value) {
|
||||
*value = fields->value;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
HTTP_METHOD http_head_get_method(struct http_head *http_head)
|
||||
{
|
||||
return http_head->method;
|
||||
}
|
||||
|
||||
const char *http_head_get_url(struct http_head *http_head)
|
||||
{
|
||||
return http_head->url;
|
||||
}
|
||||
|
||||
const char *http_head_get_httpversion(struct http_head *http_head)
|
||||
{
|
||||
return http_head->version;
|
||||
}
|
||||
|
||||
int http_head_get_httpcode(struct http_head *http_head)
|
||||
{
|
||||
return http_head->code;
|
||||
}
|
||||
|
||||
char *http_head_get_httpcode_msg(struct http_head *http_head)
|
||||
{
|
||||
return http_head->code_msg;
|
||||
}
|
||||
|
||||
HTTP_HEAD_TYPE http_head_get_head_type(struct http_head *http_head)
|
||||
{
|
||||
return http_head->head_type;
|
||||
}
|
||||
|
||||
char *http_head_get_data(struct http_head *http_head)
|
||||
{
|
||||
return http_head->data;
|
||||
}
|
||||
|
||||
int http_head_get_data_len(struct http_head *http_head)
|
||||
{
|
||||
return http_head->data_len;
|
||||
}
|
||||
|
||||
static int _http_head_add_fields(struct http_head *http_head, char *name, char *value)
|
||||
{
|
||||
unsigned long key = 0;
|
||||
struct http_head_fields *fields = NULL;
|
||||
fields = malloc(sizeof(*fields));
|
||||
if (fields == NULL) {
|
||||
return -1;
|
||||
}
|
||||
memset(fields, 0, sizeof(*fields));
|
||||
|
||||
fields->name = name;
|
||||
fields->value = value;
|
||||
|
||||
list_add_tail(&fields->list, &http_head->field_head.list);
|
||||
key = hash_string(name);
|
||||
hash_add(http_head->field_map, &fields->node, key);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _http_head_parse_response(struct http_head *http_head, char *key, char *value)
|
||||
{
|
||||
char *field_start = NULL;
|
||||
char *tmp_ptr = NULL;
|
||||
char *result = NULL;
|
||||
char *ret_code = NULL;
|
||||
|
||||
if (strstr(key, "HTTP/") == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (tmp_ptr = value; *tmp_ptr != 0; tmp_ptr++) {
|
||||
if (field_start == NULL) {
|
||||
field_start = tmp_ptr;
|
||||
}
|
||||
|
||||
if (*tmp_ptr == ' ') {
|
||||
*tmp_ptr = '\0';
|
||||
if (ret_code == NULL) {
|
||||
ret_code = field_start;
|
||||
} else if (result == NULL) {
|
||||
result = field_start;
|
||||
break;
|
||||
}
|
||||
|
||||
field_start = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (field_start && result == NULL) {
|
||||
result = field_start;
|
||||
}
|
||||
|
||||
if (ret_code == NULL || result == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
http_head->code = atol(ret_code);
|
||||
http_head->code_msg = result;
|
||||
http_head->version = key;
|
||||
http_head->head_type = HTTP_HEAD_RESPONSE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _http_head_parse_request(struct http_head *http_head, char *key, char *value)
|
||||
{
|
||||
int method = HTTP_METHOD_INVALID;
|
||||
char *url = NULL;
|
||||
char *version = NULL;
|
||||
char *tmp_ptr = value;
|
||||
char *field_start = NULL;
|
||||
|
||||
if (strncmp(key, "GET", sizeof("GET")) == 0) {
|
||||
method = HTTP_METHOD_GET;
|
||||
} else if (strncmp(key, "POST", sizeof("POST")) == 0) {
|
||||
method = HTTP_METHOD_POST;
|
||||
} else if (strncmp(key, "PUT", sizeof("PUT")) == 0) {
|
||||
method = HTTP_METHOD_PUT;
|
||||
} else if (strncmp(key, "DELETE", sizeof("DELETE")) == 0) {
|
||||
method = HTTP_METHOD_DELETE;
|
||||
} else if (strncmp(key, "TRACE", sizeof("TRACE")) == 0) {
|
||||
method = HTTP_METHOD_TRACE;
|
||||
} else if (strncmp(key, "CONNECT", sizeof("CONNECT")) == 0) {
|
||||
method = HTTP_METHOD_CONNECT;
|
||||
} else {
|
||||
return _http_head_parse_response(http_head, key, value);
|
||||
}
|
||||
|
||||
for (tmp_ptr = value; *tmp_ptr != 0; tmp_ptr++) {
|
||||
if (field_start == NULL) {
|
||||
field_start = tmp_ptr;
|
||||
}
|
||||
if (*tmp_ptr == ' ') {
|
||||
*tmp_ptr = '\0';
|
||||
if (url == NULL) {
|
||||
url = field_start;
|
||||
}
|
||||
|
||||
field_start = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (field_start && version == NULL) {
|
||||
version = field_start;
|
||||
}
|
||||
|
||||
http_head->method = method;
|
||||
http_head->url = url;
|
||||
http_head->version = version;
|
||||
http_head->head_type = HTTP_HEAD_REQUEST;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _http_head_parse(struct http_head *http_head)
|
||||
{
|
||||
int i = 0;
|
||||
char *key = NULL;
|
||||
char *value = NULL;
|
||||
char *data;
|
||||
int has_first_line = 0;
|
||||
|
||||
int inkey = 1;
|
||||
int invalue = 0;
|
||||
|
||||
data = http_head->buff;
|
||||
for (i = 0; i < http_head->head_len; i++, data++) {
|
||||
if (inkey) {
|
||||
if (key == NULL && *data != ' ' && *data != '\r' && *data != '\n') {
|
||||
key = data;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*data == ':' || *data == ' ') {
|
||||
*data = '\0';
|
||||
inkey = 0;
|
||||
invalue = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (invalue) {
|
||||
if (value == NULL && *data != ' ') {
|
||||
value = data;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*data == '\r' || *data == '\n') {
|
||||
*data = '\0';
|
||||
inkey = 1;
|
||||
invalue = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (key && value && invalue == 0) {
|
||||
if (has_first_line == 0) {
|
||||
if (_http_head_parse_request(http_head, key, value) != 0) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
has_first_line = 1;
|
||||
} else {
|
||||
if (_http_head_add_fields(http_head, key, value) != 0) {
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
key = NULL;
|
||||
value = NULL;
|
||||
inkey = 1;
|
||||
invalue = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int http_head_parse(struct http_head *http_head, const char *data, int data_len)
|
||||
{
|
||||
int i = 0;
|
||||
char *buff_end = NULL;
|
||||
int left_size = 0;
|
||||
int process_data_len = 0;
|
||||
|
||||
left_size = http_head->buff_size - http_head->buff_len;
|
||||
|
||||
if (left_size < data_len) {
|
||||
return -3;
|
||||
}
|
||||
|
||||
buff_end = http_head->buff + http_head->buff_len;
|
||||
if (http_head->head_ok == 0) {
|
||||
for (i = 0; i < data_len; i++, data++) {
|
||||
*(buff_end + i) = *data;
|
||||
if (*data == '\n') {
|
||||
if (http_head->buff_len + i < 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*(buff_end + i - 2) == '\n') {
|
||||
http_head->head_ok = 1;
|
||||
http_head->head_len = http_head->buff_len + i - 2;
|
||||
i++;
|
||||
buff_end += i;
|
||||
data_len -= i;
|
||||
data++;
|
||||
if (_http_head_parse(http_head) != 0) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
const char *content_len = NULL;
|
||||
content_len = http_head_get_fields_value(http_head, "Content-Length");
|
||||
if (content_len) {
|
||||
http_head->expect_data_len = atol(content_len);
|
||||
} else {
|
||||
http_head->expect_data_len = 0;
|
||||
}
|
||||
|
||||
if (http_head->expect_data_len < 0) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
process_data_len += i;
|
||||
if (http_head->head_ok == 0) {
|
||||
// Read data again */
|
||||
http_head->buff_len += process_data_len;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (http_head->head_ok == 1) {
|
||||
int get_data_len = (http_head->expect_data_len > data_len) ? data_len : http_head->expect_data_len;
|
||||
if (http_head->data == NULL) {
|
||||
http_head->data = buff_end;
|
||||
}
|
||||
|
||||
memcpy(buff_end, data, get_data_len);
|
||||
process_data_len += get_data_len;
|
||||
http_head->data_len += get_data_len;
|
||||
}
|
||||
|
||||
http_head->buff_len += process_data_len;
|
||||
if (http_head->data_len < http_head->expect_data_len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return process_data_len;
|
||||
}
|
||||
|
||||
void http_head_destroy(struct http_head *http_head)
|
||||
{
|
||||
struct http_head_fields *fields, *tmp;
|
||||
|
||||
list_for_each_entry_safe(fields, tmp, &http_head->field_head.list, list)
|
||||
{
|
||||
list_del(&fields->list);
|
||||
free(fields);
|
||||
}
|
||||
|
||||
if (http_head->buff) {
|
||||
free(http_head->buff);
|
||||
}
|
||||
|
||||
free(http_head);
|
||||
}
|
||||
69
src/http_parse.h
Normal file
69
src/http_parse.h
Normal file
@@ -0,0 +1,69 @@
|
||||
#ifndef HTTP_PARSER_H
|
||||
#define HTTP_PARSER_H
|
||||
|
||||
#ifdef __cpluscplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct http_head;
|
||||
struct http_head_fields;
|
||||
|
||||
typedef enum HTTP_METHOD {
|
||||
HTTP_METHOD_INVALID = 0,
|
||||
HTTP_METHOD_GET,
|
||||
HTTP_METHOD_HEAD,
|
||||
HTTP_METHOD_POST,
|
||||
HTTP_METHOD_PUT,
|
||||
HTTP_METHOD_DELETE,
|
||||
HTTP_METHOD_TRACE,
|
||||
HTTP_METHOD_CONNECT,
|
||||
} HTTP_METHOD;
|
||||
|
||||
typedef enum HTTP_HEAD_TYPE {
|
||||
HTTP_HEAD_INVALID = 0,
|
||||
HTTP_HEAD_REQUEST = 1,
|
||||
HTTP_HEAD_RESPONSE = 2,
|
||||
} HTTP_HEAD_TYPE;
|
||||
|
||||
struct http_head *http_head_init(int buffsize);
|
||||
|
||||
HTTP_HEAD_TYPE http_head_get_head_type(struct http_head *http_head);
|
||||
|
||||
HTTP_METHOD http_head_get_method(struct http_head *http_head);
|
||||
|
||||
const char *http_head_get_url(struct http_head *http_head);
|
||||
|
||||
const char *http_head_get_httpversion(struct http_head *http_head);
|
||||
|
||||
int http_head_get_httpcode(struct http_head *http_head);
|
||||
|
||||
char *http_head_get_httpcode_msg(struct http_head *http_head);
|
||||
|
||||
char *http_head_get_data(struct http_head *http_head);
|
||||
|
||||
int http_head_get_data_len(struct http_head *http_head);
|
||||
|
||||
struct http_head_fields *http_head_first_fields(struct http_head *http_head);
|
||||
|
||||
struct http_head_fields *http_head_next_fields(struct http_head_fields *fields);
|
||||
|
||||
const char *http_head_get_fields_value(struct http_head *http_head, const char *name);
|
||||
|
||||
int http_head_lookup_fields(struct http_head_fields *fields, const char **name, const char **value);
|
||||
|
||||
/*
|
||||
* Returns:
|
||||
* >=0 - success http data len
|
||||
* -1 - Incomplete request
|
||||
* -2 - parse failed
|
||||
* -3 - buffer is small
|
||||
*/
|
||||
int http_head_parse(struct http_head *http_head, const char *data, int data_len);
|
||||
|
||||
void http_head_destroy(struct http_head *http_head);
|
||||
|
||||
#ifdef __cpluscplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // !HTTP_PARSER_H
|
||||
@@ -127,10 +127,38 @@ static int _smartdns_add_servers(void)
|
||||
int ret = 0;
|
||||
struct dns_server_groups *group = NULL;
|
||||
struct dns_servers *server = NULL;
|
||||
struct client_dns_server_flags flags;
|
||||
|
||||
for (i = 0; i < dns_conf_server_num; i++) {
|
||||
ret = dns_client_add_server(dns_conf_servers[i].server, dns_conf_servers[i].port, dns_conf_servers[i].type, dns_conf_servers[i].server_flag,
|
||||
dns_conf_servers[i].result_flag, dns_conf_servers[i].ttl, dns_conf_servers[i].spki);
|
||||
memset(&flags, 0, sizeof(flags));
|
||||
switch (dns_conf_servers[i].type) {
|
||||
case DNS_SERVER_UDP: {
|
||||
struct client_dns_server_flag_udp *flag_udp = &flags.udp;
|
||||
flag_udp->ttl = dns_conf_servers[i].ttl;
|
||||
} break;
|
||||
case DNS_SERVER_HTTPS: {
|
||||
struct client_dns_server_flag_https *flag_http = &flags.https;
|
||||
flag_http->spi_len = dns_client_spki_decode(dns_conf_servers[i].spki, (unsigned char *)flag_http->spki);
|
||||
strncpy(flag_http->host, dns_conf_servers[i].hostname, sizeof(flag_http->host));
|
||||
strncpy(flag_http->path, dns_conf_servers[i].path, sizeof(flag_http->path));
|
||||
} break;
|
||||
case DNS_SERVER_TLS: {
|
||||
struct client_dns_server_flag_tls *flag_tls = &flags.tls;
|
||||
flag_tls->spi_len = dns_client_spki_decode(dns_conf_servers[i].spki, (unsigned char *)flag_tls->spki);
|
||||
strncpy(flag_tls->host, dns_conf_servers[i].hostname, sizeof(flag_tls->host));
|
||||
} break;
|
||||
break;
|
||||
case DNS_SERVER_TCP:
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
flags.type = dns_conf_servers[i].type;
|
||||
flags.server_flag = dns_conf_servers[i].server_flag;
|
||||
flags.result_flag = dns_conf_servers[i].result_flag;
|
||||
ret = dns_client_add_server(dns_conf_servers[i].server, dns_conf_servers[i].port, dns_conf_servers[i].type, &flags);
|
||||
if (ret != 0) {
|
||||
tlog(TLOG_ERROR, "add server failed, %s:%d", dns_conf_servers[i].server, dns_conf_servers[i].port);
|
||||
return -1;
|
||||
@@ -297,7 +325,7 @@ static void _sig_error_exit(int signo, siginfo_t *siginfo, void *ct)
|
||||
#elif defined(__mips__)
|
||||
PC = context->uc_mcontext.pc;
|
||||
#endif
|
||||
tlog(TLOG_ERROR, "process exit with signal %d, code = %d, errno = %d, pid = %d, self = %d, pc = %#lx, addr = %#lx, build(%s %s)\n", signo, siginfo->si_code,
|
||||
tlog(TLOG_FATAL, "process exit with signal %d, code = %d, errno = %d, pid = %d, self = %d, pc = %#lx, addr = %#lx, build(%s %s)\n", signo, siginfo->si_code,
|
||||
siginfo->si_errno, siginfo->si_pid, getpid(), PC, (unsigned long)siginfo->si_addr, __DATE__, __TIME__);
|
||||
|
||||
sleep(1);
|
||||
|
||||
248
src/util.c
248
src/util.c
@@ -12,10 +12,11 @@
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#define TMP_BUFF_LEN_32 32
|
||||
|
||||
@@ -192,6 +193,53 @@ int parse_ip(const char *value, char *ip, int *port)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_uri(char *value, char *scheme, char *host, int *port, char *path)
|
||||
{
|
||||
char *scheme_end = NULL;
|
||||
int field_len = 0;
|
||||
char *process_ptr = value;
|
||||
char host_name[PATH_MAX];
|
||||
|
||||
char *host_end = NULL;
|
||||
|
||||
scheme_end = strstr(value, "://");
|
||||
if (scheme_end) {
|
||||
field_len = scheme_end - value;
|
||||
if (scheme) {
|
||||
memcpy(scheme, value, field_len);
|
||||
scheme[field_len + 1] = 0;
|
||||
}
|
||||
process_ptr += field_len + 3;
|
||||
} else {
|
||||
if (scheme) {
|
||||
scheme[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
host_end = strstr(process_ptr, "/");
|
||||
if (host_end == NULL) {
|
||||
return parse_ip(process_ptr, host, port);
|
||||
};
|
||||
|
||||
field_len = host_end - process_ptr;
|
||||
if (field_len >= sizeof(host_name)) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(host_name, process_ptr, field_len);
|
||||
host_name[field_len + 1] = 0;
|
||||
|
||||
if (parse_ip(host_name, host, port) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
process_ptr += field_len;
|
||||
|
||||
if (path) {
|
||||
strcpy(path, process_ptr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int set_fd_nonblock(int fd, int nonblock)
|
||||
{
|
||||
int ret;
|
||||
@@ -457,7 +505,7 @@ static __attribute__((unused)) void _pthreads_locking_callback(int mode, int typ
|
||||
}
|
||||
}
|
||||
|
||||
static __attribute__((unused)) unsigned long _pthreads_thread_id(void)
|
||||
static __attribute__((unused)) unsigned long _pthreads_thread_id(void)
|
||||
{
|
||||
unsigned long ret;
|
||||
|
||||
@@ -499,3 +547,197 @@ void SSL_CRYPTO_thread_cleanup(void)
|
||||
OPENSSL_free(lock_cs);
|
||||
OPENSSL_free(lock_count);
|
||||
}
|
||||
|
||||
#define SERVER_NAME_LEN 256
|
||||
#define TLS_HEADER_LEN 5
|
||||
#define TLS_HANDSHAKE_CONTENT_TYPE 0x16
|
||||
#define TLS_HANDSHAKE_TYPE_CLIENT_HELLO 0x01
|
||||
#ifndef MIN
|
||||
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
|
||||
#endif
|
||||
typedef struct Protocol {
|
||||
const char *const name;
|
||||
const uint16_t default_port;
|
||||
int (*const parse_packet)(const char*, size_t, char *, const char **);
|
||||
const char *const abort_message;
|
||||
const size_t abort_message_len;
|
||||
} protocol_t;
|
||||
|
||||
static int parse_extensions(const char *, size_t, char *, const char **);
|
||||
static int parse_server_name_extension(const char *, size_t, char *, const char **);
|
||||
|
||||
const struct Protocol *const tls_protocol;
|
||||
|
||||
static const protocol_t tls_protocol_st = {
|
||||
.default_port = 443,
|
||||
.parse_packet = &parse_tls_header,
|
||||
};
|
||||
const protocol_t *const tls_protocol = &tls_protocol_st;
|
||||
|
||||
/* Parse a TLS packet for the Server Name Indication extension in the client
|
||||
* hello handshake, returning the first servername found (pointer to static
|
||||
* array)
|
||||
*
|
||||
* Returns:
|
||||
* >=0 - length of the hostname and updates *hostname
|
||||
* caller is responsible for freeing *hostname
|
||||
* -1 - Incomplete request
|
||||
* -2 - No Host header included in this request
|
||||
* -3 - Invalid hostname pointer
|
||||
* -4 - malloc failure
|
||||
* < -4 - Invalid TLS client hello
|
||||
*/
|
||||
int parse_tls_header(const char *data, size_t data_len, char *hostname, const char **hostname_ptr)
|
||||
{
|
||||
char tls_content_type;
|
||||
char tls_version_major;
|
||||
char tls_version_minor;
|
||||
size_t pos = TLS_HEADER_LEN;
|
||||
size_t len;
|
||||
|
||||
if (hostname == NULL)
|
||||
return -3;
|
||||
|
||||
/* Check that our TCP payload is at least large enough for a TLS header */
|
||||
if (data_len < TLS_HEADER_LEN)
|
||||
return -1;
|
||||
|
||||
/* SSL 2.0 compatible Client Hello
|
||||
*
|
||||
* High bit of first byte (length) and content type is Client Hello
|
||||
*
|
||||
* See RFC5246 Appendix E.2
|
||||
*/
|
||||
if (data[0] & 0x80 && data[2] == 1) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
tls_content_type = data[0];
|
||||
if (tls_content_type != TLS_HANDSHAKE_CONTENT_TYPE) {
|
||||
return -5;
|
||||
}
|
||||
|
||||
tls_version_major = data[1];
|
||||
tls_version_minor = data[2];
|
||||
if (tls_version_major < 3) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* TLS record length */
|
||||
len = ((unsigned char)data[3] << 8) + (unsigned char)data[4] + TLS_HEADER_LEN;
|
||||
data_len = MIN(data_len, len);
|
||||
|
||||
/* Check we received entire TLS record length */
|
||||
if (data_len < len)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Handshake
|
||||
*/
|
||||
if (pos + 1 > data_len) {
|
||||
return -5;
|
||||
}
|
||||
if (data[pos] != TLS_HANDSHAKE_TYPE_CLIENT_HELLO) {
|
||||
return -5;
|
||||
}
|
||||
|
||||
/* Skip past fixed length records:
|
||||
* 1 Handshake Type
|
||||
* 3 Length
|
||||
* 2 Version (again)
|
||||
* 32 Random
|
||||
* to Session ID Length
|
||||
*/
|
||||
pos += 38;
|
||||
|
||||
/* Session ID */
|
||||
if (pos + 1 > data_len)
|
||||
return -5;
|
||||
len = (unsigned char)data[pos];
|
||||
pos += 1 + len;
|
||||
|
||||
/* Cipher Suites */
|
||||
if (pos + 2 > data_len)
|
||||
return -5;
|
||||
len = ((unsigned char)data[pos] << 8) + (unsigned char)data[pos + 1];
|
||||
pos += 2 + len;
|
||||
|
||||
/* Compression Methods */
|
||||
if (pos + 1 > data_len)
|
||||
return -5;
|
||||
len = (unsigned char)data[pos];
|
||||
pos += 1 + len;
|
||||
|
||||
if (pos == data_len && tls_version_major == 3 && tls_version_minor == 0) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* Extensions */
|
||||
if (pos + 2 > data_len)
|
||||
return -5;
|
||||
len = ((unsigned char)data[pos] << 8) + (unsigned char)data[pos + 1];
|
||||
pos += 2;
|
||||
|
||||
if (pos + len > data_len)
|
||||
return -5;
|
||||
return parse_extensions(data + pos, len, hostname, hostname_ptr);
|
||||
}
|
||||
|
||||
static int parse_extensions(const char *data, size_t data_len, char *hostname, const char **hostname_ptr)
|
||||
{
|
||||
size_t pos = 0;
|
||||
size_t len;
|
||||
|
||||
/* Parse each 4 bytes for the extension header */
|
||||
while (pos + 4 <= data_len) {
|
||||
/* Extension Length */
|
||||
len = ((unsigned char)data[pos + 2] << 8) + (unsigned char)data[pos + 3];
|
||||
|
||||
/* Check if it's a server name extension */
|
||||
if (data[pos] == 0x00 && data[pos + 1] == 0x00) {
|
||||
/* There can be only one extension of each type, so we break
|
||||
* our state and move p to beinnging of the extension here */
|
||||
if (pos + 4 + len > data_len)
|
||||
return -5;
|
||||
return parse_server_name_extension(data + pos + 4, len, hostname, hostname_ptr);
|
||||
}
|
||||
pos += 4 + len; /* Advance to the next extension header */
|
||||
}
|
||||
/* Check we ended where we expected to */
|
||||
if (pos != data_len)
|
||||
return -5;
|
||||
|
||||
return -2;
|
||||
}
|
||||
|
||||
static int parse_server_name_extension(const char *data, size_t data_len, char *hostname, const char **hostname_ptr)
|
||||
{
|
||||
size_t pos = 2; /* skip server name list length */
|
||||
size_t len;
|
||||
|
||||
while (pos + 3 < data_len) {
|
||||
len = ((unsigned char)data[pos + 1] << 8) + (unsigned char)data[pos + 2];
|
||||
|
||||
if (pos + 3 + len > data_len)
|
||||
return -5;
|
||||
|
||||
switch (data[pos]) { /* name type */
|
||||
case 0x00: /* host_name */
|
||||
strncpy(hostname, data + pos + 3, len);
|
||||
if (hostname_ptr) {
|
||||
*hostname_ptr = data + pos + 3;
|
||||
}
|
||||
hostname[len] = '\0';
|
||||
|
||||
return len;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
pos += 3 + len;
|
||||
}
|
||||
/* Check we ended where we expected to */
|
||||
if (pos != data_len)
|
||||
return -5;
|
||||
|
||||
return -2;
|
||||
}
|
||||
|
||||
17
src/util.h
17
src/util.h
@@ -16,6 +16,8 @@ int getaddr_by_host(char *host, struct sockaddr *addr, socklen_t *addr_len);
|
||||
|
||||
int parse_ip(const char *value, char *ip, int *port);
|
||||
|
||||
int parse_uri(char *value, char *scheme, char *host, int *port, char *path);
|
||||
|
||||
int set_fd_nonblock(int fd, int nonblock);
|
||||
|
||||
char *reverse_string(char *output, char *input, int len);
|
||||
@@ -36,4 +38,19 @@ int SSL_base64_decode(const char *in, unsigned char *out);
|
||||
|
||||
int create_pid_file(const char *pid_file);
|
||||
|
||||
/* Parse a TLS packet for the Server Name Indication extension in the client
|
||||
* hello handshake, returning the first servername found (pointer to static
|
||||
* array)
|
||||
*
|
||||
* Returns:
|
||||
* >=0 - length of the hostname and updates *hostname
|
||||
* caller is responsible for freeing *hostname
|
||||
* -1 - Incomplete request
|
||||
* -2 - No Host header included in this request
|
||||
* -3 - Invalid hostname pointer
|
||||
* -4 - malloc failure
|
||||
* < -4 - Invalid TLS client hello
|
||||
*/
|
||||
int parse_tls_header(const char *data, size_t data_len, char *hostname, const char **hostname_ptr);
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user