| Safe Haskell | None |
|---|
Control.Proxy.TCP.TLS.Safe
Contents
Description
This module exports functions that allow you to use TLS-secured
TCP connections as Proxy streams, as well as utilities to connect to a
TLS-enabled TCP server or running your own, possibly within the pipeline
itself by relying on the facilities provided by ExceptionP from the
pipes-safe library.
If you don't need to establish new TLS connections within your pipeline, then consider using the simpler and similar functions exported by Control.Proxy.TCP.TLS.
This module re-exports many functions and types from Network.Simple.TCP.TLS
module in the network-simple package. You might refer to that module for
more documentation.
- connect :: (Proxy p, Monad m) => (forall x. SafeIO x -> m x) -> ClientSettings -> HostName -> ServiceName -> ((Context, SockAddr) -> ExceptionP p a' a b' b m r) -> ExceptionP p a' a b' b m r
- data ClientSettings
- getDefaultClientSettings :: IO ClientSettings
- makeClientSettings :: [Credential] -> Maybe HostName -> CertificateStore -> ClientSettings
- connectReadS :: Proxy p => Maybe Int -> ClientSettings -> HostName -> ServiceName -> () -> Producer (ExceptionP p) ByteString SafeIO ()
- connectWriteD :: Proxy p => Maybe Int -> ClientSettings -> HostName -> ServiceName -> x -> ExceptionP p x ByteString x ByteString SafeIO r
- serve :: (Proxy p, Monad m) => (forall x. SafeIO x -> m x) -> ServerSettings -> HostPreference -> ServiceName -> ((Context, SockAddr) -> IO ()) -> ExceptionP p a' a b' b m r
- data ServerSettings
- makeServerSettings :: Credential -> Maybe CertificateStore -> ServerSettings
- listen :: (Proxy p, Monad m) => (forall x. SafeIO x -> m x) -> HostPreference -> ServiceName -> ((Socket, SockAddr) -> ExceptionP p a' a b' b m r) -> ExceptionP p a' a b' b m r
- accept :: (Proxy p, Monad m) => (forall x. SafeIO x -> m x) -> ServerSettings -> Socket -> ((Context, SockAddr) -> ExceptionP p a' a b' b m r) -> ExceptionP p a' a b' b m r
- acceptFork :: (Proxy p, Monad m) => (forall x. SafeIO x -> m x) -> ServerSettings -> Socket -> ((Context, SockAddr) -> IO ()) -> ExceptionP p a' a b' b m ThreadId
- serveReadS :: Proxy p => Maybe Int -> ServerSettings -> HostPreference -> ServiceName -> () -> Producer (ExceptionP p) ByteString SafeIO ()
- serveWriteD :: Proxy p => Maybe Int -> ServerSettings -> HostPreference -> ServiceName -> x -> ExceptionP p x ByteString x ByteString SafeIO r
- contextReadS :: Proxy p => Maybe Int -> Context -> () -> Producer (ExceptionP p) ByteString SafeIO ()
- contextWriteD :: Proxy p => Maybe Int -> Context -> x -> ExceptionP p x ByteString x ByteString SafeIO r
- withSocketsDo :: IO a -> IO a
- data HostPreference
- data Credential = Credential !X509 !PrivateKey [X509]
- data Timeout = Timeout String
Client side
Here's how you could run a simple TLS-secured TCP client:
import Control.Proxy.TCP.TLS.Safe settings <-getDefaultClientSettingsconnectsettings "www.example.org" "443" $ (tlsCtx, remoteAddr) -> do tryIO . putStrLn $ "Secure connection established to " ++ show remoteAddr -- now you may use tlsCtx as you please within this scope, possibly with -- thecontextReadSorcontextWriteDproxies explained below.
You might prefer to use the simpler but less general solutions offered by
connectReadS and connectWriteD, so check those too.
Arguments
| :: (Proxy p, Monad m) | |
| => (forall x. SafeIO x -> m x) | Monad morphism. |
| -> ClientSettings | TLS settings. |
| -> HostName | Server hostname. |
| -> ServiceName | Server service port. |
| -> ((Context, SockAddr) -> ExceptionP p a' a b' b m r) | Computation to run in a different thread once a TLS-secured connection is established. Takes the TLS connection context and remote end address. |
| -> ExceptionP p a' a b' b m r |
Connect to a TLS-secured TCP server and use the connection.
A TLS handshake is performed immediately after establishing the TCP connection.
The connection is properly closed when done or in case of exceptions. If you
need to manage the lifetime of the connection resources yourself, then use
connectTls instead.
data ClientSettings
Abstract type representing the configuration settings for a TLS client.
Use makeClientSettings or getDefaultClientSettings to obtain your
ClientSettings value.
getDefaultClientSettings :: IO ClientSettings
Get the system default ClientSettings.
See makeClientSettings for the for the default TLS settings used.
Arguments
| :: [Credential] | Credentials to provide to the server, if requested. The first one is used in case we can't choose one based on information provided by the server. |
| -> Maybe HostName | Explicit Server Name Identification (SNI). |
| -> CertificateStore | CAs used to verify the server certificate.
Use |
| -> ClientSettings |
Make defaults ClientSettings.
The following TLS settings are used by default:
- Supported versions
-
TLS10,TLS11,TLS12. - Version reported during ClientHello
-
TLS10. - Supported cipher suites
- In decreasing order of preference:
cipher_AES256_SHA256,cipher_AES256_SHA1,cipher_AES128_SHA256,cipher_AES128_SHA1,cipher_RC4_128_SHA1,cipher_RC4_128_MD5.
Streaming
The following proxies allow you to easily connect to a TLS-secured TCP server and immediately interact with it using streams, all at once, instead of having to perform the individual steps separately.
Arguments
| :: Proxy p | |
| => Maybe Int | Optional timeout in microseconds (1/10^6 seconds). |
| -> ClientSettings | TLS settings. |
| -> HostName | |
| -> ServiceName | Server service port. |
| -> () | |
| -> Producer (ExceptionP p) ByteString SafeIO () |
Connect to a TLS-secured TCP server and send downstream the decrypted bytes received from the remote end.
Up to 16384 decrypted bytes will be received at once. The TLS connection is
automatically renegotiated if a ClientHello message is received.
If an optional timeout is given and receiveing data from the remote end takes
more time that such timeout, then throw a Timeout exception in the
ExceptionP proxy transformer.
If the remote peer closes its side of the connection of EOF is reached, this proxy returns.
The connection is closed when done or in case of exceptions.
Arguments
| :: Proxy p | |
| => Maybe Int | Optional timeout in microseconds (1/10^6 seconds). |
| -> ClientSettings | TLS settings. |
| -> HostName | Server host name. |
| -> ServiceName | Server service port. |
| -> x | |
| -> ExceptionP p x ByteString x ByteString SafeIO r |
Connects to a TLS-secured TCP server, encrypts and sends to the remote end the bytes received from upstream, then forwards such same bytes downstream.
Requests from downstream are forwarded upstream.
If an optional timeout is given and sending data to the remote end takes
more time that such timeout, then throw a Timeout exception in the
ExceptionP proxy transformer.
The connection is properly closed when done or in case of exceptions.
Server side
Here's how you could run a simple TLS-secured TCP server that handles in
different threads each incoming connection to port 4433 at hostname
example.org. You will need a X509 certificate and a private key appropiate
to be used at that hostname.
import Control.Proxy.TCP.TLS.Safe import Network.TLS.Extra (fileReadCertificate, fileReadPrivateKey) cert <-fileReadCertificate"~/example.org.crt" pkey <-fileReadPrivateKey"~/example.org.key" let cred =Credentialcert pkey [] settings =makeServerSettingscred Nothingservesettings (Host"example.org") "4433" $ (tlsCtx, remoteAddr) -> do tryIO . putStrLn $ "Secure connection established from " ++ show remoteAddr -- now you may use tlsCtx as you please within this scope, possibly with -- thecontextReadSorcontextWriteDproxies explained below.
You might prefer to use the simpler but less general solutions offered by
serveReadS and serveWriteD, or if you need to control the way your
server runs, then you can use more advanced functions such as listen,
accept and acceptFork, so check those functions too.
Arguments
| :: (Proxy p, Monad m) | |
| => (forall x. SafeIO x -> m x) | Monad morphism. |
| -> ServerSettings | TLS settings. |
| -> HostPreference | Preferred host to bind. |
| -> ServiceName | Service port to bind. |
| -> ((Context, SockAddr) -> IO ()) | Computation to run in a different thread once an incomming connection is accepted and a TLS-secured communication is established. Takes the TLS connection context and remote end address. |
| -> ExceptionP p a' a b' b m r |
Start a TLS-secured TCP server that accepts incoming connections and handles each of them concurrently, in different threads.
A TLS handshake is performed immediately after establishing each TCP connection.
Any acquired network resources are properly closed and discarded when done or in case of exceptions.
Note: This function binds a listening socket, accepts an connection, performs a TLS handshake and then safely closes the connection. You don't need to perform any of those steps manually.
data ServerSettings
Abstract type representing the configuration settings for a TLS server.
Use makeServerSettings to obtain your ServerSettings value, and
updateServerParams to update it.
Arguments
| :: Credential | Server credential. |
| -> Maybe CertificateStore | CAs used to verify the client certificate. If specified, then a valid client certificate will be expected during on handshake. |
| -> ServerSettings |
Make default ServerSettings.
The following TLS settings are used by default:
- Supported versions
-
TLS10,TLS11,TLS12. - Supported cipher suites for
TLS10 -
In decreasing order of preference:
cipher_AES256_SHA256,cipher_AES256_SHA1,cipher_AES128_SHA256,cipher_AES128_SHA1,cipher_RC4_128_SHA1,cipher_RC4_128_MD5. The cipher suite preferred by the client is used. - Supported cipher suites for
TLS11andTLS12 -
In decreasing order of preference:
cipher_AES256_SHA256,cipher_AES256_SHA1,cipher_AES128_SHA256,cipher_AES128_SHA1. The cipher suite preferred by the client is used.
Listening
Arguments
| :: (Proxy p, Monad m) | |
| => (forall x. SafeIO x -> m x) | Monad morphism. |
| -> HostPreference | Preferred host to bind. |
| -> ServiceName | Service port to bind. |
| -> ((Socket, SockAddr) -> ExceptionP p a' a b' b m r) | Computation taking the listening socket and the address it's bound to. |
| -> ExceptionP p a' a b' b m r |
Bind a TCP listening socket and use it.
The listening socket is closed when done or in case of exceptions.
If you prefer to acquire and close the socket yourself, then use
bindSock and the listen and sClose functions from
Network.Socket instead.
Note: maxListenQueue is tipically 128, which is too small for high
performance servers. So, we use the maximum between maxListenQueue and
2048 as the default size of the listening queue.
Accepting
Arguments
| :: (Proxy p, Monad m) | |
| => (forall x. SafeIO x -> m x) | Monad morphism. |
| -> ServerSettings | TLS settings. |
| -> Socket | Listening and bound socket. |
| -> ((Context, SockAddr) -> ExceptionP p a' a b' b m r) | Computation to run once an incomming connection is accepted and a TLS-secured communication is established. Takes the TLS connection context and remote end address. |
| -> ExceptionP p a' a b' b m r |
Accept a single incoming TLS-secured TCP connection and use it.
A TLS handshake is performed immediately after establishing each TCP connection.
The connection properly closed when done or in case of exceptions.
Arguments
| :: (Proxy p, Monad m) | |
| => (forall x. SafeIO x -> m x) | Monad morphism. |
| -> ServerSettings | TLS settings. |
| -> Socket | Listening and bound socket. |
| -> ((Context, SockAddr) -> IO ()) | Computation to run in a different thread once an incomming connection is accepted and a TLS-secured communication is established. Takes the TLS connection context and remote end address. |
| -> ExceptionP p a' a b' b m ThreadId |
Like accept, except it uses a different thread to performs the TLS
handshake and run the given computation.
Streaming
The following proxies allow you to easily run a TLS-secured TCP server and immediately interact with incoming connections using streams, all at once, instead of having to perform the individual steps separately.
Arguments
| :: Proxy p | |
| => Maybe Int | Optional timeout in microseconds (1/10^6 seconds). |
| -> ServerSettings | TLS settings. |
| -> HostPreference | Preferred host to bind. |
| -> ServiceName | Service port to bind. |
| -> () | |
| -> Producer (ExceptionP p) ByteString SafeIO () |
Binds a listening TCP socket, accepts a single TLS-secured connection and sends downstream any decrypted bytes received from the remote end.
Up to 16384 decrypted bytes will be received at once. The TLS connection is
automatically renegotiated if a ClientHello message is received.
If an optional timeout is given and receiveing data from the remote end takes
more time that such timeout, then throw a Timeout exception in the
ExceptionP proxy transformer.
If the remote peer closes its side of the connection of EOF is reached, this proxy returns.
Both the listening and connection sockets are closed when done or in case of exceptions.
Arguments
| :: Proxy p | |
| => Maybe Int | Optional timeout in microseconds (1/10^6 seconds). |
| -> ServerSettings | TLS settings. |
| -> HostPreference | Preferred host to bind. |
| -> ServiceName | Service port to bind. |
| -> x | |
| -> ExceptionP p x ByteString x ByteString SafeIO r |
Binds a listening TCP socket, accepts a single TLS-secured connection, sends to the remote end the bytes received from upstream and then forwards such sames bytesdownstream.
Requests from downstream are forwarded upstream.
If an optional timeout is given and sending data to the remote end takes
more time that such timeout, then throw a Timeout exception in the
ExceptionP proxy transformer.
If the remote peer closes its side of the connection, this proxy returns.
Both the listening and connection sockets are closed when done or in case of exceptions.
Socket streams
Once you have a an established TLS Context, you can use the following
Proxys to interact with the other connection end using pipes streams.
Arguments
| :: Proxy p | |
| => Maybe Int | Optional timeout in microseconds (1/10^6 seconds). |
| -> Context | Established TLS connection context. |
| -> () | |
| -> Producer (ExceptionP p) ByteString SafeIO () |
Receives decrypted bytes from the remote end, sending them downstream.
Up to 16384 decrypted bytes will be received at once. The TLS connection is
automatically renegotiated if a ClientHello message is received.
If an optional timeout is given and receiveing data from the remote end takes
more time that such timeout, then throw a Timeout exception in the
ExceptionP proxy transformer.
If the remote peer closes its side of the connection or EOF is reached, this proxy returns.
Arguments
| :: Proxy p | |
| => Maybe Int | Optional timeout in microseconds (1/10^6 seconds). |
| -> Context | Established TLS connection context. |
| -> x | |
| -> ExceptionP p x ByteString x ByteString SafeIO r |
Encrypts and sends to the remote end the bytes received from upstream, then forwards such same bytes downstream.
If an optional timeout is given and sending data to the remote end takes
more time that such timeout, then throw a Timeout exception in the
ExceptionP proxy transformer.
If the remote peer closes its side of the connection, this proxy returns.
Requests from downstream are forwarded upstream.
Note to Windows users
If you are running Windows, then you must call withSocketsDo, just
once, right at the beginning of your program. That is, change your program's
main function from:
main = do print "Hello world" -- rest of the program...
To:
main = withSocketsDo $ do
print "Hello world"
-- rest of the program...
If you don't do this, your networking code won't work and you will get many unexpected errors at runtime. If you use an operating system other than Windows then you don't need to do this, but it is harmless to do it, so it's recommended that you do for portability reasons.
withSocketsDo :: IO a -> IO a
On Windows operating systems, the networking subsystem has to be
initialised using withSocketsDo before any networking operations can
be used. eg.
main = withSocketsDo $ do {...}
Although this is only strictly necessary on Windows platforms, it is harmless on other platforms, so for portability it is good practice to use it all the time.
Exports
data HostPreference
Preferred host to bind.
Constructors
| HostAny | Any available host. |
| HostIPv4 | Any available IPv4 host. |
| HostIPv6 | Any available IPv6 host. |
| Host HostName | An explicit host name. |
Instances
| Eq HostPreference | |
| Ord HostPreference | |
| Read HostPreference | |
| Show HostPreference | |
| IsString HostPreference | The following special values are recognized: |
data Credential
Primary certificate, private key and the rest of the certificate chain.
Constructors
| Credential !X509 !PrivateKey [X509] |
Instances