summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--OnionRouter.hs28
-rw-r--r--Roster.hs29
-rw-r--r--examples/dhtd.hs1
-rw-r--r--src/Network/Tox.hs4
-rw-r--r--src/Network/Tox/DHT/Transport.hs3
-rw-r--r--src/Network/Tox/Onion/Handlers.hs3
-rw-r--r--src/Network/Tox/Onion/Transport.hs98
7 files changed, 117 insertions, 49 deletions
diff --git a/OnionRouter.hs b/OnionRouter.hs
index 289dc7f4..26bc6525 100644
--- a/OnionRouter.hs
+++ b/OnionRouter.hs
@@ -31,9 +31,6 @@ import Network.Socket
31import System.Endian 31import System.Endian
32import System.IO 32import System.IO
33 33
34newtype RouteId = RouteId Int
35 deriving Show
36
37-- Toxcore saves a maximum of 12 paths: 6 paths are reserved for announcing 34-- Toxcore saves a maximum of 12 paths: 6 paths are reserved for announcing
38-- ourselves and 6 others are used to search for friends. 35-- ourselves and 6 others are used to search for friends.
39-- 36--
@@ -210,8 +207,8 @@ randomIvalInteger (l,h) rng
210selectTrampolines :: OnionRouter -> STM [NodeInfo] 207selectTrampolines :: OnionRouter -> STM [NodeInfo]
211selectTrampolines or = do 208selectTrampolines or = do
212 cnt <- readTVar (trampolineCount or) 209 cnt <- readTVar (trampolineCount or)
213 drg0 <- readTVar (onionDRG or)
214 ts <- readTVar (trampolineNodes or) 210 ts <- readTVar (trampolineNodes or)
211 drg0 <- readTVar (onionDRG or)
215 let (a, drg1) = randomR (0,cnt - 1) drg0 212 let (a, drg1) = randomR (0,cnt - 1) drg0
216 (b0, drg2) = randomR (0,cnt - 2) drg1 213 (b0, drg2) = randomR (0,cnt - 2) drg1
217 (c0, drg ) = randomR (0,cnt - 3) drg2 214 (c0, drg ) = randomR (0,cnt - 3) drg2
@@ -289,29 +286,6 @@ handleEvent getnodes or e@(BuildRoute (RouteId rid)) = do
289 Just _ -> hPutStrLn stderr $ "ONION Finished RouteId " ++ show rid 286 Just _ -> hPutStrLn stderr $ "ONION Finished RouteId " ++ show rid
290 Nothing -> hPutStrLn stderr $ "ONION Failed RouteId " ++ show rid 287 Nothing -> hPutStrLn stderr $ "ONION Failed RouteId " ++ show rid
291 288
292-- We used to derive the RouteId from the Nonce8 associated with the query.
293-- This is problematic because a nonce generated by toxcore will not validate
294-- if it is received via a different route than it was issued. This is
295-- described by the Tox spec:
296--
297-- Toxcore generates `ping_id`s by taking a 32 byte sha hash of the current
298-- time, some secret bytes generated when the instance is created, the
299-- current time divided by a 20 second timeout, the public key of the
300-- requester and the source ip/port that the packet was received from. Since
301-- the ip/port that the packet was received from is in the `ping_id`, the
302-- announce packets being sent with a ping id must be sent using the same
303-- path as the packet that we received the `ping_id` from or announcing will
304-- fail.
305--
306-- The original idea was:
307--
308-- > routeId :: Nonce8 -> RouteId
309-- > routeId (Nonce8 w8) = RouteId $ mod (fromIntegral w8) 12
310--
311-- Instead, we'll just hash the destination node id.
312routeId :: NodeId -> RouteId
313routeId nid = RouteId $ mod (hash nid) 12
314
315lookupSender :: OnionRouter -> SockAddr -> Nonce8 -> IO (Maybe (OnionDestination RouteId)) 289lookupSender :: OnionRouter -> SockAddr -> Nonce8 -> IO (Maybe (OnionDestination RouteId))
316lookupSender or saddr (Nonce8 w8) = do 290lookupSender or saddr (Nonce8 w8) = do
317 result <- atomically $ do 291 result <- atomically $ do
diff --git a/Roster.hs b/Roster.hs
index 94ab462d..ab2f9911 100644
--- a/Roster.hs
+++ b/Roster.hs
@@ -1,13 +1,15 @@
1{-# LANGUAGE NamedFieldPuns #-} 1{-# LANGUAGE NamedFieldPuns #-}
2module Roster where 2module Roster where
3 3
4import Crypto.PubKey.Curve25519 4import System.IO
5import Network.Tox.Onion.Transport as Onion 5import Control.Monad
6import Network.Tox.DHT.Transport as DHT
7import Network.Tox.NodeId
8import Control.Concurrent.STM 6import Control.Concurrent.STM
7import Crypto.PubKey.Curve25519
9import qualified Data.HashMap.Strict as HashMap 8import qualified Data.HashMap.Strict as HashMap
10import Data.HashMap.Strict (HashMap) 9 ;import Data.HashMap.Strict (HashMap)
10import Network.Tox.DHT.Transport as DHT
11import Network.Tox.NodeId
12import Network.Tox.Onion.Transport as Onion
11 13
12newtype Roster = Roster { accounts :: TVar (HashMap NodeId Account) } 14newtype Roster = Roster { accounts :: TVar (HashMap NodeId Account) }
13 15
@@ -32,6 +34,7 @@ delRoster (Roster as) pk = modifyTVar' as $ HashMap.delete (key2id pk)
32 34
33updateRoster :: Roster -> Onion.AnnouncedRendezvous -> (PublicKey,Onion.OnionData) -> IO () 35updateRoster :: Roster -> Onion.AnnouncedRendezvous -> (PublicKey,Onion.OnionData) -> IO ()
34updateRoster roster Onion.AnnouncedRendezvous{remoteUserKey} (localUserKey,omsg) = do 36updateRoster roster Onion.AnnouncedRendezvous{remoteUserKey} (localUserKey,omsg) = do
37 hPutStrLn stderr "updateRoster!!!"
35 atomically $ do 38 atomically $ do
36 as <- readTVar (accounts roster) 39 as <- readTVar (accounts roster)
37 maybe (return ()) 40 maybe (return ())
@@ -53,3 +56,19 @@ updateAccount remoteUserKey (Onion.OnionDHTPublicKey dhtpk) acc = do
53updateAccount remoteUserKey (Onion.OnionFriendRequest fr) acc = do 56updateAccount remoteUserKey (Onion.OnionFriendRequest fr) acc = do
54 -- TODO 57 -- TODO
55 return () 58 return ()
59
60dnsPresentation :: Roster -> STM String
61dnsPresentation (Roster accsvar) = do
62 accs <- readTVar accsvar
63 ms <- forM accs $ \Account { userSecret = sec, contacts = cvar } -> do
64 cs <- readTVar cvar
65 return $
66 "; local key = " ++ show (key2id $ toPublic sec) ++ "\n"
67 ++ concatMap dnsPresentation1 (HashMap.toList cs)
68 return $ concat ms
69
70dnsPresentation1 :: (NodeId,DHTPublicKey) -> String
71dnsPresentation1 (nid,dk) = unlines
72 [ concat [ show nid, ".tox. IN CNAME ", show (key2id $ dhtpk dk), ".dht." ]
73 ]
74
diff --git a/examples/dhtd.hs b/examples/dhtd.hs
index cf0328e8..4dad2fe7 100644
--- a/examples/dhtd.hs
+++ b/examples/dhtd.hs
@@ -430,6 +430,7 @@ clientSession s@Session{..} sock cnum h = do
430 forM pairs $ \(_,pk) -> delRoster roster pk 430 forM pairs $ \(_,pk) -> delRoster roster pk
431 readTVar userkeys 431 readTVar userkeys
432 hPutClient h . showReport $ map mkrow ks 432 hPutClient h . showReport $ map mkrow ks
433 ("roster", s) -> cmd0 $ atomically (dnsPresentation roster) >>= hPutClient h
433 ("g", s) | Just DHT{..} <- Map.lookup netname dhts 434 ("g", s) | Just DHT{..} <- Map.lookup netname dhts
434 -> cmd0 $ do 435 -> cmd0 $ do
435 -- arguments: method 436 -- arguments: method
diff --git a/src/Network/Tox.hs b/src/Network/Tox.hs
index 93e3c663..29591a23 100644
--- a/src/Network/Tox.hs
+++ b/src/Network/Tox.hs
@@ -247,12 +247,12 @@ addVerbosity :: Transport err SockAddr ByteString -> Transport err SockAddr Byte
247addVerbosity tr = 247addVerbosity tr =
248 tr { awaitMessage = \kont -> awaitMessage tr $ \m -> do 248 tr { awaitMessage = \kont -> awaitMessage tr $ \m -> do
249 forM_ m $ mapM_ $ \(msg,addr) -> do 249 forM_ m $ mapM_ $ \(msg,addr) -> do
250 when (isLocalHost addr || not (B.null msg || elem (B.head msg) [0,1,2,4,0x81,0x82,0x8c,0x8d])) $ do 250 when (not (B.null msg || elem (B.head msg) [0,1,2,4,0x81,0x82,0x8c,0x8d])) $ do
251 mapM_ (\x -> hPutStrLn stderr ( (show addr) ++ " --> " ++ x)) 251 mapM_ (\x -> hPutStrLn stderr ( (show addr) ++ " --> " ++ x))
252 $ xxd 0 msg 252 $ xxd 0 msg
253 kont m 253 kont m
254 , sendMessage = \addr msg -> do 254 , sendMessage = \addr msg -> do
255 when (isLocalHost addr || not (B.null msg || elem (B.head msg) [0,1,2,4,0x81,0x82,0x8c,0x8d])) $ do 255 when (not (B.null msg || elem (B.head msg) [0,1,2,4,0x81,0x8c,0x8d])) $ do
256 mapM_ (\x -> hPutStrLn stderr ( (show addr) ++ " <-- " ++ x)) 256 mapM_ (\x -> hPutStrLn stderr ( (show addr) ++ " <-- " ++ x))
257 $ xxd 0 msg 257 $ xxd 0 msg
258 sendMessage tr addr msg 258 sendMessage tr addr msg
diff --git a/src/Network/Tox/DHT/Transport.hs b/src/Network/Tox/DHT/Transport.hs
index 0787c2c1..47505a21 100644
--- a/src/Network/Tox/DHT/Transport.hs
+++ b/src/Network/Tox/DHT/Transport.hs
@@ -210,6 +210,8 @@ data DHTPublicKey = DHTPublicKey
210 , dhtpk :: PublicKey -- dht public key 210 , dhtpk :: PublicKey -- dht public key
211 , dhtpkNodes :: SendNodes -- other reachable nodes 211 , dhtpkNodes :: SendNodes -- other reachable nodes
212 } 212 }
213 deriving (Eq, Show)
214
213 215
214-- int8_t (0x20 sent over onion, 0x12 for sent over net_crypto) 216-- int8_t (0x20 sent over onion, 0x12 for sent over net_crypto)
215-- [uint32_t nospam][Message (UTF8) 1 to ONION_CLIENT_MAX_DATA_SIZE bytes] 217-- [uint32_t nospam][Message (UTF8) 1 to ONION_CLIENT_MAX_DATA_SIZE bytes]
@@ -217,6 +219,7 @@ data FriendRequest = FriendRequest
217 { friendNoSpam :: Word32 219 { friendNoSpam :: Word32
218 , friendRequestText :: ByteString -- UTF8 220 , friendRequestText :: ByteString -- UTF8
219 } 221 }
222 deriving (Eq, Show)
220 223
221-- When sent as a DHT request packet (this is the data sent in the DHT request 224-- When sent as a DHT request packet (this is the data sent in the DHT request
222-- packet): 225-- packet):
diff --git a/src/Network/Tox/Onion/Handlers.hs b/src/Network/Tox/Onion/Handlers.hs
index 3eec0390..76908df8 100644
--- a/src/Network/Tox/Onion/Handlers.hs
+++ b/src/Network/Tox/Onion/Handlers.hs
@@ -117,13 +117,16 @@ dataToRouteH ::
117 -> IO () 117 -> IO ()
118dataToRouteH keydb udp _ (OnionToRoute pub asymm) = do 118dataToRouteH keydb udp _ (OnionToRoute pub asymm) = do
119 let k = key2id pub 119 let k = key2id pub
120 hPutStrLn stderr $ "dataToRouteH "++ show k
120 mb <- atomically $ do 121 mb <- atomically $ do
121 ks <- readTVar keydb 122 ks <- readTVar keydb
122 forM (MinMaxPSQ.lookup' k (keyAssoc ks)) $ \(p,(cnt,rpath)) -> do 123 forM (MinMaxPSQ.lookup' k (keyAssoc ks)) $ \(p,(cnt,rpath)) -> do
123 writeTVar keydb $ ks { keyAssoc = MinMaxPSQ.insert' k (cnt + 1, rpath) p (keyAssoc ks) } 124 writeTVar keydb $ ks { keyAssoc = MinMaxPSQ.insert' k (cnt + 1, rpath) p (keyAssoc ks) }
124 return rpath 125 return rpath
126 hPutStrLn stderr $ "dataToRouteH "++ show (fmap (const ()) mb)
125 forM_ mb $ \rpath -> do 127 forM_ mb $ \rpath -> do
126 -- forward 128 -- forward
129 hPutStrLn stderr $ "dataToRouteH sendMessage"
127 sendMessage udp (toOnionDestination rpath) $ OnionToRouteResponse asymm 130 sendMessage udp (toOnionDestination rpath) $ OnionToRouteResponse asymm
128 hPutStrLn stderr $ "Forwarding data-to-route -->"++show k 131 hPutStrLn stderr $ "Forwarding data-to-route -->"++show k
129 132
diff --git a/src/Network/Tox/Onion/Transport.hs b/src/Network/Tox/Onion/Transport.hs
index 6635fad1..85cf095d 100644
--- a/src/Network/Tox/Onion/Transport.hs
+++ b/src/Network/Tox/Onion/Transport.hs
@@ -44,6 +44,8 @@ module Network.Tox.Onion.Transport
44 , onionKey 44 , onionKey
45 , onionAliasSelector 45 , onionAliasSelector
46 , selectAlias 46 , selectAlias
47 , RouteId(..)
48 , routeId
47 ) where 49 ) where
48 50
49import Network.Address (fromSockAddr,toSockAddr,setPort,either4or6,sockAddrPort) 51import Network.Address (fromSockAddr,toSockAddr,setPort,either4or6,sockAddrPort)
@@ -51,7 +53,7 @@ import Network.QueryResponse
51import Crypto.Tox hiding (encrypt,decrypt) 53import Crypto.Tox hiding (encrypt,decrypt)
52import Network.Tox.NodeId 54import Network.Tox.NodeId
53import qualified Crypto.Tox as ToxCrypto 55import qualified Crypto.Tox as ToxCrypto
54import Network.Tox.DHT.Transport (NodeInfo(..),NodeId(..),SendNodes(..),nodeInfo,DHTPublicKey,FriendRequest,asymNodeInfo) 56import Network.Tox.DHT.Transport (NodeInfo(..),NodeId(..),SendNodes(..),nodeInfo,DHTPublicKey(..),FriendRequest,asymNodeInfo)
55 57
56import Control.Applicative 58import Control.Applicative
57import Control.Arrow 59import Control.Arrow
@@ -76,6 +78,7 @@ import GHC.TypeLits
76import Network.Socket 78import Network.Socket
77import System.IO 79import System.IO
78import qualified Text.ParserCombinators.ReadP as RP 80import qualified Text.ParserCombinators.ReadP as RP
81import Data.Hashable
79 82
80type HandleLo a = Maybe (Either String (ByteString, SockAddr)) -> IO a 83type HandleLo a = Maybe (Either String (ByteString, SockAddr)) -> IO a
81 84
@@ -200,15 +203,44 @@ putOnionMsg (OnionToRoute pubkey a) = putOnionAsymm 0x85 (putPublicKey
200putOnionMsg (OnionAnnounceResponse n8 n24 x) = put (0x84 :: Word8) >> put n8 >> put n24 >> put x 203putOnionMsg (OnionAnnounceResponse n8 n24 x) = put (0x84 :: Word8) >> put n8 >> put n24 >> put x
201putOnionMsg (OnionToRouteResponse a) = putOnionAsymm 0x86 (return ()) a 204putOnionMsg (OnionToRouteResponse a) = putOnionAsymm 0x86 (return ()) a
202 205
203encodeOnionAddr :: (NodeInfo -> r -> IO (Maybe OnionRoute)) 206newtype RouteId = RouteId Int
204 -> (OnionMessage Encrypted,OnionDestination r) 207 deriving Show
208
209
210-- We used to derive the RouteId from the Nonce8 associated with the query.
211-- This is problematic because a nonce generated by toxcore will not validate
212-- if it is received via a different route than it was issued. This is
213-- described by the Tox spec:
214--
215-- Toxcore generates `ping_id`s by taking a 32 byte sha hash of the current
216-- time, some secret bytes generated when the instance is created, the
217-- current time divided by a 20 second timeout, the public key of the
218-- requester and the source ip/port that the packet was received from. Since
219-- the ip/port that the packet was received from is in the `ping_id`, the
220-- announce packets being sent with a ping id must be sent using the same
221-- path as the packet that we received the `ping_id` from or announcing will
222-- fail.
223--
224-- The original idea was:
225--
226-- > routeId :: Nonce8 -> RouteId
227-- > routeId (Nonce8 w8) = RouteId $ mod (fromIntegral w8) 12
228--
229-- Instead, we'll just hash the destination node id.
230routeId :: NodeId -> RouteId
231routeId nid = RouteId $ mod (hash nid) 12
232
233
234encodeOnionAddr :: (NodeInfo -> RouteId -> IO (Maybe OnionRoute))
235 -> (OnionMessage Encrypted,OnionDestination RouteId)
205 -> IO (Maybe (ByteString, SockAddr)) 236 -> IO (Maybe (ByteString, SockAddr))
206encodeOnionAddr _ (msg,OnionToOwner ni p) = 237encodeOnionAddr _ (msg,OnionToOwner ni p) =
207 return $ Just ( runPut $ putResponse (OnionResponse p msg) 238 return $ Just ( runPut $ putResponse (OnionResponse p msg)
208 , nodeAddr ni ) 239 , nodeAddr ni )
209encodeOnionAddr _ (msg,OnionDestination _ _ Nothing) = do 240encodeOnionAddr getRoute (msg,OnionDestination x ni Nothing) = do
210 hPutStrLn stderr $ "ONION encode missing routeid" 241 encodeOnionAddr getRoute (msg,OnionDestination x ni (Just $ routeId $ nodeId ni) )
211 return Nothing 242 -- hPutStrLn stderr $ "ONION encode missing routeid"
243 -- return Nothing
212encodeOnionAddr getRoute (msg,OnionDestination _ ni (Just rid)) = do 244encodeOnionAddr getRoute (msg,OnionDestination _ ni (Just rid)) = do
213 let go route = do 245 let go route = do
214 return ( runPut $ putRequest $ wrapForRoute msg ni route 246 return ( runPut $ putRequest $ wrapForRoute msg ni route
@@ -601,6 +633,7 @@ data OnionData
601 -- 633 --
602 -- 634 --
603 OnionFriendRequest FriendRequest -- 0x20 635 OnionFriendRequest FriendRequest -- 0x20
636 deriving (Eq,Show)
604 637
605instance Sized OnionData where 638instance Sized OnionData where
606 size = VarSize $ \case 639 size = VarSize $ \case
@@ -790,26 +823,46 @@ parseDataToRoute
790 :: TransportCrypto 823 :: TransportCrypto
791 -> (OnionMessage Encrypted,OnionDestination r) 824 -> (OnionMessage Encrypted,OnionDestination r)
792 -> IO (Either ((PublicKey,OnionData),AnnouncedRendezvous) (OnionMessage Encrypted, OnionDestination r)) 825 -> IO (Either ((PublicKey,OnionData),AnnouncedRendezvous) (OnionMessage Encrypted, OnionDestination r))
793parseDataToRoute crypto (OnionToRouteResponse dta, od) = 826parseDataToRoute crypto (OnionToRouteResponse dta, od) = do
794 return $ either (const $ Right (OnionToRouteResponse dta,od)) Left $ do 827 ks <- atomically $ readTVar $ userKeys crypto
795 -- XXX: Do something with decryption failure? 828
796 dtr <- fmap runIdentity 829 let eOuter = do
830 fmap runIdentity
797 $ uncomposed 831 $ uncomposed
798 $ decryptMessage (rendezvousSecret crypto,rendezvousPublic crypto) 832 $ decryptMessage (rendezvousSecret crypto,rendezvousPublic crypto)
799 (asymmNonce dta) 833 (asymmNonce dta)
800 (Right dta) 834 (Right dta) -- using Asymm{senderKey} as remote key
801 let (sk,pk) = case onionAliasSelector od of 835
802 SearchingAlias -> (onionAliasSecret &&& onionAliasPublic) crypto 836 -- TODO: We don't currently have a way to look up which user key we
803 AnnouncingAlias sk pk -> (sk,pk) 837 -- announced using along this onion route. Therefore, for now, we will
838 -- try all our user keys to see if any can decrypt the packet.
839 eInners = flip map ks $ \(sk,pk) -> do
840 dtr <- eOuter
804 omsg <- fmap runIdentity 841 omsg <- fmap runIdentity
805 $ uncomposed 842 $ uncomposed
806 $ decryptMessage (sk,pk) 843 $ decryptMessage (sk,pk)
807 (asymmNonce dta) 844 (asymmNonce dta)
808 (Left (dataFromKey dtr, dataToRoute dtr)) 845 (Left (dataFromKey dtr, dataToRoute dtr))
846 return (pk,dtr,omsg)
847
848 eInner = foldr1 (<|>) eInners
849
850 e = do
851 (pk,dtr,omsg) <- eInner
809 return ( (pk, omsg) 852 return ( (pk, omsg)
810 , AnnouncedRendezvous 853 , AnnouncedRendezvous
811 (dataFromKey dtr) 854 (dataFromKey dtr)
812 $ Rendezvous (rendezvousPublic crypto) $ onionNodeInfo od ) 855 $ Rendezvous (rendezvousPublic crypto) $ onionNodeInfo od )
856 r = either (const $ Right (OnionToRouteResponse dta,od)) Left e
857 -- parseDataToRoute OnionToRouteResponse decipherAndAuth: auth fail
858 hPutStrLn stderr $ unlines
859 [ "parseDataToRoute " ++ either id (const "Right") e
860 , " crypto inner.me =" ++ either id (\(pk,_,_) -> show $ key2id pk) eInner
861 , " inner.you=" ++ either id (show . key2id . dataFromKey) eOuter
862 , " outer.me =" ++ show (key2id $ rendezvousPublic crypto)
863 , " outer.you=" ++ show (key2id $ senderKey dta)
864 ]
865 return r
813parseDataToRoute _ msg = return $ Right msg 866parseDataToRoute _ msg = return $ Right msg
814 867
815encodeDataToRoute :: TransportCrypto 868encodeDataToRoute :: TransportCrypto
@@ -825,7 +878,22 @@ encodeDataToRoute crypto ((me,omsg), AnnouncedRendezvous toxid (Rendezvous pub n
825 , dataToRoute = encryptMessage sk toxid nonce omsg 878 , dataToRoute = encryptMessage sk toxid nonce omsg
826 } 879 }
827 let dta = encryptMessage (onionAliasSecret crypto) pub nonce plain 880 let dta = encryptMessage (onionAliasSecret crypto) pub nonce plain
828 return $ Just ( OnionToRoute pub -- Public key of destination node 881 hPutStrLn stderr $ unlines
882 [ "encodeDataToRoute me=" ++ show (key2id me)
883 , " dhtpk=" ++ case omsg of
884 OnionDHTPublicKey dmsg -> show (key2id $ dhtpk dmsg)
885 OnionFriendRequest fr -> "friend request"
886 , " ns=" ++ case omsg of
887 OnionDHTPublicKey dmsg -> show (dhtpkNodes dmsg)
888 OnionFriendRequest fr -> "friend request"
889 , " crypto inner.me =" ++ show (key2id pk)
890 , " inner.you=" ++ show (key2id toxid)
891 , " outer.me =" ++ show (key2id $ onionAliasPublic crypto)
892 , " outer.you=" ++ show (key2id pub)
893 , " " ++ show (AnnouncedRendezvous toxid (Rendezvous pub ni))
894 , " " ++ show dta
895 ]
896 return $ Just ( OnionToRoute toxid -- Public key of destination node
829 Asymm { senderKey = onionAliasPublic crypto 897 Asymm { senderKey = onionAliasPublic crypto
830 , asymmNonce = nonce 898 , asymmNonce = nonce
831 , asymmData = dta 899 , asymmData = dta