📅  最后修改于: 2023-12-03 15:20:20.575000             🧑  作者: Mango
当进行SSL握手时,SSL客户端会根据服务器提供的证书中的主机名信息来检查是否匹配服务器的主机名。如果这个主机名检查失败,客户端将会拒绝和服务器建立安全连接。在这个过程中,开发者可能会发现SSL_get_servername函数返回null。
SSL_get_servername函数获取在客户端SSL对象中保存的服务器名称。该信息在客户端SSL握手过程中传递给SSL服务器。如果用户名不为空,则应用程序可以使用此信息来确定服务器的原始请求。
以下是SSL_get_servername函数的函数原型:
const char *SSL_get_servername(const SSL *ssl, const int type);
在SSL客户端应用程序中,SSL_get_servername函数可能会返回null。这可能是因为以下几种情况:
如果SSL_get_servername返回null,可以先检查是否已成功建立连接。如果已经建立了连接,则SSL服务器可能没有提供SNI扩展。在这种情况下,您可以使用服务器的IP地址或域名。
如果尚未建立连接,并且仍然返回null,则SSL客户端可能未接收到SNI扩展。您可以尝试重新启动连接,以便在此后尝试获取扩展。
以下是一个基本的代码示例,可用于获取SSL服务器的主机名和IP地址:
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
int main(int argc, char **argv)
{
const char* hostname = "www.example.com"; // 主机名
int port = 443; // 端口号
const char* ipaddress = NULL;
const char* servername = NULL;
struct addrinfo* addr;
struct addrinfo hints;
SSL_CTX* ctx;
SSL* ssl;
BIO* bio;
int sockfd;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if (getaddrinfo(hostname, NULL, &hints, &addr) != 0)
perror("getaddrinfo");
sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
connect(sockfd, addr->ai_addr, addr->ai_addrlen);
ctx = SSL_CTX_new(TLS_client_method());
ssl = SSL_new(ctx);
bio = BIO_new_socket(sockfd, BIO_NOCLOSE);
SSL_set_bio(ssl, bio, bio);
SSL_connect(ssl);
// 获取服务器的主机名
servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
// 获取服务器的IP地址
struct sockaddr_in sa;
socklen_t len = sizeof(sa);
if (getsockname(sockfd, (struct sockaddr *)(&sa), &len) == -1) {
perror("getsockname() failed");
} else {
ipaddress = inet_ntoa(sa.sin_addr);
}
SSL_shutdown(ssl);
SSL_free(ssl);
SSL_CTX_free(ctx);
close(sockfd);
freeaddrinfo(addr);
printf("Server hostname: %s\n", servername);
printf("Server IP Address: %s\n", ipaddress);
return 0;
}
上面的示例可以用来获取SSL服务器的主机名和IP地址。如果SSL_get_servername返回null,则使用getsockname获取IP地址。