2

私はssl認証サーバーへのインターフェースとして動作するgen_serverを練習として実装しています。受信したパケットが間違っている場合 (たとえば、ユーザー名とパスワードが間違っている場合)、ssl サーバーは接続を切断します。接続は持続的でなければなりません。

gen_server で、handle_cast/2 を使用してサーバーへの ssl 接続を開きます。

 handle_cast(connect, State) ->
    ......
    case ssl:connect(Address, Port, Options, Timeout) of
        {ok, NewSocket} ->
           {noreply, State#state{socket=NewSocket}};
        {error, Reason} ->
           gen_server:cast(?SERVER, connect),
           {noreply, State#state{socket=undefined}};

そして、たとえば以下を使用して送信できる handle_cast/2 内の他のメッセージを待ちます。

 gen_server:cast(Pid, {authenticate, User, Password}).

このようなキャスト メッセージを受け取るたびに、gen_server:call/3 を使用してサーバー状態から SSL ソケットを回復し、認証メッセージを SSL サーバーに送信する新しい関数を生成します。送信部分がエラーを返した場合、再接続を試みます。それ以外の場合は、ソケットをしばらく読み込んで、ソケットがダウンしていないことを確認し、ダウンしている場合は再接続します。

send_auth(_, _, 0) ->
    {error, max_num_reached}; 

send_auth(User, Password, Num) ->
    Socket = gen_server:call(?SERVER, socket),
    %% also a check that socket is not 'undefined'
    case ssl:send(Socket, AuthMessage) of
      ok ->
          case ssl:recv(Socket, 0, 2000) of
            {error, timeout} ->
                ok;
            _ ->
                gen_server:cast(?SERVER, connect),
                send_auth(User, Password, Num-1)
          end,
      {error, closed} ->
          gen_server:cast(?SERVER, connect),
          send_auth(User, Password, Num-1)
    end.

私は多くのテストを行いましたが、毎回、1 つのメッセージ (最後のメッセージではない) が間違っていると、次のメッセージはどれも実際には配信されません。

すべての有効な認証メッセージが認証サーバーに配信されることを許可するにはどうすればよいですか? さらに、サーバーがまだ接続しようとしていない場合にのみ、サーバーが接続することをどのように確認できますか? そうでなければ、それは DOS 攻撃のようなものです!

4

1 に答える 1

0
  1. 私が理解できるように、システムには認証サーバーが 1 つしかないのに、なぜgen_serverの init で直接接続できないのでしょうか? 接続がある程度信頼できる場合、接続に問題がある場合はgen_serverを強制終了し、スーパーバイザーに再起動させることができます。それはおそらくあなたの DOS の問題を解決するでしょう。
  2. send_authを使用して追加のプロセスを生成する場合、gen_server 呼び出しを行う代わりに、ソケット接続を引数に渡すことができます。
  3. 配信を保証するために、プロトコルにある種の確認を追加します。認証サーバーは、send_authに応答して、それを取得したことを確認する必要があります。そして、send_authは、その確認応答を受信するまで再試行するか、そうでない場合に備えて他のフォールバック動作を行う必要があります。
于 2012-11-01T00:43:17.747 に答える