hookup-0.8: Abstraction over creating network connections with SOCKS5 and TLS

Copyright | (c) Eric Mertens 2016
License | ISC
Maintainer | emertens@gmail.com
Safe Haskell | None
Language | Haskell2010

Hookup

Contents

- Connections
- Reading and writing data
- Configuration
- Errors
- SSL Information

Description

This module provides a uniform interface to network connections with optional support for TLS and SOCKS.

This library is careful to support both IPv4 and IPv6. It will attempt to all of the addresses that a domain name resolves to until one the first successful connection.

Use `connect` and `close` to establish and close network connections.

Use `recv`, `recvLine`, and `send` to receive and transmit data on an open network connection.

TLS and SOCKS parameters can be provided. When both are provided a connection will first be established to the SOCKS server and then the TLS connection will be established through that proxy server. This is most useful when connecting through a dynamic port forward of an SSH client via the `-D` flag.

Synopsis

- data Connection
- connect :: ConnectionParams -> IO Connection
- connectWithSocket :: ConnectionParams -> Socket -> IO Connection
- close :: Connection -> IO ()
- upgradeTls :: TlsParams -> String -> Connection -> IO ()
- recv :: Connection -> Int -> IO ByteString
- recvLine :: Connection -> Int -> IO (Maybe ByteString)
- send :: Connection -> ByteString -> IO ()
- putBuf :: Connection -> ByteString -> IO ()
- data ConnectionParams = ConnectionParams {
  - cpHost :: HostName
  - cpPort :: PortNumber
  - cpSocks :: Maybe SocksParams
  - cpTls :: Maybe TlsParams
  - cpBind :: Maybe HostName
  }
- data SocksParams = SocksParams {
  - spHost :: HostName
  - spPort :: PortNumber
  - spAuth :: SocksAuthentication
  }
- data SocksAuthentication
  - = NoSocksAuthentication
  - | UsernamePasswordSocksAuthentication ByteString ByteString
- data TlsParams = TlsParams {
  - tpClientCertificate :: Maybe FilePath
  - tpClientPrivateKey :: Maybe FilePath
  - tpClientPrivateKeyPassword :: Maybe ByteString
  - tpServerCertificate :: Maybe FilePath
  - tpCipherSuite :: String
  - tpCipherSuiteTls13 :: Maybe String
  - tpVerify :: TlsVerify
  }
- data TlsVerify
  - = VerifyDefault
  - | VerifyNone
  - | VerifyHostname String
- data PemPasswordSupply
  - = PwNone
  - | PwStr String
  - | PwBS ByteString
  - | PwCallback PemPasswordCallback
  - | PwTTY
- defaultTlsParams :: TlsParams
- data ConnectionFailure
  - = HostnameResolutionFailure HostName String
  - | ConnectionFailure [ConnectError]
  - | LineTooLong
  - | LineTruncated
  - | SocksError CommandReply
  - | SocksAuthenticationMethodRejected
  - | SocksAuthenticationCredentialsRejected
  - | SocksBadAuthenticationCredentials
  - | SocksProtocolError
  - | SocksBadDomainName
- newtype CommandReply where
  - CommandReply Word8
  - pattern Succeeded :: CommandReply
  - pattern GeneralFailure :: CommandReply
  - pattern NotAllowed :: CommandReply
  - pattern NetUnreachable :: CommandReply
  - pattern HostUnreachable :: CommandReply
  - pattern ConnectionRefused :: CommandReply
  - pattern TTLExpired :: CommandReply
  - pattern CmdNotSupported :: CommandReply
  - pattern AddrNotSupported :: CommandReply
- getClientCertificate :: Connection -> IO (Maybe X509)
- getPeerCertificate :: Connection -> IO (Maybe X509)
- getPeerCertFingerprintSha1 :: Connection -> IO (Maybe ByteString)
- getPeerCertFingerprintSha256 :: Connection -> IO (Maybe ByteString)
- getPeerCertFingerprintSha512 :: Connection -> IO (Maybe ByteString)
- getPeerPubkeyFingerprintSha1 :: Connection -> IO (Maybe ByteString)
- getPeerPubkeyFingerprintSha256 :: Connection -> IO (Maybe ByteString)
- getPeerPubkeyFingerprintSha512 :: Connection -> IO (Maybe ByteString)

# Connections

data Connection Source #

A connection to a network service along with its read buffer used for line-oriented protocols. The connection could be a plain network connection, SOCKS connected, or TLS.

connect Source #

Arguments

:: ConnectionParams | parameters
-> IO Connection | open connection

Open network connection to TCP service specified by the given parameters.

The resulting connection MUST be closed with `close` to avoid leaking resources.

