为什么我的套接字 connect() 在 WSASetSocketSecurity() 之后失败?
Why does my socket connect() fail after WSASetSocketSecurity()?
我正在教 class,我想向学生展示如何在 C++ 中打开套接字并阅读 Linux 和 [=29= 下的 http: 和 https: 网页]. Linux 版本轻而易举地使用了 OpenSSL. But under Windows using Microsoft's WSA socket library, I've only been able to read non-ssl pages. I cannot figure out how to get their WSASetSocketSecurity() 功能。
通过注释掉以下代码片段中的 WSASetSocketSecurity 调用,我能够读取 http:(端口 80)页面。我能够 connect() to https: (port 443) hosts but attempts to send an HTML GET request and then recv() 页面按预期失败,没有返回任何内容或来自某些服务器的 400 错误请求页面,因为我没有协商加密。
取消对 WSASetSocketSecurity 调用的注释以保证加密,在 http: 和 https: 页面上,连接调用总是失败并显示 WSAGetLastError = 10060(连接超时)。
调用 WSASetSocketSecurity 但指定允许不安全的连接允许我读取 http: 页面但 https: 页面失败,就像根本没有调用 WSASetSocketSecurity 一样。
基本上,我无法打开加密然后连接,我不知道为什么。
我已经尝试过用 WSAxxx() 版本替换套接字、连接和其他调用的实验,想象可能会有类似于在 [=32 中连接后必须进行 SSL_connect 调用的区别=] 但这没有区别。我唯一能想到但尚未尝试的是使用 WSASetSocketPeerTargetName() 对主机进行身份验证,但在我看来,如果我想要的只是一个 SSL link,我不需要这样做。
我在这里错过了什么?有人做过这个吗?
// Initialize the socket library.
// wVersionRequested = 2.2 (current latest)
WSADATA wsaData;
int wsaStartupResult = WSAStartup( MAKEWORD( 2, 2 ), &wsaData );
assert( wsaStartupResult == 0 );
// Get the host address.
ADDRINFOA *addressInfo;
int addrInfoResult = getaddrinfo( url.Host, url.Service,
nullptr, &addressInfo );
assert( addrInfoResult == 0 );
sockaddr *socketAddress = addressInfo->ai_addr;
size_t socketAddressLength = addressInfo->ai_addrlen;
PrintAddress( socketAddress, socketAddressLength );
// Create a TCP/IP socket.
SOCKET s = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
assert( s != INVALID_SOCKET );
// Turn on SSL.
SOCKET_SECURITY_SETTINGS security =
{
SOCKET_SECURITY_PROTOCOL_DEFAULT,
SOCKET_SETTINGS_GUARANTEE_ENCRYPTION
// SOCKET_SETTINGS_ALLOW_INSECURE
};
/*
int setSecurityResult = WSASetSocketSecurity( s,
&security, sizeof( security ), nullptr, nullptr );
assert( setSecurityResult == 0 );
*/
// Connect to the host.
int connectResult = connect( s, socketAddress, socketAddressLength );
if ( connectResult != 0 )
cerr << "Connect failed, WSAGetLastError = " << WSAGetLastError( ) << endl;
assert( connectResult == 0 );
// Send a GET message for the desired page.
string getMessage = "GET ";
getMessage += url.CompleteUrl;
getMessage += " HTTP/1.1\r\nHost: ";
getMessage += url.Host;
getMessage += "\r\nConnection: close\r\n\r\n";
cout << getMessage << endl;
send( s, getMessage.c_str( ), getMessage.length( ), 0 );
// Read from the socket until there's no more data.
HANDLE Stdout = GetStdHandle( STD_OUTPUT_HANDLE );
char buffer[ 10240 ];
int bytes;
DWORD length;
while ( ( bytes = recv( s, buffer, sizeof( buffer ), 0 ) ) > 0 )
WriteFile( Stdout, buffer, bytes, &length, nullptr );
freeaddrinfo( addressInfo );
closesocket( s );
WSACleanup( );
您关于套接字安全性开启 SSL/TLS 的假设是错误的。它实际上是为了强制使用 IPsec 协议。请参阅 Winsock Secure Socket Extensions. If you need SSL/TLS then you should use Secure Channel(built-in Windows SSL/TLS 库)、OpenSSL 或其他在套接字之上工作的专用库。
我正在教 class,我想向学生展示如何在 C++ 中打开套接字并阅读 Linux 和 [=29= 下的 http: 和 https: 网页]. Linux 版本轻而易举地使用了 OpenSSL. But under Windows using Microsoft's WSA socket library, I've only been able to read non-ssl pages. I cannot figure out how to get their WSASetSocketSecurity() 功能。
通过注释掉以下代码片段中的 WSASetSocketSecurity 调用,我能够读取 http:(端口 80)页面。我能够 connect() to https: (port 443) hosts but attempts to send an HTML GET request and then recv() 页面按预期失败,没有返回任何内容或来自某些服务器的 400 错误请求页面,因为我没有协商加密。
取消对 WSASetSocketSecurity 调用的注释以保证加密,在 http: 和 https: 页面上,连接调用总是失败并显示 WSAGetLastError = 10060(连接超时)。
调用 WSASetSocketSecurity 但指定允许不安全的连接允许我读取 http: 页面但 https: 页面失败,就像根本没有调用 WSASetSocketSecurity 一样。
基本上,我无法打开加密然后连接,我不知道为什么。
我已经尝试过用 WSAxxx() 版本替换套接字、连接和其他调用的实验,想象可能会有类似于在 [=32 中连接后必须进行 SSL_connect 调用的区别=] 但这没有区别。我唯一能想到但尚未尝试的是使用 WSASetSocketPeerTargetName() 对主机进行身份验证,但在我看来,如果我想要的只是一个 SSL link,我不需要这样做。
我在这里错过了什么?有人做过这个吗?
// Initialize the socket library.
// wVersionRequested = 2.2 (current latest)
WSADATA wsaData;
int wsaStartupResult = WSAStartup( MAKEWORD( 2, 2 ), &wsaData );
assert( wsaStartupResult == 0 );
// Get the host address.
ADDRINFOA *addressInfo;
int addrInfoResult = getaddrinfo( url.Host, url.Service,
nullptr, &addressInfo );
assert( addrInfoResult == 0 );
sockaddr *socketAddress = addressInfo->ai_addr;
size_t socketAddressLength = addressInfo->ai_addrlen;
PrintAddress( socketAddress, socketAddressLength );
// Create a TCP/IP socket.
SOCKET s = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
assert( s != INVALID_SOCKET );
// Turn on SSL.
SOCKET_SECURITY_SETTINGS security =
{
SOCKET_SECURITY_PROTOCOL_DEFAULT,
SOCKET_SETTINGS_GUARANTEE_ENCRYPTION
// SOCKET_SETTINGS_ALLOW_INSECURE
};
/*
int setSecurityResult = WSASetSocketSecurity( s,
&security, sizeof( security ), nullptr, nullptr );
assert( setSecurityResult == 0 );
*/
// Connect to the host.
int connectResult = connect( s, socketAddress, socketAddressLength );
if ( connectResult != 0 )
cerr << "Connect failed, WSAGetLastError = " << WSAGetLastError( ) << endl;
assert( connectResult == 0 );
// Send a GET message for the desired page.
string getMessage = "GET ";
getMessage += url.CompleteUrl;
getMessage += " HTTP/1.1\r\nHost: ";
getMessage += url.Host;
getMessage += "\r\nConnection: close\r\n\r\n";
cout << getMessage << endl;
send( s, getMessage.c_str( ), getMessage.length( ), 0 );
// Read from the socket until there's no more data.
HANDLE Stdout = GetStdHandle( STD_OUTPUT_HANDLE );
char buffer[ 10240 ];
int bytes;
DWORD length;
while ( ( bytes = recv( s, buffer, sizeof( buffer ), 0 ) ) > 0 )
WriteFile( Stdout, buffer, bytes, &length, nullptr );
freeaddrinfo( addressInfo );
closesocket( s );
WSACleanup( );
您关于套接字安全性开启 SSL/TLS 的假设是错误的。它实际上是为了强制使用 IPsec 协议。请参阅 Winsock Secure Socket Extensions. If you need SSL/TLS then you should use Secure Channel(built-in Windows SSL/TLS 库)、OpenSSL 或其他在套接字之上工作的专用库。