summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Command/EnableTor.hs20
-rw-r--r--Utility/Tor.hs67
-rw-r--r--doc/git-annex-enable-tor.mdwn6
3 files changed, 55 insertions, 38 deletions
diff --git a/Command/EnableTor.hs b/Command/EnableTor.hs
index 8d9dd6f0a..1a54c6c5d 100644
--- a/Command/EnableTor.hs
+++ b/Command/EnableTor.hs
@@ -10,19 +10,25 @@ module Command.EnableTor where
import Command
import Utility.Tor
+-- This runs as root, so avoid making any commits or initializing
+-- git-annex, as that would create root-owned files.
cmd :: Command
cmd = noCommit $ dontCheck repoExists $
command "enable-tor" SectionPlumbing ""
- paramNumber (withParams seek)
+ "userid uuid" (withParams seek)
seek :: CmdParams -> CommandSeek
seek = withWords start
start :: CmdParams -> CommandStart
-start (localport:[]) = case readish localport of
- Nothing -> error "Bad localport"
- Just lp -> do
- (onionaddr, onionport) <- liftIO $ addHiddenService lp
- liftIO $ putStrLn (onionaddr ++ ":" ++ show onionport)
+start (suserid:uuid:[]) = case readish suserid of
+ Nothing -> error "Bad userid"
+ Just userid -> do
+ (onionaddr, onionport, onionsocket) <- liftIO $
+ addHiddenService userid uuid
+ liftIO $ putStrLn $
+ onionaddr ++ ":" ++
+ show onionport ++ " " ++
+ show onionsocket
stop
-start _ = error "Need 1 localport parameter"
+start _ = error "Bad params"
diff --git a/Utility/Tor.hs b/Utility/Tor.hs
index b15a23dcc..a0a609008 100644
--- a/Utility/Tor.hs
+++ b/Utility/Tor.hs
@@ -9,39 +9,39 @@ module Utility.Tor where
import Common
import Utility.ThreadScheduler
+import System.PosixCompat.Types
import Data.Char
-type LocalPort = Int
type OnionPort = Int
type OnionAddress = String
+type OnionSocket = FilePath
--- | Adds a hidden service connecting to localhost on the specified local port.
+-- | Adds a hidden service connecting to localhost, using some kind
+-- of unique identifier.
+--
-- This will only work if run as root, and tor has to already be running.
--
-- Picks a port number for the hidden service that is not used by any
-- other hidden service (and is >= 1024). Returns the hidden service's
--- onion address and port.
-
--- If there is already a hidden service for the specified local port,
--- returns its information without making any changes.
-addHiddenService :: LocalPort -> IO (OnionAddress, OnionPort)
-addHiddenService localport = do
- ls <- map (separate isSpace) . lines <$> readFile torrc
- let usedports = mapMaybe readish $
- map (drop 1 . dropWhile (/= ':')) $
- map snd $
- filter (\(k, _) -> k == "HiddenServicePort") ls
- let newport = Prelude.head $ filter (`notElem` usedports) [1024..]
- let dir = libDir </> "hidden_service" ++ show localport
- if localport `elem` usedports
- then waithiddenservice 1 dir newport
- else do
+-- onion address, port, and the unix socket file to use.
+--
+-- 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 uid ident = do
+ ls <- lines <$> readFile torrc
+ let portssocks = mapMaybe (parseportsock . separate isSpace) ls
+ case filter (\(_, s) -> s == sockfile) portssocks of
+ ((p, _s):_) -> waithiddenservice 1 p
+ _ -> do
+ let newport = Prelude.head $
+ filter (`notElem` map fst portssocks) [1024..]
writeFile torrc $ unlines $
- map (\(k, v) -> k ++ " " ++ v) ls ++
+ ls ++
[ ""
- , "HiddenServiceDir " ++ dir
+ , "HiddenServiceDir " ++ hsdir
, "HiddenServicePort " ++ show newport ++
- " 127.0.0.1:" ++ show localport
+ " unix:" ++ sockfile
]
-- Reload tor, so it will see the new hidden
-- service and generate the hostname file for it.
@@ -51,21 +51,32 @@ addHiddenService localport = do
]
unless reloaded $
error "failed to reload tor, perhaps the tor service is not running"
- waithiddenservice 120 dir newport
+ waithiddenservice 120 newport
where
- waithiddenservice :: Int -> FilePath -> OnionPort -> IO (OnionAddress, OnionPort)
- waithiddenservice 0 _ _ = error "tor failed to create hidden service, perhaps the tor service is not running"
- waithiddenservice n dir newport = do
- v <- tryIO $ readFile (dir </> "hostname")
+ parseportsock ("HiddenServicePort", l) = do
+ p <- readish $ takeWhile (not . isSpace) l
+ return (p, drop 1 (dropWhile (/= ':') l))
+ parseportsock _ = Nothing
+
+ hsdir = libDir </> "hidden_service_" ++ show uid ++ "_" ++ ident
+ sockfile = runDir uid </> ident ++ ".sock"
+
+ 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")
case v of
Right s | ".onion\n" `isSuffixOf` s ->
- return (takeWhile (/= '\n') s, newport)
+ return (takeWhile (/= '\n') s, p, sockfile)
_ -> do
threadDelaySeconds (Seconds 1)
- waithiddenservice (n-1) dir newport
+ waithiddenservice (n-1) p
torrc :: FilePath
torrc = "/etc/tor/torrc"
libDir :: FilePath
libDir = "/var/lib/tor"
+
+runDir :: UserID -> FilePath
+runDir uid = "/var/run/user" </> show uid
diff --git a/doc/git-annex-enable-tor.mdwn b/doc/git-annex-enable-tor.mdwn
index 961eef172..b44cf817c 100644
--- a/doc/git-annex-enable-tor.mdwn
+++ b/doc/git-annex-enable-tor.mdwn
@@ -4,13 +4,13 @@ git-annex enable-tor - enable tor hidden service
# SYNOPSIS
-git annex enable-tor localport
+git annex enable-tor userid uuid
# DESCRIPTION
This plumbing-level command enables a tor hidden service for git-annex,
-using the specified local port number. It outputs to stdout a line
-of the form "address.onion:onionport"
+using the specified repository uuid and userid.
+It outputs to stdout a line of the form "address.onion:onionport socketfile"
This command has to be run by root, since it modifies `/etc/tor/torrc`.