diff --git a/app/Main.hs b/app/Main.hs index b1e8f76..fbf6c87 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -31,6 +31,8 @@ data WsTunnel = WsTunnel , verbose :: Bool , quiet :: Bool , pathPrefix :: String + , hostHeader :: String + , tlsSNI :: String , wsTunnelCredentials :: String } deriving (Show, Data, Typeable) @@ -69,6 +71,10 @@ cmdLine = WsTunnel &= typ "USER[:PASS]" , proxy = def &= explicit &= name "p" &= name "httpProxy" &= help "If set, will use this proxy to connect to the server" &= typ "USER:PASS@HOST:PORT" + , hostHeader = def &= explicit &= name "hostHeader" &= groupname "Client options" + &= help "If set, add the custom string as host http header" &= typ "String" &= groupname "Client options" + , tlsSNI = def &= explicit &= name "tlsSNI" &= groupname "Client options" + &= help "If set, use custom string in the SNI during TLS handshake" &= typ "String" &= groupname "Client options" , soMark = def &= explicit &= name "soMark" &= help "(linux only) Mark network packet with SO_MARK sockoption with the specified value. You need to use {root, sudo, capabilities} to run wstunnel when using this option" &= typ "int" , wsTunnelServer = def &= argPos 0 &= typ "ws[s]://wstunnelServer[:port]" @@ -228,6 +234,8 @@ runApp cfg serverInfo , upgradePrefix = pathPrefix cfg , upgradeCredentials = BC.pack $ wsTunnelCredentials cfg , udpTimeout = Main.udpTimeout cfg + , tlsSNI = BC.pack $ Main.tlsSNI cfg + , hostHeader = BC.pack $ Main.hostHeader cfg } toTcpLocalToRemoteTunnelSetting cfg serverInfo (TunnelInfo lHost lPort rHost rPort) = @@ -245,6 +253,8 @@ runApp cfg serverInfo , upgradePrefix = pathPrefix cfg , upgradeCredentials = BC.pack $ wsTunnelCredentials cfg , udpTimeout = Main.udpTimeout cfg + , tlsSNI = BC.pack $ Main.tlsSNI cfg + , hostHeader = BC.pack $ Main.hostHeader cfg } toUdpLocalToRemoteTunnelSetting cfg serverInfo (TunnelInfo lHost lPort rHost rPort) = @@ -262,6 +272,8 @@ runApp cfg serverInfo , upgradePrefix = pathPrefix cfg , upgradeCredentials = BC.pack $ wsTunnelCredentials cfg , udpTimeout = Main.udpTimeout cfg + , tlsSNI = BC.pack $ Main.tlsSNI cfg + , hostHeader = BC.pack $ Main.hostHeader cfg } toDynamicTunnelSetting cfg serverInfo (TunnelInfo lHost lPort _ _) = @@ -279,4 +291,6 @@ runApp cfg serverInfo , upgradePrefix = pathPrefix cfg , upgradeCredentials = BC.pack $ wsTunnelCredentials cfg , udpTimeout = Main.udpTimeout cfg + , tlsSNI = BC.pack $ Main.tlsSNI cfg + , hostHeader = BC.pack $ Main.hostHeader cfg } diff --git a/src/Tunnel.hs b/src/Tunnel.hs index 09603b8..40e09d7 100644 --- a/src/Tunnel.hs +++ b/src/Tunnel.hs @@ -65,7 +65,8 @@ tunnelingClientP cfg@TunnelSettings{..} app conn = onError $ do debug "Oppening Websocket stream" stream <- connectionToStream conn - let headers = if not (null upgradeCredentials) then [("Authorization", "Basic " <> B64.encode upgradeCredentials)] else [] + let headers = (if not (null upgradeCredentials) then [("Authorization", "Basic " <> B64.encode upgradeCredentials)] else []) + <> (if not (null hostHeader) then [("Host", hostHeader)] else []) ret <- WS.runClientWithStream stream serverHost (toPath cfg) WS.defaultConnectionOptions headers run debug "Closing Websocket stream" @@ -99,7 +100,7 @@ tlsClientP TunnelSettings{..} app conn = onError $ do , NC.settingDisableSession = False , NC.settingUseServerName = False } - connectionParams = NC.ConnectionParams { NC.connectionHostname = serverHost + connectionParams = NC.ConnectionParams { NC.connectionHostname = if tlsSNI == mempty then serverHost else BC.unpack tlsSNI , NC.connectionPort = serverPort , NC.connectionUseSecure = Just tlsSettings , NC.connectionUseSocks = Nothing diff --git a/src/Types.hs b/src/Types.hs index 3ebfd09..3730f09 100644 --- a/src/Types.hs +++ b/src/Types.hs @@ -79,6 +79,8 @@ data TunnelSettings = TunnelSettings , upgradePrefix :: String , upgradeCredentials :: ByteString + , tlsSNI :: ByteString + , hostHeader :: ByteString , udpTimeout :: Int } diff --git a/test/Spec.hs b/test/Spec.hs index dfe32fc..b428ee2 100644 --- a/test/Spec.hs +++ b/test/Spec.hs @@ -47,6 +47,9 @@ testTCPLocalToRemote useTLS = do , useSocks = False , upgradePrefix = "wstunnel" , udpTimeout = 0 + , upgradeCredentials = "" + , hostHeader = "toto.com" + , tlsSNI = "toto.com" } let client = runClient tunnelSetting @@ -104,6 +107,9 @@ testUDPLocalToRemote useTLS = do , useSocks = False , upgradePrefix = "wstunnel" , udpTimeout = -1 + , upgradeCredentials = "" + , hostHeader = "toto.com" + , tlsSNI = "toto.com" } let client = runClient tunnelSetting @@ -160,6 +166,9 @@ testSocks5Tunneling useTLS = do , useSocks = False , upgradePrefix = "wstunnel" , udpTimeout = -1 + , upgradeCredentials = "" + , hostHeader = "toto.com" + , tlsSNI = "toto.com" } let client = runClient tunnelSetting