Throws `IOError`, `SocksError`, `ProtocolError`, `ConnectionFailure`

connectWithSocket Source #

Arguments

:: ConnectionParams | parameters
-> Socket | connected socket
-> IO Connection | open connection

Create a new `Connection` using an already connected socket. This will attempt to start TLS if configured but will ignore any SOCKS server settings as it is assumed that the socket is already actively connected to the intended service.

Throws `ProtocolError`

close Source #

Arguments

:: Connection | open connection
-> IO () |

Close network connection.

upgradeTls Source #

Arguments

:: TlsParams | connection params
-> String | hostname
-> Connection |
-> IO () |

# Reading and writing data

recv Source #

Arguments

:: Connection | open connection
-> Int | maximum underlying recv size
-> IO ByteString | next chunk from stream

Receive the next chunk from the stream. This operation will first return the buffer if it contains a non-empty chunk. Otherwise it will request up to the requested number of bytes from the stream.

Throws: `IOError`, `ConnectionAbruptlyTerminated`, `ProtocolError`

recvLine Source #

Arguments

:: Connection | open connection
-> Int | maximum line length
-> IO (Maybe ByteString) | next line or end-of-stream

Receive a line from the network connection. Both `"\r\n"` and `"\n"` are recognized.

Returning `Nothing` means that the peer has closed its half of the connection.

Unterminated lines will raise a `LineTruncated` exception. This can happen if the peer transmits some data and closes its end without transmitting a line terminator.

Throws: `ConnectionAbruptlyTerminated`, `ProtocolError`, `ConnectionFailure`, `IOError`

send Source #

Arguments

:: Connection | open connection
-> ByteString | chunk
-> IO () |

Send bytes on the network connection. This ensures the whole chunk is transmitted, which might take multiple underlying sends.

Throws: `IOError`, `ProtocolError`

putBuf Source #

Arguments

:: Connection | connection
-> ByteString | new head of buffer
-> IO () |

Push a `ByteString` onto the buffer so that it will be the first bytes to be read on the next receive operation. This could perhaps be useful for putting the unused portion of a `recv` back into the buffer for future `recvLine` or `recv` operations.

# Configuration

data ConnectionParams Source #

Parameters for `connect`.

Common defaults for fields: `defaultFamily`, `defaultTlsParams`

When a `SocksParams` is provided the connection will be established using a SOCKS (version 5) proxy.

When a `TlsParams` is provided the connection negotiate TLS at connect time in order to protect the stream.

The binding hostname can be used to force the connect to use a particular interface or IP protocol version.

Constructors

ConnectionParams |

Fields

- cpHost :: HostName

  Destination host

- cpPort :: PortNumber

  Destination TCP port

- cpSocks :: Maybe SocksParams

  Optional SOCKS parameters

- cpTls :: Maybe TlsParams

  Optional TLS parameters

- cpBind :: Maybe HostName

  Source address to bind

#### Instances

Instances details

Show ConnectionParams Source # |
Instance details Defined in Hookup Methods showsPrec :: Int -> ConnectionParams -> ShowS Source # show :: ConnectionParams -> String Source # showList :: [ConnectionParams] -> ShowS Source #

data SocksParams Source #

SOCKS connection parameters

Constructors

SocksParams |

Fields

- spHost :: HostName

  SOCKS server host

- spPort :: PortNumber

  SOCKS server port

- spAuth :: SocksAuthentication

  SOCKS authentication method

#### Instances

Instances details

Show SocksParams Source # |
Instance details Defined in Hookup Methods showsPrec :: Int -> SocksParams -> ShowS Source # show :: SocksParams -> String Source # showList :: [SocksParams] -> ShowS Source #

data SocksAuthentication Source #

Constructors

NoSocksAuthentication | no credentials
UsernamePasswordSocksAuthentication ByteString ByteString | RFC 1929 username and password

#### Instances

Instances details

Show SocksAuthentication Source # |
Instance details Defined in Hookup Methods showsPrec :: Int -> SocksAuthentication -> ShowS Source # show :: SocksAuthentication -> String Source # showList :: [SocksAuthentication] -> ShowS Source #

data TlsParams Source #

TLS connection parameters. These parameters are passed to OpenSSL when making a secure connection.

Constructors

TlsParams |

Fields

- tpClientCertificate :: Maybe FilePath

  Path to client certificate

- tpClientPrivateKey :: Maybe FilePath

  Path to client private key

- tpClientPrivateKeyPassword :: Maybe ByteString

  Private key decryption password

- tpServerCertificate :: Maybe FilePath

  Path to CA certificate bundle

- tpCipherSuite :: String

  OpenSSL cipher suite name (e.g. `"HIGH"`)

