diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -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:
diff --git a/network-simple-tls.cabal b/network-simple-tls.cabal
--- a/network-simple-tls.cabal
+++ b/network-simple-tls.cabal
@@ -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
 
diff --git a/src/Network/Simple/TCP/TLS.hs b/src/Network/Simple/TCP/TLS.hs
--- a/src/Network/Simple/TCP/TLS.hs
+++ b/src/Network/Simple/TCP/TLS.hs
@@ -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.
