2

私は、C++ でソケットを開き、Linux と Windows の両方で http: と https: の両方の Web ページを読み取る方法を学生に示したいクラスを教えています。Linux版版はOpenSSLで楽々でした。しかし、Microsoft の WSA ソケット ライブラリを使用する Windows では、非 SSL ページしか読み取れませんでした。WSASetSocketSecurity()関数を機能させる方法がわかりません。

次のコード フラグメントの WSASetSocketSecurity 呼び出しをコメント アウトすると、http: (ポート 80) ページを読み取ることができます。https: (ポート 443) ホストにconnect()することはできますが、HTML GET リクエストを送信してからrecv()ページを送信しようとする と、何も返されないか、一部のサーバーから 400 の不正なリクエスト ページが返されて、期待どおりに失敗します。暗号化をネゴシエートしません。

暗号化を保証するために WSASetSocketSecurity 呼び出しのコメントを外すと、http: ページと https: ページの両方で接続呼び出しが常に WSAGetLastError = 10060 (接続タイムアウト) で失敗します。

WSASetSocketSecurity を呼び出して、安全でない接続を許可するように指定すると、http: ページを読み取ることができますが、WSASetSocketSecurity がまったく呼び出されていない場合と同じように、https: ページで失敗します。

基本的に、暗号化をオンにして接続することができず、その理由がわかりません。

ソケット、接続、およびその他の呼び出しを 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( );          
4

1 に答える 1