packages feed

socks 0.4.2 → 0.5.0

raw patch · 7 files changed

+387/−239 lines, 7 files

Files

Network/Socks5.hs view
@@ -7,42 +7,76 @@ -- Stability   : experimental -- Portability : unknown --+-- This is an implementation of SOCKS5 as defined in RFC 1928+--+-- In Wikipedia's words:+--+--   SOCKet Secure (SOCKS) is an Internet protocol that routes network packets+--   between a client and server through a proxy server. SOCKS5 additionally+--   provides authentication so only authorized users may access a server.+--   Practically, a SOCKS server will proxy TCP connections to an arbitrary IP+--   address as well as providing a means for UDP packets to be forwarded.+--+-- BIND and UDP ASSOCIATE messages are not implemented.+-- However main usage of SOCKS is covered in this implementation.+-- module Network.Socks5-	( SocksConf(..)-	, defaultSocksConf-	, socksConnectAddr-	, socksConnectName-	, socksConnectTo-	, socksConnectWith-	) where+    (+    -- * Types+      SocksAddress(..)+    , SocksHostAddress(..)+    , SocksReply(..)+    , SocksError(..)+    -- * Configuration+    , module Network.Socks5.Conf+    -- * Methods+    , socksConnectWithSocket+    , socksConnect+    -- * Variants+    , socksConnectAddr+    , socksConnectName+    , socksConnectTo+    , socksConnectWith+    ) where  import Control.Monad import Control.Exception+import qualified Data.ByteString.Char8 as BC import Network.Socket import Network.BSD-import Network.Socks5.Command+import qualified Network.Socks5.Command as Cmd+import Network.Socks5.Conf import Network.Socks5.Types+import Network.Socks5.Lowlevel import Network import System.IO --- | SOCKS configuration structure.--- this structure will be extended in future to support authentification.--- use defaultSocksConf to create new record.-data SocksConf = SocksConf-	{ socksHost    :: String     -- ^ SOCKS host.-	, socksPort    :: PortNumber -- ^ SOCKS port.-	, socksVersion :: Int        -- ^ SOCKS version to use, only 5 supported for now.-	}---- | defaultSocksConf create a new record, making sure--- API remains compatible when the record is extended.-defaultSocksConf host port = SocksConf host port 5+-- | connect a user specified new socket to the socks server,+-- and connect the stream on the server side to the 'SockAddress' specified.+--+-- |socket|-----sockServer----->|server|----destAddr----->|destination|+--+socksConnectWithSocket :: Socket       -- ^ Socket to use.+                       -> SocksConf    -- ^ SOCKS configuration for the server.+                       -> SocksAddress -- ^ SOCKS Address to connect to.+                       -> IO (SocksHostAddress, PortNumber)+socksConnectWithSocket sock serverConf destAddr = do+    serverAddr <- resolveToSockAddr (socksServer serverConf)+    connect sock serverAddr+    r <- Cmd.establish sock [SocksMethodNone]+    when (r == SocksMethodNotAcceptable) $ error "cannot connect with no socks method of authentication"+    Cmd.rpc_ sock (Connect destAddr) -withSocks sock sockaddr f = do-	connect sock sockaddr-	r <- socks5Establish sock [SocksMethodNone]-	when (r == SocksMethodNotAcceptable) $ error "cannot connect with no socks method of authentication"-	f+-- | connect a new socket to a socks server and connect the stream on the+-- server side to the 'SocksAddress' specified.+socksConnect :: SocksConf    -- ^ SOCKS configuration for the server.+             -> SocksAddress -- ^ SOCKS Address to connect to.+             -> IO (Socket, (SocksHostAddress, PortNumber))+socksConnect serverConf destAddr =+    getProtocolNumber "tcp" >>= \proto ->+    bracketOnError (socket AF_INET Stream proto) sClose $ \sock -> do+        ret <- socksConnectWithSocket sock serverConf destAddr+        return (sock, ret)  -- | connect a new socket to the socks server, and connect the stream on the server side -- to the sockaddr specified. the sockaddr need to be SockAddrInet or SockAddrInet6.@@ -50,19 +84,22 @@ -- a unix sockaddr will raises an exception. -- -- |socket|-----sockServer----->|server|----destAddr----->|destination|+{-# DEPRECATED socksConnectAddr "use socksConnectWithSocket" #-} socksConnectAddr :: Socket -> SockAddr -> SockAddr -> IO ()-socksConnectAddr sock sockserver destaddr = withSocks sock sockserver $ do-	case destaddr of-		SockAddrInet p h      -> socks5ConnectIPV4 sock h p >> return ()-		SockAddrInet6 p _ h _ -> socks5ConnectIPV6 sock h p >> return ()-		_                     -> error "unsupported unix sockaddr type"+socksConnectAddr sock sockserver destaddr =+    socksConnectWithSocket sock+                           (defaultSocksConfFromSockAddr sockserver)+                           (socksServer $ defaultSocksConfFromSockAddr destaddr) >>+    return ()  -- | connect a new socket to the socks server, and connect the stream to a FQDN -- resolved on the server side. socksConnectName :: Socket -> SockAddr -> String -> PortNumber -> IO ()-socksConnectName sock sockserver destination port = withSocks sock sockserver $ do-	_ <- socks5ConnectDomainName sock destination port-	return ()+socksConnectName sock sockserver destination port = do+    socksConnectWithSocket sock+                           (defaultSocksConfFromSockAddr sockserver)+                           (SocksAddress (SocksAddrDomainName $ BC.pack destination) port)+    >> return ()  -- | create a new socket and connect in to a destination through the specified -- SOCKS configuration.@@ -70,22 +107,21 @@                  -> String    -- ^ destination hostname                  -> PortID    -- ^ destination port                  -> IO Socket-socksConnectWith sockConf desthost destport = do-	dport <- resolvePortID destport-	proto <- getProtocolNumber "tcp"-	bracketOnError (socket AF_INET Stream proto) sClose $ \sock -> do-		he <- getHostByName $ socksHost sockConf-		let sockaddr = SockAddrInet (socksPort sockConf) (hostAddress he)-		socksConnectName sock sockaddr desthost dport-		return sock+socksConnectWith socksConf desthost destport = do+    dport <- resolvePortID destport+    proto <- getProtocolNumber "tcp"+    bracketOnError (socket AF_INET Stream proto) sClose $ \sock -> do+        sockaddr <- resolveToSockAddr (socksServer socksConf)+        socksConnectName sock sockaddr desthost dport+        return sock  -- | similar to Network connectTo but use a socks proxy with default socks configuration. socksConnectTo :: String -> PortID -> String -> PortID -> IO Handle socksConnectTo sockshost socksport desthost destport = do-	sport <- resolvePortID socksport-	let socksConf = defaultSocksConf sockshost sport-	sock <- socksConnectWith socksConf desthost destport-	socketToHandle sock ReadWriteMode+    sport <- resolvePortID socksport+    let socksConf = defaultSocksConf sockshost sport+    sock <- socksConnectWith socksConf desthost destport+    socketToHandle sock ReadWriteMode  resolvePortID (Service serv) = getServicePortNumber serv resolvePortID (PortNumber n) = return n
Network/Socks5/Command.hs view
@@ -8,13 +8,18 @@ -- Portability : unknown -- module Network.Socks5.Command-	( socks5Establish-	, socks5ConnectIPV4-	, socks5ConnectIPV6-	, socks5ConnectDomainName-	-- * lowlevel interface-	, socks5Rpc-	) where+    ( establish+    , Connect(..)+    , Command(..)+    , connectIPV4+    , connectIPV6+    , connectDomainName+    -- * lowlevel interface+    , rpc+    , rpc_+    , sendSerialized+    , waitSerialized+    ) where  import Control.Applicative import Control.Exception@@ -29,56 +34,73 @@ import Network.Socks5.Types import Network.Socks5.Wire -socks5Establish :: Socket -> [SocksMethod] -> IO SocksMethod-socks5Establish socket methods = do-	sendAll socket (encode $ SocksHello methods)-	getSocksHelloResponseMethod <$> runGetDone get (recv socket 4096)+establish :: Socket -> [SocksMethod] -> IO SocksMethod+establish socket methods = do+    sendAll socket (encode $ SocksHello methods)+    getSocksHelloResponseMethod <$> runGetDone get (recv socket 4096) -socks5ConnectIPV4 :: Socket -> HostAddress -> PortNumber -> IO (HostAddress, PortNumber)-socks5ConnectIPV4 socket hostaddr port = onReply <$> socks5Rpc socket request-	where-		request = SocksRequest-			{ requestCommand  = SocksCommandConnect-			, requestDstAddr  = SocksAddrIPV4 hostaddr-			, requestDstPort  = fromIntegral port-			}+newtype Connect = Connect SocksAddress deriving (Show,Eq) -		onReply (SocksAddrIPV4 h, p) = (h, p)-		onReply _                    = error "ipv4 requested, got something different"+class Command a where+    toRequest   :: a -> SocksRequest+    fromRequest :: SocksRequest -> Maybe a -socks5ConnectIPV6 :: Socket -> HostAddress6 -> PortNumber -> IO (HostAddress6, PortNumber)-socks5ConnectIPV6 socket hostaddr6 port = onReply <$> socks5Rpc socket request-	where-		request = SocksRequest-			{ requestCommand  = SocksCommandConnect-			, requestDstAddr  = SocksAddrIPV6 hostaddr6-			, requestDstPort  = fromIntegral port-			}-		onReply (SocksAddrIPV6 h, p) = (h, p)-		onReply _                    = error "ipv6 requested, got something different"+instance Command SocksRequest where+    toRequest   = id+    fromRequest = Just +instance Command Connect where+    toRequest (Connect (SocksAddress ha port)) = SocksRequest+            { requestCommand  = SocksCommandConnect+            , requestDstAddr  = ha+            , requestDstPort  = fromIntegral port+            }+    fromRequest req+        | requestCommand req /= SocksCommandConnect = Nothing+        | otherwise = Just $ Connect $ SocksAddress (requestDstAddr req) (requestDstPort req)++connectIPV4 :: Socket -> HostAddress -> PortNumber -> IO (HostAddress, PortNumber)+connectIPV4 socket hostaddr port = onReply <$> rpc_ socket (Connect $ SocksAddress (SocksAddrIPV4 hostaddr) port)+    where onReply (SocksAddrIPV4 h, p) = (h, p)+          onReply _                    = error "ipv4 requested, got something different"++connectIPV6 :: Socket -> HostAddress6 -> PortNumber -> IO (HostAddress6, PortNumber)+connectIPV6 socket hostaddr6 port = onReply <$> rpc_ socket (Connect $ SocksAddress (SocksAddrIPV6 hostaddr6) port)+    where onReply (SocksAddrIPV6 h, p) = (h, p)+          onReply _                    = error "ipv6 requested, got something different"+ -- TODO: FQDN should only be ascii, maybe putting a "fqdn" data type -- in front to make sure and make the BC.pack safe.-socks5ConnectDomainName :: Socket -> String -> PortNumber -> IO (SocksAddr, PortNumber)-socks5ConnectDomainName socket fqdn port = socks5Rpc socket $ SocksRequest-	{ requestCommand  = SocksCommandConnect-	, requestDstAddr  = SocksAddrDomainName $ BC.pack fqdn-	, requestDstPort  = fromIntegral port-	}+connectDomainName :: Socket -> String -> PortNumber -> IO (SocksHostAddress, PortNumber)+connectDomainName socket fqdn port = rpc_ socket $ Connect $ SocksAddress (SocksAddrDomainName $ BC.pack fqdn) port -socks5Rpc :: Socket -> SocksRequest -> IO (SocksAddr, PortNumber)-socks5Rpc socket req = do-	sendAll socket (encode req)-	onReply <$> runGetDone get (recv socket 4096)-	where onReply res@(responseReply -> reply)-		| reply /= SocksReplySuccess = throw $ SocksError reply-		| otherwise                 =-			(responseBindAddr res, fromIntegral $ responseBindPort res)+sendSerialized :: Serialize a => Socket -> a -> IO ()+sendSerialized sock a = sendAll sock $ encode a -runGetDone :: Show a => Get a -> IO ByteString -> IO a+waitSerialized :: Serialize a => Socket -> IO a+waitSerialized sock = runGetDone get (getMore sock)++rpc :: Command a => Socket -> a -> IO (Either SocksError (SocksHostAddress, PortNumber))+rpc socket req = do+    sendSerialized socket (toRequest req)+    onReply <$> runGetDone get (getMore socket)+    where onReply res@(responseReply -> reply) =+                case reply of+                    SocksReplySuccess -> Right (responseBindAddr res, fromIntegral $ responseBindPort res)+                    SocksReplyError e -> Left e++rpc_ :: Command a => Socket -> a -> IO (SocksHostAddress, PortNumber)+rpc_ socket req = rpc socket req >>= either throwIO return++-- this function expect all the data to be consumed. this is fine for intertwined message,+-- but might not be a good idea for multi messages from one party.+runGetDone :: Serialize a => Get a -> IO ByteString -> IO a runGetDone getter ioget = ioget >>= return . runGetPartial getter >>= r where-	r (Fail s)       = error s-	r (Partial cont) = ioget >>= r . cont-	r (Done a b)-		| not $ B.null b = error "got too many bytes while receiving data"-		| otherwise      = return a+    r (Fail s)       = error s+    r (Partial cont) = ioget >>= r . cont+    r (Done a b)+        | not $ B.null b = error "got too many bytes while receiving data"+        | otherwise      = return a++getMore :: Socket -> IO ByteString+getMore socket = recv socket 4096
+ Network/Socks5/Conf.hs view
@@ -0,0 +1,43 @@+module Network.Socks5.Conf+    ( SocksConf(..)+    , socksHost+    , socksPort+    , defaultSocksConf +    , defaultSocksConfFromSockAddr+    ) where++import Network.Socket+import Network.Socks5.Types (SocksAddress(..), SocksHostAddress(..), SocksVersion(..))+import qualified Data.ByteString.Char8 as BC++-- | SOCKS configuration structure.+-- this structure will be extended in future to support authentification.+-- use defaultSocksConf to create new record.+data SocksConf = SocksConf+    { socksServer  :: SocksAddress -- ^ SOCKS Address+    , socksVersion :: SocksVersion -- ^ SOCKS version to use+    }++-- | SOCKS Host+socksHost :: SocksConf -> SocksHostAddress+socksHost conf = ha where (SocksAddress ha _) = socksServer conf++-- | SOCKS Port+socksPort :: SocksConf -> PortNumber+socksPort conf = port where (SocksAddress _ port) = socksServer conf++-- | defaultSocksConf create a new record, making sure+-- API remains compatible when the record is extended.+defaultSocksConf host port = SocksConf server SocksVer5+    where server = SocksAddress haddr port+          haddr  = SocksAddrDomainName $ BC.pack host++-- | same as defaultSocksConf except the server address is determined from a 'SockAddr'+--+-- A unix SockAddr will raises an error. Only Inet and Inet6 types supported+defaultSocksConfFromSockAddr sockaddr = SocksConf server SocksVer5+    where server       = SocksAddress haddr port+          (haddr,port) = case sockaddr of+                             SockAddrInet p h      -> (SocksAddrIPV4 h, p)+                             SockAddrInet6 p _ h _ -> (SocksAddrIPV6 h, p)+                             _                     -> error "unsupported unix sockaddr type"
+ Network/Socks5/Lowlevel.hs view
@@ -0,0 +1,29 @@+module Network.Socks5.Lowlevel+    ( resolveToSockAddr+    , socksListen+    -- * lowlevel types+    , module Network.Socks5.Wire+    , module Network.Socks5.Command+    ) where++import Network.Socket+import Network.BSD+import Network.Socks5.Command+import Network.Socks5.Wire+import Network.Socks5.Types+import qualified Data.ByteString.Char8 as BC++resolveToSockAddr :: SocksAddress -> IO SockAddr+resolveToSockAddr (SocksAddress sockHostAddr port) =+    case sockHostAddr of+        SocksAddrIPV4 ha       -> return $ SockAddrInet port ha+        SocksAddrIPV6 ha6      -> return $ SockAddrInet6 port 0 ha6 0+        SocksAddrDomainName bs -> do he <- getHostByName (BC.unpack bs)+                                     return $ SockAddrInet port (hostAddress he)++socksListen :: Socket -> IO SocksRequest+socksListen sock = do+    hello <- waitSerialized sock+    case getSocksHelloMethods hello of+        _ -> do sendSerialized sock (SocksHelloResponse SocksMethodNone)+                waitSerialized sock
Network/Socks5/Types.hs view
@@ -6,109 +6,121 @@ -- Stability   : experimental -- Portability : unknown module Network.Socks5.Types-	( SocksCommand(..)-	, SocksMethod(..)-	, SocksAddr(..)-	, SocksReply(..)-	, SocksVersionNotSupported(..)-	, SocksError(..)-	) where+    ( SocksVersion(..)+    , SocksCommand(..)+    , SocksMethod(..)+    , SocksHostAddress(..)+    , SocksAddress(..)+    , SocksReply(..)+    , SocksVersionNotSupported(..)+    , SocksError(..)+    ) where  import Data.ByteString (ByteString) import Data.Word import Data.Data-import Network.Socket (HostAddress, HostAddress6)+import Network.Socket (HostAddress, HostAddress6, PortNumber) import Control.Exception +-- | Socks Version+data SocksVersion = SocksVer5+                  deriving (Show,Eq)+ data SocksCommand =-	  SocksCommandConnect-	| SocksCommandBind-	| SocksCommandUdpAssociate-	| SocksCommandOther Word8-	deriving (Show,Eq,Ord)+      SocksCommandConnect+    | SocksCommandBind+    | SocksCommandUdpAssociate+    | SocksCommandOther Word8+    deriving (Show,Eq,Ord)  data SocksMethod =-	  SocksMethodNone-	| SocksMethodGSSAPI-	| SocksMethodUsernamePassword-	| SocksMethodOther Word8-	| SocksMethodNotAcceptable-	deriving (Show,Eq,Ord)+      SocksMethodNone+    | SocksMethodGSSAPI+    | SocksMethodUsernamePassword+    | SocksMethodOther Word8+    | SocksMethodNotAcceptable+    deriving (Show,Eq,Ord) -data SocksAddr =-	  SocksAddrIPV4 HostAddress-	| SocksAddrDomainName ByteString-	| SocksAddrIPV6 HostAddress6-	deriving (Show,Eq)+data SocksHostAddress =+      SocksAddrIPV4 HostAddress+    | SocksAddrDomainName ByteString+    | SocksAddrIPV6 HostAddress6+    deriving (Show,Eq) +data SocksAddress = SocksAddress SocksHostAddress PortNumber+    deriving (Show,Eq)+ data SocksReply =-	  SocksReplySuccess-	| SocksReplyGeneralServerFailure-	| SocksReplyConnectionNotAllowedByRule-	| SocksReplyNetworkUnreachable-	| SocksReplyHostUnreachable-	| SocksReplyConnectionRefused-	| SocksReplyTTLExpired-	| SocksReplyCommandNotSupported-	| SocksReplyAddrTypeNotSupported-	| SocksReplyOther Word8-	deriving (Show,Eq,Ord,Data,Typeable)+      SocksReplySuccess+    | SocksReplyError SocksError+    deriving (Show,Eq,Ord,Data,Typeable) -data SocksVersionNotSupported = SocksVersionNotSupported-	deriving (Show,Data,Typeable)+data SocksError =+      SocksErrorGeneralServerFailure+    | SocksErrorConnectionNotAllowedByRule+    | SocksErrorNetworkUnreachable+    | SocksErrorHostUnreachable+    | SocksErrorConnectionRefused+    | SocksErrorTTLExpired+    | SocksErrorCommandNotSupported+    | SocksErrorAddrTypeNotSupported+    | SocksErrorOther Word8+    deriving (Show,Eq,Ord,Data,Typeable) -data SocksError = SocksError SocksReply-	deriving (Show,Eq,Data,Typeable)+data SocksVersionNotSupported = SocksVersionNotSupported+    deriving (Show,Data,Typeable)  instance Exception SocksError instance Exception SocksVersionNotSupported  instance Enum SocksCommand where-	toEnum 1 = SocksCommandConnect-	toEnum 2 = SocksCommandBind-	toEnum 3 = SocksCommandUdpAssociate-	toEnum w-		| w < 256   = SocksCommandOther $ fromIntegral w-		| otherwise = error "socks command is only 8 bits"-	fromEnum SocksCommandConnect      = 1-	fromEnum SocksCommandBind         = 2-	fromEnum SocksCommandUdpAssociate = 3-	fromEnum (SocksCommandOther w)    = fromIntegral w+    toEnum 1 = SocksCommandConnect+    toEnum 2 = SocksCommandBind+    toEnum 3 = SocksCommandUdpAssociate+    toEnum w+        | w < 256   = SocksCommandOther $ fromIntegral w+        | otherwise = error "socks command is only 8 bits"+    fromEnum SocksCommandConnect      = 1+    fromEnum SocksCommandBind         = 2+    fromEnum SocksCommandUdpAssociate = 3+    fromEnum (SocksCommandOther w)    = fromIntegral w  instance Enum SocksMethod where-	toEnum 0    = SocksMethodNone-	toEnum 1    = SocksMethodGSSAPI-	toEnum 2    = SocksMethodUsernamePassword-	toEnum 0xff = SocksMethodNotAcceptable-	toEnum w-		| w < 256   = SocksMethodOther $ fromIntegral w-		| otherwise = error "socks method is only 8 bits"-	fromEnum SocksMethodNone             = 0-	fromEnum SocksMethodGSSAPI           = 1-	fromEnum SocksMethodUsernamePassword = 2-	fromEnum (SocksMethodOther w)        = fromIntegral w-	fromEnum SocksMethodNotAcceptable    = 0xff+    toEnum 0    = SocksMethodNone+    toEnum 1    = SocksMethodGSSAPI+    toEnum 2    = SocksMethodUsernamePassword+    toEnum 0xff = SocksMethodNotAcceptable+    toEnum w+        | w < 256   = SocksMethodOther $ fromIntegral w+        | otherwise = error "socks method is only 8 bits"+    fromEnum SocksMethodNone             = 0+    fromEnum SocksMethodGSSAPI           = 1+    fromEnum SocksMethodUsernamePassword = 2+    fromEnum (SocksMethodOther w)        = fromIntegral w+    fromEnum SocksMethodNotAcceptable    = 0xff +instance Enum SocksError where+    fromEnum SocksErrorGeneralServerFailure       = 1+    fromEnum SocksErrorConnectionNotAllowedByRule = 2+    fromEnum SocksErrorNetworkUnreachable         = 3+    fromEnum SocksErrorHostUnreachable            = 4+    fromEnum SocksErrorConnectionRefused          = 5+    fromEnum SocksErrorTTLExpired                 = 6+    fromEnum SocksErrorCommandNotSupported        = 7+    fromEnum SocksErrorAddrTypeNotSupported       = 8+    fromEnum (SocksErrorOther w)                  = fromIntegral w+    toEnum 1 = SocksErrorGeneralServerFailure+    toEnum 2 = SocksErrorConnectionNotAllowedByRule+    toEnum 3 = SocksErrorNetworkUnreachable+    toEnum 4 = SocksErrorHostUnreachable+    toEnum 5 = SocksErrorConnectionRefused+    toEnum 6 = SocksErrorTTLExpired+    toEnum 7 = SocksErrorCommandNotSupported+    toEnum 8 = SocksErrorAddrTypeNotSupported+    toEnum w = SocksErrorOther $ fromIntegral w+ instance Enum SocksReply where-	fromEnum SocksReplySuccess                    = 0-	fromEnum SocksReplyGeneralServerFailure       = 1-	fromEnum SocksReplyConnectionNotAllowedByRule = 2-	fromEnum SocksReplyNetworkUnreachable         = 3-	fromEnum SocksReplyHostUnreachable            = 4-	fromEnum SocksReplyConnectionRefused          = 5-	fromEnum SocksReplyTTLExpired                 = 6-	fromEnum SocksReplyCommandNotSupported        = 7-	fromEnum SocksReplyAddrTypeNotSupported       = 8-	fromEnum (SocksReplyOther w)                  = fromIntegral w-	toEnum 0 = SocksReplySuccess-	toEnum 1 = SocksReplyGeneralServerFailure-	toEnum 2 = SocksReplyConnectionNotAllowedByRule-	toEnum 3 = SocksReplyNetworkUnreachable-	toEnum 4 = SocksReplyHostUnreachable-	toEnum 5 = SocksReplyConnectionRefused-	toEnum 6 = SocksReplyTTLExpired-	toEnum 7 = SocksReplyCommandNotSupported-	toEnum 8 = SocksReplyAddrTypeNotSupported-	toEnum w-		| w < 256   = SocksReplyOther $ fromIntegral w-		| otherwise = error "sock reply is only 8 bits"+    fromEnum SocksReplySuccess                    = 0+    fromEnum (SocksReplyError e)                  = fromEnum e+    toEnum 0 = SocksReplySuccess+    toEnum n = SocksReplyError (toEnum n)
Network/Socks5/Wire.hs view
@@ -6,11 +6,11 @@ -- Stability   : experimental -- Portability : unknown module Network.Socks5.Wire-	( SocksHello(..)-	, SocksHelloResponse(..)-	, SocksRequest(..)-	, SocksResponse(..)-	) where+    ( SocksHello(..)+    , SocksHelloResponse(..)+    , SocksRequest(..)+    , SocksResponse(..)+    ) where  import Control.Applicative import Control.Monad@@ -21,23 +21,28 @@  import Network.Socks5.Types +-- | Initial message sent by client with the list of authentification methods supported data SocksHello = SocksHello { getSocksHelloMethods :: [SocksMethod] }-	deriving (Show,Eq)+    deriving (Show,Eq) +-- | Initial message send by server in return from Hello, with the+-- server chosen method of authentication data SocksHelloResponse = SocksHelloResponse { getSocksHelloResponseMethod :: SocksMethod }-	deriving (Show,Eq)+    deriving (Show,Eq) +-- | Define a SOCKS requests data SocksRequest = SocksRequest-	{ requestCommand  :: SocksCommand-	, requestDstAddr  :: SocksAddr-	, requestDstPort  :: PortNumber-	} deriving (Show,Eq)+    { requestCommand  :: SocksCommand+    , requestDstAddr  :: SocksHostAddress+    , requestDstPort  :: PortNumber+    } deriving (Show,Eq) +-- | Define a SOCKS response data SocksResponse = SocksResponse-	{ responseReply    :: SocksReply-	, responseBindAddr :: SocksAddr-	, responseBindPort :: PortNumber-	} deriving (Show,Eq)+    { responseReply    :: SocksReply+    , responseBindAddr :: SocksHostAddress+    , responseBindPort :: PortNumber+    } deriving (Show,Eq)  getAddr 1 = SocksAddrIPV4 <$> getWord32be getAddr 3 = SocksAddrDomainName <$> (getWord8 >>= getByteString . fromIntegral)@@ -49,58 +54,57 @@ putAddr (SocksAddrIPV6 (a,b,c,d)) = putWord8 4 >> mapM_ putWord32host [a,b,c,d]  getSocksRequest 5 = do-	cmd <- toEnum . fromIntegral <$> getWord8-	_   <- getWord8-	addr <- getWord8 >>= getAddr-	port <- fromIntegral <$> getWord16be-	return $ SocksRequest cmd addr port+    cmd <- toEnum . fromIntegral <$> getWord8+    _   <- getWord8+    addr <- getWord8 >>= getAddr+    port <- fromIntegral <$> getWord16be+    return $ SocksRequest cmd addr port getSocksRequest v =-	error ("unsupported version of the protocol " ++ show v)+    error ("unsupported version of the protocol " ++ show v)  getSocksResponse 5 = do-	reply <- toEnum . fromIntegral <$> getWord8-	_     <- getWord8-	addr <- getWord8 >>= getAddr-	port <- fromIntegral <$> getWord16be-	return $ SocksResponse reply addr port+    reply <- toEnum . fromIntegral <$> getWord8+    _     <- getWord8+    addr <- getWord8 >>= getAddr+    port <- fromIntegral <$> getWord16be+    return $ SocksResponse reply addr port getSocksResponse v =-	error ("unsupported version of the protocol " ++ show v)+    error ("unsupported version of the protocol " ++ show v)  instance Serialize SocksHello where-	put (SocksHello ms) = do-		putWord8 5-		putWord8 $ fromIntegral $ length ms-		mapM_ (putWord8 . fromIntegral . fromEnum) ms-	get = do-		v <- getWord8-		case v of-			5 -> getWord8 >>= flip replicateM (toEnum . fromIntegral <$> getWord8) . fromIntegral >>= return . SocksHello-			_ -> error "unsupported sock hello version"+    put (SocksHello ms) = do+        putWord8 5+        putWord8 $ fromIntegral $ length ms+        mapM_ (putWord8 . fromIntegral . fromEnum) ms+    get = do+        v <- getWord8+        case v of+            5 -> getWord8 >>= flip replicateM (toEnum . fromIntegral <$> getWord8) . fromIntegral >>= return . SocksHello+            _ -> error "unsupported sock hello version"  instance Serialize SocksHelloResponse where-	put (SocksHelloResponse m) = putWord8 5 >> putWord8 (fromIntegral $ fromEnum $ m)-	get = do-		v <- getWord8-		case v of-			5 -> SocksHelloResponse . toEnum . fromIntegral <$> getWord8-			_ -> error "unsupported sock hello response version"+    put (SocksHelloResponse m) = putWord8 5 >> putWord8 (fromIntegral $ fromEnum $ m)+    get = do+        v <- getWord8+        case v of+            5 -> SocksHelloResponse . toEnum . fromIntegral <$> getWord8+            _ -> error "unsupported sock hello response version"  instance Serialize SocksRequest where-	put req = do-		putWord8 5-		putWord8 $ fromIntegral $ fromEnum $ requestCommand req-		putWord8 0-		putAddr $ requestDstAddr req-		putWord16be $ fromIntegral $ requestDstPort req-		-	get = getWord8 >>= getSocksRequest+    put req = do+        putWord8 5+        putWord8 $ fromIntegral $ fromEnum $ requestCommand req+        putWord8 0+        putAddr $ requestDstAddr req+        putWord16be $ fromIntegral $ requestDstPort req+        +    get = getWord8 >>= getSocksRequest  instance Serialize SocksResponse where-	put req = do-		putWord8 5-		putWord8 $ fromIntegral $ fromEnum $ responseReply req-		putWord8 0-		putAddr $ responseBindAddr req-		putWord16be $ fromIntegral $ responseBindPort req-	get = getWord8 >>= getSocksResponse-+    put req = do+        putWord8 5+        putWord8 $ fromIntegral $ fromEnum $ responseReply req+        putWord8 0+        putAddr $ responseBindAddr req+        putWord16be $ fromIntegral $ responseBindPort req+    get = getWord8 >>= getSocksResponse
socks.cabal view
@@ -1,5 +1,5 @@ Name:                socks-Version:             0.4.2+Version:             0.5.0 Description:         Socks proxy (version 5) implementation. License:             BSD3 License-file:        LICENSE@@ -20,8 +20,10 @@                    , cereal >= 0.3.1                    , network >= 2.3   Exposed-modules:   Network.Socks5-  Other-modules:     Network.Socks5.Wire+                     Network.Socks5.Lowlevel                      Network.Socks5.Types+  Other-modules:     Network.Socks5.Wire+                     Network.Socks5.Conf                      Network.Socks5.Command   ghc-options:       -Wall -fno-warn-missing-signatures