diff options
-rw-r--r-- | src/Data/Tox/Relay.hs | 14 | ||||
-rw-r--r-- | src/Network/Tox.hs | 4 | ||||
-rw-r--r-- | src/Network/Tox/Onion/Transport.hs | 73 | ||||
-rw-r--r-- | src/Network/Tox/Relay.hs | 15 | ||||
-rw-r--r-- | src/Network/Tox/TCP.hs | 75 | ||||
-rw-r--r-- | src/Network/Tox/Transport.hs | 2 |
6 files changed, 143 insertions, 40 deletions
diff --git a/src/Data/Tox/Relay.hs b/src/Data/Tox/Relay.hs index 1437c9cd..1fe6d256 100644 --- a/src/Data/Tox/Relay.hs +++ b/src/Data/Tox/Relay.hs | |||
@@ -45,8 +45,8 @@ data RelayPacket | |||
45 | | RelayPong Nonce8 | 45 | | RelayPong Nonce8 |
46 | | OOBSend PublicKey ByteString | 46 | | OOBSend PublicKey ByteString |
47 | | OOBRecv PublicKey ByteString | 47 | | OOBRecv PublicKey ByteString |
48 | | OnionPacket (OnionRequest N0) | 48 | | OnionPacket Nonce24 (Addressed (Forwarding N2 (OnionMessage Encrypted))) -- (OnionRequest N0) |
49 | | OnionPacketResponse (OnionResponse N1) | 49 | | OnionPacketResponse (OnionMessage Encrypted) |
50 | -- 0x0A through 0x0F reserved for future use. | 50 | -- 0x0A through 0x0F reserved for future use. |
51 | | RelayData ByteString ConId | 51 | | RelayData ByteString ConId |
52 | deriving (Eq,Ord,Show,Data) | 52 | deriving (Eq,Ord,Show,Data) |
@@ -65,9 +65,9 @@ instance Sized RelayPacket where | |||
65 | RelayPong pingid -> 8 | 65 | RelayPong pingid -> 8 |
66 | OOBSend k bs -> 32 + B.length bs | 66 | OOBSend k bs -> 32 + B.length bs |
67 | OOBRecv k bs -> 32 + B.length bs | 67 | OOBRecv k bs -> 32 + B.length bs |
68 | OnionPacket query -> case contramap (`asTypeOf` query) size of | 68 | OnionPacket n24 query -> 24 + case contramap (`asTypeOf` query) size of |
69 | ConstSize n -> n | 69 | ConstSize n -> n |
70 | VarSize f -> f query | 70 | VarSize f -> f query |
71 | OnionPacketResponse answer -> case contramap (`asTypeOf` answer) size of | 71 | OnionPacketResponse answer -> case contramap (`asTypeOf` answer) size of |
72 | ConstSize n -> n | 72 | ConstSize n -> n |
73 | VarSize f -> f answer | 73 | VarSize f -> f answer |
@@ -86,7 +86,7 @@ instance Serialize RelayPacket where | |||
86 | 5 -> RelayPong <$> get | 86 | 5 -> RelayPong <$> get |
87 | 6 -> OOBSend <$> getPublicKey <*> (remaining >>= getBytes) | 87 | 6 -> OOBSend <$> getPublicKey <*> (remaining >>= getBytes) |
88 | 7 -> OOBRecv <$> getPublicKey <*> (remaining >>= getBytes) | 88 | 7 -> OOBRecv <$> getPublicKey <*> (remaining >>= getBytes) |
89 | 8 -> OnionPacket <$> get | 89 | 8 -> OnionPacket <$> get <*> get |
90 | 9 -> OnionPacketResponse <$> get | 90 | 9 -> OnionPacketResponse <$> get |
91 | conid -> (`RelayData` ConId conid) <$> (remaining >>= getBytes) | 91 | conid -> (`RelayData` ConId conid) <$> (remaining >>= getBytes) |
92 | 92 | ||
@@ -101,7 +101,7 @@ instance Serialize RelayPacket where | |||
101 | RelayPong pingid -> put pingid | 101 | RelayPong pingid -> put pingid |
102 | OOBSend k bs -> putPublicKey k >> putByteString bs | 102 | OOBSend k bs -> putPublicKey k >> putByteString bs |
103 | OOBRecv k bs -> putPublicKey k >> putByteString bs | 103 | OOBRecv k bs -> putPublicKey k >> putByteString bs |
104 | OnionPacket query -> put query | 104 | OnionPacket n24 query -> put n24 >> put query |
105 | OnionPacketResponse answer -> put answer | 105 | OnionPacketResponse answer -> put answer |
106 | RelayData bs _ -> putByteString bs | 106 | RelayData bs _ -> putByteString bs |
107 | 107 | ||
diff --git a/src/Network/Tox.hs b/src/Network/Tox.hs index 83a17037..46d87094 100644 --- a/src/Network/Tox.hs +++ b/src/Network/Tox.hs | |||
@@ -240,7 +240,7 @@ newTox :: TVar Onion.AnnouncedKeys -- ^ Store of announced keys we are a rende | |||
240 | -> [String] -- ^ Bind-address to listen on. Must provide at least one. | 240 | -> [String] -- ^ Bind-address to listen on. Must provide at least one. |
241 | -> ( ContactInfo extra -> SockAddr -> Session -> IO () ) | 241 | -> ( ContactInfo extra -> SockAddr -> Session -> IO () ) |
242 | -> Maybe SecretKey -- ^ Optional DHT secret key to use. | 242 | -> Maybe SecretKey -- ^ Optional DHT secret key to use. |
243 | -> ( Int -> Onion.OnionResponse Onion.N1 -> IO () ) -- ^ TCP-bound onion responses. | 243 | -> ( Int -> Onion.OnionMessage Encrypted -> IO () ) -- ^ TCP-bound onion responses. |
244 | -> IO (Tox extra) | 244 | -> IO (Tox extra) |
245 | newTox keydb bindspecs onsess suppliedDHTKey tcp = do | 245 | newTox keydb bindspecs onsess suppliedDHTKey tcp = do |
246 | addrs <- mapM (`getBindAddress` True) bindspecs | 246 | addrs <- mapM (`getBindAddress` True) bindspecs |
@@ -262,7 +262,7 @@ newToxOverTransport :: TVar Onion.AnnouncedKeys | |||
262 | -> ( ContactInfo extra -> SockAddr -> Session -> IO () ) | 262 | -> ( ContactInfo extra -> SockAddr -> Session -> IO () ) |
263 | -> Maybe SecretKey | 263 | -> Maybe SecretKey |
264 | -> Onion.UDPTransport | 264 | -> Onion.UDPTransport |
265 | -> ( Int -> Onion.OnionResponse Onion.N1 -> IO () ) -- ^ TCP-bound onion responses. | 265 | -> ( Int -> Onion.OnionMessage Encrypted -> IO () ) -- ^ TCP-bound onion responses. |
266 | -> IO (Tox extra) | 266 | -> IO (Tox extra) |
267 | newToxOverTransport keydb addr onNewSession suppliedDHTKey udp tcp = do | 267 | newToxOverTransport keydb addr onNewSession suppliedDHTKey udp tcp = do |
268 | roster <- newContactInfo | 268 | roster <- newContactInfo |
diff --git a/src/Network/Tox/Onion/Transport.hs b/src/Network/Tox/Onion/Transport.hs index 0cb03718..8918f913 100644 --- a/src/Network/Tox/Onion/Transport.hs +++ b/src/Network/Tox/Onion/Transport.hs | |||
@@ -44,14 +44,18 @@ module Network.Tox.Onion.Transport | |||
44 | , OnionRoute(..) | 44 | , OnionRoute(..) |
45 | , N0 | 45 | , N0 |
46 | , N1 | 46 | , N1 |
47 | , N2 | ||
47 | , N3 | 48 | , N3 |
48 | , onionKey | 49 | , onionKey |
49 | , onionAliasSelector | 50 | , onionAliasSelector |
50 | , selectAlias | 51 | , selectAlias |
51 | , RouteId(..) | 52 | , RouteId(..) |
52 | , routeId | 53 | , routeId |
53 | , rewrap | ||
54 | , putRequest | 54 | , putRequest |
55 | , wrapForRoute | ||
56 | , wrapSymmetric | ||
57 | , wrapOnion | ||
58 | , wrapOnionPure | ||
55 | ) where | 59 | ) where |
56 | 60 | ||
57 | import Network.Address (fromSockAddr,toSockAddr,setPort,either4or6,sockAddrPort) | 61 | import Network.Address (fromSockAddr,toSockAddr,setPort,either4or6,sockAddrPort) |
@@ -91,6 +95,7 @@ import DPut | |||
91 | import DebugTag | 95 | import DebugTag |
92 | import Data.Word64Map (fitsInInt) | 96 | import Data.Word64Map (fitsInInt) |
93 | import Data.Bits (shiftR,shiftL) | 97 | import Data.Bits (shiftR,shiftL) |
98 | import qualified Rank2 | ||
94 | 99 | ||
95 | type HandleLo a = Maybe (Either String (ByteString, SockAddr)) -> IO a | 100 | type HandleLo a = Maybe (Either String (ByteString, SockAddr)) -> IO a |
96 | 101 | ||
@@ -124,6 +129,26 @@ deriving instance ( Show (f (AnnounceRequest, Nonce8)) | |||
124 | , Show (f DataToRoute) | 129 | , Show (f DataToRoute) |
125 | ) => Show (OnionMessage f) | 130 | ) => Show (OnionMessage f) |
126 | 131 | ||
132 | instance Data (OnionMessage Encrypted) where | ||
133 | gfoldl f z txt = z (either error id . S.decode) `f` S.encode txt | ||
134 | toConstr _ = error "OnionMessage.toConstr" | ||
135 | gunfold _ _ = error "OnionMessage.gunfold" | ||
136 | #if MIN_VERSION_base(4,2,0) | ||
137 | dataTypeOf _ = mkNoRepType "Network.Tox.Onion.Transport.OnionMessage" | ||
138 | #else | ||
139 | dataTypeOf _ = mkNorepType "Network.Tox.Onion.Transport.OnionMessage" | ||
140 | #endif | ||
141 | |||
142 | instance Rank2.Functor OnionMessage where | ||
143 | f <$> m = mapPayload (Proxy :: Proxy Serialize) f m | ||
144 | |||
145 | instance Payload Serialize OnionMessage where | ||
146 | mapPayload _ f (OnionAnnounce a) = OnionAnnounce (fmap f a) | ||
147 | mapPayload _ f (OnionAnnounceResponse n8 n24 a) = OnionAnnounceResponse n8 n24 (f a) | ||
148 | mapPayload _ f (OnionToRoute k a) = OnionToRoute k a | ||
149 | mapPayload _ f (OnionToRouteResponse a) = OnionToRouteResponse a | ||
150 | |||
151 | |||
127 | msgNonce :: OnionMessage f -> Nonce24 | 152 | msgNonce :: OnionMessage f -> Nonce24 |
128 | msgNonce (OnionAnnounce a) = asymmNonce a | 153 | msgNonce (OnionAnnounce a) = asymmNonce a |
129 | msgNonce (OnionAnnounceResponse _ n24 _) = n24 | 154 | msgNonce (OnionAnnounceResponse _ n24 _) = n24 |
@@ -274,10 +299,10 @@ encodeOnionAddr crypto getRoute (msg,OnionDestination _ ni (Just rid)) = do | |||
274 | return x | 299 | return x |
275 | 300 | ||
276 | 301 | ||
277 | forwardOnions :: TransportCrypto -> UDPTransport -> (Int -> OnionResponse N1 -> IO ()) {- ^ TCP relay send -} -> UDPTransport | 302 | forwardOnions :: TransportCrypto -> UDPTransport -> (Int -> OnionMessage Encrypted -> IO ()) {- ^ TCP relay send -} -> UDPTransport |
278 | forwardOnions crypto udp sendTCP = udp { awaitMessage = forwardAwait crypto udp sendTCP } | 303 | forwardOnions crypto udp sendTCP = udp { awaitMessage = forwardAwait crypto udp sendTCP } |
279 | 304 | ||
280 | forwardAwait :: TransportCrypto -> UDPTransport -> (Int -> OnionResponse N1 -> IO ()) {- ^ TCP relay send -} -> HandleLo a -> IO a | 305 | forwardAwait :: TransportCrypto -> UDPTransport -> (Int -> OnionMessage Encrypted -> IO ()) {- ^ TCP relay send -} -> HandleLo a -> IO a |
281 | forwardAwait crypto udp sendTCP kont = do | 306 | forwardAwait crypto udp sendTCP kont = do |
282 | fix $ \another -> do | 307 | fix $ \another -> do |
283 | awaitMessage udp $ \case | 308 | awaitMessage udp $ \case |
@@ -325,6 +350,7 @@ data OnionRequest n = OnionRequest | |||
325 | deriving (Eq,Ord) | 350 | deriving (Eq,Ord) |
326 | 351 | ||
327 | 352 | ||
353 | {- | ||
328 | instance (Typeable n, Sized (ReturnPath n), Serialize (ReturnPath n) | 354 | instance (Typeable n, Sized (ReturnPath n), Serialize (ReturnPath n) |
329 | , Serialize (Forwarding (ThreeMinus n) (OnionMessage Encrypted)) | 355 | , Serialize (Forwarding (ThreeMinus n) (OnionMessage Encrypted)) |
330 | ) => Data (OnionRequest n) where | 356 | ) => Data (OnionRequest n) where |
@@ -336,6 +362,8 @@ instance (Typeable n, Sized (ReturnPath n), Serialize (ReturnPath n) | |||
336 | #else | 362 | #else |
337 | dataTypeOf _ = mkNorepType "Network.Tox.Onion.Transport.OnionRequest" | 363 | dataTypeOf _ = mkNorepType "Network.Tox.Onion.Transport.OnionRequest" |
338 | #endif | 364 | #endif |
365 | -} | ||
366 | |||
339 | 367 | ||
340 | instance (Typeable n, Serialize (ReturnPath n)) => Data (OnionResponse n) where | 368 | instance (Typeable n, Serialize (ReturnPath n)) => Data (OnionResponse n) where |
341 | gfoldl f z txt = z (either error id . S.decode) `f` S.encode txt | 369 | gfoldl f z txt = z (either error id . S.decode) `f` S.encode txt |
@@ -397,7 +425,17 @@ instance (Sized (ReturnPath n)) => Sized (OnionResponse (S n)) where | |||
397 | 425 | ||
398 | data Addressed a = Addressed { sockAddr :: SockAddr, unaddressed :: a } | 426 | data Addressed a = Addressed { sockAddr :: SockAddr, unaddressed :: a } |
399 | | TCPIndex { tcpIndex :: Int, unaddressed :: a } | 427 | | TCPIndex { tcpIndex :: Int, unaddressed :: a } |
400 | deriving (Eq,Show) | 428 | deriving (Eq,Ord,Show) |
429 | |||
430 | instance (Typeable a, Serialize a) => Data (Addressed a) where | ||
431 | gfoldl f z a = z (either error id . S.decode) `f` S.encode a | ||
432 | toConstr _ = error "Addressed.toConstr" | ||
433 | gunfold _ _ = error "Addressed.gunfold" | ||
434 | #if MIN_VERSION_base(4,2,0) | ||
435 | dataTypeOf _ = mkNoRepType "Network.Tox.Onion.Transport.Addressed" | ||
436 | #else | ||
437 | dataTypeOf _ = mkNorepType "Network.Tox.Onion.Transport.Addressed" | ||
438 | #endif | ||
401 | 439 | ||
402 | instance Sized a => Sized (Addressed a) where | 440 | instance Sized a => Sized (Addressed a) where |
403 | size = case size :: Size a of | 441 | size = case size :: Size a of |
@@ -434,6 +472,10 @@ addrToIndex _ = 0 | |||
434 | indexToAddr :: Int -> SockAddr | 472 | indexToAddr :: Int -> SockAddr |
435 | indexToAddr x = SockAddrInet6 0 0 (fromIntegral x, fromIntegral (x `shiftR` 32),0,0) 0 | 473 | indexToAddr x = SockAddrInet6 0 0 (fromIntegral x, fromIntegral (x `shiftR` 32),0,0) 0 |
436 | 474 | ||
475 | -- Note, toxcore would check an address family byte here to detect a TCP-bound | ||
476 | -- packet, but we instead use the IPv6 id and rely on the port number being | ||
477 | -- zero. Since it will be symmetrically encrypted for our eyes only, it's not | ||
478 | -- important to conform on this point. | ||
437 | instance Serialize a => Serialize (Addressed a) where | 479 | instance Serialize a => Serialize (Addressed a) where |
438 | get = do saddr <- getForwardAddr | 480 | get = do saddr <- getForwardAddr |
439 | a <- get | 481 | a <- get |
@@ -549,6 +591,7 @@ instance (Serialize (Encrypted (Addressed (Forwarding n msg)))) => Serialize (Fo | |||
549 | get = Forwarding <$> getPublicKey <*> get | 591 | get = Forwarding <$> getPublicKey <*> get |
550 | put (Forwarding k x) = putPublicKey k >> put x | 592 | put (Forwarding k x) = putPublicKey k >> put x |
551 | 593 | ||
594 | {- | ||
552 | rewrap :: (ThreeMinus n ~ S (ThreeMinus (S n)), | 595 | rewrap :: (ThreeMinus n ~ S (ThreeMinus (S n)), |
553 | Serialize (ReturnPath n), | 596 | Serialize (ReturnPath n), |
554 | Serialize | 597 | Serialize |
@@ -565,6 +608,7 @@ rewrap crypto saddr (OnionRequest nonce msg rpath) = do | |||
565 | Addressed dst msg' | 608 | Addressed dst msg' |
566 | -> Right (OnionRequest nonce msg' $ wrapSymmetric sym snonce saddr rpath, dst) | 609 | -> Right (OnionRequest nonce msg' $ wrapSymmetric sym snonce saddr rpath, dst) |
567 | _ -> Left "Onion forward to TCP client?" | 610 | _ -> Left "Onion forward to TCP client?" |
611 | -} | ||
568 | 612 | ||
569 | handleOnionRequest :: forall a proxy n. | 613 | handleOnionRequest :: forall a proxy n. |
570 | ( LessThanThree n | 614 | ( LessThanThree n |
@@ -584,7 +628,6 @@ handleOnionRequest proxy crypto saddr udp kont (OnionRequest nonce msg rpath) = | |||
584 | 628 | ||
585 | case peeled of | 629 | case peeled of |
586 | Left e -> do | 630 | Left e -> do |
587 | -- todo report encryption error | ||
588 | dput XOnion $ unwords [ "peelOnion:", show n, showDestination, e] | 631 | dput XOnion $ unwords [ "peelOnion:", show n, showDestination, e] |
589 | kont | 632 | kont |
590 | Right (Addressed dst msg') -> do | 633 | Right (Addressed dst msg') -> do |
@@ -617,7 +660,7 @@ handleOnionResponse :: (KnownPeanoNat n, Sized (ReturnPath n), Serialize (Return | |||
617 | -> TransportCrypto | 660 | -> TransportCrypto |
618 | -> SockAddr | 661 | -> SockAddr |
619 | -> UDPTransport | 662 | -> UDPTransport |
620 | -> (Int -> OnionResponse N1 -> IO ()) -- ^ TCP-relay onion send. | 663 | -> (Int -> OnionMessage Encrypted -> IO ()) -- ^ TCP-relay onion send. |
621 | -> IO a | 664 | -> IO a |
622 | -> OnionResponse (S n) | 665 | -> OnionResponse (S n) |
623 | -> IO a | 666 | -> IO a |
@@ -633,10 +676,9 @@ handleOnionResponse proxy crypto saddr udp sendTCP kont (OnionResponse path msg) | |||
633 | sendMessage udp dst (runPut $ putResponse $ OnionResponse path' msg) | 676 | sendMessage udp dst (runPut $ putResponse $ OnionResponse path' msg) |
634 | kont | 677 | kont |
635 | Right (TCPIndex dst path') -> do | 678 | Right (TCPIndex dst path') -> do |
636 | -- This should only occur for OnionResponse N1 | 679 | case peanoVal path' of |
637 | case gcast (OnionResponse path' msg) of | 680 | 0 -> sendTCP dst msg |
638 | Just supported -> sendTCP dst supported | 681 | n -> dput XUnexpected $ "handleOnionResponse: TCP-bound OnionResponse" ++ show n ++ " not supported." |
639 | Nothing -> dput XUnexpected "handleOnionResponse: TCP-bound message not supported." | ||
640 | kont | 682 | kont |
641 | 683 | ||
642 | 684 | ||
@@ -900,6 +942,17 @@ wrapOnion crypto skey nonce destkey saddr fwd = do | |||
900 | secret <- lookupSharedSecret crypto skey destkey nonce | 942 | secret <- lookupSharedSecret crypto skey destkey nonce |
901 | return $ Forwarding (toPublic skey) $ ToxCrypto.encrypt secret plain | 943 | return $ Forwarding (toPublic skey) $ ToxCrypto.encrypt secret plain |
902 | 944 | ||
945 | wrapOnionPure :: Serialize (Forwarding n msg) => | ||
946 | SecretKey | ||
947 | -> ToxCrypto.State | ||
948 | -> SockAddr | ||
949 | -> Forwarding n msg | ||
950 | -> Forwarding (S n) msg | ||
951 | wrapOnionPure skey st saddr fwd = Forwarding (toPublic skey) (ToxCrypto.encrypt st plain) | ||
952 | where | ||
953 | plain = encodePlain $ Addressed saddr fwd | ||
954 | |||
955 | |||
903 | 956 | ||
904 | -- TODO | 957 | -- TODO |
905 | -- Two types of packets may be sent to Rendezvous via OnionToRoute requests. | 958 | -- Two types of packets may be sent to Rendezvous via OnionToRoute requests. |
diff --git a/src/Network/Tox/Relay.hs b/src/Network/Tox/Relay.hs index 7af14ed6..2842fcc2 100644 --- a/src/Network/Tox/Relay.hs +++ b/src/Network/Tox/Relay.hs | |||
@@ -201,22 +201,23 @@ handlePacket cons thistcp me crypto sendOnion sendToMe session = \case | |||
201 | sendToThem' <- IntMap.lookup i $ associated mySession | 201 | sendToThem' <- IntMap.lookup i $ associated mySession |
202 | return $ sendToThem' $ RelayData bs | 202 | return $ sendToThem' $ RelayData bs |
203 | 203 | ||
204 | OnionPacket p -> do | 204 | OnionPacket n24 (Addressed addr req) -> do |
205 | mp <- rewrap crypto (TCPIndex thistcp) p | 205 | rpath <- atomically $ do |
206 | case mp of | 206 | sym <- transportSymmetric crypto |
207 | Right (p',addr) -> sendOnion addr p' | 207 | n <- transportNewNonce crypto |
208 | _ -> return () | 208 | return $ wrapSymmetric sym n (TCPIndex thistcp) NoReturnPath |
209 | sendOnion addr $ OnionRequest n24 req rpath | ||
209 | 210 | ||
210 | _ -> return () | 211 | _ -> return () |
211 | 212 | ||
212 | 213 | ||
213 | sendTCP_ :: TVar (IntMap (RelayPacket -> IO ())) -> Int -> OnionResponse N1 -> IO () | 214 | sendTCP_ :: TVar (IntMap (RelayPacket -> IO ())) -> Int -> OnionMessage Encrypted -> IO () |
214 | sendTCP_ st addr x = join $ atomically | 215 | sendTCP_ st addr x = join $ atomically |
215 | $ IntMap.lookup addr <$> readTVar st >>= \case | 216 | $ IntMap.lookup addr <$> readTVar st >>= \case |
216 | Nothing -> return $ return () | 217 | Nothing -> return $ return () |
217 | Just send -> return $ send $ OnionPacketResponse x | 218 | Just send -> return $ send $ OnionPacketResponse x |
218 | 219 | ||
219 | tcpRelay :: SockAddr -> (SockAddr -> OnionRequest N1 -> IO ()) -> IO (ServerHandle, Int -> OnionResponse N1 -> IO ()) | 220 | tcpRelay :: SockAddr -> (SockAddr -> OnionRequest N1 -> IO ()) -> IO (ServerHandle, Int -> OnionMessage Encrypted -> IO ()) |
220 | tcpRelay udp_addr sendOnion = do | 221 | tcpRelay udp_addr sendOnion = do |
221 | crypto <- newCrypto | 222 | crypto <- newCrypto |
222 | cons <- newTVarIO Map.empty | 223 | cons <- newTVarIO Map.empty |
diff --git a/src/Network/Tox/TCP.hs b/src/Network/Tox/TCP.hs index 608becc3..c9c3d9a6 100644 --- a/src/Network/Tox/TCP.hs +++ b/src/Network/Tox/TCP.hs | |||
@@ -7,6 +7,7 @@ module Network.Tox.TCP where | |||
7 | import Control.Arrow | 7 | import Control.Arrow |
8 | import Control.Concurrent | 8 | import Control.Concurrent |
9 | import Control.Concurrent.STM | 9 | import Control.Concurrent.STM |
10 | import Control.Monad | ||
10 | import Crypto.Random | 11 | import Crypto.Random |
11 | import Data.Functor.Contravariant | 12 | import Data.Functor.Contravariant |
12 | import Data.Functor.Identity | 13 | import Data.Functor.Identity |
@@ -22,11 +23,12 @@ import DebugTag | |||
22 | import DPut | 23 | import DPut |
23 | import Network.Address (setPort,PortNumber) | 24 | import Network.Address (setPort,PortNumber) |
24 | import Network.Kademlia.Routing | 25 | import Network.Kademlia.Routing |
25 | import Network.Kademlia.Search | 26 | import Network.Kademlia.Search hiding (sendQuery) |
26 | import Network.QueryResponse | 27 | import Network.QueryResponse |
27 | import Network.QueryResponse.TCP | 28 | import Network.QueryResponse.TCP |
28 | import Network.Tox.DHT.Handlers (toxSpace) | 29 | import Network.Tox.DHT.Handlers (toxSpace) |
29 | import Network.Tox.Onion.Transport (OnionMessage(..),OnionResponse(..),N1) | 30 | import Network.Tox.Onion.Transport hiding (encrypt,decrypt) |
31 | import Network.Tox.Onion.Handlers (unwrapAnnounceResponse) | ||
30 | import qualified Network.Tox.NodeId as UDP | 32 | import qualified Network.Tox.NodeId as UDP |
31 | 33 | ||
32 | 34 | ||
@@ -103,30 +105,77 @@ toxTCP crypto = tcpTransport 30 (tcpStream crypto) | |||
103 | tcpSpace :: KademliaSpace NodeId NodeInfo | 105 | tcpSpace :: KademliaSpace NodeId NodeInfo |
104 | tcpSpace = contramap udpNodeInfo toxSpace | 106 | tcpSpace = contramap udpNodeInfo toxSpace |
105 | 107 | ||
106 | nodeSearch :: Client err meth tid NodeInfo RelayPacket -> Search NodeId (IP, PortNumber) () NodeInfo NodeInfo | 108 | nodeSearch :: TCPClient err () Nonce8 -> Search NodeId (IP, PortNumber) () NodeInfo NodeInfo |
107 | nodeSearch client = Search | 109 | nodeSearch tcp = Search |
108 | { searchSpace = tcpSpace | 110 | { searchSpace = tcpSpace |
109 | , searchNodeAddress = nodeIP &&& tcpPort | 111 | , searchNodeAddress = nodeIP &&& tcpPort |
110 | , searchQuery = getNodes client | 112 | , searchQuery = getTCPNodes tcp |
111 | } | 113 | } |
112 | 114 | ||
113 | getNodes :: Client err meth tid NodeInfo RelayPacket -> NodeId -> NodeInfo -> IO (Maybe ([NodeInfo], [NodeInfo], Maybe ())) | 115 | data TCPClient err meth tid = TCPClient |
114 | getNodes client seeking dst = do | 116 | { tcpCrypto :: TransportCrypto |
115 | return Nothing -- TODO | 117 | , tcpClient :: Client err () tid NodeInfo RelayPacket |
118 | , tcpGetGateway :: UDP.NodeInfo -> STM (Maybe NodeInfo) | ||
119 | } | ||
120 | |||
121 | getTCPNodes :: TCPClient err () Nonce8 -> NodeId -> NodeInfo -> IO (Maybe ([NodeInfo],[NodeInfo],Maybe ())) | ||
122 | getTCPNodes tcp seeking dst = do | ||
123 | r <- getUDPNodes tcp seeking (udpNodeInfo dst) | ||
124 | let tcps (ns,_,mb) = (ns',ns',mb) | ||
125 | where ns' = do | ||
126 | n <- ns | ||
127 | [ NodeInfo n (fromIntegral 443) , NodeInfo n (fromIntegral 80) , NodeInfo n (UDP.nodePort n) ] | ||
128 | return $ tcps <$> r | ||
129 | |||
130 | getUDPNodes :: TCPClient err () Nonce8 -> NodeId -> UDP.NodeInfo -> IO (Maybe ([UDP.NodeInfo], [UDP.NodeInfo], Maybe ())) | ||
131 | getUDPNodes tcp seeking dst = do | ||
132 | mgateway <- atomically $ tcpGetGateway tcp dst | ||
133 | fmap join $ forM mgateway $ \gateway -> do | ||
134 | (b,c,n24) <- atomically $ do | ||
135 | b <- transportNewKey (tcpCrypto tcp) | ||
136 | c <- transportNewKey (tcpCrypto tcp) | ||
137 | n24 <- transportNewNonce (tcpCrypto tcp) | ||
138 | return (b,c,n24) | ||
139 | wrap2 <- lookupNonceFunction (tcpCrypto tcp) b (UDP.id2key $ UDP.nodeId dst) | ||
140 | wrap1 <- lookupNonceFunction (tcpCrypto tcp) c (UDP.id2key $ nodeId gateway) | ||
141 | wrap0 <- lookupNonceFunction (tcpCrypto tcp) (transportSecret $ tcpCrypto tcp) (UDP.id2key $ UDP.nodeId dst) | ||
142 | let meth = MethodSerializer -- MethodSerializer Nonce8 NodeInfo RelayPacket meth AnnounceRequest (Either String AnnounceResponse) | ||
143 | { methodTimeout = \tid addr -> return (addr,8000000) -- 8 second timeout | ||
144 | , method = () -- meth | ||
145 | , wrapQuery = \n8 src dst x -> | ||
146 | OnionPacket n24 $ Addressed (UDP.nodeAddr $ udpNodeInfo dst) | ||
147 | $ wrapOnionPure b (wrap2 n24) (UDP.nodeAddr $ udpNodeInfo dst) | ||
148 | $ wrapOnionPure c (wrap1 n24) (nodeAddr gateway) | ||
149 | $ NotForwarded $ encryptPayload (wrap0 n24) | ||
150 | $ OnionAnnounce Asymm | ||
151 | { senderKey = transportPublic (tcpCrypto tcp) | ||
152 | , asymmNonce = n24 | ||
153 | , asymmData = pure (x,n8) | ||
154 | } | ||
155 | , unwrapResponse = \case | ||
156 | OnionPacketResponse (OnionAnnounceResponse _ n24' r) | ||
157 | -> decrypt (wrap0 n24') r >>= decodePlain | ||
158 | x -> Left $ "getUDPNodes: unwrapResponse fail " ++ show x | ||
159 | } | ||
160 | r <- sendQuery (tcpClient tcp) meth (AnnounceRequest zeros32 seeking UDP.zeroID) gateway | ||
161 | forM r $ \response -> do | ||
162 | let (ns,_,mb) = either (const ([],[],Nothing)) (unwrapAnnounceResponse Nothing dst) $ response | ||
163 | return (ns,ns, const () <$> mb) | ||
164 | |||
116 | 165 | ||
117 | handleOOB :: PublicKey -> ByteString -> NodeInfo -> NodeInfo -> IO (Maybe (RelayPacket -> RelayPacket)) | 166 | handleOOB :: PublicKey -> ByteString -> NodeInfo -> NodeInfo -> IO (Maybe (RelayPacket -> RelayPacket)) |
118 | handleOOB k bs src dst = do | 167 | handleOOB k bs src dst = do |
119 | dput XMisc $ "TODO: handleOOB " ++ show src | 168 | dput XMisc $ "TODO: handleOOB " ++ show src |
120 | return Nothing | 169 | return Nothing |
121 | 170 | ||
122 | handle2route :: OnionResponse N1 -> NodeInfo -> NodeInfo -> IO (Maybe (RelayPacket -> RelayPacket)) | 171 | handle2route :: OnionMessage Encrypted -> NodeInfo -> NodeInfo -> IO (Maybe (RelayPacket -> RelayPacket)) |
123 | handle2route o src dst = do | 172 | handle2route o src dst = do |
124 | dput XMisc $ "TODO: handle2route " ++ show src | 173 | dput XMisc $ "TODO: handle2route " ++ show src |
125 | return Nothing | 174 | return Nothing |
126 | 175 | ||
127 | 176 | ||
128 | tcpClient :: TransportCrypto -> IO (Client String () Nonce8 NodeInfo RelayPacket) | 177 | newClient :: TransportCrypto -> IO (Client String () Nonce8 NodeInfo RelayPacket) |
129 | tcpClient crypto = do | 178 | newClient crypto = do |
130 | net <- toxTCP crypto | 179 | net <- toxTCP crypto |
131 | drg <- drgNew | 180 | drg <- drgNew |
132 | map_var <- atomically $ newTVar (drg, Data.Word64Map.empty) | 181 | map_var <- atomically $ newTVar (drg, Data.Word64Map.empty) |
@@ -136,8 +185,8 @@ tcpClient crypto = do | |||
136 | { classifyInbound = \case | 185 | { classifyInbound = \case |
137 | RelayPing n -> IsQuery () n | 186 | RelayPing n -> IsQuery () n |
138 | RelayPong n -> IsResponse n | 187 | RelayPong n -> IsResponse n |
139 | OnionPacketResponse (OnionResponse _ (OnionAnnounceResponse n8 n24 ciphered)) -> IsResponse n8 | 188 | OnionPacketResponse (OnionAnnounceResponse n8 n24 ciphered) -> IsResponse n8 |
140 | OnionPacketResponse o@(OnionResponse _ (OnionToRouteResponse _)) -> IsUnsolicited $ handle2route o | 189 | OnionPacketResponse o@(OnionToRouteResponse _) -> IsUnsolicited $ handle2route o |
141 | OOBRecv k bs -> IsUnsolicited $ handleOOB k bs | 190 | OOBRecv k bs -> IsUnsolicited $ handleOOB k bs |
142 | , lookupHandler = \() -> Just MethodHandler | 191 | , lookupHandler = \() -> Just MethodHandler |
143 | { methodParse = \(RelayPing n8) -> Right () | 192 | { methodParse = \(RelayPing n8) -> Right () |
diff --git a/src/Network/Tox/Transport.hs b/src/Network/Tox/Transport.hs index 0b34e8f8..e79e4d8b 100644 --- a/src/Network/Tox/Transport.hs +++ b/src/Network/Tox/Transport.hs | |||
@@ -22,7 +22,7 @@ toxTransport :: | |||
22 | -> OnionRouter | 22 | -> OnionRouter |
23 | -> (PublicKey -> IO (Maybe NodeInfo)) | 23 | -> (PublicKey -> IO (Maybe NodeInfo)) |
24 | -> UDPTransport | 24 | -> UDPTransport |
25 | -> (Int -> OnionResponse N1 -> IO ()) -- ^ TCP-bound callback. | 25 | -> (Int -> OnionMessage Encrypted -> IO ()) -- ^ TCP-bound callback. |
26 | -> IO ( Transport String SockAddr (CryptoPacket Encrypted) | 26 | -> IO ( Transport String SockAddr (CryptoPacket Encrypted) |
27 | , Transport String NodeInfo (DHTMessage Encrypted8) | 27 | , Transport String NodeInfo (DHTMessage Encrypted8) |
28 | , Transport String (OnionDestination RouteId) (OnionMessage Encrypted) | 28 | , Transport String (OnionDestination RouteId) (OnionMessage Encrypted) |