Я удалил некоторые сокеты на стороне сервера Windows в c и хочу добавить указание имени сервера sni для поддержки sni
, но обратный вызов servername никогда не вызывался и не может получить имя сервера, есть ли какие-либо предложения?
Я определил некоторые функции для инициализации ssl перед основной функцией:
void init_openssl()
{
SSL_load_error_strings();
OpenSSL_add_ssl_algorithms();
}
SSL_CTX *create_context()
{
const SSL_METHOD *method;
SSL_CTX *ctx;
//method = SSLv23_server_method();
method = TLSv1_1_server_method();
ctx = SSL_CTX_new(method);
if (!ctx) {
perror("Unable to create SSL context");
ERR_print_errors_fp(stderr);
exit(EXIT_FAILURE);
}
return ctx;
}
void configure_context(SSL_CTX *ctx)
{
SSL_CTX_set_ecdh_auto(ctx, 1);
/* Set the key and cert */
if (SSL_CTX_use_certificate_file(ctx, "somesite.cer", SSL_FILETYPE_PEM) <= 0) {
ERR_print_errors_fp(stderr);
exit(EXIT_FAILURE);
}
if (SSL_CTX_use_PrivateKey_file(ctx, "key.pem", SSL_FILETYPE_PEM) <= 0) {
ERR_print_errors_fp(stderr);
exit(EXIT_FAILURE);
}
}
static int ssl_servername_cb(SSL *ssl, int *ad, void *arg)
{
if (ssl == NULL)
return SSL_TLSEXT_ERR_NOACK;
const char* servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
printf("ServerName: %s\n", servername);
}
и вот моя основная функция:
int main()
{
SSL_CTX *ctx;
init_openssl();
ctx = create_context();
configure_context(ctx);
SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb);
WSADATA wsaData;
int iResult;
SOCKET ListenSocket = INVALID_SOCKET;
SOCKET ClientSocket = INVALID_SOCKET;
struct addrinfo *result = NULL;
struct addrinfo hints;
int iSendResult;
char recvbuf[DEFAULT_BUFLEN];
int recvbuflen = DEFAULT_BUFLEN;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
// Resolve the server address and port
//iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
iResult = getaddrinfo("192.168.200.1", DEFAULT_PORT, &hints, &result);
//iResult = getaddrinfo("127.0.0.1", DEFAULT_PORT, &hints, &result);
if (iResult != 0) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}
// Create a SOCKET for connecting to server
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
}
// Setup the TCP listening socket
iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR) {
printf("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
return 1;
}
freeaddrinfo(result);
iResult = listen(ListenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR) {
printf("listen failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
// Accept a client socket
ClientSocket = accept(ListenSocket, NULL, NULL);
SSL *ssl;
if (ClientSocket == INVALID_SOCKET) {
printf("accept failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
// No longer need server socket
closesocket(ListenSocket);
// Receive until the peer shuts down the connection
do {
ssl = SSL_new(ctx);
SSL_set_fd(ssl, ClientSocket);
//added this line for handling server name
SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb);
int rr = SSL_accept(ssl);
iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
//int type=SSL_get_servername_type(ssl);
//const char[] x=SSL_get_servername(ssl, type);
const char *zx= SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
if (iResult > 0) {
printf("Bytes received: %d\n", iResult);
// Echo the buffer back to the sender
iSendResult = send(ClientSocket, recvbuf, iResult, 0);
if (iSendResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
printf("Bytes sent: %d\n", iSendResult);
}
else if (iResult == 0)
printf("Connection closing...\n");
else {
printf("recv failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
} while (iResult > 0);
return 0;
}
В функции do while, которую я пытался вызвать
const char* servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
но ничего не нашел.Я знаю, что рукопожатие clienthello находится в первых байтах, полученных из сокета.
iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
И я получаю 219 байтов данных.Мне нужно обработать имя сервера и найти его, загрузить файл сертификата и выполнять непрерывную работу, и, возможно, после этого продолжать работать с более высоким уровнем в классе c # sslstream.Любое предложение?