summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/dhtd.hs1
-rw-r--r--examples/toxrelay.hs91
-rw-r--r--src/Data/Tox/Relay.hs10
-rw-r--r--src/Network/Tox.hs10
-rw-r--r--src/Network/Tox/Onion/Transport.hs93
-rw-r--r--src/Network/Tox/Transport.hs5
6 files changed, 144 insertions, 66 deletions
diff --git a/examples/dhtd.hs b/examples/dhtd.hs
index 5279ea54..7562f2ad 100644
--- a/examples/dhtd.hs
+++ b/examples/dhtd.hs
@@ -1303,6 +1303,7 @@ initTox opts ssvar keysdb mbxmpp = case porttox opts of
1303 Nothing -> \_ _ _ -> return () 1303 Nothing -> \_ _ _ -> return ()
1304 Just xmpp -> onNewToxSession xmpp ssvar) 1304 Just xmpp -> onNewToxSession xmpp ssvar)
1305 (dhtkey opts) 1305 (dhtkey opts)
1306 (\_ _ -> return ()) -- TODO: TCP relay send
1306 (quitTox, toxStrap4, toxStrap6) <- Tox.forkTox tox True 1307 (quitTox, toxStrap4, toxStrap6) <- Tox.forkTox tox True
1307 1308
1308 toxSearches <- atomically $ newTVar Map.empty 1309 toxSearches <- atomically $ newTVar Map.empty
diff --git a/examples/toxrelay.hs b/examples/toxrelay.hs
index f03605f9..953b230b 100644
--- a/examples/toxrelay.hs
+++ b/examples/toxrelay.hs
@@ -15,6 +15,7 @@ import qualified Data.Map as Map
15 ;import Data.Map (Map) 15 ;import Data.Map (Map)
16import Data.Serialize 16import Data.Serialize
17import Data.Word 17import Data.Word
18import Network.Socket (SockAddr)
18import System.IO 19import System.IO
19import System.IO.Error 20import System.IO.Error
20import System.Timeout 21import System.Timeout
@@ -26,6 +27,7 @@ import Data.Tox.Relay
26import Network.Address (getBindAddress) 27import Network.Address (getBindAddress)
27import Network.StreamServer 28import Network.StreamServer
28import Network.Tox (newCrypto) 29import Network.Tox (newCrypto)
30import Network.Tox.Onion.Transport hiding (encrypt,decrypt)
29 31
30 32
31 33
@@ -41,9 +43,9 @@ hGetSized h = runGet get <$> B.hGet h len -- We treat parse-fail the same as EOF
41 ConstSize len = size :: Size x 43 ConstSize len = size :: Size x
42 44
43data RelaySession = RelaySession 45data RelaySession = RelaySession
44 { indexPool :: IntSet -- ^ Ints that are either solicited or associated. 46 { indexPool :: IntSet -- ^ Ints that are either solicited or associated.
45 , solicited :: Map PublicKey Int -- ^ Reserved ids, not yet in associated. 47 , solicited :: Map PublicKey Int -- ^ Reserved ids, not yet in associated.
46 , associated :: IntMap (RelayPacket -> IO ()) -- ^ Peers this session is connected to. 48 , associated :: IntMap ((ConId -> RelayPacket) -> IO ()) -- ^ Peers this session is connected to.
47 } 49 }
48 50
49freshSession :: RelaySession 51freshSession :: RelaySession
@@ -63,16 +65,17 @@ disconnect cons who = join $ atomically $ do
63 Just (_,session) -> do 65 Just (_,session) -> do
64 modifyTVar' cons $ Map.delete who 66 modifyTVar' cons $ Map.delete who
65 RelaySession { associated = cs } <- readTVar session 67 RelaySession { associated = cs } <- readTVar session
66 return $ let notifyPeer i send = (send (DisconnectNotification $ key2c i) >>) 68 return $ let notifyPeer i send = ((send DisconnectNotification) >>)
67 in IntMap.foldrWithKey notifyPeer (return ()) cs 69 in IntMap.foldrWithKey notifyPeer (return ()) cs
68 70
69relaySession :: TransportCrypto 71relaySession :: TransportCrypto
70 -> TVar (Map PublicKey (RelayPacket -> IO (),TVar RelaySession)) 72 -> TVar (Map PublicKey (RelayPacket -> IO (),TVar RelaySession))
73 -> (SockAddr -> OnionRequest N1 -> IO ())
71 -> sock 74 -> sock
72 -> Int 75 -> Int
73 -> Handle 76 -> Handle
74 -> IO () 77 -> IO ()
75relaySession crypto cons _ conid h = do 78relaySession crypto cons sendOnion _ conid h = do
76 -- atomically $ modifyTVar' cons $ IntMap.insert conid h 79 -- atomically $ modifyTVar' cons $ IntMap.insert conid h
77 80
78 -- mhello <- fmap (>>= \h -> decryptPayload (computeSharedSecret me (helloFrom h) (helloNonce h)) h) $ hGetSized h 81 -- mhello <- fmap (>>= \h -> decryptPayload (computeSharedSecret me (helloFrom h) (helloNonce h)) h) $ hGetSized h
@@ -98,16 +101,6 @@ relaySession crypto cons _ conid h = do
98 noncef' <- let them' = sessionPublicKey (runIdentity $ helloData hello) 101 noncef' <- let them' = sessionPublicKey (runIdentity $ helloData hello)
99 in lookupNonceFunction crypto me' them' 102 in lookupNonceFunction crypto me' them'
100 103
101 sendPacket <- do
102 v <- newMVar (sessionBaseNonce $ runIdentity $ welcomeData welcome)
103 return $ \p -> do
104 n24 <- takeMVar v
105 let bs = encode $ encrypt (noncef' n24) $ encodePlain (p :: RelayPacket)
106 do B.hPut h $ encode (fromIntegral (B.length bs) :: Word16)
107 B.hPut h bs
108 `catchIOError` \_ -> return ()
109 putMVar v (incrementNonce24 n24)
110
111 let readPacket n24 = (>>= decrypt (noncef' n24) >=> decodePlain) <$> hGetPrefixed h 104 let readPacket n24 = (>>= decrypt (noncef' n24) >=> decodePlain) <$> hGetPrefixed h
112 base = sessionBaseNonce $ runIdentity $ helloData hello 105 base = sessionBaseNonce $ runIdentity $ helloData hello
113 106
@@ -116,33 +109,47 @@ relaySession crypto cons _ conid h = do
116 forM_ mpkt0 $ \pkt0 -> do 109 forM_ mpkt0 $ \pkt0 -> do
117 110
118 disconnect cons (helloFrom hello) 111 disconnect cons (helloFrom hello)
119 session <- atomically $ do 112 (sendPacket,session) <- do
120 session <- newTVar freshSession 113 session <- atomically $ newTVar freshSession
121 modifyTVar' cons $ Map.insert (helloFrom hello) (sendPacket,session) 114 sendPacket <- do
122 return session 115 v <- newMVar (sessionBaseNonce $ runIdentity $ welcomeData welcome)
123 116 return $ \p -> do
124 handlePacket cons (helloFrom hello) sendPacket session pkt0 117 case p of
118 DisconnectNotification con -> atomically $ do
119 modifyTVar' session $ \s -> s
120 { indexPool = maybe id IntSet.delete (c2key con) (indexPool s)
121 , associated = maybe id IntMap.delete (c2key con) (associated s)
122 }
123 _ -> return ()
124 n24 <- takeMVar v
125 let bs = encode $ encrypt (noncef' n24) $ encodePlain (p :: RelayPacket)
126 do B.hPut h $ encode (fromIntegral (B.length bs) :: Word16)
127 B.hPut h bs
128 `catchIOError` \_ -> return ()
129 putMVar v (incrementNonce24 n24)
130 atomically $ modifyTVar' cons $ Map.insert (helloFrom hello) (sendPacket,session)
131 return (sendPacket,session)
132
133 handlePacket cons conid (helloFrom hello) crypto sendOnion sendPacket session pkt0
125 134
126 flip fix (incrementNonce24 base) $ \loop n24 -> do 135 flip fix (incrementNonce24 base) $ \loop n24 -> do
127 m <- readPacket n24 136 m <- readPacket n24
128 forM_ m $ \p -> do 137 forM_ m $ \p -> do
129 handlePacket cons (helloFrom hello) sendPacket session p 138 handlePacket cons conid (helloFrom hello) crypto sendOnion sendPacket session p
130 loop (incrementNonce24 n24) 139 loop (incrementNonce24 n24)
131 `finally` 140 `finally`
132 disconnect cons (helloFrom hello) 141 disconnect cons (helloFrom hello)
133 142
134data R = R { routingRequest :: PublicKey -> IO ConId
135 , reply :: RelayPacket -> IO ()
136 , routeOOB :: PublicKey -> IO (Maybe (RelayPacket -> IO ()))
137 }
138
139handlePacket :: TVar (Map PublicKey (RelayPacket -> IO (), TVar RelaySession)) 143handlePacket :: TVar (Map PublicKey (RelayPacket -> IO (), TVar RelaySession))
144 -> Int
140 -> PublicKey 145 -> PublicKey
146 -> TransportCrypto
147 -> (SockAddr -> OnionRequest N1 -> IO ())
141 -> (RelayPacket -> IO ()) 148 -> (RelayPacket -> IO ())
142 -> TVar RelaySession 149 -> TVar RelaySession
143 -> RelayPacket 150 -> RelayPacket
144 -> IO () 151 -> IO ()
145handlePacket cons me sendToMe session = \case 152handlePacket cons thistcp me crypto sendOnion sendToMe session = \case
146 RoutingRequest them -> join $ atomically $ do 153 RoutingRequest them -> join $ atomically $ do
147 mySession <- readTVar session 154 mySession <- readTVar session
148 mi <- case Map.lookup them (solicited mySession) of 155 mi <- case Map.lookup them (solicited mySession) of
@@ -161,16 +168,18 @@ handlePacket cons me sendToMe session = \case
161 forM mp $ \(sendToThem,peer) -> do 168 forM mp $ \(sendToThem,peer) -> do
162 theirSession <- readTVar peer 169 theirSession <- readTVar peer
163 forM (Map.lookup me $ solicited theirSession) $ \reserved_id -> do 170 forM (Map.lookup me $ solicited theirSession) $ \reserved_id -> do
171 let sendToThem' f = sendToThem $ f $ key2c reserved_id
172 sendToMe' f = sendToMe $ f $ key2c i
164 writeTVar peer theirSession 173 writeTVar peer theirSession
165 { solicited = Map.delete me (solicited theirSession) 174 { solicited = Map.delete me (solicited theirSession)
166 , associated = IntMap.insert reserved_id sendToMe (associated theirSession) 175 , associated = IntMap.insert reserved_id sendToMe' (associated theirSession)
167 } 176 }
168 writeTVar session mySession 177 writeTVar session mySession
169 { solicited = Map.delete them (solicited mySession) 178 { solicited = Map.delete them (solicited mySession)
170 , associated = IntMap.insert i sendToThem (associated mySession) 179 , associated = IntMap.insert i sendToThem' (associated mySession)
171 } 180 }
172 return $ do sendToThem $ ConnectNotification (key2c reserved_id) 181 return $ do sendToThem' ConnectNotification
173 sendToMe $ ConnectNotification (key2c i) 182 sendToMe' ConnectNotification
174 return $ do sendToMe $ RoutingResponse (maybe badcon key2c mi) them 183 return $ do sendToMe $ RoutingResponse (maybe badcon key2c mi) them
175 sequence_ notifyConnect 184 sequence_ notifyConnect
176 185
@@ -180,7 +189,7 @@ handlePacket cons me sendToMe session = \case
180 m <- atomically $ Map.lookup them <$> readTVar cons 189 m <- atomically $ Map.lookup them <$> readTVar cons
181 forM_ m $ \(sendToThem,_) -> sendToThem $ OOBRecv me bs 190 forM_ m $ \(sendToThem,_) -> sendToThem $ OOBRecv me bs
182 191
183 RelayData con bs -> join $ atomically $ do 192 RelayData bs con -> join $ atomically $ do
184 -- Data: Data packets can only be sent and received if the 193 -- Data: Data packets can only be sent and received if the
185 -- corresponding connection_id is connection (a Connect notification 194 -- corresponding connection_id is connection (a Connect notification
186 -- has been received from it) if the server receives a Data packet for 195 -- has been received from it) if the server receives a Data packet for
@@ -188,8 +197,14 @@ handlePacket cons me sendToMe session = \case
188 mySession <- readTVar session 197 mySession <- readTVar session
189 return $ sequence_ $ do 198 return $ sequence_ $ do
190 i <- c2key con 199 i <- c2key con
191 sendToThem <- IntMap.lookup i $ associated mySession 200 sendToThem' <- IntMap.lookup i $ associated mySession
192 return $ sendToThem $ RelayData _todo bs 201 return $ sendToThem' $ RelayData bs
202
203 OnionPacket p -> do
204 mp <- rewrap crypto (TCPIndex thistcp) p
205 case mp of
206 Right (p',addr) -> sendOnion addr p'
207 _ -> return ()
193 208
194 _ -> return () 209 _ -> return ()
195 210
@@ -199,9 +214,11 @@ main = do
199 crypto <- newCrypto 214 crypto <- newCrypto
200 cons <- newTVarIO Map.empty 215 cons <- newTVarIO Map.empty
201 a <- getBindAddress "33445" True 216 a <- getBindAddress "33445" True
217 let sendOnion :: SockAddr -> OnionRequest N1 -> IO ()
218 sendOnion _ _ = return ()
202 h <- streamServer ServerConfig 219 h <- streamServer ServerConfig
203 { serverWarn = hPutStrLn stderr 220 { serverWarn = hPutStrLn stderr
204 , serverSession = relaySession crypto cons 221 , serverSession = relaySession crypto cons sendOnion
205 } 222 }
206 a 223 a
207 224
diff --git a/src/Data/Tox/Relay.hs b/src/Data/Tox/Relay.hs
index f801d1cd..82fef126 100644
--- a/src/Data/Tox/Relay.hs
+++ b/src/Data/Tox/Relay.hs
@@ -48,11 +48,11 @@ data RelayPacket
48 | OnionPacket (OnionRequest N0) 48 | OnionPacket (OnionRequest N0)
49 | OnionPacketResponse (OnionResponse N1) 49 | OnionPacketResponse (OnionResponse N1)
50 -- 0x0A through 0x0F reserved for future use. 50 -- 0x0A through 0x0F reserved for future use.
51 | RelayData ConId ByteString -- Word8 is a connection id. Encoded as number 16 to 255. 51 | RelayData ByteString ConId -- Word8 is a connection id. Encoded as number 16 to 255.
52 deriving (Eq,Ord,Show,Data) 52 deriving (Eq,Ord,Show,Data)
53 53
54packetNumber :: RelayPacket -> Word8 54packetNumber :: RelayPacket -> Word8
55packetNumber (RelayData (ConId conid) _) = conid -- 0 to 15 not allowed. 55packetNumber (RelayData _ (ConId conid)) = conid -- 0 to 15 not allowed.
56packetNumber rp = fromIntegral $ pred $ constrIndex $ toConstr rp 56packetNumber rp = fromIntegral $ pred $ constrIndex $ toConstr rp
57 57
58instance Sized RelayPacket where 58instance Sized RelayPacket where
@@ -71,7 +71,7 @@ instance Sized RelayPacket where
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
74 RelayData _ bs -> B.length bs 74 RelayData bs _ -> B.length bs
75 75
76instance Serialize RelayPacket where 76instance Serialize RelayPacket where
77 77
@@ -88,7 +88,7 @@ instance Serialize RelayPacket where
88 7 -> OOBRecv <$> getPublicKey <*> (remaining >>= getBytes) 88 7 -> OOBRecv <$> getPublicKey <*> (remaining >>= getBytes)
89 8 -> OnionPacket <$> get 89 8 -> OnionPacket <$> 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
93 put rp = do 93 put rp = do
94 putWord8 $ packetNumber rp 94 putWord8 $ packetNumber rp
@@ -103,7 +103,7 @@ instance Serialize RelayPacket where
103 OOBRecv k bs -> putPublicKey k >> putByteString bs 103 OOBRecv k bs -> putPublicKey k >> putByteString bs
104 OnionPacket query -> put query 104 OnionPacket query -> put query
105 OnionPacketResponse answer -> put answer 105 OnionPacketResponse answer -> put answer
106 RelayData _ bs -> putByteString bs 106 RelayData bs _ -> putByteString bs
107 107
108-- | Initial client-to-server handshake message. 108-- | Initial client-to-server handshake message.
109newtype Hello (f :: * -> *) = Hello (Asymm (f HelloData)) 109newtype Hello (f :: * -> *) = Hello (Asymm (f HelloData))
diff --git a/src/Network/Tox.hs b/src/Network/Tox.hs
index ddb22d50..b22cfdf3 100644
--- a/src/Network/Tox.hs
+++ b/src/Network/Tox.hs
@@ -271,10 +271,11 @@ newTox :: TVar Onion.AnnouncedKeys -- ^ Store of announced keys we are a rende
271 -> SockAddr -- ^ Bind-address to listen on. 271 -> SockAddr -- ^ Bind-address to listen on.
272 -> ( ContactInfo extra -> SockAddr -> Session -> IO () ) 272 -> ( ContactInfo extra -> SockAddr -> Session -> IO () )
273 -> Maybe SecretKey -- ^ Optional DHT secret key to use. 273 -> Maybe SecretKey -- ^ Optional DHT secret key to use.
274 -> ( Int -> Onion.OnionResponse Onion.N1 -> IO () ) -- ^ TCP-bound onion responses.
274 -> IO (Tox extra) 275 -> IO (Tox extra)
275newTox keydb addr onsess suppliedDHTKey = do 276newTox keydb addr onsess suppliedDHTKey tcp = do
276 (udp,sock) <- {- addVerbosity <$> -} udpTransport' addr 277 (udp,sock) <- {- addVerbosity <$> -} udpTransport' addr
277 tox <- newToxOverTransport keydb addr onsess suppliedDHTKey udp 278 tox <- newToxOverTransport keydb addr onsess suppliedDHTKey udp tcp
278 return tox { toxAnnounceToLan = announceToLan sock (key2id $ transportPublic $ toxCryptoKeys tox) } 279 return tox { toxAnnounceToLan = announceToLan sock (key2id $ transportPublic $ toxCryptoKeys tox) }
279 280
280-- | This version of 'newTox' is useful for automated tests using 'testPairTransport'. 281-- | This version of 'newTox' is useful for automated tests using 'testPairTransport'.
@@ -283,8 +284,9 @@ newToxOverTransport :: TVar Onion.AnnouncedKeys
283 -> ( ContactInfo extra -> SockAddr -> Session -> IO () ) 284 -> ( ContactInfo extra -> SockAddr -> Session -> IO () )
284 -> Maybe SecretKey 285 -> Maybe SecretKey
285 -> Onion.UDPTransport 286 -> Onion.UDPTransport
287 -> ( Int -> Onion.OnionResponse Onion.N1 -> IO () ) -- ^ TCP-bound onion responses.
286 -> IO (Tox extra) 288 -> IO (Tox extra)
287newToxOverTransport keydb addr onNewSession suppliedDHTKey udp = do 289newToxOverTransport keydb addr onNewSession suppliedDHTKey udp tcp = do
288 roster <- newContactInfo 290 roster <- newContactInfo
289 crypto0 <- newCrypto 291 crypto0 <- newCrypto
290 let -- patch in supplied DHT key 292 let -- patch in supplied DHT key
@@ -306,7 +308,7 @@ newToxOverTransport keydb addr onNewSession suppliedDHTKey udp = do
306 308
307 mkrouting <- DHT.newRouting addr crypto updateIP updateIP 309 mkrouting <- DHT.newRouting addr crypto updateIP updateIP
308 orouter <- newOnionRouter $ dput XRoutes 310 orouter <- newOnionRouter $ dput XRoutes
309 (cryptonet,dhtcrypt,onioncrypt,dtacrypt,handshakes) <- toxTransport crypto orouter lookupClose udp 311 (cryptonet,dhtcrypt,onioncrypt,dtacrypt,handshakes) <- toxTransport crypto orouter lookupClose udp tcp
310 sessions <- initSessions (sendMessage cryptonet) 312 sessions <- initSessions (sendMessage cryptonet)
311 313
312 let dhtnet0 = layerTransportM (DHT.decrypt crypto) (DHT.encrypt crypto) dhtcrypt 314 let dhtnet0 = layerTransportM (DHT.decrypt crypto) (DHT.encrypt crypto) dhtcrypt
diff --git a/src/Network/Tox/Onion/Transport.hs b/src/Network/Tox/Onion/Transport.hs
index 160b99f7..f6d9ca31 100644
--- a/src/Network/Tox/Onion/Transport.hs
+++ b/src/Network/Tox/Onion/Transport.hs
@@ -50,6 +50,7 @@ module Network.Tox.Onion.Transport
50 , selectAlias 50 , selectAlias
51 , RouteId(..) 51 , RouteId(..)
52 , routeId 52 , routeId
53 , rewrap
53 ) where 54 ) where
54 55
55import Network.Address (fromSockAddr,toSockAddr,setPort,either4or6,sockAddrPort) 56import Network.Address (fromSockAddr,toSockAddr,setPort,either4or6,sockAddrPort)
@@ -87,6 +88,8 @@ import qualified Text.ParserCombinators.ReadP as RP
87import Data.Hashable 88import Data.Hashable
88import DPut 89import DPut
89import DebugTag 90import DebugTag
91import Data.Word64Map (fitsInInt)
92import Data.Bits (shiftR,shiftL)
90 93
91type HandleLo a = Maybe (Either String (ByteString, SockAddr)) -> IO a 94type HandleLo a = Maybe (Either String (ByteString, SockAddr)) -> IO a
92 95
@@ -270,20 +273,20 @@ encodeOnionAddr crypto getRoute (msg,OnionDestination _ ni (Just rid)) = do
270 return x 273 return x
271 274
272 275
273forwardOnions :: TransportCrypto -> UDPTransport -> UDPTransport 276forwardOnions :: TransportCrypto -> UDPTransport -> (Int -> OnionResponse N1 -> IO ()) {- ^ TCP relay send -} -> UDPTransport
274forwardOnions crypto udp = udp { awaitMessage = forwardAwait crypto udp } 277forwardOnions crypto udp sendTCP = udp { awaitMessage = forwardAwait crypto udp sendTCP }
275 278
276forwardAwait :: TransportCrypto -> UDPTransport -> HandleLo a -> IO a 279forwardAwait :: TransportCrypto -> UDPTransport -> (Int -> OnionResponse N1 -> IO ()) {- ^ TCP relay send -} -> HandleLo a -> IO a
277forwardAwait crypto udp kont = do 280forwardAwait crypto udp sendTCP kont = do
278 fix $ \another -> do 281 fix $ \another -> do
279 awaitMessage udp $ \case 282 awaitMessage udp $ \case
280 m@(Just (Right (bs,saddr))) -> case B.head bs of 283 m@(Just (Right (bs,saddr))) -> case B.head bs of
281 0x80 -> forward kont bs $ handleOnionRequest (Proxy :: Proxy N0) crypto saddr udp another 284 0x80 -> forward kont bs $ handleOnionRequest (Proxy :: Proxy N0) crypto (Addressed saddr) udp another
282 0x81 -> forward kont bs $ handleOnionRequest (Proxy :: Proxy N1) crypto saddr udp another 285 0x81 -> forward kont bs $ handleOnionRequest (Proxy :: Proxy N1) crypto (Addressed saddr) udp another
283 0x82 -> forward kont bs $ handleOnionRequest (Proxy :: Proxy N2) crypto saddr udp another 286 0x82 -> forward kont bs $ handleOnionRequest (Proxy :: Proxy N2) crypto (Addressed saddr) udp another
284 0x8c -> forward kont bs $ handleOnionResponse (Proxy :: Proxy N3) crypto saddr udp another 287 0x8c -> forward kont bs $ handleOnionResponse (Proxy :: Proxy N3) crypto saddr udp sendTCP another
285 0x8d -> forward kont bs $ handleOnionResponse (Proxy :: Proxy N2) crypto saddr udp another 288 0x8d -> forward kont bs $ handleOnionResponse (Proxy :: Proxy N2) crypto saddr udp sendTCP another
286 0x8e -> forward kont bs $ handleOnionResponse (Proxy :: Proxy N1) crypto saddr udp another 289 0x8e -> forward kont bs $ handleOnionResponse (Proxy :: Proxy N1) crypto saddr udp sendTCP another
287 _ -> kont m 290 _ -> kont m
288 m -> kont m 291 m -> kont m
289 292
@@ -392,6 +395,7 @@ instance (Sized (ReturnPath n)) => Sized (OnionResponse (S n)) where
392 size = contramap pathToOwner size <> contramap msgToOwner size 395 size = contramap pathToOwner size <> contramap msgToOwner size
393 396
394data Addressed a = Addressed { sockAddr :: SockAddr, unaddressed :: a } 397data Addressed a = Addressed { sockAddr :: SockAddr, unaddressed :: a }
398 | TCPIndex { tcpIndex :: Int, unaddressed :: a }
395 deriving (Eq,Show) 399 deriving (Eq,Show)
396 400
397instance Sized a => Sized (Addressed a) where 401instance Sized a => Sized (Addressed a) where
@@ -419,9 +423,24 @@ putForwardAddr saddr = fromMaybe (return $ error "unsupported SockAddr family")
419 IPv6 ip6 -> S.put (0x0a :: Word8) >> S.put ip6 423 IPv6 ip6 -> S.put (0x0a :: Word8) >> S.put ip6
420 S.put port 424 S.put port
421 425
426addrToIndex :: SockAddr -> Int
427addrToIndex (SockAddrInet6 _ _ (lo, hi, _, _) _) =
428 if fitsInInt (Proxy :: Proxy Word64)
429 then fromIntegral lo + (fromIntegral hi `shiftL` 32)
430 else fromIntegral lo
431addrToIndex _ = 0
432
433indexToAddr :: Int -> SockAddr
434indexToAddr x = SockAddrInet6 0 0 (fromIntegral x, fromIntegral (x `shiftR` 32),0,0) 0
435
422instance Serialize a => Serialize (Addressed a) where 436instance Serialize a => Serialize (Addressed a) where
423 get = Addressed <$> getForwardAddr <*> get 437 get = do saddr <- getForwardAddr
438 a <- get
439 case sockAddrPort saddr of
440 Just 0 -> return $ TCPIndex (addrToIndex saddr) a
441 _ -> return $ Addressed saddr a
424 put (Addressed addr x) = putForwardAddr addr >> put x 442 put (Addressed addr x) = putForwardAddr addr >> put x
443 put (TCPIndex idx x) = putForwardAddr (indexToAddr idx) >> put x
425 444
426data N0 445data N0
427data S n 446data S n
@@ -529,31 +548,55 @@ instance (Serialize (Encrypted (Addressed (Forwarding n msg)))) => Serialize (Fo
529 get = Forwarding <$> getPublicKey <*> get 548 get = Forwarding <$> getPublicKey <*> get
530 put (Forwarding k x) = putPublicKey k >> put x 549 put (Forwarding k x) = putPublicKey k >> put x
531 550
551rewrap :: (ThreeMinus n ~ S (ThreeMinus (S n)),
552 Serialize (ReturnPath n),
553 Serialize
554 (Forwarding (ThreeMinus (S n)) (OnionMessage Encrypted))) =>
555 TransportCrypto
556 -> (forall x. x -> Addressed x)
557 -> OnionRequest n
558 -> IO (Either String (OnionRequest (S n), SockAddr))
559rewrap crypto saddr (OnionRequest nonce msg rpath) = do
560 (sym, snonce) <- atomically ( (,) <$> transportSymmetric crypto
561 <*> transportNewNonce crypto )
562 peeled <- peelOnion crypto nonce msg
563 return $ peeled >>= \case
564 Addressed dst msg'
565 -> Right (OnionRequest nonce msg' $ wrapSymmetric sym snonce saddr rpath, dst)
566 _ -> Left "Onion forward to TCP client?"
567
532handleOnionRequest :: forall a proxy n. 568handleOnionRequest :: forall a proxy n.
533 ( LessThanThree n 569 ( LessThanThree n
534 , KnownPeanoNat n 570 , KnownPeanoNat n
535 , Sized (ReturnPath n) 571 , Sized (ReturnPath n)
536 , Typeable n 572 , Typeable n
537 ) => proxy n -> TransportCrypto -> SockAddr -> UDPTransport -> IO a -> OnionRequest n -> IO a 573 ) => proxy n -> TransportCrypto -> (forall x. x -> Addressed x) -> UDPTransport -> IO a -> OnionRequest n -> IO a
538handleOnionRequest proxy crypto saddr udp kont (OnionRequest nonce msg rpath) = do 574handleOnionRequest proxy crypto saddr udp kont (OnionRequest nonce msg rpath) = do
539 let n = peanoVal rpath 575 let n = peanoVal rpath
540 dput XOnion $ "handleOnionRequest " ++ show n 576 dput XOnion $ "handleOnionRequest " ++ show n
541 (sym, snonce) <- atomically ( (,) <$> transportSymmetric crypto 577 (sym, snonce) <- atomically ( (,) <$> transportSymmetric crypto
542 <*> transportNewNonce crypto ) 578 <*> transportNewNonce crypto )
543 peeled <- peelOnion crypto nonce msg 579 peeled <- peelOnion crypto nonce msg
580 let showDestination = case saddr () of
581 Addressed a _ -> either show show $ either4or6 a
582 TCPIndex i _ -> "TCP" ++ show [i]
583
544 case peeled of 584 case peeled of
545 Left e -> do 585 Left e -> do
546 -- todo report encryption error 586 -- todo report encryption error
547 dput XOnion $ unwords [ "peelOnion:", show n, either show show (either4or6 saddr), e] 587 dput XOnion $ unwords [ "peelOnion:", show n, showDestination, e]
548 kont 588 kont
549 Right (Addressed dst msg') -> do 589 Right (Addressed dst msg') -> do
550 dput XOnion $ unwords [ "peelOnion:", show n, either show show (either4or6 saddr), "-->", either show show (either4or6 dst), "SUCCESS"] 590 dput XOnion $ unwords [ "peelOnion:", show n, showDestination, "-->", either show show (either4or6 dst), "SUCCESS"]
551 sendMessage udp dst (runPut $ putRequest $ OnionRequest nonce msg' $ wrapSymmetric sym snonce saddr rpath) 591 sendMessage udp dst (runPut $ putRequest $ OnionRequest nonce msg' $ wrapSymmetric sym snonce saddr rpath)
552 kont 592 kont
593 Right (TCPIndex {}) -> do
594 dput XUnexpected "handleOnionRequest: Onion forward to TCP client?"
595 kont
553 596
554wrapSymmetric :: Serialize (ReturnPath n) => 597wrapSymmetric :: Serialize (ReturnPath n) =>
555 SymmetricKey -> Nonce24 -> SockAddr -> ReturnPath n -> ReturnPath (S n) 598 SymmetricKey -> Nonce24 -> (forall x. x -> Addressed x) -> ReturnPath n -> ReturnPath (S n)
556wrapSymmetric sym n saddr rpath = ReturnPath n $ encryptSymmetric sym n (encodePlain $ Addressed saddr rpath) 599wrapSymmetric sym n saddr rpath = ReturnPath n $ encryptSymmetric sym n (encodePlain $ saddr rpath)
557 600
558peelSymmetric :: Serialize (Addressed (ReturnPath n)) 601peelSymmetric :: Serialize (Addressed (ReturnPath n))
559 => SymmetricKey -> ReturnPath (S n) -> Either String (Addressed (ReturnPath n)) 602 => SymmetricKey -> ReturnPath (S n) -> Either String (Addressed (ReturnPath n))
@@ -568,8 +611,16 @@ peelOnion :: Serialize (Addressed (Forwarding n t))
568peelOnion crypto nonce (Forwarding k fwd) = do 611peelOnion crypto nonce (Forwarding k fwd) = do
569 fmap runIdentity . uncomposed <$> decryptMessage crypto (dhtKey crypto) nonce (Right $ Asymm k nonce fwd) 612 fmap runIdentity . uncomposed <$> decryptMessage crypto (dhtKey crypto) nonce (Right $ Asymm k nonce fwd)
570 613
571handleOnionResponse :: (KnownPeanoNat n, Sized (ReturnPath n), Serialize (ReturnPath n)) => proxy (S n) -> TransportCrypto -> SockAddr -> UDPTransport -> IO a -> OnionResponse (S n) -> IO a 614handleOnionResponse :: (KnownPeanoNat n, Sized (ReturnPath n), Serialize (ReturnPath n), Typeable n) =>
572handleOnionResponse proxy crypto saddr udp kont (OnionResponse path msg) = do 615 proxy (S n)
616 -> TransportCrypto
617 -> SockAddr
618 -> UDPTransport
619 -> (Int -> OnionResponse N1 -> IO ()) -- ^ TCP-relay onion send.
620 -> IO a
621 -> OnionResponse (S n)
622 -> IO a
623handleOnionResponse proxy crypto saddr udp sendTCP kont (OnionResponse path msg) = do
573 sym <- atomically $ transportSymmetric crypto 624 sym <- atomically $ transportSymmetric crypto
574 case peelSymmetric sym path of 625 case peelSymmetric sym path of
575 Left e -> do 626 Left e -> do
@@ -580,6 +631,12 @@ handleOnionResponse proxy crypto saddr udp kont (OnionResponse path msg) = do
580 Right (Addressed dst path') -> do 631 Right (Addressed dst path') -> do
581 sendMessage udp dst (runPut $ putResponse $ OnionResponse path' msg) 632 sendMessage udp dst (runPut $ putResponse $ OnionResponse path' msg)
582 kont 633 kont
634 Right (TCPIndex dst path') -> do
635 -- This should only occur for OnionResponse N1
636 case gcast (OnionResponse path' msg) of
637 Just supported -> sendTCP dst supported
638 Nothing -> dput XUnexpected "handleOnionResponse: TCP-bound message not supported."
639 kont
583 640
584 641
585data AnnounceRequest = AnnounceRequest 642data AnnounceRequest = AnnounceRequest
diff --git a/src/Network/Tox/Transport.hs b/src/Network/Tox/Transport.hs
index 0b03ed19..0b34e8f8 100644
--- a/src/Network/Tox/Transport.hs
+++ b/src/Network/Tox/Transport.hs
@@ -22,14 +22,15 @@ 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 -> IO ( Transport String SockAddr (CryptoPacket Encrypted) 26 -> IO ( Transport String SockAddr (CryptoPacket Encrypted)
26 , Transport String NodeInfo (DHTMessage Encrypted8) 27 , Transport String NodeInfo (DHTMessage Encrypted8)
27 , Transport String (OnionDestination RouteId) (OnionMessage Encrypted) 28 , Transport String (OnionDestination RouteId) (OnionMessage Encrypted)
28 , Transport String AnnouncedRendezvous (PublicKey,OnionData) 29 , Transport String AnnouncedRendezvous (PublicKey,OnionData)
29 , Transport String SockAddr (Handshake Encrypted)) 30 , Transport String SockAddr (Handshake Encrypted))
30toxTransport crypto orouter closeLookup udp = do 31toxTransport crypto orouter closeLookup udp tcp = do
31 (netcrypto, udp0) <- partitionTransport parseCrypto encodeCrypto udp 32 (netcrypto, udp0) <- partitionTransport parseCrypto encodeCrypto udp
32 (dht,udp1) <- partitionTransportM (parseDHTAddr crypto) (fmap Just . encodeDHTAddr) $ forwardOnions crypto udp0 33 (dht,udp1) <- partitionTransportM (parseDHTAddr crypto) (fmap Just . encodeDHTAddr) $ forwardOnions crypto udp0 tcp
33 (onion1,udp2) <- partitionTransportM (parseOnionAddr $ lookupSender orouter) 34 (onion1,udp2) <- partitionTransportM (parseOnionAddr $ lookupSender orouter)
34 (encodeOnionAddr crypto $ lookupRoute orouter) 35 (encodeOnionAddr crypto $ lookupRoute orouter)
35 udp1 36 udp1