network-simple-tls 0.3 → 0.3.1
raw patch · 3 files changed
+85/−24 lines, 3 filesdep +safe-exceptionsdep −exceptions
Dependencies added: safe-exceptions
Dependencies removed: exceptions
Files
- changelog.md +8/−0
- network-simple-tls.cabal +4/−4
- src/Network/Simple/TCP/TLS.hs +73/−20
changelog.md view
@@ -1,3 +1,11 @@+# Version 0.3.1++* Added SOCKS5 proxy support. See functions `connectOverSOCKS5` and+ `connectTlsOverSOCKS5`.++* Use `safe-exceptions`.++ # Version 0.3 * BREAKING CHANGE: Changed type of the following functions:
network-simple-tls.cabal view
@@ -1,5 +1,5 @@ name: network-simple-tls-version: 0.3+version: 0.3.1 synopsis: Simple interface to TLS secured network sockets. description: Simple interface to TLS secured network sockets. homepage: https://github.com/k0001/network-simple-tls@@ -23,15 +23,15 @@ exposed-modules: Network.Simple.TCP.TLS build-depends: base (>=4.5 && <5.0) , bytestring+ , data-default , network- , exceptions , network-simple+ , safe-exceptions , tls , transformers , x509- , x509-system , x509-store+ , x509-system , x509-validation- , data-default ghc-options: -Wall -O2
src/Network/Simple/TCP/TLS.hs view
@@ -10,7 +10,7 @@ -- in the @network-simple@ package. Consider using that module directly if you -- need a similar API without TLS support. ----- This module uses 'MonadIO' and 'C.MonadMask' extensively so that you can+-- This module uses 'MonadIO' and 'E.MonadMask' extensively so that you can -- reuse these functions in monads other than 'IO'. However, if you don't care -- about any of that, just pretend you are using the 'IO' monad all the time -- and everything will work as expected.@@ -31,6 +31,7 @@ -- * Client side , connect+ , connectOverSOCKS5 -- ** Client TLS Settings , ClientSettings , makeClientSettings@@ -47,6 +48,7 @@ , useTlsThenClose , useTlsThenCloseFork , connectTls+ , connectTlsOverSOCKS5 , acceptTls , makeClientContext , makeServerContext@@ -64,9 +66,8 @@ import Control.Concurrent (ThreadId, forkFinally)-import qualified Control.Exception as E+import qualified Control.Exception.Safe as E import Control.Monad-import qualified Control.Monad.Catch as C import Control.Monad.IO.Class (MonadIO, liftIO) import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as BL@@ -320,7 +321,7 @@ -- in case of exceptions. If you need to manage the lifetime of the connection -- resources yourself, then use 'acceptTls' instead. accept- :: (MonadIO m, C.MonadMask m)+ :: (MonadIO m, E.MonadMask m) => ServerSettings -- ^TLS settings. -> Socket -- ^Listening and bound socket. -> ((Context, SockAddr) -> m r)@@ -329,7 +330,7 @@ -- TLS-secured communication is established. Takes the -- TLS connection context and remote end address. -> m r-accept ss lsock k = C.bracket (acceptTls ss lsock)+accept ss lsock k = E.bracket (acceptTls ss lsock) (liftIO . T.contextClose . fst) (useTls k) @@ -359,19 +360,44 @@ -- in case of exceptions. If you need to manage the lifetime of the connection -- resources yourself, then use 'connectTls' instead. connect- :: (MonadIO m, C.MonadMask m)- => ClientSettings -- ^TLS settings.- -> HostName -- ^Server hostname.- -> ServiceName -- ^Server service port.+ :: (MonadIO m, E.MonadMask m)+ => ClientSettings -- ^ TLS settings.+ -> HostName -- ^ Server hostname.+ -> ServiceName -- ^ Destination server service port name or number. -> ((Context, SockAddr) -> m r)- -- ^Computation to run after establishing TLS-secured- -- TCP connection to the remote server. Takes the TLS- -- connection context and remote end address.+ -- ^ Computation to run after establishing TLS-secured TCP connection to the+ -- remote server. Takes the TLS connection context and remote end address. -> m r-connect cs host port k = C.bracket (connectTls cs host port)+connect cs host port k = E.bracket (connectTls cs host port) (liftIO . T.contextClose . fst) (useTls k) +-- | Like 'connect', but connects to the destination server over a SOCKS5 proxy.+connectOverSOCKS5+ :: (MonadIO m, E.MonadMask m)+ => HostName -- ^ SOCKS5 proxy server hostname or IP address.+ -> ServiceName -- ^ SOCKS5 proxy server service port name or number.+ -> ClientSettings -- ^ TLS settings.+ -> HostName+ -- ^ Destination server hostname or IP address. We connect to this host+ -- /through/ the SOCKS5 proxy specified in the previous arguments.+ --+ -- Note that if hostname resolution on this 'HostName' is necessary, it+ -- will happen on the proxy side for security reasons, not locally.+ -> ServiceName -- ^ Destination server service port name or number.+ -> ((Context, SockAddr, SockAddr) -> m r)+ -- ^ Computation to run after establishing TLS-secured TCP connection to the+ -- remote server. Takes the TLS connection that can be used to interact with+ -- the destination server, as well as the address of the SOCKS5 server and the+ -- address of the destination server, in that order.+ -> m r+connectOverSOCKS5 phn psn cs dhn dsn k = do+ E.bracket (connectTlsOverSOCKS5 phn psn cs dhn dsn)+ (\(ctx, _, _) -> liftIO (T.contextClose ctx))+ (\(ctx, paddr, daddr) ->+ useTls (\_ -> k (ctx, paddr, daddr))+ (ctx, paddr))+ -------------------------------------------------------------------------------- -- | Estalbishes a TCP connection to a remote server and returns a TLS@@ -387,9 +413,9 @@ -- 'useTlsThenCloseFork' can help you with that. connectTls :: MonadIO m- => ClientSettings -- ^TLS settings.- -> HostName -- ^Server hostname.- -> ServiceName -- ^Service port to bind.+ => ClientSettings -- ^ TLS settings.+ -> HostName -- ^ Server hostname.+ -> ServiceName -- ^ Server service name or port number. -> m (Context, SockAddr) connectTls cs host port = liftIO $ do E.bracketOnError@@ -399,6 +425,33 @@ ctx <- makeClientContext cs sock return (ctx, addr)) +-- | Like 'connectTls', but connects to the destination server over a SOCKS5+-- proxy.+connectTlsOverSOCKS5+ :: MonadIO m+ => HostName -- ^ SOCKS5 proxy server hostname or IP address.+ -> ServiceName -- ^ SOCKS5 proxy server service port name or number.+ -> ClientSettings -- ^ TLS settings.+ -> HostName+ -- ^ Destination server hostname or IP address. We connect to this host+ -- /through/ the SOCKS5 proxy specified in the previous arguments.+ --+ -- Note that if hostname resolution on this 'HostName' is necessary, it+ -- will happen on the proxy side for security reasons, not locally.+ -> ServiceName -- ^ Destination server service port name or number.+ -> m (Context, SockAddr, SockAddr)+ -- ^ Returns the 'Context' that can be used to interact with the destination+ -- server, as well as the address of the SOCKS5 server and the address of the+ -- destination server, in that order.+connectTlsOverSOCKS5 phn psn cs dhn dsn = liftIO $ do+ E.bracketOnError+ (S.connectSock phn psn)+ (S.closeSock . fst)+ (\(psock, paddr) -> do+ daddr <- S.connectSockSOCKS5 psock dhn dsn+ ctx <- makeClientContext cs psock+ return (ctx, paddr, daddr))+ -- | Make a client-side TLS 'Context' for the given settings, on top of the -- given TCP `Socket` connected to the remote end. makeClientContext :: MonadIO m => ClientSettings -> Socket -> m Context@@ -446,20 +499,20 @@ -- Prefer to use `useTlsThenClose` or `useTlsThenCloseFork` if you need that -- behavior. Otherwise, you must call `T.contextClose` yourself at some point. useTls- :: (MonadIO m, C.MonadMask m)+ :: (MonadIO m, E.MonadMask m) => ((Context, SockAddr) -> m a) -> ((Context, SockAddr) -> m a)-useTls k conn@(ctx,_) = C.bracket_ (T.handshake ctx)+useTls k conn@(ctx,_) = E.bracket_ (T.handshake ctx) (liftIO $ silentBye ctx) (k conn) -- | Like 'useTls', except it also fully closes the TCP connection when done. useTlsThenClose- :: (MonadIO m, C.MonadMask m)+ :: (MonadIO m, E.MonadMask m) => ((Context, SockAddr) -> m a) -> ((Context, SockAddr) -> m a) useTlsThenClose k conn@(ctx,_) = do- useTls k conn `C.finally` liftIO (T.contextClose ctx)+ useTls k conn `E.finally` liftIO (T.contextClose ctx) -- | Similar to 'useTlsThenClose', except it performs the all the IO actions -- in a new thread.