TLS Sunucusu uygulamak için HsOpenSSL API'sinin doğru kullanımı


141

Eşzamanlı bağlamda OpenSSL.Session API nasıl kullanılacağını anlamaya çalışıyorum

Örneğin, uygulamak istediğimi varsayalım stunnel-style ssl-wrapper, bir saf uygulayan aşağıdaki temel iskelet yapısına sahip olmayı beklerdimfull-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

Yukarıdaki iskeleti nasıl a'ya dönüştürebilirim full-duplex ssl-wrapping tcp-forwarding proxy? HsOpenSSL API tarafından sağlanan işlev çağrılarının WRT'nin eşzamanlı / paralel yürütülmesine (yukarıdaki kullanım durumu bağlamında) neden olduğu tehlikeler nelerdir?

PS: Hala istisnalar ve kaynak sızıntıları için kodu sağlam wrt nasıl tam olarak anlamak için mücadele ediyorum. Bu nedenle, bu sorunun birincil odağı olmasa da, yukarıdaki kodda kötü bir şey fark ederseniz, lütfen bir yorum bırakın.


11
Bence bu SO için çok geniş bir soru olabilir.
Don Stewart

1
Sana bu konuda geri döneceğim :-)
Abhineet

2
dokümanın bağlantısı kopuk, işte çalışan: hackage.haskell.org/packages/archive/HsOpenSSL/0.10.2/doc/html/…
Pascal Qyy

4
Benzer bir şey yaptım ( full-duplex ssl-rewrapping tcp-forwarding), ama bunun yerine Network.TLS(paket tls) kullandı. Ve çirkindi. Eğer ilgileniyorsanız, burada bulabilirsiniz .

Yanıtlar:


7

Bunu yapmak için copySocket, biri düz soketten SSL'ye, diğeri SSL'den düz sokete veri işlemek için iki farklı işlevle değiştirmeniz gerekir :

  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

Sonra connectToServerbir SSL bağlantısı kuracak şekilde değiştirmeniz gerekir

  -- |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

ve finalizeSSL oturumunu kapatmak için değiştirin

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

Son olarak, ana öğelerinizi içerideki withOpenSSLgibi çalıştırmayı unutmayın .

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

Bu zaten çok yardımcı oluyor; bu, stunnelsistemci moduna karşılık gelen bir yerel-ssl-uzak-ssl proxy'si sağlar , ayrıca yerel bir ssl soketinin nasıl dinleneceğine ilişkin bir örnek verebilir misiniz (örneğin, yerel-ssl-uzak-olmayan- ssl proxy)?
hvr
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.