packages feed

socks 0.5.4 → 0.6.1

raw patch · 10 files changed

Files

Example.hs view
@@ -1,9 +1,10 @@ {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeApplications #-} import Network.Socks5-import Network.Socket hiding (recv)+import Network.Socket hiding (recv, close) import Network.Socket.ByteString+import Network.Socket (close) import Network.BSD-import Network import Data.ByteString.Char8 () import qualified Data.ByteString.Char8 as BC @@ -24,34 +25,22 @@     example1 socksServerAddr destinationName     example2 socksServerAddr destinationName -    example3 serverName serverPort destinationName 80-   where         -- connect to @destName on port 80 through the socks server         -- www.google.com get resolve on the client here and then the sockaddr is         -- passed to socksConnectAddr         example1 socksServerAddr destName = do-            socket <- socket AF_INET Stream defaultProtocol-            -            gHost <- getHostByName destName-            let destinationAddr = SockAddrInet 80 (head $ hostAddresses gHost)-            socksConnectAddr socket socksServerAddr destinationAddr+            (socket, _) <- socksConnect (defaultSocksConf socksServerAddr)+                        (SocksAddress (SocksAddrDomainName $ BC.pack destName) 80)              sendAll socket "GET / HTTP/1.0\r\n\r\n"             recv socket 4096 >>= putStrLn . show-            sClose socket+            close socket         -- connect to @destName on port 80 through the socks server         -- the server is doing the resolution itself         example2 socksServerAddr destName = do             socket <- socket AF_INET Stream defaultProtocol-            socksConnectName socket socksServerAddr destName 80+            socksConnectName socket (defaultSocksConf socksServerAddr) destName 80             sendAll socket "GET / HTTP/1.0\r\n\r\n"             recv socket 4096 >>= putStrLn . show-            sClose socket--        example3 sname sport dname dport = do    -            handle <- socksConnectTo sname (PortNumber sport) dname (PortNumber dport)-            BC.hPut handle "GET / HTTP/1.0\r\n\r\n"-            hFlush handle-            BC.hGet handle 1024 >>= putStrLn . show-            hClose handle+            close socket
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2010-2011 Vincent Hanquez <vincent@snarc.org>+Copyright (c) 2010-2019 Vincent Hanquez <vincent@snarc.org>  All rights reserved. 
Network/Socks5.hs view
@@ -33,30 +33,24 @@     , socksConnectWithSocket     , socksConnect     -- * Variants-    , socksConnectAddr     , socksConnectName-    , socksConnectTo-    , socksConnectWith     ) where  import Control.Monad import Control.Exception import qualified Data.ByteString.Char8 as BC-import Network.Socket ( sClose, Socket, SocketType(..), SockAddr(..), Family(..)-                      , socket, socketToHandle, connect)-import Network.BSD-import Network (PortID(..))+import Network.Socket ( close, Socket, SocketType(..), Family(..)+                      , socket, connect, PortNumber, defaultProtocol)  import qualified Network.Socks5.Command as Cmd import Network.Socks5.Conf import Network.Socks5.Types import Network.Socks5.Lowlevel -import System.IO---- | connect a user specified new socket to the socks server,--- and connect the stream on the server side to the 'SockAddress' specified.+-- | connect a user specified new socket on the socks server to a destination --+-- The socket in parameter needs to be already connected to the socks server+-- -- |socket|-----sockServer----->|server|----destAddr----->|destination| -- socksConnectWithSocket :: Socket       -- ^ Socket to use.@@ -64,9 +58,7 @@                        -> 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]+    r <- Cmd.establish (socksVersion serverConf) sock [SocksMethodNone]     when (r == SocksMethodNotAcceptable) $ error "cannot connect with no socks method of authentication"     Cmd.rpc_ sock (Connect destAddr) @@ -76,56 +68,22 @@              -> 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+    bracketOnError (socket AF_INET Stream defaultProtocol) close $ \sock -> do+        connect sock (socksServer serverConf)         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.+-- | connect a new socket to the socks server, and connect the stream to a FQDN+-- resolved on the server side. ----- a unix sockaddr will raises an exception.+-- The socket needs to *not* be already connected. ----- |socket|-----sockServer----->|server|----destAddr----->|destination|-{-# DEPRECATED socksConnectAddr "use socksConnectWithSocket" #-}-socksConnectAddr :: Socket -> SockAddr -> SockAddr -> IO ()-socksConnectAddr sock sockserver destaddr =-    socksConnectWithSocket sock-                           (defaultSocksConfFromSockAddr sockserver)-                           (socksServer $ defaultSocksConfFromSockAddr destaddr) >>+-- The destination need to be an ASCII string, otherwise unexpected behavior will ensue.+-- For unicode destination, punycode encoding should be used.+socksConnectName :: Socket -> SocksConf -> String -> PortNumber -> IO ()+socksConnectName sock sockConf destination port = do+    connect sock (socksServer sockConf)+    (_,_) <- socksConnectWithSocket sock sockConf addr     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 = 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.-socksConnectWith :: SocksConf -- ^ SOCKS configuration-                 -> String    -- ^ destination hostname-                 -> PortID    -- ^ destination port-                 -> IO Socket-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--resolvePortID (Service serv) = getServicePortNumber serv-resolvePortID (PortNumber n) = return n-resolvePortID _              = error "unsupported unix PortID"+  where+    addr = SocksAddress (SocksAddrDomainName $ BC.pack destination) port
Network/Socks5/Command.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE CPP #-} -- | -- Module      : Network.Socks5.Command@@ -22,11 +23,11 @@     , waitSerialized     ) where -import Control.Applicative-import Control.Exception+import Basement.Compat.Base import Data.ByteString (ByteString) import qualified Data.ByteString as B import qualified Data.ByteString.Char8 as BC+import qualified Prelude import Data.Serialize  import Network.Socket (Socket, PortNumber, HostAddress, HostAddress6)@@ -35,8 +36,8 @@ import Network.Socks5.Types import Network.Socks5.Wire -establish :: Socket -> [SocksMethod] -> IO SocksMethod-establish socket methods = do+establish :: SocksVersion -> Socket -> [SocksMethod] -> IO SocksMethod+establish SocksVer5 socket methods = do     sendAll socket (encode $ SocksHello methods)     getSocksHelloResponseMethod <$> runGetDone get (recv socket 4096) @@ -54,7 +55,7 @@     toRequest (Connect (SocksAddress ha port)) = SocksRequest             { requestCommand  = SocksCommandConnect             , requestDstAddr  = ha-            , requestDstPort  = fromIntegral port+            , requestDstPort  = Prelude.fromIntegral port             }     fromRequest req         | requestCommand req /= SocksCommandConnect = Nothing@@ -72,7 +73,7 @@  -- TODO: FQDN should only be ascii, maybe putting a "fqdn" data type -- in front to make sure and make the BC.pack safe.-connectDomainName :: Socket -> String -> PortNumber -> IO (SocksHostAddress, PortNumber)+connectDomainName :: Socket -> [Char] -> PortNumber -> IO (SocksHostAddress, PortNumber) connectDomainName socket fqdn port = rpc_ socket $ Connect $ SocksAddress (SocksAddrDomainName $ BC.pack fqdn) port  sendSerialized :: Serialize a => Socket -> a -> IO ()@@ -87,7 +88,7 @@     onReply <$> runGetDone get (getMore socket)     where onReply res@(responseReply -> reply) =                 case reply of-                    SocksReplySuccess -> Right (responseBindAddr res, fromIntegral $ responseBindPort res)+                    SocksReplySuccess -> Right (responseBindAddr res, Prelude.fromIntegral $ responseBindPort res)                     SocksReplyError e -> Left e  rpc_ :: Command a => Socket -> a -> IO (SocksHostAddress, PortNumber)
Network/Socks5/Conf.hs view
@@ -9,43 +9,32 @@ 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+import Network.Socks5.Types (SocksVersion(..)) --- | SOCKS configuration structure.+-- | SOCKS identification and 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+    { socksServer  :: SockAddr     -- ^ Address of server     , 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+socksHost :: SocksConf -> SockAddr+socksHost conf = 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+defaultSocksConf :: SockAddr -> SocksConf+defaultSocksConf host = SocksConf host SocksVer5 --- | same as defaultSocksConf except the server address is determined from a 'SockAddr'+-- | same as defaultSocksConf. ----- 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"+-- soft deprecation: use 'defaultSocksConf"+defaultSocksConfFromSockAddr = defaultSocksConf
Network/Socks5/Lowlevel.hs view
@@ -1,25 +1,14 @@ module Network.Socks5.Lowlevel-    ( resolveToSockAddr-    , socksListen+    ( 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
+ Network/Socks5/Parse.hs view
@@ -0,0 +1,221 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE OverloadedStrings #-}+-- |+-- Module      : Network.Socks5.Parse+-- License     : BSD-style+-- Maintainer  : Vincent Hanquez <vincent@snarc.org>+-- Stability   : experimental+-- Portability : portable+--+-- A very simple bytestring parser related to Parsec and Attoparsec+--+-- Simple example:+--+-- > > parse ((,) <$> take 2 <*> byte 0x20 <*> (bytes "abc" *> anyByte)) "xx abctest"+-- > ParseOK "est" ("xx", 116)+--+module Network.Socks5.Parse+    ( Parser+    , Result(..)+    -- * run the Parser+    , parse+    , parseFeed+    -- * Parser methods+    , byte+    , anyByte+    , bytes+    , take+    , takeWhile+    , takeAll+    , skip+    , skipWhile+    , skipAll+    , takeStorable+    ) where++import Control.Applicative+import Control.Monad+import Data.ByteString (ByteString)+import qualified Data.ByteString as B+import qualified Data.ByteString.Internal as B (toForeignPtr)+import Data.Word+import Foreign.Storable (Storable, peekByteOff, sizeOf)+import Foreign.ForeignPtr (withForeignPtr)+import Prelude hiding (take, takeWhile)++import System.IO.Unsafe (unsafePerformIO)++-- | Simple parsing result, that represent respectively:+--+-- * failure: with the error message+--+-- * continuation: that need for more input data+--+-- * success: the remaining unparsed data and the parser value+data Result a =+      ParseFail String+    | ParseMore (ByteString -> Result a)+    | ParseOK   ByteString a++instance Show a => Show (Result a) where+    show (ParseFail err) = "ParseFailure: " ++ err+    show (ParseMore _)   = "ParseMore _"+    show (ParseOK b a)   = "ParseOK " ++ show a ++ " " ++ show b++type Failure r = ByteString -> String -> Result r+type Success a r = ByteString -> a -> Result r++-- | Simple ByteString parser structure+newtype Parser a = Parser+    { runParser :: forall r . ByteString -> Failure r -> Success a r -> Result r }++instance Monad Parser where+    return v = Parser $ \buf _ ok -> ok buf v+    m >>= k = Parser $ \buf err ok ->+         runParser m buf err (\buf' a -> runParser (k a) buf' err ok)+#if MIN_VERSION_base(4,13,0)+instance MonadFail Parser where+#endif+    fail errorMsg = Parser $ \buf err _ -> err buf ("failed: " ++ errorMsg)+instance MonadPlus Parser where+    mzero = fail "Parser.MonadPlus.mzero"+    mplus f g = Parser $ \buf err ok ->+        -- rewrite the err callback of @f to call @g+        runParser f buf (\_ _ -> runParser g buf err ok) ok+instance Functor Parser where+    fmap f p = Parser $ \buf err ok ->+        runParser p buf err (\b a -> ok b (f a))+instance Applicative Parser where+    pure      = return+    (<*>) d e = d >>= \b -> e >>= \a -> return (b a)+instance Alternative Parser where+    empty = fail "Parser.Alternative.empty"+    (<|>) = mplus++-- | Run a parser on an @initial ByteString.+--+-- If the Parser need more data than available, the @feeder function+-- is automatically called and fed to the More continuation.+parseFeed :: Monad m => m B.ByteString -> Parser a -> B.ByteString -> m (Result a)+parseFeed feeder p initial = loop $ parse p initial+  where loop (ParseMore k) = feeder >>= (loop . k)+        loop r             = return r++-- | Run a Parser on a ByteString and return a 'Result'+parse :: Parser a -> ByteString -> Result a+parse p s = runParser p s (\_ msg -> ParseFail msg) (\b a -> ParseOK b a)++------------------------------------------------------------+getMore :: Parser ()+getMore = Parser $ \buf err ok -> ParseMore $ \nextChunk ->+    if B.null nextChunk+        then err buf "EOL: need more data"+        else ok (B.append buf nextChunk) ()++getAll :: Parser ()+getAll = Parser $ \buf err ok -> ParseMore $ \nextChunk ->+    if B.null nextChunk+        then ok buf ()+        else runParser getAll (B.append buf nextChunk) err ok++flushAll :: Parser ()+flushAll = Parser $ \buf err ok -> ParseMore $ \nextChunk ->+    if B.null nextChunk+        then ok buf ()+        else runParser getAll B.empty err ok++------------------------------------------------------------++-- | Get the next byte from the parser+anyByte :: Parser Word8+anyByte = Parser $ \buf err ok ->+    case B.uncons buf of+        Nothing      -> runParser (getMore >> anyByte) buf err ok+        Just (c1,b2) -> ok b2 c1++-- | Parse a specific byte at current position+--+-- if the byte is different than the expected on,+-- this parser will raise a failure.+byte :: Word8 -> Parser ()+byte w = Parser $ \buf err ok ->+    case B.uncons buf of+        Nothing      -> runParser (getMore >> byte w) buf err ok+        Just (c1,b2) | c1 == w   -> ok b2 ()+                     | otherwise -> err buf ("byte " ++ show w ++ " : failed")++-- | Parse a sequence of bytes from current position+--+-- if the following bytes don't match the expected+-- bytestring completely, the parser will raise a failure+bytes :: ByteString -> Parser ()+bytes allExpected = consumeEq allExpected+  where errMsg = "bytes " ++ show allExpected ++ " : failed"++        -- partially consume as much as possible or raise an error.+        consumeEq expected = Parser $ \actual err ok ->+            let eLen = B.length expected in+            if B.length actual >= eLen+                then    -- enough data for doing a full match+                        let (aMatch,aRem) = B.splitAt eLen actual+                         in if aMatch == expected+                                then ok aRem ()+                                else err actual errMsg+                else    -- not enough data, match as much as we have, and then recurse.+                        let (eMatch, eRem) = B.splitAt (B.length actual) expected+                         in if actual == eMatch+                                then runParser (getMore >> consumeEq eRem) B.empty err ok+                                else err actual errMsg++------------------------------------------------------------++-- | Take a storable from the current position in the stream+takeStorable :: Storable d+             => Parser d+takeStorable = anyStorable undefined+  where+    anyStorable :: Storable d => d -> Parser d+    anyStorable a = do+        (fptr, off, _) <- B.toForeignPtr <$> take (sizeOf a)+        return $ unsafePerformIO $ withForeignPtr fptr $ \ptr -> peekByteOff ptr off++-- | Take @n bytes from the current position in the stream+take :: Int -> Parser ByteString+take n = Parser $ \buf err ok ->+    if B.length buf >= n+        then let (b1,b2) = B.splitAt n buf in ok b2 b1+        else runParser (getMore >> take n) buf err ok++-- | Take bytes while the @predicate hold from the current position in the stream+takeWhile :: (Word8 -> Bool) -> Parser ByteString+takeWhile predicate = Parser $ \buf err ok ->+    case B.span predicate buf of+        (_, b2) | B.null b2 -> runParser (getMore >> takeWhile predicate) buf err ok+        (b1, b2) -> ok b2 b1++-- | Take the remaining bytes from the current position in the stream+takeAll :: Parser ByteString+takeAll = Parser $ \buf err ok ->+    runParser (getAll >> returnBuffer) buf err ok+  where+    returnBuffer = Parser $ \buf _ ok -> ok B.empty buf++-- | Skip @n bytes from the current position in the stream+skip :: Int -> Parser ()+skip n = Parser $ \buf err ok ->+    if B.length buf >= n+        then ok (B.drop n buf) ()+        else runParser (getMore >> skip (n - B.length buf)) B.empty err ok++-- | Skip bytes while the @predicate hold from the current position in the stream+skipWhile :: (Word8 -> Bool) -> Parser ()+skipWhile p = Parser $ \buf err ok ->+    case B.span p buf of+        (_, b2) | B.null b2 -> runParser (getMore >> skipWhile p) B.empty err ok+        (_, b2) -> ok b2 ()++-- | Skip all the remaining bytes from the current position in the stream+skipAll :: Parser ()+skipAll = Parser $ \buf err ok -> runParser flushAll buf err ok
Network/Socks5/Types.hs view
@@ -16,12 +16,14 @@     , SocksError(..)     ) where +import qualified Basement.String as UTF8+import           Basement.Compat.IsList import Data.ByteString (ByteString) import Data.Word import Data.Data import Network.Socket (HostAddress, HostAddress6, PortNumber) import Control.Exception-import qualified Data.ByteString.Char8 as BC+import qualified Data.ByteString as B import Numeric (showHex) import Data.List (intersperse) @@ -52,14 +54,20 @@ -- | A Host address on the SOCKS protocol. data SocksHostAddress =       SocksAddrIPV4 !HostAddress-    | SocksAddrDomainName !ByteString+    | SocksAddrDomainName !FQDN     | SocksAddrIPV6 !HostAddress6     deriving (Eq,Ord) +type FQDN = ByteString+ instance Show SocksHostAddress where     show (SocksAddrIPV4 ha)       = "SocksAddrIPV4(" ++ showHostAddress ha ++ ")"     show (SocksAddrIPV6 ha6)      = "SocksAddrIPV6(" ++ showHostAddress6 ha6 ++ ")"-    show (SocksAddrDomainName dn) = "SocksAddrDomainName(" ++ BC.unpack dn ++ ")"+    show (SocksAddrDomainName dn) = "SocksAddrDomainName(" ++ showFQDN dn ++ ")"++-- | Converts a FQDN to a String+showFQDN :: FQDN -> String+showFQDN bs = toList $ fst $ UTF8.fromBytesLenient $ fromList $ B.unpack bs  -- | Converts a HostAddress to a String in dot-decimal notation showHostAddress :: HostAddress -> String
Network/Socks5/Wire.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE NoImplicitPrelude #-} -- | -- Module      : Network.Socks5.Wire -- License     : BSD-style@@ -12,10 +13,11 @@     , SocksResponse(..)     ) where -import Control.Applicative+import Basement.Compat.Base import Control.Monad import qualified Data.ByteString as B import Data.Serialize+import qualified Prelude  import Network.Socket (PortNumber) @@ -45,66 +47,78 @@     } deriving (Show,Eq)  getAddr 1 = SocksAddrIPV4 <$> getWord32host-getAddr 3 = SocksAddrDomainName <$> (getWord8 >>= getByteString . fromIntegral)+getAddr 3 = SocksAddrDomainName <$> (getLength8 >>= getByteString) getAddr 4 = SocksAddrIPV6 <$> (liftM4 (,,,) getWord32host getWord32host getWord32host getWord32host)-getAddr n = error ("cannot get unknown socket address type: " ++ show n)+getAddr n = error ("cannot get unknown socket address type: " <> show n)  putAddr (SocksAddrIPV4 h)         = putWord8 1 >> putWord32host h-putAddr (SocksAddrDomainName b)   = putWord8 3 >> putWord8 (fromIntegral $ B.length b) >> putByteString b+putAddr (SocksAddrDomainName b)   = putWord8 3 >> putLength8 (B.length b) >> putByteString b putAddr (SocksAddrIPV6 (a,b,c,d)) = putWord8 4 >> mapM_ putWord32host [a,b,c,d] +putEnum8 :: Enum e => e -> Put+putEnum8 = putWord8 . Prelude.fromIntegral . fromEnum++getEnum8 :: Enum e => Get e+getEnum8 = toEnum . Prelude.fromIntegral <$> getWord8++putLength8 :: Int -> Put+putLength8 = putWord8 . Prelude.fromIntegral++getLength8 :: Get Int+getLength8 = Prelude.fromIntegral <$> getWord8+ getSocksRequest 5 = do-    cmd <- toEnum . fromIntegral <$> getWord8+    cmd <- getEnum8     _   <- getWord8     addr <- getWord8 >>= getAddr-    port <- fromIntegral <$> getWord16be+    port <- Prelude.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+    reply <- getEnum8     _     <- getWord8     addr <- getWord8 >>= getAddr-    port <- fromIntegral <$> getWord16be+    port <- Prelude.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+        putLength8 (Prelude.length ms)+        mapM_ putEnum8 ms     get = do         v <- getWord8         case v of-            5 -> getWord8 >>= flip replicateM (toEnum . fromIntegral <$> getWord8) . fromIntegral >>= return . SocksHello+            5 -> SocksHello <$> (getLength8 >>= flip replicateM getEnum8)             _ -> error "unsupported sock hello version"  instance Serialize SocksHelloResponse where-    put (SocksHelloResponse m) = putWord8 5 >> putWord8 (fromIntegral $ fromEnum $ m)+    put (SocksHelloResponse m) = putWord8 5 >> putEnum8 m     get = do         v <- getWord8         case v of-            5 -> SocksHelloResponse . toEnum . fromIntegral <$> getWord8+            5 -> SocksHelloResponse <$> getEnum8             _ -> error "unsupported sock hello response version"  instance Serialize SocksRequest where     put req = do         putWord8 5-        putWord8 $ fromIntegral $ fromEnum $ requestCommand req+        putEnum8 $ requestCommand req         putWord8 0         putAddr $ requestDstAddr req-        putWord16be $ fromIntegral $ requestDstPort req+        putWord16be $ Prelude.fromIntegral $ requestDstPort req              get = getWord8 >>= getSocksRequest  instance Serialize SocksResponse where     put req = do         putWord8 5-        putWord8 $ fromIntegral $ fromEnum $ responseReply req+        putEnum8 $ responseReply req         putWord8 0         putAddr $ responseBindAddr req-        putWord16be $ fromIntegral $ responseBindPort req+        putWord16be $ Prelude.fromIntegral $ responseBindPort req     get = getWord8 >>= getSocksResponse
socks.cabal view
@@ -1,31 +1,34 @@ Name:                socks-Version:             0.5.4+Version:             0.6.1+Synopsis:            Socks proxy (ver 5) Description:         Socks proxy (version 5) implementation. License:             BSD3 License-file:        LICENSE Copyright:           Vincent Hanquez <vincent@snarc.org> Author:              Vincent Hanquez <vincent@snarc.org> Maintainer:          Vincent Hanquez <vincent@snarc.org>-Synopsis:            Socks proxy (version 5) implementation. Build-Type:          Simple Category:            Network stability:           experimental-Cabal-Version:       >=1.6+Cabal-Version:       1.18 Homepage:            http://github.com/vincenthz/hs-socks-data-files:          README.md, Example.hs+extra-doc-files:     README.md, Example.hs  Library   Build-Depends:     base >= 3 && < 5                    , bytestring                    , cereal >= 0.3.1-                   , network >= 2.3+                   , network >= 2.6+                   , basement   Exposed-modules:   Network.Socks5                      Network.Socks5.Lowlevel                      Network.Socks5.Types   Other-modules:     Network.Socks5.Wire                      Network.Socks5.Conf                      Network.Socks5.Command+                     Network.Socks5.Parse   ghc-options:       -Wall -fno-warn-missing-signatures -fwarn-tabs+  default-language:  Haskell2010  source-repository head   type: git