module Network.Socks5
(
SocksAddress (..)
, SocksHostAddress (..)
, SocksReply (..)
, SocksError (..)
, SocksConf (..)
, socksHost
, defaultSocksConf
, defaultSocksConfFromSockAddr
, socksConnectWithSocket
, socksConnect
, socksConnectName
) where
import Control.Exception ( bracketOnError )
import Control.Monad ( when )
import Data.ByteString.Char8 ( pack )
import Network.Socket
( close, Socket, SocketType(..), Family(..), socket, connect
, PortNumber, defaultProtocol
)
import Network.Socks5.Command ( Connect (..), establish, rpc_ )
import Network.Socks5.Conf
( SocksConf (..), defaultSocksConf
, defaultSocksConfFromSockAddr, socksHost
)
import Network.Socks5.Types
( SocksAddress (..), SocksError (..), SocksHostAddress (..)
, SocksMethod (..), SocksReply (..)
)
socksConnectWithSocket ::
Socket
-> SocksConf
-> SocksAddress
-> IO (SocksHostAddress, PortNumber)
socksConnectWithSocket :: Socket
-> SocksConf -> SocksAddress -> IO (SocksHostAddress, PortNumber)
socksConnectWithSocket Socket
sock SocksConf
serverConf SocksAddress
destAddr = do
r <- SocksVersion -> Socket -> [SocksMethod] -> IO SocksMethod
establish (SocksConf -> SocksVersion
socksVersion SocksConf
serverConf) Socket
sock [SocksMethod
SocksMethodNone]
when (r == SocksMethodNotAcceptable) $
error "cannot connect with no socks method of authentication"
rpc_ sock (Connect destAddr)
socksConnect ::
SocksConf
-> SocksAddress
-> IO (Socket, (SocksHostAddress, PortNumber))
socksConnect :: SocksConf
-> SocksAddress -> IO (Socket, (SocksHostAddress, PortNumber))
socksConnect SocksConf
serverConf SocksAddress
destAddr =
IO Socket
-> (Socket -> IO ())
-> (Socket -> IO (Socket, (SocksHostAddress, PortNumber)))
-> IO (Socket, (SocksHostAddress, PortNumber))
forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracketOnError (Family -> SocketType -> ProtocolNumber -> IO Socket
socket Family
AF_INET SocketType
Stream ProtocolNumber
defaultProtocol) Socket -> IO ()
close ((Socket -> IO (Socket, (SocksHostAddress, PortNumber)))
-> IO (Socket, (SocksHostAddress, PortNumber)))
-> (Socket -> IO (Socket, (SocksHostAddress, PortNumber)))
-> IO (Socket, (SocksHostAddress, PortNumber))
forall a b. (a -> b) -> a -> b
$ \Socket
sock -> do
Socket -> SockAddr -> IO ()
connect Socket
sock (SocksConf -> SockAddr
socksServer SocksConf
serverConf)
ret <- Socket
-> SocksConf -> SocksAddress -> IO (SocksHostAddress, PortNumber)
socksConnectWithSocket Socket
sock SocksConf
serverConf SocksAddress
destAddr
return (sock, ret)
socksConnectName ::
Socket
-> SocksConf
-> String
-> PortNumber
-> IO ()
socksConnectName :: Socket -> SocksConf -> [Char] -> PortNumber -> IO ()
socksConnectName Socket
sock SocksConf
sockConf [Char]
destination PortNumber
port = do
Socket -> SockAddr -> IO ()
connect Socket
sock (SocksConf -> SockAddr
socksServer SocksConf
sockConf)
(_, _) <- Socket
-> SocksConf -> SocksAddress -> IO (SocksHostAddress, PortNumber)
socksConnectWithSocket Socket
sock SocksConf
sockConf SocksAddress
addr
return ()
where
addr :: SocksAddress
addr = SocksHostAddress -> PortNumber -> SocksAddress
SocksAddress (SocksFQDN -> SocksHostAddress
SocksAddrDomainName (SocksFQDN -> SocksHostAddress) -> SocksFQDN -> SocksHostAddress
forall a b. (a -> b) -> a -> b
$ [Char] -> SocksFQDN
pack [Char]
destination) PortNumber
port