[解決済み] TLSサーバーを実装するためのHsOpenSSL APIの適切な使用法
2022-05-25 16:48:17
質問
を正しく使用する方法を考えています。 OpenSSL.Session API を並列コンテキストで適切に使用する方法を考えています。
例えば、私が以下のような実装をしたいとします。
stunnel-style ssl-wrapper
を実装するとしたら、次のような基本的なスケルトン構造を期待します。
full-duplex tcp-port-forwarder:
runProxy :: PortID -> AddrInfo -> IO ()
runProxy localPort@(PortNumber lpn) serverAddrInfo = do
listener <- listenOn localPort
forever $ do
(sClient, clientAddr) <- accept listener
let finalize sServer = do
sClose sServer
sClose sClient
forkIO $ do
tidToServer <- myThreadId
bracket (connectToServer serverAddrInfo) finalize $ \sServer -> do
-- execute one 'copySocket' thread for each data direction
-- and make sure that if one direction dies, the other gets
-- pulled down as well
bracket (forkIO (copySocket sServer sClient
`finally` killThread tidToServer))
(killThread) $ \_ -> do
copySocket sClient sServer -- "controlling" thread
where
-- |Copy data from source to dest until EOF occurs on source
-- Copying may also be aborted due to exceptions
copySocket :: Socket -> Socket -> IO ()
copySocket src dst = go
where
go = do
buf <- B.recv src 4096
unless (B.null buf) $ do
B.sendAll dst buf
go
-- |Create connection to given AddrInfo target and return socket
connectToServer saddr = do
sServer <- socket (addrFamily saddr) Stream defaultProtocol
connect sServer (addrAddress saddr)
return sServer
上記のスケルトンをどのようにして
full-duplex ssl-wrapping tcp-forwarding proxy
? HsOpenSSL APIによって提供される関数呼び出しの同時/並列実行(上記のユースケースのコンテキストにおいて)に対する危険性はどこにあるのでしょうか?
PS: 私はまだ、例外とリソースリークに対して堅牢なコードを作る方法を完全に理解するのに苦労しています。したがって、この質問の主要な焦点ではありませんが、もしあなたが上記のコードで何か悪いことに気づいたら、コメントを残してください。
どのように解決するのですか?
これを行うには、次のように置き換える必要があります。
copySocket
を2つの異なる関数で置き換える必要があります。1つはプレーンソケットからSSLへのデータを処理するもので、もう1つはSSLからプレーンソケットへのデータを処理するものです。
copyIn :: SSL.SSL -> Socket -> IO ()
copyIn src dst = go
where
go = do
buf <- SSL.read src 4096
unless (B.null buf) $ do
SB.sendAll dst buf
go
copyOut :: Socket -> SSL.SSL -> IO ()
copyOut src dst = go
where
go = do
buf <- SB.recv src 4096
unless (B.null buf) $ do
SSL.write dst buf
go
次に
connectToServer
を修正して、SSL接続を確立するようにします。
-- |Create connection to given AddrInfo target and return socket
connectToServer saddr = do
sServer <- socket (addrFamily saddr) Stream defaultProtocol
putStrLn "connecting"
connect sServer (addrAddress saddr)
putStrLn "establishing ssl context"
ctx <- SSL.context
putStrLn "setting ciphers"
SSL.contextSetCiphers ctx "DEFAULT"
putStrLn "setting verfication mode"
SSL.contextSetVerificationMode ctx SSL.VerifyNone
putStrLn "making ssl connection"
sslServer <- SSL.connection ctx sServer
putStrLn "doing handshake"
SSL.connect sslServer
putStrLn "connected"
return sslServer
と変更し
finalize
を変更して、SSL セッションをシャットダウンします。
let finalize sServer = do
putStrLn "shutting down ssl"
SSL.shutdown sServer SSL.Unidirectional
putStrLn "closing server socket"
maybe (return ()) sClose (SSL.sslSocket sServer)
putStrLn "closing client socket"
sClose sClient
最後に、メインとなるものを
withOpenSSL
のように
main = withOpenSSL $ do
let hints = defaultHints { addrSocketType = Stream, addrFamily = AF_INET }
addrs <- getAddrInfo (Just hints) (Just "localhost") (Just "22222")
let addr = head addrs
print addr
runProxy (PortNumber 11111) addr
関連
-
[解決済み】Haskellでの挿入ソート
-
[解決済み] エラー haskell: スコープ内にありません。どういう意味ですか?
-
[解決済み] Haskellです。パターンでのパースエラー
-
[解決済み] Haskellで大規模設計?[クローズド]
-
[解決済み] サーバーから証明書を取得するためにopensslを使用する
-
[解決済み] Haskellにはなぜ "data "と "newtype "があるのですか?重複] [重複] [重複
-
[解決済み] Haskellにおける "リフティング "とは?
-
[解決済み] なぜ依存型でないのか?
-
[解決済み] レコードの単一フィールドを割り当て、残りのフィールドはコピーするための省略記法?
-
[解決済み] HaskellとF#の主な違いは何ですか?[クローズド]
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】haskellでリストを逆順にする
-
[解決済み] 一般的に `{- |` で始まるHaskellのコメントは何を意味するのですか?
-
[解決済み] Haskell - Ord aの型は何を意味するのでしょうか?
-
[解決済み] Haskell タプルをリスト化する?
-
[解決済み] Haskell における `mod` と `rem` の違い
-
[解決済み] Haskellにおける "リフティング "とは?
-
[解決済み] Haskellのマルチコアプログラミングはどうなっているのか?
-
[解決済み] Haskellでメモ化?
-
[解決済み] TLSサーバーを実装するためのHsOpenSSL APIの適切な使用法
-
[解決済み] Haskell型とデータコンストラクタ