diff options
author | Joey Hess <joeyh@joeyh.name> | 2016-11-20 15:45:01 -0400 |
---|---|---|
committer | Joey Hess <joeyh@joeyh.name> | 2016-11-20 15:48:12 -0400 |
commit | dce8e76ef443e33d88b8301c86ebf080fceff511 (patch) | |
tree | 204d7f7b2eaaeaa4acd7ed2e1182fb208b829c2c | |
parent | 8e28135b26db1c920ebde7438db9bad87d3026ee (diff) |
remotedaemon: serve tor hidden service
-rw-r--r-- | CHANGELOG | 2 | ||||
-rw-r--r-- | Command/RemoteDaemon.hs | 2 | ||||
-rw-r--r-- | Remote/Helper/P2P/IO.hs | 6 | ||||
-rw-r--r-- | RemoteDaemon/Core.hs | 9 | ||||
-rw-r--r-- | RemoteDaemon/Transport.hs | 4 | ||||
-rw-r--r-- | RemoteDaemon/Transport/Tor.hs | 51 | ||||
-rw-r--r-- | Utility/Tor.hs | 19 | ||||
-rw-r--r-- | git-annex.cabal | 1 |
8 files changed, 83 insertions, 11 deletions
@@ -1,5 +1,7 @@ git-annex (6.20161119) UNRELEASED; urgency=medium + * enable-tor: New command, enables tor hidden service for P2P syncing. + * remotedaemon: Serve tor hidden service. * remotedaemon: Fork to background by default. Added --foreground switch to enable old behavior. diff --git a/Command/RemoteDaemon.hs b/Command/RemoteDaemon.hs index c68cf816a..c17417104 100644 --- a/Command/RemoteDaemon.hs +++ b/Command/RemoteDaemon.hs @@ -14,7 +14,7 @@ import RemoteDaemon.Core import Utility.Daemon cmd :: Command -cmd = noCommit $ dontCheck repoExists $ +cmd = noCommit $ command "remotedaemon" SectionMaintenance "persistent communication with remotes" paramNothing (run <$$> const parseDaemonOptions) diff --git a/Remote/Helper/P2P/IO.hs b/Remote/Helper/P2P/IO.hs index 7179adc2b..82ba2d6f9 100644 --- a/Remote/Helper/P2P/IO.hs +++ b/Remote/Helper/P2P/IO.hs @@ -9,7 +9,7 @@ module Remote.Helper.P2P.IO ( RunProto - , runProtoHandle + , runNetProtoHandle ) where import Remote.Helper.P2P @@ -38,8 +38,8 @@ data S = S -- Implementation of the protocol, communicating with a peer -- over a Handle. No Local actions will be run. -runProtoHandle :: MonadIO m => Handle -> Repo -> Proto a -> m a -runProtoHandle h r = go +runNetProtoHandle :: MonadIO m => Handle -> Repo -> Proto a -> m a +runNetProtoHandle h r = go where go :: RunProto go (Pure a) = pure a diff --git a/RemoteDaemon/Core.hs b/RemoteDaemon/Core.hs index 3b3f6d98d..446948da6 100644 --- a/RemoteDaemon/Core.hs +++ b/RemoteDaemon/Core.hs @@ -45,7 +45,9 @@ runInteractive = do let controller = runController ichan ochan -- If any thread fails, the rest will be killed. - void $ tryIO $ reader `concurrently` writer `concurrently` controller + void $ tryIO $ reader + `concurrently` writer + `concurrently` controller runNonInteractive :: IO () runNonInteractive = do @@ -59,7 +61,9 @@ runNonInteractive = do void $ atomically $ readTChan ochan let controller = runController ichan ochan - void $ tryIO $ reader `concurrently` writer `concurrently` controller + void $ tryIO $ reader + `concurrently` writer + `concurrently` controller type RemoteMap = M.Map Git.Repo (IO (), TChan Consumed) @@ -70,6 +74,7 @@ runController ichan ochan = do h <- genTransportHandle m <- genRemoteMap h ochan startrunning m + mapM_ (\s -> async (s h)) remoteServers go h False m where go h paused m = do diff --git a/RemoteDaemon/Transport.hs b/RemoteDaemon/Transport.hs index 0e2040d1f..6605012de 100644 --- a/RemoteDaemon/Transport.hs +++ b/RemoteDaemon/Transport.hs @@ -10,6 +10,7 @@ module RemoteDaemon.Transport where import RemoteDaemon.Types import qualified RemoteDaemon.Transport.Ssh import qualified RemoteDaemon.Transport.GCrypt +import qualified RemoteDaemon.Transport.Tor import qualified Git.GCrypt import qualified Data.Map as M @@ -22,3 +23,6 @@ remoteTransports = M.fromList [ ("ssh:", RemoteDaemon.Transport.Ssh.transport) , (Git.GCrypt.urlScheme, RemoteDaemon.Transport.GCrypt.transport) ] + +remoteServers :: [TransportHandle -> IO ()] +remoteServers = [RemoteDaemon.Transport.Tor.server] diff --git a/RemoteDaemon/Transport/Tor.hs b/RemoteDaemon/Transport/Tor.hs new file mode 100644 index 000000000..1527939b1 --- /dev/null +++ b/RemoteDaemon/Transport/Tor.hs @@ -0,0 +1,51 @@ +{- 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 +import Remote.Helper.P2P +import Remote.Helper.P2P.IO +import Annex.UUID +import Types.UUID + +import System.PosixCompat.User +import Network.Socket +import Control.Concurrent +import System.Log.Logger (debugM) + +-- Run tor hidden service. +server :: TransportHandle -> IO () +server th@(TransportHandle (LocalRepo r) _) = do + u <- liftAnnex th getUUID + uid <- getRealUserID + let ident = fromUUID u + let sock = socketFile uid ident + 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 + forkIO $ do + debugM "remotedaemon" "handling a connection" + h <- socketToHandle conn ReadWriteMode + hSetBuffering h LineBuffering + hSetBinaryMode h False + runNetProtoHandle h r (serve u) + hClose h + diff --git a/Utility/Tor.hs b/Utility/Tor.hs index a0a609008..b673c7105 100644 --- a/Utility/Tor.hs +++ b/Utility/Tor.hs @@ -15,6 +15,7 @@ import Data.Char type OnionPort = Int type OnionAddress = String type OnionSocket = FilePath +type UniqueIdent = String -- | Adds a hidden service connecting to localhost, using some kind -- of unique identifier. @@ -27,7 +28,7 @@ type OnionSocket = FilePath -- -- If there is already a hidden service for the specified unique -- identifier, returns its information without making any changes. -addHiddenService :: UserID -> String -> IO (OnionAddress, OnionPort, OnionSocket) +addHiddenService :: UserID -> UniqueIdent -> IO (OnionAddress, OnionPort, OnionSocket) addHiddenService uid ident = do ls <- lines <$> readFile torrc let portssocks = mapMaybe (parseportsock . separate isSpace) ls @@ -39,7 +40,7 @@ addHiddenService uid ident = do writeFile torrc $ unlines $ ls ++ [ "" - , "HiddenServiceDir " ++ hsdir + , "HiddenServiceDir " ++ hiddenServiceDir uid ident , "HiddenServicePort " ++ show newport ++ " unix:" ++ sockfile ] @@ -58,13 +59,12 @@ addHiddenService uid ident = do return (p, drop 1 (dropWhile (/= ':') l)) parseportsock _ = Nothing - hsdir = libDir </> "hidden_service_" ++ show uid ++ "_" ++ ident - sockfile = runDir uid </> ident ++ ".sock" + sockfile = socketFile uid ident waithiddenservice :: Int -> OnionPort -> IO (OnionAddress, OnionPort, OnionSocket) waithiddenservice 0 _ = error "tor failed to create hidden service, perhaps the tor service is not running" waithiddenservice n p = do - v <- tryIO $ readFile (hsdir </> "hostname") + v <- tryIO $ readFile $ hiddenServiceHostnameFile uid ident case v of Right s | ".onion\n" `isSuffixOf` s -> return (takeWhile (/= '\n') s, p, sockfile) @@ -80,3 +80,12 @@ libDir = "/var/lib/tor" runDir :: UserID -> FilePath runDir uid = "/var/run/user" </> show uid + +socketFile :: UserID -> UniqueIdent -> FilePath +socketFile uid ident = runDir uid </> ident ++ ".sock" + +hiddenServiceDir :: UserID -> UniqueIdent -> FilePath +hiddenServiceDir uid ident = libDir </> "hidden_service_" ++ show uid ++ "_" ++ ident + +hiddenServiceHostnameFile :: UserID -> UniqueIdent -> FilePath +hiddenServiceHostnameFile uid ident = hiddenServiceDir uid ident </> "hostname" diff --git a/git-annex.cabal b/git-annex.cabal index 77c50b66e..7a0e34b3a 100644 --- a/git-annex.cabal +++ b/git-annex.cabal @@ -937,6 +937,7 @@ Executable git-annex RemoteDaemon.Core RemoteDaemon.Transport RemoteDaemon.Transport.GCrypt + RemoteDaemon.Transport.Tor RemoteDaemon.Transport.Ssh RemoteDaemon.Transport.Ssh.Types RemoteDaemon.Types |