moesocks-0.1.0.3: src/Network/MoeSocks/BuilderAndParser.hs
module Network.MoeSocks.BuilderAndParser where
import Control.Lens
import Data.Attoparsec.ByteString
import Data.Monoid
import Data.Word
import Network.MoeSocks.Constant
import Network.MoeSocks.Helper
import Network.MoeSocks.Type
import Prelude hiding ((-), take)
import qualified Data.ByteString as S
import qualified Data.ByteString.Builder as B
socksVersion :: Word8
socksVersion = 5
socksHeader :: Parser Word8
socksHeader = word8 socksVersion
greetingParser :: Parser ClientGreeting
greetingParser = do
socksHeader
let maxNoOfMethods = 5
_numberOfAuthenticationMethods <- satisfy (<= maxNoOfMethods)
ClientGreeting <$>
count (fromIntegral _numberOfAuthenticationMethods) anyWord8
greetingReplyBuilder :: B.Builder
greetingReplyBuilder = B.word8 socksVersion
<> B.word8 _No_authentication
requestParser :: Parser ClientRequest
requestParser = do
__connectionType <- choice
[
TCP_IP_stream_connection <$ word8 1
, TCP_IP_port_binding <$ word8 2
, UDP_port <$ word8 3
]
word8 _ReservedByte
__addressType <- addressTypeParser
__portNumber <- (,) <$> anyWord8 <*> anyWord8
pure -
ClientRequest
__connectionType
__addressType
__portNumber
connectionParser :: Parser ClientRequest
connectionParser = do
socksHeader
requestParser
{- Special hack for polipo
-0500 0001 0000 0000 1010
-}
nonStandardReplyBuilder :: B.Builder
nonStandardReplyBuilder =
B.word8 socksVersion
<> B.word8 _Request_Granted
<> B.word8 _ReservedByte
<> B.word8 1
<> B.word8 0
<> B.word8 0
<> B.word8 0
<> B.word8 0
<> B.word8 16
<> B.word8 16
connectionReplyBuilder :: ClientRequest -> B.Builder
connectionReplyBuilder _clientRequest =
B.word8 socksVersion
<> B.word8 _Request_Granted
<> B.word8 _ReservedByte
<> addressTypeBuilder (_clientRequest ^. addressType)
<> foldMapOf each B.word8 (_clientRequest ^. portNumber)
addressTypeBuilder :: AddressType -> B.Builder
addressTypeBuilder aAddressType =
case aAddressType of
IPv4_address _address ->
B.word8 1
<> foldMap B.word8 (_address)
Domain_name x ->
B.word8 3
<> B.word8 (fromIntegral (S.length x))
<> B.byteString x
IPv6_address xs ->
B.word8 4
<> B.byteString (S.pack - xs)
connectionType_To_Word8 :: ConnectionType -> Word8
connectionType_To_Word8 TCP_IP_stream_connection = 1
connectionType_To_Word8 TCP_IP_port_binding = 2
connectionType_To_Word8 UDP_port = 3
requestBuilder :: ClientRequest -> B.Builder
requestBuilder aClientRequest =
B.word8 (connectionType_To_Word8 - aClientRequest ^. connectionType)
<> B.word8 _ReservedByte
<> addressTypeBuilder (aClientRequest ^. addressType)
<> foldMapOf each B.word8 (aClientRequest ^. portNumber)
shadowsocksRequestBuilder :: ClientRequest -> B.Builder
shadowsocksRequestBuilder aClientRequest =
addressTypeBuilder (aClientRequest ^. addressType)
<> foldMapOf each B.word8 (aClientRequest ^. portNumber)
addressTypeParser :: Parser AddressType
addressTypeParser = choice
[
IPv4_address <$> do
word8 1
count 4 anyWord8
, Domain_name <$> do
word8 3
let maxDomainNameLength = 32
_nameLength <- satisfy (<= maxDomainNameLength)
take - fromIntegral _nameLength
, IPv6_address <$> do
word8 4
count 16 anyWord8
]
portParser :: Parser (Word8, Word8)
portParser = (,) <$> anyWord8 <*> anyWord8
shadowsocksRequestParser :: Parser ClientRequest
shadowsocksRequestParser = do
__addressType <- addressTypeParser
__portNumber <- (,) <$> anyWord8 <*> anyWord8
pure -
ClientRequest
TCP_IP_stream_connection
__addressType
__portNumber