为什么我的socket connect()在WSASetSocketSecurity()之后失败?

时间:2018-02-17 15:43:56

标签: c++ sockets windows-socket-api

我正在上课,我想向学生展示如何在C ++中打开套接字,并在Linux和Windows下同时阅读http:和https:webpages。使用OpenSSL轻松实现Linux版本。但在使用Microsoft的WSA套接字库的Windows下,我只能读取非ssl页面。我无法弄清楚如何让他们的WSASetSocketSecurity()功能起作用。

通过以下代码片段中的WSASetSocketSecurity调用注释掉,我能够读取http :(端口80)页面。一些我可以connect()到https :(端口443)主机但尝试发送HTML GET请求,然后recv()页面按预期失败,并且没有返回任何内容或某些400错误的请求页面服务器,因为我没有协商加密。

取消注释WSASetSocketSecurity调用以保证加密,在http:和https:pages上,连接调用始终失败并且WSAGetLastError = 10060(连接超时)。

调用WSASetSocketSecurity但指定allow insecure connections允许我读取http:pages但是使用https:pages失败的方式与完全没有调用WSASetSocketSecurity的方式相同。

从根本上说,我无法启用加密然后连接,我不知道为什么。

我已尝试用WSAxxx()版本替换套接字,连接和其他调用的实验,想象可能存在类似于在Linux中连接之后执行SSL_connect调用的方式的区别,但这没有任何区别。我唯一能想到的就是我还没有尝试过使用WSASetSocketPeerTargetName()来验证主机,但在我看来,如果我想要的只是一个SSL链接,我就不需要这样做。

我在这里缺少什么?有没有人做过这项工作?

   // 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( );          

1 个答案:

答案 0 :(得分:3)

您认为套接字安全性启用SSL / TLS是错误的。它实际上是用于强制使用IPsec协议。见Winsock Secure Socket Extensions。如果您需要SSL / TLS,那么您应该使用Secure Channel(内置Windows SSL / TLS库),OpenSSL或其他在套接字上工作的专用库。