Socks5 done \O/

This commit is contained in:
Erèbe 2016-08-24 22:49:33 +02:00
parent ff6c4164b8
commit e9b5137afb
4 changed files with 72 additions and 58 deletions

View file

@ -146,15 +146,15 @@ main = do
, useSocks = False , useSocks = False
} }
else if not $ null (dynamicToRemote cfg) else if not $ null (dynamicToRemote cfg)
then let (TunnelInfo lHost lPort _ _) = parseTunnelInfo $ (localToRemote cfg) ++ ":127.0.0.1:0" then let (TunnelInfo lHost lPort _ _) = parseTunnelInfo $ (dynamicToRemote cfg) ++ ":127.0.0.1:1212"
in runClient TunnelSettings { localBind = lHost in runClient TunnelSettings { localBind = lHost
, Tunnel.localPort = fromIntegral lPort , Tunnel.localPort = fromIntegral lPort
, serverHost = Main.host serverInfo , serverHost = Main.host serverInfo
, serverPort = fromIntegral $ Main.port serverInfo , serverPort = fromIntegral $ Main.port serverInfo
, destHost = "" , destHost = ""
, destPort = fromIntegral 0 , destPort = 0
, Tunnel.useTls = Main.useTls serverInfo , Tunnel.useTls = Main.useTls serverInfo
, protocol = if udpMode cfg then UDP else TCP , protocol = SOCKS5
, proxySetting = parseProxyInfo (proxy cfg) , proxySetting = parseProxyInfo (proxy cfg)
, useSocks = True , useSocks = True
} }

View file

