gpt4 book ai didi

haskell - 正确使用 HsOpenSSL API 来实现 TLS 服务器

转载 作者:太空宇宙 更新时间:2023-11-03 12:36:32 24 4
gpt4 key购买 nike

我正在尝试弄清楚如何正确使用 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:我仍在努力完全理解如何使代码健壮 w.r.t.异常和资源泄漏。因此,尽管这不是这个问题的主要焦点,但如果您发现上面的代码有问题,请发表评论。

最佳答案

为此,您需要将 copySocket 替换为两个不同的函数,一个用于处理从普通套接字到 SSL 的数据,另一个用于处理从 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 session

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 - 正确使用 HsOpenSSL API 来实现 TLS 服务器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8241821/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com