moesocks-0.1.0.7: src/Network/MoeSocks/BuilderAndParser.hs
{-# LANGUAGE OverloadedStrings #-}
module Network.MoeSocks.BuilderAndParser where
import Control.Lens
import Data.Attoparsec.ByteString
import Data.Binary
import Data.Binary.Put
import Data.Maybe
import Data.Monoid
import Data.Text.Lens
import Data.Text.Strict.Lens (utf8)
import Network.MoeSocks.Constant
import Network.MoeSocks.Helper
import Network.MoeSocks.Type
import Network.Socket
import Prelude hiding ((-), take)
import Safe (readMay)
import qualified Data.ByteString as S
import qualified Data.ByteString.Builder as B
import qualified Prelude as P
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
portParser :: Parser Int
portParser = do
__portNumberPair <- (,) <$> anyWord8 <*> anyWord8
pure - portPairToInt __portNumberPair
portBuilder :: (Integral i) => i -> B.Builder
portBuilder i =
let _i = fromIntegral i :: Word16
in
foldMapOf both B.word8 -
(decode - runPut - put _i :: (Word8, Word8))
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 <- portParser
pure -
ClientRequest
__connectionType
__addressType
__portNumber
connectionParser :: Parser ClientRequest
connectionParser = do
socksHeader
requestParser
sockAddr_To_Pair :: SockAddr -> (AddressType, Port)
sockAddr_To_Pair aSockAddr = case aSockAddr of
SockAddrInet _port _host ->
let
_r@(_a, _b, _c, _d) =
decode . runPut . put - _host
:: (Word8, Word8, Word8, Word8)
in
( IPv4_address - flip4 _r
, fromIntegral _port
)
SockAddrInet6 _port _ _host _ ->
let
_r@(_a, _b, _c, _d) =
decode . runPut . put - _host
:: (Word32, Word32, Word32, Word32)
in
( IPv6_address - flip4 _r
, fromIntegral _port
)
SockAddrUnix x ->
let
_host = P.takeWhile (/= ':') x
_port = x & reverse
& P.takeWhile (/= ':')
& reverse
in
( Domain_name - (_host & review _Text)
, fromMaybe 0 - readMay _port
)
x ->
error - "SockAddrCan not implemented: "
<> show x
connectionReplyBuilder :: SockAddr -> B.Builder
connectionReplyBuilder aSockAddr =
let _r@(__addressType, _port) = sockAddr_To_Pair aSockAddr
in
B.word8 socksVersion
<> B.word8 _Request_Granted
<> B.word8 _ReservedByte
<> addressTypeBuilder __addressType
<> portBuilder _port
addressTypeBuilder :: AddressType -> B.Builder
addressTypeBuilder aAddressType =
case aAddressType of
IPv4_address _address ->
B.word8 1
<> foldMapOf each B.word8 _address
Domain_name x ->
B.word8 3
<> B.word8 (fromIntegral (S.length (review utf8 x)))
<> B.byteString (review utf8 x)
IPv6_address _address ->
B.word8 4
<> foldMapOf each B.word32BE _address
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)
<> portBuilder (aClientRequest ^. portNumber)
shadowSocksRequestBuilder :: ClientRequest -> B.Builder
shadowSocksRequestBuilder aClientRequest =
addressTypeBuilder (aClientRequest ^. addressType)
<> portBuilder (aClientRequest ^. portNumber)
anyWord32be :: Parser Word32
anyWord32be = do
_b <- count 4 anyWord8
pure - decode - runPut - put _b
addressTypeParser :: Parser AddressType
addressTypeParser = choice
[
IPv4_address <$> do
word8 1
_a <- anyWord8
_b <- anyWord8
_c <- anyWord8
_d <- anyWord8
pure - (_a, _b, _c, _d)
, Domain_name <$> do
word8 3
_nameLength <- anyWord8
view utf8 <$> (take - fromIntegral _nameLength)
{-, IPv6_address <$> do-}
{-word8 4 -}
{-_a <- anyWord32be-}
{-_b <- anyWord32be-}
{-_c <- anyWord32be-}
{-_d <- anyWord32be -}
{-pure - (_a, _b, _c, _d)-}
]
shadowSocksRequestParser :: Parser ClientRequest
shadowSocksRequestParser = do
__addressType <- addressTypeParser
__portNumber <- portParser
pure -
ClientRequest
TCP_IP_stream_connection
__addressType
__portNumber