Update: question now contains the final edited answer!
I now use the following (final answer):
module Main where
import Control.Concurrent (forkIO)
import Control.Monad (when,forever,void)
import Network (PortID(PortNumber),listenOn)
import Network.Socket hiding (listen,recv,send)
import Network.Socket.ByteString (recv,sendAll)
import qualified Data.ByteString as B
import System
type Host = String
type Port = PortNumber
main :: IO ()
main = do
[lp,h,p] <- getArgs
start (port lp) h (port p)
where
port = fromInteger . read
start :: Port -> Host -> Port -> IO ()
start lp rh rp = withSocketsDo $ do
proxy <- listenOn $ PortNumber lp
forever $ do
(client,_) <- accept proxy
void . forkIO $ (client >-<) =<< rh .@. rp
(.@.) :: Host -> Port -> IO Socket
host .@. port = do
addr:_ <- getAddrInfo Nothing (Just host) (Just $ show port)
server <- socket (addrFamily addr) Stream defaultProtocol
connect server (addrAddress addr)
return server
(>-<) :: Socket -> Socket -> IO ()
x >-< y = do x >- y; y >- x
(>-) :: Socket -> Socket -> IO ()
s >- r = void . forkIO . handle $ forever stream
where
stream = recv s (64 * 1024) >>= ifNot0 >>= sendAll r
ifNot0 = \c -> do when (B.null c) $ handle (error "0"); return c
handle = flip catch $ \e -> print e >> sClose s >> sClose r
which can be run like this:
proxy 2000 localhost 3389
Using mRemote, if I connect to localhost:2000, I do see the login screen of the local machine! :)
*If I find a way to improve (>-)
even further, I will update this answer!
It seems that you came to this tcp proxy gist when looking for information. At this time, is is broken and a bit messy. In such case, please don't hesitate to ping the author (in this case, me) so that he can fix the gist for future references :)
I'll fix it ASAP and link to this SO question. The fixed version will include sendAll as well as all nice suggestions coming from this SO question, so please share your best thoughts. As a side note, this branch of throttle already had the sendAll fix, in case of interest.
EDIT : the gist is fixed now
Found this gist a few months ago when I was getting started with Haskell.
It's really simple and easy to understand.
EDIT: Based on the gist above, here is a tested RDP proxy. Difference is replacing
send
withsendAll
to make sure all data is delivered. Found this problem when testing through the linux rdp server (large payload disconnects).