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
SocksMethod
r <- SocksVersion -> Socket -> [SocksMethod] -> IO SocksMethod
establish (SocksConf -> SocksVersion
socksVersion SocksConf
serverConf) Socket
sock [SocksMethod
SocksMethodNone]
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (SocksMethod
r SocksMethod -> SocksMethod -> Bool
forall a. Eq a => a -> a -> Bool
== SocksMethod
SocksMethodNotAcceptable) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
[Char] -> IO ()
forall a. HasCallStack => [Char] -> a
error [Char]
"cannot connect with no socks method of authentication"
Socket -> Connect -> IO (SocksHostAddress, PortNumber)
forall a.
Command a =>
Socket -> a -> IO (SocksHostAddress, PortNumber)
rpc_ Socket
sock (SocksAddress -> Connect
Connect SocksAddress
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)
(SocksHostAddress, PortNumber)
ret <- Socket
-> SocksConf -> SocksAddress -> IO (SocksHostAddress, PortNumber)
socksConnectWithSocket Socket
sock SocksConf
serverConf SocksAddress
destAddr
(Socket, (SocksHostAddress, PortNumber))
-> IO (Socket, (SocksHostAddress, PortNumber))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Socket
sock, (SocksHostAddress, PortNumber)
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)
(SocksHostAddress
_, PortNumber
_) <- Socket
-> SocksConf -> SocksAddress -> IO (SocksHostAddress, PortNumber)
socksConnectWithSocket Socket
sock SocksConf
sockConf SocksAddress
addr
() -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
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