From 297ea29639806e1a2677a19d735246fed95654c2 Mon Sep 17 00:00:00 2001 From: Nick Peng Date: Sun, 2 Aug 2020 01:00:46 +0800 Subject: [PATCH] Client: Fix ssl crash issue. --- src/dns_client.c | 38 +++++++++++++++++++++----------------- src/http_parse.c | 28 +++++++++++++--------------- src/util.c | 10 ++++++++++ src/util.h | 2 ++ 4 files changed, 46 insertions(+), 32 deletions(-) diff --git a/src/dns_client.c b/src/dns_client.c index 8a5a577..02882cd 100644 --- a/src/dns_client.c +++ b/src/dns_client.c @@ -858,10 +858,13 @@ static int _dns_client_server_add(char *server_ip, char *server_host, int port, tlog(TLOG_ERROR, "init ssl failed."); goto errout; } - + + SSL_CTX_set_options(server_info->ssl_ctx, SSL_OP_ALL | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); + if (_dns_client_set_trusted_cert(server_info->ssl_ctx) != 0) { tlog(TLOG_WARN, "disable check certificate for %s.", server_info->ip); server_info->skip_check_cert = 1; + SSL_CTX_set_verify(server_info->ssl_ctx, SSL_VERIFY_NONE, NULL); } } @@ -905,7 +908,7 @@ errout: if (server_info->ping_host) { fast_ping_stop(server_info->ping_host); } - + if (server_info->ssl_ctx) { SSL_CTX_free(server_info->ssl_ctx); server_info->ssl_ctx = NULL; @@ -929,6 +932,7 @@ static void _dns_client_close_socket(struct dns_server_info *server_info) if (server_info->ssl) { /* Shutdown ssl */ + SSL_shutdown(server_info->ssl); SSL_free(server_info->ssl); server_info->ssl = NULL; } @@ -1573,9 +1577,9 @@ static int _DNS_client_create_socket_tls(struct dns_server_info *server_info, ch } // ? this cause ssl crash ? - // setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)); - // setsockopt(fd, IPPROTO_TCP, TCP_THIN_DUPACK, &yes, sizeof(yes)); - // setsockopt(fd, IPPROTO_TCP, TCP_THIN_LINEAR_TIMEOUTS, &yes, sizeof(yes)); + setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)); + setsockopt(fd, IPPROTO_TCP, TCP_THIN_DUPACK, &yes, sizeof(yes)); + setsockopt(fd, IPPROTO_TCP, TCP_THIN_LINEAR_TIMEOUTS, &yes, sizeof(yes)); set_sock_keepalive(fd, 15, 3, 4); setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)); setsockopt(fd, IPPROTO_IP, IP_TOS, &ip_tos, sizeof(ip_tos)); @@ -1587,6 +1591,7 @@ static int _DNS_client_create_socket_tls(struct dns_server_info *server_info, ch } } + SSL_set_connect_state(ssl); if (SSL_set_fd(ssl, fd) == 0) { tlog(TLOG_ERROR, "ssl set fd failed."); goto errout; @@ -1597,7 +1602,7 @@ static int _DNS_client_create_socket_tls(struct dns_server_info *server_info, ch SSL_set_session(ssl, server_info->ssl_session); } - SSL_set_mode(ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + SSL_set_mode(ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE); if (hostname[0] != 0) { SSL_set_tlsext_host_name(ssl, hostname); } @@ -1623,6 +1628,7 @@ errout: } if (ssl) { + SSL_shutdown(ssl); SSL_free(ssl); } @@ -1734,10 +1740,6 @@ static int _dns_client_socket_ssl_send(SSL *ssl, const void *buf, int num) ssl_ret = SSL_get_error(ssl, ret); switch (ssl_ret) { case SSL_ERROR_NONE: - errno = EAGAIN; - return -1; - break; - case SSL_ERROR_ZERO_RETURN: return 0; break; case SSL_ERROR_WANT_READ: @@ -1790,8 +1792,7 @@ static int _dns_client_socket_ssl_recv(SSL *ssl, void *buf, int num) ssl_ret = SSL_get_error(ssl, ret); switch (ssl_ret) { case SSL_ERROR_NONE: - errno = EAGAIN; - return -1; + return 0; break; case SSL_ERROR_ZERO_RETURN: return 0; @@ -2236,7 +2237,7 @@ static int _dns_client_process_tls(struct dns_server_info *server_info, struct e if (server_info->status == DNS_SERVER_STATUS_CONNECTING) { /* do SSL hand shake */ - ret = SSL_connect(server_info->ssl); + ret = SSL_do_handshake(server_info->ssl); if (ret == 0) { goto errout; } else if (ret < 0) { @@ -2245,8 +2246,11 @@ static int _dns_client_process_tls(struct dns_server_info *server_info, struct e if (ssl_ret == SSL_ERROR_WANT_READ) { fd_event.events = EPOLLIN; } else if (ssl_ret == SSL_ERROR_WANT_WRITE) { - fd_event.events = EPOLLOUT; + fd_event.events = EPOLLOUT | EPOLLIN; } else { + unsigned long ssl_err = ERR_get_error(); + tlog(TLOG_ERROR, "Handshake with %s failed, error no: %s(%ld)\n", server_info->ip, + ERR_reason_error_string(ssl_err), ssl_err); goto errout; } @@ -2285,7 +2289,7 @@ static int _dns_client_process_tls(struct dns_server_info *server_info, struct e server_info->status = DNS_SERVER_STATUS_CONNECTED; memset(&fd_event, 0, sizeof(fd_event)); - fd_event.events = EPOLLIN | EPOLLOUT; + fd_event.events = EPOLLIN; fd_event.data.ptr = server_info; if (epoll_ctl(client.epoll_fd, EPOLL_CTL_MOD, server_info->fd, &fd_event) != 0) { tlog(TLOG_ERROR, "epoll ctl failed, %s", strerror(errno)); @@ -2550,10 +2554,10 @@ static int _dns_client_send_packet(struct dns_query_struct *query, void *packet, if (ret != 0) { if (send_err != ENOMEM) { tlog(TLOG_ERROR, "send query to %s failed, %s, type: %d", server_info->ip, strerror(send_err), - server_info->type); + server_info->type); } else { tlog(TLOG_DEBUG, "send query to %s failed, %s, type: %d", server_info->ip, strerror(send_err), - server_info->type); + server_info->type); time_t now; time(&now); if (now - 5 > server_info->last_recv) { diff --git a/src/http_parse.c b/src/http_parse.c index 57564c7..e79d336 100644 --- a/src/http_parse.c +++ b/src/http_parse.c @@ -214,7 +214,7 @@ static int _http_head_parse_response(struct http_head *http_head, char *key, cha { char *field_start = NULL; char *tmp_ptr = NULL; - char *result = NULL; + char *ret_msg = NULL; char *ret_code = NULL; if (strstr(key, "HTTP/") == NULL) { @@ -226,29 +226,27 @@ static int _http_head_parse_response(struct http_head *http_head, char *key, cha 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 (*tmp_ptr != ' ') { + continue; } + + *tmp_ptr = '\0'; + ret_code = field_start; + ret_msg = tmp_ptr + 1; + field_start = NULL; + break; } - if (field_start && result == NULL) { - result = field_start; + if (ret_code == NULL || ret_msg == NULL) { + return -1; } - if (ret_code == NULL || result == NULL) { + if (is_numeric(ret_code) != 0) { return -1; } http_head->code = atol(ret_code); - http_head->code_msg = result; + http_head->code_msg = ret_msg; http_head->version = key; http_head->head_type = HTTP_HEAD_RESPONSE; diff --git a/src/util.c b/src/util.c index 8d0c39a..66212f3 100644 --- a/src/util.c +++ b/src/util.c @@ -947,6 +947,16 @@ void get_compiled_time(struct tm *tm) tm->tm_sec = sec; } +int is_numeric(const char *str) +{ + while (*str != '\0') { + if (*str < '0' || *str > '9') + return -1; + str++; + } + return 0; +} + int has_network_raw_cap(void) { int fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); diff --git a/src/util.h b/src/util.h index 1c581ae..2325daa 100644 --- a/src/util.h +++ b/src/util.h @@ -98,6 +98,8 @@ int parse_tls_header(const char *data, size_t data_len, char *hostname, const ch void get_compiled_time(struct tm *tm); +int is_numeric(const char *str); + int has_network_raw_cap(void); int set_sock_keepalive(int fd, int keepidle, int keepinterval, int keepcnt);