diff --git a/src/Network/Anonymous/Tor.hs b/src/Network/Anonymous/Tor.hs index 95fc397..602ae54 100644 --- a/src/Network/Anonymous/Tor.hs +++ b/src/Network/Anonymous/Tor.hs @@ -179,4 +179,4 @@ accept sock port pkey callback = do return ())) -- Do the onion mapping after that - P.mapOnion sock port port False pkey + P.mapOnionV3 sock port port False pkey diff --git a/src/Network/Anonymous/Tor/Protocol.hs b/src/Network/Anonymous/Tor/Protocol.hs index 99c6f2e..3c04dfc 100644 --- a/src/Network/Anonymous/Tor/Protocol.hs +++ b/src/Network/Anonymous/Tor/Protocol.hs @@ -16,7 +16,8 @@ module Network.Anonymous.Tor.Protocol ( Availability (..) , connect' , protocolInfo , authenticate - , mapOnion ) where + , mapOnion + , mapOnionV3 ) where import Control.Concurrent.MVar @@ -239,7 +240,7 @@ authenticate s = do errorF (Ast.Line 250 _) = Nothing errorF _ = Just . E.permissionDeniedErrorType $ "Authentication failed." --- | Creates a new hidden service and maps a public port to a local port. Useful +-- | Creates a new hidden service v2 and maps a public port to a local port. Useful -- for bridging a local service (e.g. a webserver or irc daemon) as a Tor -- hidden service. If a private key is supplied, it is used to instantiate the -- service. @@ -253,7 +254,7 @@ mapOnion :: MonadIO m mapOnion s rport lport detach pkey = do reply <- sendCommand s $ BS8.concat [ "ADD_ONION " - , maybe "NEW:BEST" (\pk -> "RSA1024:" `BS.append` pk) pkey + , maybe "NEW:RSA1024" (\pk -> "RSA1024:" `BS.append` pk) pkey , if detach then " Flags=Detach " else " " , "Port=" , BS8.pack (show rport) @@ -262,3 +263,27 @@ mapOnion s rport lport detach pkey = do , "\n"] return . B32.b32String' . fromJust . Ast.tokenValue . head . Ast.lineMessage . fromJust $ Ast.line (BS8.pack "ServiceID") reply + +-- | Creates a new hidden service v3 and maps a public port to a local port. Useful +-- for bridging a local service (e.g. a webserver or irc daemon) as a Tor +-- hidden service. If a private key is supplied, it is used to instantiate the +-- service. +mapOnionV3 :: MonadIO m + => Network.Socket -- ^ Connection with tor Control port + -> Integer -- ^ Remote point of hidden service to listen at + -> Integer -- ^ Local port to map onion service to + -> Bool -- ^ Wether to detach the hidden service from the current session + -> Maybe BS.ByteString -- ^ Optional private key to use to set up the hidden service + -> m B32.Base32String -- ^ The address/service id of the Onion without the .onion part +mapOnionV3 s rport lport detach pkey = do + reply <- sendCommand s $ BS8.concat + [ "ADD_ONION " + , maybe "NEW:ED25519-V3" (\pk -> "ED25519-V3:" `BS.append` pk) pkey + , if detach then " Flags=Detach " else " " + , "Port=" + , BS8.pack (show rport) + , ",127.0.0.1:" + , BS8.pack(show lport) + , "\n"] + + return . B32.b32String' . fromJust . Ast.tokenValue . head . Ast.lineMessage . fromJust $ Ast.line (BS8.pack "ServiceID") reply \ No newline at end of file diff --git a/test/Network/Anonymous/Tor/ProtocolSpec.hs b/test/Network/Anonymous/Tor/ProtocolSpec.hs index 0998e8e..2f948eb 100644 --- a/test/Network/Anonymous/Tor/ProtocolSpec.hs +++ b/test/Network/Anonymous/Tor/ProtocolSpec.hs @@ -94,7 +94,7 @@ spec = do takeMVar done `shouldReturn` True - describe "when mapping an onion address" $ do + describe "when mapping an onion address v2" $ do it "should succeed in creating a mapping" $ let serverSock sock = do putStrLn "got client connecting to hidden service!" @@ -125,3 +125,34 @@ spec = do P.connect' controlSock (constructSocksDestination addr) clientSock killThread thread + + describe "when mapping an onion address v3" $ do + it "should succeed in creating a mapping" $ + let serverSock sock = do + putStrLn "got client connecting to hidden service!" + NS.send sock "HELLO\n" + clientSock _ = + putStrLn "Got a connection with hidden service!" + + destinationAddress onion = + TE.encodeUtf8 $ T.concat [B32.toText onion, T.pack ".ONION"] + + constructSocksDestination onion = + SocksT.SocksAddress (SocksT.SocksAddrDomainName (destinationAddress onion)) 80 + + in do + thread <- liftIO $ mockServer "8080" serverSock + + _ <- connect $ \controlSock -> do + P.authenticate controlSock + addr <- P.mapOnionV3 controlSock 80 8080 False Nothing + + putStrLn ("got onion address: " ++ show addr) + putStrLn ("waiting 1 minute..") + + threadDelay 60000000 + + putStrLn ("waited 1 minute, connecting..") + + P.connect' controlSock (constructSocksDestination addr) clientSock + killThread thread