使用GnuTLS库建立HTTPS连接时握手触发TLS致命警报问题
问题分析与修复方案
你的代码核心问题出在IPv4地址的字节顺序错误,导致连接到了错误的服务器,进而握手失败,以下是具体说明和修复方案:
1. 核心错误:IP字节序颠倒
你手动构造的IP地址为(7u << 24u) | (32u << 16u) | (18u << 8u) | 104u,但实际解析出的104.18.32.7是主机字节序,转换为网络字节序(大端)时,需要将最高位字节放在最左侧:
- 正确的网络字节序IP构造应为:
(104u << 24u) | (18u << 16u) | (32u << 8u) | 7u - 当前写法相当于把IP写成了
7.32.18.104,并非Stack Overflow的真实服务IP,连接到错误服务器后,握手自然会触发TLS致命警报。
2. 额外优化建议
- 避免硬编码IP:推荐使用
getaddrinfo动态解析域名,既能避免IP变更问题,也能自动处理字节序转换 - 完善错误处理:原代码中错误发生时直接返回0,没有输出具体错误信息,建议添加
perror或gnutls_strerror打印错误,方便调试 - 清理资源:程序结束前记得关闭socket和GNUTLS会话,避免资源泄漏
修复后的代码示例
#include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <gnutls/gnutls.h> #include <string.h> #include <unistd.h> int main () { int Result_d, SocketFileDescriptor; gnutls_session_t GnutlsSession; struct sockaddr_in SockAddr; SocketFileDescriptor = socket (AF_INET, SOCK_STREAM, 0); if (SocketFileDescriptor == -1) { perror("socket creation failed"); return 1; } SockAddr.sin_family = AF_INET; SockAddr.sin_port = htons (443u); // 修复IP字节序:正确对应104.18.32.7的网络字节序 SockAddr.sin_addr.s_addr = (104u << 24u) | (18u << 16u) | (32u << 8u) | 7u; Result_d = connect (SocketFileDescriptor, (struct sockaddr *) &SockAddr, sizeof (SockAddr)); if (Result_d != 0) { perror("connect failed"); close(SocketFileDescriptor); return 1; } Result_d = gnutls_init (&GnutlsSession, GNUTLS_CLIENT); if (Result_d != GNUTLS_E_SUCCESS) { fprintf(stderr, "gnutls_init failed: %s\n", gnutls_strerror(Result_d)); close(SocketFileDescriptor); return 1; } Result_d = gnutls_set_default_priority (GnutlsSession); if (Result_d != GNUTLS_E_SUCCESS) { fprintf(stderr, "gnutls_set_default_priority failed: %s\n", gnutls_strerror(Result_d)); gnutls_deinit(GnutlsSession); close(SocketFileDescriptor); return 1; } gnutls_transport_set_int (GnutlsSession, SocketFileDescriptor); // "stackoverflow.com"长度为17,此处参数正确 Result_d = gnutls_server_name_set (GnutlsSession, GNUTLS_NAME_DNS, "stackoverflow.com", 17u); if (Result_d != GNUTLS_E_SUCCESS) { fprintf(stderr, "gnutls_server_name_set failed: %s\n", gnutls_strerror(Result_d)); gnutls_deinit(GnutlsSession); close(SocketFileDescriptor); return 1; } Result_d = gnutls_handshake (GnutlsSession); if (Result_d != GNUTLS_E_SUCCESS) { fprintf (stderr, "gnutls_handshake() returned: %s\n", gnutls_strerror (Result_d)); gnutls_deinit(GnutlsSession); close(SocketFileDescriptor); return 1; } printf("TLS handshake successful!\n"); // 清理资源 gnutls_deinit(GnutlsSession); close(SocketFileDescriptor); return 0; }
内容的提问来源于stack exchange,提问作者Kolodez
相关产品推荐
相关产品推荐