- tpCipherSuiteTls13 :: Maybe String

  OpenSSL cipher suites for TLS 1.3

- tpVerify :: TlsVerify

  Hostname to use when checking certificate validity

#### Instances

Instances details

Show TlsParams Source # |
Instance details Defined in Hookup Methods showsPrec :: Int -> TlsParams -> ShowS Source # show :: TlsParams -> String Source # showList :: [TlsParams] -> ShowS Source #

data TlsVerify Source #

Constructors

VerifyDefault | Use the connection hostname to verify
VerifyNone | No verification
VerifyHostname String | Use the given hostname to verify

#### Instances

Instances details

Show TlsVerify Source # |
Instance details Defined in Hookup Methods showsPrec :: Int -> TlsVerify -> ShowS Source # show :: TlsVerify -> String Source # showList :: [TlsVerify] -> ShowS Source #

data PemPasswordSupply Source #

``PemPasswordSupply`` represents a way to supply password.

FIXME: using PwTTY causes an error but I don't know why: "error:0906406D:PEM routines:DEF_CALLBACK:problems getting password"

Constructors

PwNone | no password
PwStr String | password in a static string
PwBS ByteString | password in a static bytestring.
PwCallback PemPasswordCallback | get a password by a callback
PwTTY | read a password from TTY

defaultTlsParams :: TlsParams Source #

Default values for TLS that use no client certificates, use system CA root, `"HIGH"` cipher suite, and which validate hostnames.

# Errors

data ConnectionFailure Source #

Type for errors that can be thrown by this package.

Constructors

HostnameResolutionFailure HostName String | Failure during `getAddrInfo` resolving remote host
ConnectionFailure [ConnectError] | Failure during `connect` to remote host
LineTooLong | Failure during `recvLine`
LineTruncated | Incomplete line during `recvLine`
SocksError CommandReply | Socks command rejected by server by given reply code
SocksAuthenticationMethodRejected | Socks authentication method was not accepted
SocksAuthenticationCredentialsRejected | Socks authentication method was not accepted
SocksBadAuthenticationCredentials | Username or password were too long
SocksProtocolError | Socks server sent an invalid message or no message.
SocksBadDomainName | Domain name was too long for SOCKS protocol

#### Instances

Instances details

Exception ConnectionFailure Source # | `displayException` implemented for prettier messages
Instance details Defined in Hookup Methods toException :: ConnectionFailure -> SomeException Source # fromException :: SomeException -> Maybe ConnectionFailure Source # displayException :: ConnectionFailure -> String Source # backtraceDesired :: ConnectionFailure -> Bool Source #
Show ConnectionFailure Source # |
Instance details Defined in Hookup Methods showsPrec :: Int -> ConnectionFailure -> ShowS Source # show :: ConnectionFailure -> String Source # showList :: [ConnectionFailure] -> ShowS Source #

newtype CommandReply Source #

SOCKS command reply codes

Constructors

CommandReply Word8 |

Bundled Patterns

pattern Succeeded :: CommandReply |
pattern GeneralFailure :: CommandReply |
pattern NotAllowed :: CommandReply |
pattern NetUnreachable :: CommandReply |
pattern HostUnreachable :: CommandReply |
pattern ConnectionRefused :: CommandReply |
pattern TTLExpired :: CommandReply |
pattern CmdNotSupported :: CommandReply |
pattern AddrNotSupported :: CommandReply |

#### Instances

Instances details

Show CommandReply Source # |
Instance details Defined in Hookup.Socks5 Methods showsPrec :: Int -> CommandReply -> ShowS Source # show :: CommandReply -> String Source # showList :: [CommandReply] -> ShowS Source #
Eq CommandReply Source # |
Instance details Defined in Hookup.Socks5 Methods (==) :: CommandReply -> CommandReply -> Bool Source # (/=) :: CommandReply -> CommandReply -> Bool Source #

# SSL Information

getClientCertificate :: Connection -> IO (Maybe X509) Source #

Get peer certificate if one exists.

getPeerCertificate :: Connection -> IO (Maybe X509) Source #

Get peer certificate if one exists.

getPeerCertFingerprintSha1 :: Connection -> IO (Maybe ByteString) Source #

getPeerCertFingerprintSha256 :: Connection -> IO (Maybe ByteString) Source #

getPeerCertFingerprintSha512 :: Connection -> IO (Maybe ByteString) Source #

getPeerPubkeyFingerprintSha1 :: Connection -> IO (Maybe ByteString) Source #

getPeerPubkeyFingerprintSha256 :: Connection -> IO (Maybe ByteString) Source #

getPeerPubkeyFingerprintSha512 :: Connection -> IO (Maybe ByteString) Source #