2016-08-27 16:31:32 +00:00
|
|
|
{-# LANGUAGE DeriveAnyClass #-}
|
|
|
|
{-# LANGUAGE DeriveGeneric #-}
|
|
|
|
{-# LANGUAGE StandaloneDeriving #-}
|
2020-01-04 15:39:05 +00:00
|
|
|
{-# LANGUAGE StrictData #-}
|
2016-08-27 16:31:32 +00:00
|
|
|
|
|
|
|
module Types where
|
|
|
|
|
2020-01-04 12:28:36 +00:00
|
|
|
|
2016-08-27 16:31:32 +00:00
|
|
|
import ClassyPrelude
|
|
|
|
import Data.Maybe
|
2018-12-28 08:48:50 +00:00
|
|
|
import System.IO (stdin, stdout)
|
|
|
|
import Data.ByteString (hGetSome, hPutStr)
|
2016-08-27 16:31:32 +00:00
|
|
|
|
2022-01-30 15:39:13 +00:00
|
|
|
import Data.CaseInsensitive ( CI )
|
2016-08-27 16:31:32 +00:00
|
|
|
import qualified Data.Streaming.Network as N
|
|
|
|
import qualified Network.Connection as NC
|
2020-07-12 10:38:24 +00:00
|
|
|
import Network.Socket (HostName, PortNumber)
|
2016-08-27 16:31:32 +00:00
|
|
|
import qualified Network.Socket as N hiding (recv, recvFrom,
|
|
|
|
send, sendTo)
|
|
|
|
import qualified Network.Socket.ByteString as N
|
|
|
|
|
|
|
|
import qualified Network.WebSockets.Connection as WS
|
2020-01-04 12:28:36 +00:00
|
|
|
import System.IO.Unsafe (unsafeDupablePerformIO)
|
2016-08-27 16:31:32 +00:00
|
|
|
|
2020-07-12 10:38:24 +00:00
|
|
|
|
|
|
|
instance Hashable PortNumber where
|
|
|
|
hashWithSalt s p = hashWithSalt s (fromEnum p)
|
|
|
|
|
2016-08-27 16:31:32 +00:00
|
|
|
deriving instance Generic N.SockAddr
|
|
|
|
deriving instance Hashable N.SockAddr
|
|
|
|
|
2020-07-12 10:38:24 +00:00
|
|
|
|
2020-01-04 12:28:36 +00:00
|
|
|
{-# NOINLINE defaultRecvBufferSize #-}
|
2020-01-04 12:28:36 +00:00
|
|
|
defaultRecvBufferSize :: Int
|
|
|
|
defaultRecvBufferSize = unsafeDupablePerformIO $
|
|
|
|
bracket (N.socket N.AF_INET N.Stream 0) N.close (\sock -> N.getSocketOption sock N.RecvBuffer)
|
|
|
|
|
2020-01-22 18:04:07 +00:00
|
|
|
sO_MARK :: N.SocketOption
|
2020-04-26 12:34:41 +00:00
|
|
|
sO_MARK = N.CustomSockOpt (1, 36) -- https://elixir.bootlin.com/linux/latest/source/arch/alpha/include/uapi/asm/socket.h#L64
|
2020-01-22 18:04:07 +00:00
|
|
|
|
|
|
|
{-# NOINLINE sO_MARK_Value #-}
|
|
|
|
sO_MARK_Value :: IORef Int
|
2020-02-22 12:53:51 +00:00
|
|
|
sO_MARK_Value = unsafeDupablePerformIO $ (newIORef 0)
|
2020-01-22 18:04:07 +00:00
|
|
|
|
2018-12-28 08:48:50 +00:00
|
|
|
data Protocol = UDP | TCP | STDIO | SOCKS5 deriving (Show, Read, Eq)
|
|
|
|
|
|
|
|
data StdioAppData = StdioAppData
|
2016-08-27 16:31:32 +00:00
|
|
|
|
|
|
|
data UdpAppData = UdpAppData
|
|
|
|
{ appAddr :: N.SockAddr
|
|
|
|
, appSem :: MVar ByteString
|
|
|
|
, appRead :: IO ByteString
|
|
|
|
, appWrite :: ByteString -> IO ()
|
|
|
|
}
|
|
|
|
|
|
|
|
instance N.HasReadWrite UdpAppData where
|
|
|
|
readLens f appData = fmap (\getData -> appData { appRead = getData}) (f $ appRead appData)
|
|
|
|
writeLens f appData = fmap (\writeData -> appData { appWrite = writeData}) (f $ appWrite appData)
|
|
|
|
|
|
|
|
data ProxySettings = ProxySettings
|
|
|
|
{ host :: HostName
|
|
|
|
, port :: PortNumber
|
|
|
|
, credentials :: Maybe (ByteString, ByteString)
|
|
|
|
} deriving (Show)
|
|
|
|
|
|
|
|
data TunnelSettings = TunnelSettings
|
2018-12-26 20:26:48 +00:00
|
|
|
{ proxySetting :: Maybe ProxySettings
|
|
|
|
, localBind :: HostName
|
|
|
|
, localPort :: PortNumber
|
|
|
|
, serverHost :: HostName
|
|
|
|
, serverPort :: PortNumber
|
|
|
|
, destHost :: HostName
|
|
|
|
, destPort :: PortNumber
|
|
|
|
, protocol :: Protocol
|
|
|
|
, useTls :: Bool
|
|
|
|
, useSocks :: Bool
|
|
|
|
, upgradePrefix :: String
|
2020-10-27 12:53:46 +00:00
|
|
|
, upgradeCredentials
|
|
|
|
:: ByteString
|
2020-12-07 09:29:35 +00:00
|
|
|
, tlsSNI :: ByteString
|
|
|
|
, hostHeader :: ByteString
|
2019-01-13 16:47:18 +00:00
|
|
|
, udpTimeout :: Int
|
2020-12-07 09:59:13 +00:00
|
|
|
, websocketPingFrequencySec :: Int
|
2022-01-30 15:39:13 +00:00
|
|
|
, customHeaders :: [(CI ByteString, ByteString)]
|
2016-08-27 16:31:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
instance Show TunnelSettings where
|
|
|
|
show TunnelSettings{..} = localBind <> ":" <> show localPort
|
|
|
|
<> (if isNothing proxySetting
|
|
|
|
then mempty
|
|
|
|
else " <==PROXY==> " <> host (fromJust proxySetting) <> ":" <> (show . port $ fromJust proxySetting)
|
|
|
|
)
|
|
|
|
<> " <==" <> (if useTls then "WSS" else "WS") <> "==> "
|
|
|
|
<> serverHost <> ":" <> show serverPort
|
|
|
|
<> " <==" <> show (if protocol == SOCKS5 then TCP else protocol) <> "==> " <> destHost <> ":" <> show destPort
|
|
|
|
|
|
|
|
|
|
|
|
data Connection = Connection
|
|
|
|
{ read :: IO (Maybe ByteString)
|
|
|
|
, write :: ByteString -> IO ()
|
|
|
|
, close :: IO ()
|
|
|
|
, rawConnection :: Maybe N.Socket
|
|
|
|
}
|
|
|
|
|
|
|
|
class ToConnection a where
|
|
|
|
toConnection :: a -> Connection
|
|
|
|
|
2018-12-28 08:48:50 +00:00
|
|
|
instance ToConnection StdioAppData where
|
|
|
|
toConnection conn = Connection { read = Just <$> hGetSome stdin 512
|
|
|
|
, write = hPutStr stdout
|
|
|
|
, close = return ()
|
|
|
|
, rawConnection = Nothing
|
|
|
|
}
|
|
|
|
|
2016-08-27 16:31:32 +00:00
|
|
|
instance ToConnection WS.Connection where
|
|
|
|
toConnection conn = Connection { read = Just <$> WS.receiveData conn
|
|
|
|
, write = WS.sendBinaryData conn
|
|
|
|
, close = WS.sendClose conn (mempty :: LByteString)
|
|
|
|
, rawConnection = Nothing
|
|
|
|
}
|
|
|
|
|
|
|
|
instance ToConnection N.AppData where
|
|
|
|
toConnection conn = Connection { read = Just <$> N.appRead conn
|
|
|
|
, write = N.appWrite conn
|
|
|
|
, close = N.appCloseConnection conn
|
|
|
|
, rawConnection = Nothing
|
|
|
|
}
|
|
|
|
|
|
|
|
instance ToConnection UdpAppData where
|
|
|
|
toConnection conn = Connection { read = Just <$> appRead conn
|
|
|
|
, write = appWrite conn
|
|
|
|
, close = return ()
|
|
|
|
, rawConnection = Nothing
|
|
|
|
}
|
|
|
|
|
|
|
|
instance ToConnection NC.Connection where
|
|
|
|
toConnection conn = Connection { read = Just <$> NC.connectionGetChunk conn
|
|
|
|
, write = NC.connectionPut conn
|
|
|
|
, close = NC.connectionClose conn
|
|
|
|
, rawConnection = Nothing
|
|
|
|
}
|
|
|
|
|
|
|
|
data Error = ProxyConnectionError String
|
|
|
|
| ProxyForwardError String
|
|
|
|
| LocalServerError String
|
|
|
|
| TunnelError String
|
|
|
|
| WebsocketError String
|
|
|
|
| TlsError String
|
|
|
|
| Other String
|
|
|
|
deriving (Show)
|