use socket for tor hidden service
This avoids needing to bind to the right port before something else does. The socket is in /var/run/user/$uid/ which ought to be writable by only that uid. At least it is on linux systems using systemd. For Windows, may need to revisit this and use ports or something. The first version of tor to support sockets for hidden services was 0.2.6.3. That is not in Debian stable, but is available in backports. This commit was sponsored by andrea rota.
This commit is contained in:
parent
07ad19f421
commit
57d33f7923
3 changed files with 55 additions and 38 deletions
|
@ -10,19 +10,25 @@ module Command.EnableTor where
|
||||||
import Command
|
import Command
|
||||||
import Utility.Tor
|
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 :: Command
|
||||||
cmd = noCommit $ dontCheck repoExists $
|
cmd = noCommit $ dontCheck repoExists $
|
||||||
command "enable-tor" SectionPlumbing ""
|
command "enable-tor" SectionPlumbing ""
|
||||||
paramNumber (withParams seek)
|
"userid uuid" (withParams seek)
|
||||||
|
|
||||||
seek :: CmdParams -> CommandSeek
|
seek :: CmdParams -> CommandSeek
|
||||||
seek = withWords start
|
seek = withWords start
|
||||||
|
|
||||||
start :: CmdParams -> CommandStart
|
start :: CmdParams -> CommandStart
|
||||||
start (localport:[]) = case readish localport of
|
start (suserid:uuid:[]) = case readish suserid of
|
||||||
Nothing -> error "Bad localport"
|
Nothing -> error "Bad userid"
|
||||||
Just lp -> do
|
Just userid -> do
|
||||||
(onionaddr, onionport) <- liftIO $ addHiddenService lp
|
(onionaddr, onionport, onionsocket) <- liftIO $
|
||||||
liftIO $ putStrLn (onionaddr ++ ":" ++ show onionport)
|
addHiddenService userid uuid
|
||||||
|
liftIO $ putStrLn $
|
||||||
|
onionaddr ++ ":" ++
|
||||||
|
show onionport ++ " " ++
|
||||||
|
show onionsocket
|
||||||
stop
|
stop
|
||||||
start _ = error "Need 1 localport parameter"
|
start _ = error "Bad params"
|
||||||
|
|
|
@ -9,39 +9,39 @@ module Utility.Tor where
|
||||||
|
|
||||||
import Common
|
import Common
|
||||||
import Utility.ThreadScheduler
|
import Utility.ThreadScheduler
|
||||||
|
import System.PosixCompat.Types
|
||||||
import Data.Char
|
import Data.Char
|
||||||
|
|
||||||
type LocalPort = Int
|
|
||||||
type OnionPort = Int
|
type OnionPort = Int
|
||||||
type OnionAddress = String
|
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.
|
-- 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
|
-- 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
|
-- other hidden service (and is >= 1024). Returns the hidden service's
|
||||||
-- onion address and port.
|
-- onion address, port, and the unix socket file to use.
|
||||||
|
--
|
||||||
-- If there is already a hidden service for the specified local port,
|
-- If there is already a hidden service for the specified unique
|
||||||
-- returns its information without making any changes.
|
-- identifier, returns its information without making any changes.
|
||||||
addHiddenService :: LocalPort -> IO (OnionAddress, OnionPort)
|
addHiddenService :: UserID -> String -> IO (OnionAddress, OnionPort, OnionSocket)
|
||||||
addHiddenService localport = do
|
addHiddenService uid ident = do
|
||||||
ls <- map (separate isSpace) . lines <$> readFile torrc
|
ls <- lines <$> readFile torrc
|
||||||
let usedports = mapMaybe readish $
|
let portssocks = mapMaybe (parseportsock . separate isSpace) ls
|
||||||
map (drop 1 . dropWhile (/= ':')) $
|
case filter (\(_, s) -> s == sockfile) portssocks of
|
||||||
map snd $
|
((p, _s):_) -> waithiddenservice 1 p
|
||||||
filter (\(k, _) -> k == "HiddenServicePort") ls
|
_ -> do
|
||||||
let newport = Prelude.head $ filter (`notElem` usedports) [1024..]
|
let newport = Prelude.head $
|
||||||
let dir = libDir </> "hidden_service" ++ show localport
|
filter (`notElem` map fst portssocks) [1024..]
|
||||||
if localport `elem` usedports
|
|
||||||
then waithiddenservice 1 dir newport
|
|
||||||
else do
|
|
||||||
writeFile torrc $ unlines $
|
writeFile torrc $ unlines $
|
||||||
map (\(k, v) -> k ++ " " ++ v) ls ++
|
ls ++
|
||||||
[ ""
|
[ ""
|
||||||
, "HiddenServiceDir " ++ dir
|
, "HiddenServiceDir " ++ hsdir
|
||||||
, "HiddenServicePort " ++ show newport ++
|
, "HiddenServicePort " ++ show newport ++
|
||||||
" 127.0.0.1:" ++ show localport
|
" unix:" ++ sockfile
|
||||||
]
|
]
|
||||||
-- Reload tor, so it will see the new hidden
|
-- Reload tor, so it will see the new hidden
|
||||||
-- service and generate the hostname file for it.
|
-- service and generate the hostname file for it.
|
||||||
|
@ -51,21 +51,32 @@ addHiddenService localport = do
|
||||||
]
|
]
|
||||||
unless reloaded $
|
unless reloaded $
|
||||||
error "failed to reload tor, perhaps the tor service is not running"
|
error "failed to reload tor, perhaps the tor service is not running"
|
||||||
waithiddenservice 120 dir newport
|
waithiddenservice 120 newport
|
||||||
where
|
where
|
||||||
waithiddenservice :: Int -> FilePath -> OnionPort -> IO (OnionAddress, OnionPort)
|
parseportsock ("HiddenServicePort", l) = do
|
||||||
waithiddenservice 0 _ _ = error "tor failed to create hidden service, perhaps the tor service is not running"
|
p <- readish $ takeWhile (not . isSpace) l
|
||||||
waithiddenservice n dir newport = do
|
return (p, drop 1 (dropWhile (/= ':') l))
|
||||||
v <- tryIO $ readFile (dir </> "hostname")
|
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
|
case v of
|
||||||
Right s | ".onion\n" `isSuffixOf` s ->
|
Right s | ".onion\n" `isSuffixOf` s ->
|
||||||
return (takeWhile (/= '\n') s, newport)
|
return (takeWhile (/= '\n') s, p, sockfile)
|
||||||
_ -> do
|
_ -> do
|
||||||
threadDelaySeconds (Seconds 1)
|
threadDelaySeconds (Seconds 1)
|
||||||
waithiddenservice (n-1) dir newport
|
waithiddenservice (n-1) p
|
||||||
|
|
||||||
torrc :: FilePath
|
torrc :: FilePath
|
||||||
torrc = "/etc/tor/torrc"
|
torrc = "/etc/tor/torrc"
|
||||||
|
|
||||||
libDir :: FilePath
|
libDir :: FilePath
|
||||||
libDir = "/var/lib/tor"
|
libDir = "/var/lib/tor"
|
||||||
|
|
||||||
|
runDir :: UserID -> FilePath
|
||||||
|
runDir uid = "/var/run/user" </> show uid
|
||||||
|
|
|
@ -4,13 +4,13 @@ git-annex enable-tor - enable tor hidden service
|
||||||
|
|
||||||
# SYNOPSIS
|
# SYNOPSIS
|
||||||
|
|
||||||
git annex enable-tor localport
|
git annex enable-tor userid uuid
|
||||||
|
|
||||||
# DESCRIPTION
|
# DESCRIPTION
|
||||||
|
|
||||||
This plumbing-level command enables a tor hidden service for git-annex,
|
This plumbing-level command enables a tor hidden service for git-annex,
|
||||||
using the specified local port number. It outputs to stdout a line
|
using the specified repository uuid and userid.
|
||||||
of the form "address.onion:onionport"
|
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`.
|
This command has to be run by root, since it modifies `/etc/tor/torrc`.
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue