diff options
-rw-r--r-- | dht/src/Data/Tox/DHT/Multi.hs | 45 | ||||
-rw-r--r-- | dht/src/Data/Tox/Onion.hs | 19 | ||||
-rw-r--r-- | dht/src/Network/Tox.hs | 66 | ||||
-rw-r--r-- | dht/src/Network/Tox/Onion/Routes.hs | 33 | ||||
-rw-r--r-- | dht/src/Network/Tox/Onion/Transport.hs | 53 | ||||
-rw-r--r-- | dht/src/Network/Tox/TCP.hs | 60 |
6 files changed, 161 insertions, 115 deletions
diff --git a/dht/src/Data/Tox/DHT/Multi.hs b/dht/src/Data/Tox/DHT/Multi.hs index f769e384..7c8804b5 100644 --- a/dht/src/Data/Tox/DHT/Multi.hs +++ b/dht/src/Data/Tox/DHT/Multi.hs | |||
@@ -11,6 +11,7 @@ import Crypto.PubKey.Curve25519 (PublicKey) | |||
11 | import qualified Network.Tox.NodeId as UDP | 11 | import qualified Network.Tox.NodeId as UDP |
12 | ;import Network.Tox.NodeId (NodeId) | 12 | ;import Network.Tox.NodeId (NodeId) |
13 | import qualified Network.Tox.TCP.NodeId as TCP | 13 | import qualified Network.Tox.TCP.NodeId as TCP |
14 | import Data.Tox.Onion (OnionDestination,RouteId) | ||
14 | import Data.Tox.Relay hiding (NodeInfo) | 15 | import Data.Tox.Relay hiding (NodeInfo) |
15 | import Network.Address (either4or6) | 16 | import Network.Address (either4or6) |
16 | import Network.Tox.TCP as TCP (ViaRelay(..), tcpConnectionRequest_) | 17 | import Network.Tox.TCP as TCP (ViaRelay(..), tcpConnectionRequest_) |
@@ -64,25 +65,40 @@ instance GShow S where | |||
64 | gshowsPrec _ SessionUDP = showString "UDP" | 65 | gshowsPrec _ SessionUDP = showString "UDP" |
65 | gshowsPrec _ SessionTCP = showString "TCP" | 66 | gshowsPrec _ SessionTCP = showString "TCP" |
66 | 67 | ||
68 | data O addr where | ||
69 | OnionUDP :: O (OnionDestination RouteId) | ||
70 | OnionTCP :: O (OnionDestination RouteId) | ||
71 | |||
72 | instance GEq O where | ||
73 | geq OnionUDP OnionUDP = Just Refl | ||
74 | geq OnionTCP OnionTCP = Just Refl | ||
75 | geq _ _ = Nothing | ||
76 | instance GCompare O where | ||
77 | gcompare OnionUDP OnionUDP = GEQ | ||
78 | gcompare OnionUDP OnionTCP = GLT | ||
79 | gcompare OnionTCP OnionTCP = GEQ | ||
80 | gcompare OnionTCP OnionUDP = GGT | ||
81 | instance GShow O where | ||
82 | gshowsPrec _ OnionUDP = showString "UDP" | ||
83 | gshowsPrec _ OnionTCP = showString "TCP" | ||
84 | |||
85 | untagOnion :: DSum O Identity -> OnionDestination RouteId | ||
86 | untagOnion (OnionUDP :=> Identity o) = o | ||
87 | untagOnion (OnionTCP :=> Identity o) = o | ||
88 | |||
67 | -- Canonical in case of 6-mapped-4 addresses. | 89 | -- Canonical in case of 6-mapped-4 addresses. |
68 | canonize :: DSum S Identity -> DSum S Identity | 90 | canonize :: DSum S Identity -> DSum S Identity |
69 | canonize (SessionUDP :=> Identity saddr) = SessionUDP ==> either id id (either4or6 saddr) | 91 | canonize (SessionUDP :=> Identity saddr) = SessionUDP ==> either id id (either4or6 saddr) |
70 | canonize taddr = taddr | 92 | canonize taddr = taddr |
71 | 93 | ||
72 | data A addr where | ||
73 | AddrUDP :: SockAddr -> A UDP.NodeInfo | ||
74 | AddrTCP :: Maybe ConId -> TCP.NodeInfo -> A TCP.ViaRelay | ||
75 | |||
76 | deriving instance Eq (A addr) | ||
77 | |||
78 | type NodeInfo = DSum T Identity | 94 | type NodeInfo = DSum T Identity |
79 | type SessionAddress = DSum S Identity | 95 | type SessionAddress = DSum S Identity |
80 | 96 | type OnionAddress = DSum O Identity | |
81 | type Address = DSum T A | ||
82 | 97 | ||
83 | #if MIN_VERSION_dependent_sum(0,6,0) | 98 | #if MIN_VERSION_dependent_sum(0,6,0) |
84 | deriveArgDict ''T | 99 | deriveArgDict ''T |
85 | deriveArgDict ''S | 100 | deriveArgDict ''S |
101 | deriveArgDict ''O | ||
86 | #else | 102 | #else |
87 | instance ShowTag T Identity where | 103 | instance ShowTag T Identity where |
88 | showTaggedPrec UDP = showsPrec | 104 | showTaggedPrec UDP = showsPrec |
@@ -90,6 +106,9 @@ instance ShowTag T Identity where | |||
90 | instance ShowTag S Identity where | 106 | instance ShowTag S Identity where |
91 | showTaggedPrec SessionUDP = showsPrec | 107 | showTaggedPrec SessionUDP = showsPrec |
92 | showTaggedPrec SessionTCP = showsPrec | 108 | showTaggedPrec SessionTCP = showsPrec |
109 | instance ShowTag O Identity where | ||
110 | showTaggedPrec OnionUDP = showsPrec | ||
111 | showTaggedPrec OnionTCP = showsPrec | ||
93 | instance EqTag S Identity where | 112 | instance EqTag S Identity where |
94 | eqTagged SessionUDP SessionUDP = (==) | 113 | eqTagged SessionUDP SessionUDP = (==) |
95 | eqTagged SessionTCP SessionTCP = (==) | 114 | eqTagged SessionTCP SessionTCP = (==) |
@@ -99,16 +118,6 @@ instance OrdTag S Identity where | |||
99 | #endif | 118 | #endif |
100 | 119 | ||
101 | 120 | ||
102 | {- | ||
103 | nodeInfo :: NodeId -> DSum T A -> Either String (DSum T Identity ) | ||
104 | nodeInfo nid (UDP :=> AddrUDP saddr ) = fmap (UDP ==>) $ UDP.nodeInfo nid saddr | ||
105 | nodeInfo nid (TCP :=> AddrTCP conid relay) = Right $ TCP ==> ViaRelay conid nid relay | ||
106 | |||
107 | nodeAddr :: DSum T Identity -> DSum T A | ||
108 | nodeAddr (UDP :=> Identity ni ) = UDP :=> AddrUDP (UDP.nodeAddr ni) | ||
109 | nodeAddr (TCP :=> Identity (ViaRelay conid _ relay)) = TCP :=> AddrTCP conid relay | ||
110 | -} | ||
111 | |||
112 | nodeInfo :: NodeId -> DSum S Identity -> Either String (DSum T Identity) | 121 | nodeInfo :: NodeId -> DSum S Identity -> Either String (DSum T Identity) |
113 | nodeInfo nid (SessionUDP :=> Identity saddr) = fmap (UDP ==>) $ UDP.nodeInfo nid saddr | 122 | nodeInfo nid (SessionUDP :=> Identity saddr) = fmap (UDP ==>) $ UDP.nodeInfo nid saddr |
114 | nodeInfo nid (SessionTCP :=> Identity taddr@(ViaRelay _ nid2 _)) = | 123 | nodeInfo nid (SessionTCP :=> Identity taddr@(ViaRelay _ nid2 _)) = |
diff --git a/dht/src/Data/Tox/Onion.hs b/dht/src/Data/Tox/Onion.hs index a9bc4e1d..55e81069 100644 --- a/dht/src/Data/Tox/Onion.hs +++ b/dht/src/Data/Tox/Onion.hs | |||
@@ -19,7 +19,7 @@ | |||
19 | module Data.Tox.Onion where | 19 | module Data.Tox.Onion where |
20 | 20 | ||
21 | 21 | ||
22 | import Network.Address (fromSockAddr,toSockAddr,setPort,either4or6,sockAddrPort,localhost4,localhost6) | 22 | import Network.Address (fromSockAddr,toSockAddr,setPort,either4or6,sockAddrPort,localhost4,localhost6,nullAddress4) |
23 | import Network.QueryResponse | 23 | import Network.QueryResponse |
24 | import Crypto.Tox hiding (encrypt,decrypt) | 24 | import Crypto.Tox hiding (encrypt,decrypt) |
25 | import Network.Tox.NodeId | 25 | import Network.Tox.NodeId |
@@ -873,6 +873,19 @@ data OnionRoute = OnionRoute | |||
873 | } | 873 | } |
874 | deriving Show | 874 | deriving Show |
875 | 875 | ||
876 | dummySecret :: SecretKey | ||
877 | dummySecret = fromJust $ decodeSecret "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" | ||
878 | |||
879 | dummyNodeId :: NodeId | ||
880 | dummyNodeId = read "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" | ||
881 | |||
882 | dummyNode :: NodeInfo | ||
883 | dummyNode = k where Right k = nodeInfo dummyNodeId nullAddress4 | ||
884 | |||
885 | dummyRoute :: OnionRoute | ||
886 | dummyRoute = OnionRoute dummySecret dummySecret dummySecret | ||
887 | dummyNode dummyNode dummyNode | ||
888 | Nothing | ||
876 | 889 | ||
877 | wrapOnion :: Serialize (Forwarding n msg) => | 890 | wrapOnion :: Serialize (Forwarding n msg) => |
878 | TransportCrypto | 891 | TransportCrypto |
@@ -956,6 +969,10 @@ instance Read AnnouncedRendezvous where | |||
956 | } | 969 | } |
957 | 970 | ||
958 | 971 | ||
972 | -- | Lookup the secret key for the given toxid public key. If it is not found, | ||
973 | -- then the SearchingAlias symbol will be used to indicate that a new temporary | ||
974 | -- key pair should be generated or that all known keys should be tried until one | ||
975 | -- succeeds to decrypt the message. | ||
959 | selectAlias :: TransportCrypto -> NodeId -> STM AliasSelector | 976 | selectAlias :: TransportCrypto -> NodeId -> STM AliasSelector |
960 | selectAlias crypto pkey = do | 977 | selectAlias crypto pkey = do |
961 | ks <- filter (\(sk,pk) -> pk == id2key pkey) | 978 | ks <- filter (\(sk,pk) -> pk == id2key pkey) |
diff --git a/dht/src/Network/Tox.hs b/dht/src/Network/Tox.hs index 4898513a..60b793af 100644 --- a/dht/src/Network/Tox.hs +++ b/dht/src/Network/Tox.hs | |||
@@ -34,6 +34,7 @@ import qualified Data.ByteString as B | |||
34 | ;import Data.ByteString (ByteString) | 34 | ;import Data.ByteString (ByteString) |
35 | import qualified Data.ByteString.Char8 as C8 | 35 | import qualified Data.ByteString.Char8 as C8 |
36 | import Data.Data | 36 | import Data.Data |
37 | import qualified Data.Dependent.Map as DMap | ||
37 | import Data.Dependent.Sum | 38 | import Data.Dependent.Sum |
38 | import Data.Functor.Identity | 39 | import Data.Functor.Identity |
39 | import Data.Functor.Contravariant | 40 | import Data.Functor.Contravariant |
@@ -252,37 +253,6 @@ getOnionAlias crypto dhtself remoteNode = atomically $ do | |||
252 | _ -> ni { nodeId = key2id (onionAliasPublic crypto) } | 253 | _ -> ni { nodeId = key2id (onionAliasPublic crypto) } |
253 | return $ Onion.OnionDestination Onion.SearchingAlias alias Nothing | 254 | return $ Onion.OnionDestination Onion.SearchingAlias alias Nothing |
254 | 255 | ||
255 | newOnionClient :: DRG g => | ||
256 | TransportCrypto | ||
257 | -> Transport String (Onion.OnionDestination RouteId) Onion.Message | ||
258 | -> DHT.Routing | ||
259 | -> TVar SessionTokens | ||
260 | -> TVar Onion.AnnouncedKeys | ||
261 | -> OnionRouter | ||
262 | -> TVar (g, Data.Word64Map.Word64Map a) | ||
263 | -> ((Maybe Onion.Message -> IO ()) -> a) | ||
264 | -> (a -> Maybe Onion.Message -> IO void) | ||
265 | -> Client String | ||
266 | DHT.PacketKind | ||
267 | DHT.TransactionId | ||
268 | (Onion.OnionDestination RouteId) | ||
269 | Onion.Message | ||
270 | newOnionClient crypto net r toks keydb orouter map_var store load = c | ||
271 | where | ||
272 | eprinter = logErrors | ||
273 | c = Client | ||
274 | { clientNet = addHandler (reportParseError eprinter) (handleMessage c) net | ||
275 | , clientDispatcher = DispatchMethods | ||
276 | { classifyInbound = Onion.classify | ||
277 | , lookupHandler = Onion.handlers net r toks keydb | ||
278 | , tableMethods = hookQueries orouter DHT.transactionKey | ||
279 | $ transactionMethods' store load (contramap w64Key w64MapMethods) gen | ||
280 | } | ||
281 | , clientErrorReporter = eprinter | ||
282 | , clientPending = map_var | ||
283 | , clientAddress = getOnionAlias crypto $ R.thisNode <$> readTVar (DHT.routing4 r) | ||
284 | , clientResponseId = genNonce24 map_var | ||
285 | } | ||
286 | 256 | ||
287 | newTox :: TVar Onion.AnnouncedKeys -- ^ Store of announced keys we are a rendezvous for. | 257 | newTox :: TVar Onion.AnnouncedKeys -- ^ Store of announced keys we are a rendezvous for. |
288 | -> [String] -- ^ Bind-address to listen on. Must provide at least one. | 258 | -> [String] -- ^ Bind-address to listen on. Must provide at least one. |
@@ -346,8 +316,8 @@ newToxOverTransport keydb addr onNewSession (crypto,roster) udp tcp = do | |||
346 | let lookupClose _ = return Nothing | 316 | let lookupClose _ = return Nothing |
347 | 317 | ||
348 | mkrouting <- DHT.newRouting addr crypto updateIP updateIP | 318 | mkrouting <- DHT.newRouting addr crypto updateIP updateIP |
349 | (orouter,relaynet,otbl) <- newOnionRouter crypto (dput XRoutes) (maybe False (const True) tcp) | 319 | (orouter,relaynet,onioncryptTCP) <- newOnionRouter crypto (dput XRoutes) (maybe False (const True) tcp) |
350 | (cryptonet,dhtcrypt,onioncrypt,dtacrypt,handshakes) | 320 | (cryptonet,dhtcrypt,onioncryptUDP,dtacrypt,handshakes) |
351 | <- toxTransport crypto orouter lookupClose addr udp relaynet | 321 | <- toxTransport crypto orouter lookupClose addr udp relaynet |
352 | (\dst x -> sendMessage (clientNet $ tcpClient $ tcpKademliaClient orouter) dst (True,x)) | 322 | (\dst x -> sendMessage (clientNet $ tcpClient $ tcpKademliaClient orouter) dst (True,x)) |
353 | (fromMaybe (\_ _ -> return ()) tcp) | 323 | (fromMaybe (\_ _ -> return ()) tcp) |
@@ -378,12 +348,30 @@ newToxOverTransport keydb addr onNewSession (crypto,roster) udp tcp = do | |||
378 | toks <- do | 348 | toks <- do |
379 | nil <- nullSessionTokens | 349 | nil <- nullSessionTokens |
380 | atomically $ newTVar nil { maxInterval = 20 } -- 20 second timeout on announce ping-ids. | 350 | atomically $ newTVar nil { maxInterval = 20 } -- 20 second timeout on announce ping-ids. |
381 | let onionnet = layerTransportM (Onion.decrypt crypto) (Onion.encrypt crypto) onioncrypt | 351 | |
382 | let onionclient = newOnionClient crypto onionnet (mkrouting dhtclient) toks keydb orouter' otbl | 352 | onioncrypt <- mergeTransports $ DMap.fromList |
383 | Right $ \case | 353 | [ Multi.OnionUDP :=> ByAddress onioncryptUDP |
384 | Right v -> v | 354 | , Multi.OnionTCP :=> ByAddress onioncryptTCP ] |
385 | Left v -> \_ -> | 355 | oniondrg <- drgNew |
386 | dput XUnexpected "TCP-sent onion query got response over UDP?" | 356 | let onionnet = layerTransportM |
357 | (\msg od -> Onion.decrypt crypto msg $ Multi.untagOnion od) | ||
358 | (\msg od -> do | ||
359 | (msg', od') <- Onion.encrypt crypto msg od | ||
360 | -- TODO: lookupRoute is unnecessarily done twice | ||
361 | -- because that was convenient for me. The other | ||
362 | -- call was done when building the transport. | ||
363 | -- Consider simplifying this. | ||
364 | mtcp <- case od' of | ||
365 | Onion.OnionDestination _ ni (Just rid) | ||
366 | -> (>>= Onion.routeRelayPort) <$> lookupRoute orouter' ni rid | ||
367 | _ -> return Nothing | ||
368 | return (msg', maybe (Multi.OnionUDP ==> od') (const $ Multi.OnionTCP ==> od') mtcp)) | ||
369 | onioncrypt | ||
370 | onionclient <- newClient oniondrg onionnet (const Onion.classify) | ||
371 | (getOnionAlias crypto $ R.thisNode <$> readTVar (DHT.routing4 $ mkrouting dhtclient)) | ||
372 | (const $ Onion.handlers onionnet (mkrouting dhtclient) toks keydb) | ||
373 | (hookQueries orouter' DHT.transactionKey) | ||
374 | (const id) | ||
387 | 375 | ||
388 | return Tox | 376 | return Tox |
389 | { toxDHT = dhtclient | 377 | { toxDHT = dhtclient |
diff --git a/dht/src/Network/Tox/Onion/Routes.hs b/dht/src/Network/Tox/Onion/Routes.hs index baca693b..b20ad7dd 100644 --- a/dht/src/Network/Tox/Onion/Routes.hs +++ b/dht/src/Network/Tox/Onion/Routes.hs | |||
@@ -159,9 +159,8 @@ newOnionRouter :: TransportCrypto | |||
159 | -> Bool -- is tcp enabled? | 159 | -> Bool -- is tcp enabled? |
160 | -> IO ( OnionRouter | 160 | -> IO ( OnionRouter |
161 | , Transport String TCP.ViaRelay B.ByteString | 161 | , Transport String TCP.ViaRelay B.ByteString |
162 | , TVar ( ChaChaDRG | 162 | , Transport String (OnionDestination RouteId) (OnionMessage Encrypted) |
163 | , Word64Map (Either (Maybe (Bool,TCP.RelayPacket) -> IO ()) | 163 | ) |
164 | (Maybe (OnionMessage Identity) -> IO ())))) | ||
165 | newOnionRouter crypto perror tcp_enabled = do | 164 | newOnionRouter crypto perror tcp_enabled = do |
166 | drg0 <- drgNew | 165 | drg0 <- drgNew |
167 | (rlog,pq,rm) <- atomically $ do | 166 | (rlog,pq,rm) <- atomically $ do |
@@ -169,26 +168,12 @@ newOnionRouter crypto perror tcp_enabled = do | |||
169 | pq <- newTVar W64.empty | 168 | pq <- newTVar W64.empty |
170 | rm <- newArray (0,11) Nothing | 169 | rm <- newArray (0,11) Nothing |
171 | return (rlog,pq,rm) | 170 | return (rlog,pq,rm) |
172 | ((tbl,(tcptbl,tcpcons,relaynet)),tcp) <- do | 171 | ((tbl,(tcptbl,tcpcons,relaynet,onionnet)),tcp) <- do |
173 | (tcptbl, client) <- TCP.newClient crypto Left $ \case | 172 | (tcptbl, client) <- TCP.newClient crypto |
174 | Left v -> void . v . Just . (,) False | 173 | id |
175 | Right v -> \case | 174 | (. (Just . (,) False)) |
176 | TCP.OnionPacketResponse x@(OnionAnnounceResponse n8 n24 _) -> do | 175 | (lookupSender' pq rlog) |
177 | mod <- lookupSender' pq rlog localhost4 n8 | 176 | (\_ (RouteId rid) -> atomically $ fmap storedRoute <$> readArray rm rid) |
178 | perror $ "TCP announce response from " ++ show mod | ||
179 | forM_ mod $ \od -> do | ||
180 | Onion.decrypt crypto x od >>= \case | ||
181 | Right (y,_) -> do perror $ "decrypted announce response, sending " ++ show y | ||
182 | let | ||
183 | RouteId rid = fromMaybe (routeId (nodeId (onionNodeInfo od))) | ||
184 | $ onionRouteSpec od | ||
185 | Nonce8 w8 = n8 | ||
186 | atomically $ do | ||
187 | modifyTVar' pq (W64.delete w8) | ||
188 | modifyArray rm (fmap gotResponse) rid | ||
189 | void $ v $ Just y | ||
190 | _ -> return () | ||
191 | x -> perror $ "Unexpected TCP query result: " ++ show x | ||
192 | 177 | ||
193 | let addr = SockAddrInet 0 0 | 178 | let addr = SockAddrInet 0 0 |
194 | tentative_udp = NodeInfo | 179 | tentative_udp = NodeInfo |
@@ -269,7 +254,7 @@ newOnionRouter crypto perror tcp_enabled = do | |||
269 | $ clientNet c } | 254 | $ clientNet c } |
270 | } | 255 | } |
271 | } | 256 | } |
272 | return (or,relaynet,tcptbl) | 257 | return (or,relaynet,onionnet) |
273 | 258 | ||
274 | updateTCP :: OnionRouter -> TCP.NodeInfo -> p -> IO () | 259 | updateTCP :: OnionRouter -> TCP.NodeInfo -> p -> IO () |
275 | updateTCP or addr x = do | 260 | updateTCP or addr x = do |
diff --git a/dht/src/Network/Tox/Onion/Transport.hs b/dht/src/Network/Tox/Onion/Transport.hs index 407cd387..913d339d 100644 --- a/dht/src/Network/Tox/Onion/Transport.hs +++ b/dht/src/Network/Tox/Onion/Transport.hs | |||
@@ -24,6 +24,7 @@ module Network.Tox.Onion.Transport | |||
24 | , decrypt | 24 | , decrypt |
25 | , peelSymmetric | 25 | , peelSymmetric |
26 | , OnionRoute(..) | 26 | , OnionRoute(..) |
27 | , dummyRoute | ||
27 | , N0 | 28 | , N0 |
28 | , N1 | 29 | , N1 |
29 | , N2 | 30 | , N2 |
@@ -39,9 +40,11 @@ module Network.Tox.Onion.Transport | |||
39 | , wrapOnion | 40 | , wrapOnion |
40 | , wrapOnionPure | 41 | , wrapOnionPure |
41 | , unwrapAnnounceResponse | 42 | , unwrapAnnounceResponse |
43 | , wrapIndirectHops | ||
42 | ) where | 44 | ) where |
43 | 45 | ||
44 | import Data.ByteString (ByteString) | 46 | import qualified Data.ByteString as B |
47 | ;import Data.ByteString (ByteString) | ||
45 | import Data.Maybe | 48 | import Data.Maybe |
46 | import Data.Serialize | 49 | import Data.Serialize |
47 | import Network.Socket | 50 | import Network.Socket |
@@ -50,8 +53,10 @@ import Crypto.Tox hiding (encrypt,decrypt) | |||
50 | import Network.Tox.TCP.NodeId (udpNodeInfo) | 53 | import Network.Tox.TCP.NodeId (udpNodeInfo) |
51 | import qualified Data.Tox.Relay as TCP | 54 | import qualified Data.Tox.Relay as TCP |
52 | import Data.Tox.Onion | 55 | import Data.Tox.Onion |
56 | import Network.Address (nullAddress4) | ||
53 | import Network.Tox.DHT.Transport (SendNodes(..)) | 57 | import Network.Tox.DHT.Transport (SendNodes(..)) |
54 | import Network.Tox.NodeId | 58 | import Network.Tox.NodeId |
59 | import Network.QueryResponse | ||
55 | 60 | ||
56 | {- | 61 | {- |
57 | encodeOnionAddr :: TransportCrypto | 62 | encodeOnionAddr :: TransportCrypto |
@@ -88,28 +93,28 @@ wrapForRoute :: TransportCrypto | |||
88 | -> NodeInfo | 93 | -> NodeInfo |
89 | -> OnionRoute | 94 | -> OnionRoute |
90 | -> IO (Either TCP.RelayPacket (OnionRequest N0)) | 95 | -> IO (Either TCP.RelayPacket (OnionRequest N0)) |
91 | wrapForRoute crypto msg ni r@OnionRoute{routeRelayPort=Nothing} = do | 96 | wrapForRoute crypto msg ni r@OnionRoute{routeRelayPort=Nothing} = |
92 | -- We needn't use the same nonce value here, but I think it is safe to do so. | 97 | wrapIndirectHops crypto msg ni r $ \nonce saddr msg' -> do |
93 | let nonce = msgNonce msg | 98 | fwd <- wrapOnion crypto (routeAliasA r) |
94 | fwd <- wrapOnion crypto (routeAliasA r) | 99 | nonce |
95 | nonce | 100 | (id2key . nodeId $ routeNodeA r) |
96 | (id2key . nodeId $ routeNodeA r) | 101 | saddr |
97 | (nodeAddr $ routeNodeB r) | 102 | msg' |
98 | =<< wrapOnion crypto (routeAliasB r) | 103 | return $ Right OnionRequest { onionNonce = nonce |
99 | nonce | 104 | , onionForward = fwd |
100 | (id2key . nodeId $ routeNodeB r) | 105 | , pathFromOwner = NoReturnPath |
101 | (nodeAddr $ routeNodeC r) | 106 | } |
102 | =<< wrapOnion crypto (routeAliasC r) | 107 | wrapForRoute crypto msg ni r@OnionRoute { routeRelayPort = Just _ } = |
103 | nonce | 108 | wrapIndirectHops crypto msg ni r $ \nonce saddr fwd -> |
104 | (id2key . nodeId $ routeNodeC r) | 109 | return $ Left $ TCP.OnionPacket nonce $ Addressed (nodeAddr $ routeNodeB r) fwd |
105 | (nodeAddr ni) | 110 | |
106 | (NotForwarded msg) | 111 | wrapIndirectHops :: TransportCrypto |
107 | return $ Right OnionRequest | 112 | -> OnionMessage Encrypted |
108 | { onionNonce = nonce | 113 | -> NodeInfo |
109 | , onionForward = fwd | 114 | -> OnionRoute |
110 | , pathFromOwner = NoReturnPath | 115 | -> (Nonce24 -> SockAddr -> Forwarding N2 (OnionMessage Encrypted) -> IO a) |
111 | } | 116 | -> IO a |
112 | wrapForRoute crypto msg ni r@OnionRoute{routeRelayPort = Just tcpport} = do | 117 | wrapIndirectHops crypto msg ni r fin = do |
113 | let nonce = msgNonce msg | 118 | let nonce = msgNonce msg |
114 | fwd <- wrapOnion crypto (routeAliasB r) | 119 | fwd <- wrapOnion crypto (routeAliasB r) |
115 | nonce | 120 | nonce |
@@ -120,7 +125,7 @@ wrapForRoute crypto msg ni r@OnionRoute{routeRelayPort = Just tcpport} = do | |||
120 | (id2key . nodeId $ routeNodeC r) | 125 | (id2key . nodeId $ routeNodeC r) |
121 | (nodeAddr ni) | 126 | (nodeAddr ni) |
122 | (NotForwarded msg) | 127 | (NotForwarded msg) |
123 | return $ Left $ TCP.OnionPacket nonce $ Addressed (nodeAddr $ routeNodeB r) fwd | 128 | fin nonce (nodeAddr $ routeNodeB r) fwd |
124 | 129 | ||
125 | unwrapAnnounceResponse :: Maybe NodeId -> NodeInfo -> AnnounceResponse -> ([NodeInfo], [Rendezvous], Maybe Nonce32) | 130 | unwrapAnnounceResponse :: Maybe NodeId -> NodeInfo -> AnnounceResponse -> ([NodeInfo], [Rendezvous], Maybe Nonce32) |
126 | unwrapAnnounceResponse alias ni (AnnounceResponse is_stored (SendNodes ns0)) | let ns = map udpNodeInfo ns0 | 131 | unwrapAnnounceResponse alias ni (AnnounceResponse is_stored (SendNodes ns0)) | let ns = map udpNodeInfo ns0 |
diff --git a/dht/src/Network/Tox/TCP.hs b/dht/src/Network/Tox/TCP.hs index c4727a20..04119164 100644 --- a/dht/src/Network/Tox/TCP.hs +++ b/dht/src/Network/Tox/TCP.hs | |||
@@ -43,7 +43,7 @@ import Data.Tox.Relay | |||
43 | import qualified Data.Word64Map | 43 | import qualified Data.Word64Map |
44 | import DebugTag | 44 | import DebugTag |
45 | import DPut | 45 | import DPut |
46 | import Network.Address (setPort,PortNumber,localhost4,fromSockAddr) | 46 | import Network.Address (setPort,PortNumber,localhost4,fromSockAddr,nullAddress4) |
47 | import Network.Kademlia.Routing | 47 | import Network.Kademlia.Routing |
48 | import Network.Kademlia.Search hiding (sendQuery) | 48 | import Network.Kademlia.Search hiding (sendQuery) |
49 | import Network.QueryResponse | 49 | import Network.QueryResponse |
@@ -319,21 +319,25 @@ type RelayCache = TCPCache (SessionProtocol (SessionData,RelayPacket) RelayPacke | |||
319 | -- defaults are 'id' and 'tryPutMVar'. The resulting customized table state | 319 | -- defaults are 'id' and 'tryPutMVar'. The resulting customized table state |
320 | -- will be returned to the caller along with the new client. | 320 | -- will be returned to the caller along with the new client. |
321 | newClient :: TransportCrypto | 321 | newClient :: TransportCrypto |
322 | -> ((Maybe (Bool,RelayPacket) -> IO ()) -> a) -- ^ store mvar for query | 322 | -> ((Maybe (Bool,RelayPacket) -> IO ()) -> a) -- ^ store mvar for relay query |
323 | -> (a -> RelayPacket -> IO void) -- ^ load mvar for query | 323 | -> (a -> RelayPacket -> IO void) -- ^ load mvar for relay query |
324 | -> (SockAddr -> Nonce8 -> IO (Maybe (OnionDestination RouteId))) -- ^ lookup sender of onion query | ||
325 | -> (UDP.NodeInfo -> RouteId -> IO (Maybe OnionRoute)) -- ^ lookup OnionRoute by id | ||
324 | -> IO ( ( TVar (ChaChaDRG, Data.Word64Map.Word64Map a) | 326 | -> IO ( ( TVar (ChaChaDRG, Data.Word64Map.Word64Map a) |
325 | , RelayCache | 327 | , RelayCache |
326 | , Transport String ViaRelay ByteString ) | 328 | , Transport String ViaRelay ByteString |
329 | , Transport String (OnionDestination RouteId) (OnionMessage Encrypted) ) | ||
327 | , Client String PacketNumber Nonce8 NodeInfo (Bool,RelayPacket)) | 330 | , Client String PacketNumber Nonce8 NodeInfo (Bool,RelayPacket)) |
328 | newClient crypto store load = do | 331 | newClient crypto store load lookupSender getRoute = do |
329 | (tcpcache,net0) <- toxTCP crypto | 332 | (tcpcache,net0) <- toxTCP crypto |
330 | (relaynet,net1) <- partitionRelay net0 | 333 | (relaynet,net1) <- partitionRelay net0 |
331 | let net2 = {- XXX: Client type forces this pointless layering. -} | 334 | (onionnet,net2) <- partitionOnion crypto lookupSender getRoute net1 |
332 | layerTransport ((Right .) . (,) . (,) False . snd) (,) net1 | 335 | let net3 = {- XXX: Client type forces this pointless layering. -} |
336 | layerTransport ((Right .) . (,) . (,) False . snd) (,) net2 | ||
333 | drg <- drgNew | 337 | drg <- drgNew |
334 | map_var <- atomically $ newTVar (drg, Data.Word64Map.empty) | 338 | map_var <- atomically $ newTVar (drg, Data.Word64Map.empty) |
335 | return $ (,) (map_var,tcpcache,relaynet) Client | 339 | return $ (,) (map_var,tcpcache,relaynet,onionnet) Client |
336 | { clientNet = net2 | 340 | { clientNet = net3 |
337 | , clientDispatcher = DispatchMethods | 341 | , clientDispatcher = DispatchMethods |
338 | { classifyInbound = (. snd) $ \case | 342 | { classifyInbound = (. snd) $ \case |
339 | RelayPing n -> IsQuery PingPacket n | 343 | RelayPing n -> IsQuery PingPacket n |
@@ -393,3 +397,41 @@ partitionRelay tr = partitionTransportM parse encode tr | |||
393 | encode :: (ByteString, ViaRelay) -> IO (Maybe ((Bool,RelayPacket), NodeInfo)) | 397 | encode :: (ByteString, ViaRelay) -> IO (Maybe ((Bool,RelayPacket), NodeInfo)) |
394 | encode (bs, ViaRelay (Just conid) _ ni) = return $ Just ((False,RelayData bs conid), ni) | 398 | encode (bs, ViaRelay (Just conid) _ ni) = return $ Just ((False,RelayData bs conid), ni) |
395 | encode (bs, ViaRelay Nothing nid ni) = return $ Just ((False,OOBSend (UDP.id2key nid) bs), ni) | 399 | encode (bs, ViaRelay Nothing nid ni) = return $ Just ((False,OOBSend (UDP.id2key nid) bs), ni) |
400 | |||
401 | |||
402 | partitionOnion :: TransportCrypto | ||
403 | -> (SockAddr -> Nonce8 -> IO (Maybe (OnionDestination RouteId))) | ||
404 | -> (UDP.NodeInfo -> RouteId -> IO (Maybe OnionRoute)) | ||
405 | -> TransportA err NodeInfo (SessionData,RelayPacket) (Bool,RelayPacket) | ||
406 | -> IO ( Transport err (OnionDestination RouteId) (OnionMessage Encrypted) | ||
407 | , TransportA err NodeInfo (SessionData,RelayPacket) (Bool,RelayPacket)) | ||
408 | partitionOnion crypto lookupSender getRoute tr = partitionTransportM parse encode tr | ||
409 | where | ||
410 | parse :: ((SessionData,RelayPacket), NodeInfo) | ||
411 | -> IO (Either (OnionMessage Encrypted , OnionDestination RouteId) | ||
412 | ((SessionData,RelayPacket), NodeInfo)) | ||
413 | parse pass@((_,OnionPacketResponse msg@(OnionAnnounceResponse n8 _ _)), nodeA) = do | ||
414 | m <- lookupSender (nodeAddr nodeA) n8 | ||
415 | case m of | ||
416 | Nothing -> return $ Right pass | ||
417 | Just od -> return $ Left (msg, od) | ||
418 | parse ((_,OnionPacketResponse msg@(OnionToRouteResponse asym)), nodeA) = | ||
419 | return $ | ||
420 | let Right ni = UDP.nodeInfo (UDP.key2id $ senderKey asym) nullAddress4 | ||
421 | -- -- We have this information, but currently, we're discarding it... | ||
422 | -- r = dummyRoute { routeNodeA = udpNodeInfo nodeA | ||
423 | -- , routeRelayPort = Just $ tcpPort nodeA } | ||
424 | tryAllKeys = SearchingAlias -- We unfortunately don't know what toxid was used to encrypt this. | ||
425 | -- Toxcore only supports a single toxid per DHT node and in that case, | ||
426 | -- it is unambiguous. | ||
427 | in Left (msg, OnionDestination tryAllKeys ni Nothing) | ||
428 | parse pass = return $ Right pass | ||
429 | |||
430 | encode :: (OnionMessage Encrypted,OnionDestination RouteId) -> IO (Maybe ((Bool,RelayPacket),NodeInfo)) | ||
431 | encode (msg,OnionDestination _ ni (Just rid)) = do | ||
432 | moroute <- getRoute ni rid | ||
433 | forM (moroute >>= \r -> (,) r <$> routeRelayPort r) $ \(oroute,tcpport) -> | ||
434 | wrapIndirectHops crypto msg ni oroute $ \nonce saddr fwd -> | ||
435 | return ( (True,OnionPacket nonce $ Addressed saddr fwd) | ||
436 | , NodeInfo (routeNodeA oroute) tcpport ) | ||
437 | encode _ = return Nothing | ||