@ -29,7 +29,7 @@ deriving instance Hashable PortNumber
deriving instance Generic N.SockAddr deriving instance Generic N.SockAddr
deriving instance Hashable N.SockAddr deriving instance Hashable N.SockAddr
data Protocol = UDP | TCP deriving (Show, Read) data Protocol = UDP | TCP | SOCKS5 deriving (Show, Read, Eq)
data UdpAppData = UdpAppData data UdpAppData = UdpAppData
{ appAddr :: N.SockAddr { appAddr :: N.SockAddr

View file

@ -1,13 +1,13 @@
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-} {-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-} {-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StrictData #-} {-# LANGUAGE StrictData #-}
{-# LANGUAGE ExistentialQuantification #-}
module Socks5 where module Socks5 where
@ -155,7 +155,7 @@ toHex = foldr showHex "" . unpack
data Response = Response data Response = Response
{ version :: Int { version :: Int
, returnCode :: RetCode , returnCode :: RetCode
, serverAddr :: HostAddress , serverAddr :: HostName
, serverPort :: PortNumber , serverPort :: PortNumber
} deriving (Show) } deriving (Show)
@ -182,8 +182,10 @@ instance Binary Response where
put returnCode put returnCode
putWord8 0x00 -- Reserved putWord8 0x00 -- Reserved
putWord8 0x03 -- DOMAINNAME putWord8 0x03 -- DOMAINNAME
putWord32be serverAddr let host = BC8.pack serverAddr
putWord16be $ fromIntegral serverPort putWord8 (fromIntegral . length $ host)
traverse_ put host
putWord16be (fromIntegral serverPort)
get = do get = do
@ -193,23 +195,26 @@ instance Binary Response where
getWord8 -- RESERVED getWord8 -- RESERVED
opCode <- fromIntegral <$> getWord8 -- Type opCode <- fromIntegral <$> getWord8 -- Type
guard(opCode == 0x03) guard(opCode == 0x03)
addr <- getWord32be length <- fromIntegral <$> getWord8
host <- either (const T.empty) id . E.decodeUtf8' <$> replicateM length getWord8
guard (not $ null host)
port <- getWord16be port <- getWord16be
return Response return Response
{ version = version { version = version
, returnCode = ret , returnCode = ret
, serverAddr = addr , serverAddr = unpack host
, serverPort = fromIntegral port , serverPort = fromIntegral port
} }
data ServerSettings m = ServerSettings data ServerSettings = ServerSettings
{ listenOn :: PortNumber { listenOn :: PortNumber
, bindOn :: HostName , bindOn :: HostName
, onAuthentification :: (MonadIO m, MonadError IOException m) => RequestAuth -> m ResponseAuth -- , onAuthentification :: (MonadIO m, MonadError IOException m) => RequestAuth -> m ResponseAuth
, onRequest :: (MonadIO m, MonadError IOException m) => Request -> m Response -- , onRequest :: (MonadIO m, MonadError IOException m) => Request -> m Response
} }

View file

@ -236,21 +236,21 @@ runClient :: TunnelSettings -> IO ()
runClient cfg@TunnelSettings{..} = do runClient cfg@TunnelSettings{..} = do
let withEndPoint = if isJust proxySetting then httpProxyConnection cfg else tcpConnection cfg let withEndPoint = if isJust proxySetting then httpProxyConnection cfg else tcpConnection cfg
let doTlsIf tlsNeeded app = if tlsNeeded then tlsClientP cfg app else app let doTlsIf tlsNeeded app = if tlsNeeded then tlsClientP cfg app else app
let runTunnelClient = tunnelingClientP cfg let withTunnel cfg' app = withEndPoint (doTlsIf useTls . tunnelingClientP cfg' $ app)
let withTunnel app = withEndPoint (doTlsIf useTls . runTunnelClient $ app)
let app localH = do let app cfg' localH = do
ret <- withTunnel $ \remoteH -> do ret <- withTunnel cfg' $ \remoteH -> do
info $ "CREATE tunnel :: " <> show cfg info $ "CREATE tunnel :: " <> show cfg'
ret <- remoteH <==> toConnection localH ret <- remoteH <==> toConnection localH
info $ "CLOSE tunnel :: " <> show cfg info $ "CLOSE tunnel :: " <> show cfg'
return ret return ret
handleError ret handleError ret
case protocol of case protocol of
UDP -> runUDPServer (localBind, localPort) app UDP -> runUDPServer (localBind, localPort) (app cfg)
TCP -> runTCPServer (localBind, localPort) app TCP -> runTCPServer (localBind, localPort) (app cfg)
SOCKS5 -> runSocks5Server (Socks5.ServerSettings localPort localBind) cfg app
handleError :: Either Error () -> IO () handleError :: Either Error () -> IO ()
handleError (Right ()) = return () handleError (Right ()) = return ()
@ -382,7 +382,7 @@ serverCertificate = "-----BEGIN CERTIFICATE-----\n" <>
toPath :: TunnelSettings -> String toPath :: TunnelSettings -> String
toPath TunnelSettings{..} = "/" <> toLower (show protocol) <> "/" <> destHost <> "/" <> show destPort toPath TunnelSettings{..} = "/" <> toLower (show $ if protocol == SOCKS5 then TCP else protocol) <> "/" <> destHost <> "/" <> show destPort
fromPath :: ByteString -> Maybe (Protocol, ByteString, Int) fromPath :: ByteString -> Maybe (Protocol, ByteString, Int)
fromPath path = let rets = BC.split '/' . BC.drop 1 $ path fromPath path = let rets = BC.split '/' . BC.drop 1 $ path
@ -394,41 +394,50 @@ fromPath path = let rets = BC.split '/' . BC.drop 1 $ path
return (proto, h, prt') return (proto, h, prt')
runSocks5Server :: Socks5.ServerSettings IO -> (N.AppData -> IO()) -> IO () runSocks5Server :: Socks5.ServerSettings -> TunnelSettings -> (TunnelSettings -> N.AppData -> IO()) -> IO ()
runSocks5Server Socks5.ServerSettings{..} inner = do runSocks5Server Socks5.ServerSettings{..} cfg inner = do
N.runTCPServer (N.serverSettingsTCP (fromIntegral listenOn) (fromString bindOn)) $ \cnx -> do N.runTCPServer (N.serverSettingsTCP (fromIntegral listenOn) (fromString bindOn)) $ \cnx -> do
responseAuth <- join $ onAuthentification . decode . fromStrict <$> N.appRead cnx :: IO Socks5.ResponseAuth responseAuth <- join $ onAuthentification . decode . fromStrict <$> N.appRead cnx :: IO Socks5.ResponseAuth
N.appWrite cnx (toStrict $ encode responseAuth) N.appWrite cnx (toStrict $ encode responseAuth)
request <- decode .fromStrict <$> N.appRead cnx :: IO Socks5.Request request <- decode . fromStrict <$> N.appRead cnx :: IO Socks5.Request
traceShowM request
ret <- onRequest request ret <- onRequest request
N.appWrite cnx (toStrict . encode $ ret) N.appWrite cnx (toStrict . encode $ ret)
inner cnx
let cfg' = cfg { destHost = Socks5.addr request, destPort = Socks5.port request }
inner cfg' cnx
return ()
return ()
main :: IO ()
main = do
runSocks5Server (Socks5.ServerSettings 8888 "127.0.0.1" auth req) $ \cnx -> do
putStrLn "tota"
da <- N.appRead cnx
putStrLn "toot"
print da
return () return ()
return () return ()
where where
auth authReq = do onAuthentification :: (MonadIO m, MonadError IOException m) => Socks5.RequestAuth -> m Socks5.ResponseAuth
traceShowM authReq onAuthentification authReq = do
return $ Socks5.ResponseAuth (fromIntegral Socks5.socksVersion) Socks5.NoAuth return $ Socks5.ResponseAuth (fromIntegral Socks5.socksVersion) Socks5.NoAuth
req request= do
onRequest :: (MonadIO m, MonadError IOException m) => Socks5.Request -> m Socks5.Response
onRequest request = do
traceShowM request traceShowM request
return $ Socks5.Response (fromIntegral Socks5.socksVersion) Socks5.SUCCEEDED 0x00000000 0x0000 return $ Socks5.Response (fromIntegral Socks5.socksVersion) Socks5.SUCCEEDED (Socks5.addr request) (Socks5.port request)
-- main :: IO ()
-- main = do
-- runSocks5Server (Socks5.ServerSettings 8888 "127.0.0.1") $ \cnx -> do
-- putStrLn "tota"
-- da <- N.appRead cnx
-- putStrLn "toot"
-- print da
-- return ()
-- return ()
-- where
-- auth authReq = do
-- traceShowM authReq
-- return $ Socks5.ResponseAuth (fromIntegral Socks5.socksVersion) Socks5.NoAuth
-- req request= do
-- traceShowM request
-- return $ Socks5.Response (fromIntegral Socks5.socksVersion) Socks5.SUCCEEDED 0x00000000 0x0000