2016-11-20 19:45:01 +00:00
|
|
|
{- git-remote-daemon, tor hidden service transport
|
|
|
|
-
|
|
|
|
- Copyright 2016 Joey Hess <id@joeyh.name>
|
|
|
|
-
|
|
|
|
- Licensed under the GNU GPL version 3 or higher.
|
|
|
|
-}
|
|
|
|
|
|
|
|
module RemoteDaemon.Transport.Tor (server) where
|
|
|
|
|
|
|
|
import Common
|
|
|
|
import RemoteDaemon.Types
|
|
|
|
import RemoteDaemon.Common
|
|
|
|
import Utility.Tor
|
|
|
|
import Utility.FileMode
|
2016-11-30 20:38:16 +00:00
|
|
|
import Utility.AuthToken
|
2016-11-21 21:27:38 +00:00
|
|
|
import Remote.Helper.Tor
|
2016-11-24 20:36:16 +00:00
|
|
|
import P2P.Protocol
|
|
|
|
import P2P.IO
|
2016-11-30 20:38:16 +00:00
|
|
|
import P2P.Auth
|
2016-11-20 19:45:01 +00:00
|
|
|
import Annex.UUID
|
|
|
|
import Types.UUID
|
2016-11-22 02:03:29 +00:00
|
|
|
import Messages
|
|
|
|
import Git
|
2016-11-20 19:45:01 +00:00
|
|
|
|
|
|
|
import System.PosixCompat.User
|
|
|
|
import Network.Socket
|
|
|
|
import Control.Concurrent
|
|
|
|
import System.Log.Logger (debugM)
|
2016-11-22 02:03:29 +00:00
|
|
|
import Control.Concurrent.STM
|
2016-11-20 19:45:01 +00:00
|
|
|
|
|
|
|
-- Run tor hidden service.
|
|
|
|
server :: TransportHandle -> IO ()
|
|
|
|
server th@(TransportHandle (LocalRepo r) _) = do
|
|
|
|
u <- liftAnnex th getUUID
|
2016-11-22 02:03:29 +00:00
|
|
|
|
|
|
|
q <- newTBQueueIO maxConnections
|
|
|
|
replicateM_ maxConnections $
|
2016-11-30 20:38:16 +00:00
|
|
|
forkIO $ forever $ serveClient th u r q
|
2016-11-22 02:03:29 +00:00
|
|
|
|
2016-11-20 19:45:01 +00:00
|
|
|
uid <- getRealUserID
|
|
|
|
let ident = fromUUID u
|
2016-11-29 19:43:34 +00:00
|
|
|
let sock = hiddenServiceSocketFile uid ident
|
2016-11-20 19:45:01 +00:00
|
|
|
nukeFile sock
|
|
|
|
soc <- socket AF_UNIX Stream defaultProtocol
|
|
|
|
bind soc (SockAddrUnix sock)
|
|
|
|
-- Allow everyone to read and write to the socket; tor is probably
|
|
|
|
-- running as a different user. Connections have to authenticate
|
|
|
|
-- to do anything, so it's fine that other local users can connect.
|
|
|
|
modifyFileMode sock $ addModes
|
|
|
|
[groupReadMode, groupWriteMode, otherReadMode, otherWriteMode]
|
|
|
|
listen soc 2
|
|
|
|
debugM "remotedaemon" "tor hidden service running"
|
|
|
|
forever $ do
|
|
|
|
(conn, _) <- accept soc
|
2016-11-22 02:03:29 +00:00
|
|
|
h <- torHandle conn
|
|
|
|
ok <- atomically $ ifM (isFullTBQueue q)
|
|
|
|
( return False
|
|
|
|
, do
|
|
|
|
writeTBQueue q h
|
|
|
|
return True
|
|
|
|
)
|
|
|
|
unless ok $ do
|
2016-11-20 19:45:01 +00:00
|
|
|
hClose h
|
2016-11-22 02:03:29 +00:00
|
|
|
warningIO "dropped TOR connection, too busy"
|
|
|
|
|
|
|
|
-- How many clients to serve at a time, maximum. This is to avoid DOS
|
|
|
|
-- attacks.
|
|
|
|
maxConnections :: Int
|
|
|
|
maxConnections = 10
|
|
|
|
|
2016-11-30 20:38:16 +00:00
|
|
|
serveClient :: TransportHandle -> UUID -> Repo -> TBQueue Handle -> IO ()
|
|
|
|
serveClient th u r q = bracket setup cleanup go
|
2016-11-22 02:03:29 +00:00
|
|
|
where
|
|
|
|
setup = atomically $ readTBQueue q
|
|
|
|
cleanup = hClose
|
|
|
|
go h = do
|
|
|
|
debugM "remotedaemon" "serving a TOR connection"
|
2016-11-30 20:38:16 +00:00
|
|
|
-- Load auth tokens for every connection, to notice
|
|
|
|
-- when the allowed set is changed.
|
|
|
|
allowed <- liftAnnex th loadP2PAuthTokens
|
|
|
|
let runenv = RunEnv
|
|
|
|
{ runRepo = r
|
|
|
|
, runCheckAuth = (`isAllowedAuthToken` allowed)
|
|
|
|
, runIhdl = h
|
|
|
|
, runOhdl = h
|
|
|
|
}
|
2016-12-01 04:41:01 +00:00
|
|
|
void $ runNetProto runenv (serve u)
|
2016-11-22 02:03:29 +00:00
|
|
|
debugM "remotedaemon" "done with TOR connection"
|