{-# LANGUAGE DeriveDataTypeable #-} -- | -- Module : Network.Socks5.Types -- License : BSD-style -- Maintainer : Vincent Hanquez -- Stability : experimental -- Portability : unknown module Network.Socks5.Types ( SocksVersion(..) , SocksCommand(..) , SocksMethod(..) , SocksHostAddress(..) , SocksAddress(..) , SocksReply(..) , SocksVersionNotSupported(..) , SocksError(..) ) where 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 Numeric (showHex) import Data.List (intersperse) -- | Socks Version data SocksVersion = SocksVer5 deriving (Show,Eq,Ord) -- | Command that can be send and receive on the SOCKS protocol data SocksCommand = SocksCommandConnect | SocksCommandBind | SocksCommandUdpAssociate | SocksCommandOther !Word8 deriving (Show,Eq,Ord) -- | Authentication methods available on the SOCKS protocol. -- -- Only SocksMethodNone is effectively implemented, but -- other value are enumerated for completeness. data SocksMethod = SocksMethodNone | SocksMethodGSSAPI | SocksMethodUsernamePassword | SocksMethodOther !Word8 | SocksMethodNotAcceptable deriving (Show,Eq,Ord) -- | A Host address on the SOCKS protocol. data SocksHostAddress = SocksAddrIPV4 !HostAddress | SocksAddrDomainName !ByteString | SocksAddrIPV6 !HostAddress6 deriving (Eq,Ord) instance Show SocksHostAddress where show (SocksAddrIPV4 ha) = "SocksAddrIPV4(" ++ showHostAddress ha ++ ")" show (SocksAddrIPV6 ha6) = "SocksAddrIPV6(" ++ showHostAddress6 ha6 ++ ")" show (SocksAddrDomainName dn) = "SocksAddrDomainName(" ++ BC.unpack dn ++ ")" -- | Converts a HostAddress to a String in dot-decimal notation showHostAddress :: HostAddress -> String showHostAddress num = concat [show q1, ".", show q2, ".", show q3, ".", show q4] where (num',q1) = num `quotRem` 256 (num'',q2) = num' `quotRem` 256 (num''',q3) = num'' `quotRem` 256 (_,q4) = num''' `quotRem` 256 -- | Converts a IPv6 HostAddress6 to standard hex notation showHostAddress6 :: HostAddress6 -> String showHostAddress6 (a,b,c,d) = (concat . intersperse ":" . map (flip showHex "")) [p1,p2,p3,p4,p5,p6,p7,p8] where (a',p2) = a `quotRem` 65536 (_,p1) = a' `quotRem` 65536 (b',p4) = b `quotRem` 65536 (_,p3) = b' `quotRem` 65536 (c',p6) = c `quotRem` 65536 (_,p5) = c' `quotRem` 65536 (d',p8) = d `quotRem` 65536 (_,p7) = d' `quotRem` 65536 -- | Describe a Socket address on the SOCKS protocol data SocksAddress = SocksAddress !SocksHostAddress !PortNumber deriving (Show,Eq,Ord) -- | Type of reply on the SOCKS protocol data SocksReply = SocksReplySuccess | SocksReplyError SocksError deriving (Show,Eq,Ord,Data,Typeable) -- | SOCKS error that can be received or sent data SocksError = SocksErrorGeneralServerFailure | SocksErrorConnectionNotAllowedByRule | SocksErrorNetworkUnreachable | SocksErrorHostUnreachable | SocksErrorConnectionRefused | SocksErrorTTLExpired | SocksErrorCommandNotSupported | SocksErrorAddrTypeNotSupported | SocksErrorOther Word8 deriving (Show,Eq,Ord,Data,Typeable) -- | Exception returned when using a SOCKS version that is not supported. -- -- This package only implement version 5. 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 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 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 (SocksReplyError e) = fromEnum e toEnum 0 = SocksReplySuccess toEnum n = SocksReplyError (toEnum n)