File: Types.hs

package info (click to toggle)
haskell-socks 0.6.1-5
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 104 kB
  • sloc: haskell: 571; makefile: 2
file content (176 lines) | stat: -rw-r--r-- 6,139 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
{-# LANGUAGE DeriveDataTypeable #-}
-- |
-- Module      : Network.Socks5.Types
-- License     : BSD-style
-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
-- Stability   : experimental
-- Portability : unknown
module Network.Socks5.Types
    ( SocksVersion(..)
    , SocksCommand(..)
    , SocksMethod(..)
    , SocksHostAddress(..)
    , SocksAddress(..)
    , SocksReply(..)
    , SocksVersionNotSupported(..)
    , 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 as B
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 !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(" ++ 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
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)