diff options
-rw-r--r-- | examples/dhtd.hs | 1 | ||||
-rw-r--r-- | examples/toxrelay.hs | 91 | ||||
-rw-r--r-- | src/Data/Tox/Relay.hs | 10 | ||||
-rw-r--r-- | src/Network/Tox.hs | 10 | ||||
-rw-r--r-- | src/Network/Tox/Onion/Transport.hs | 93 | ||||
-rw-r--r-- | src/Network/Tox/Transport.hs | 5 |
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) |
16 | import Data.Serialize | 16 | import Data.Serialize |
17 | import Data.Word | 17 | import Data.Word |
18 | import Network.Socket (SockAddr) | ||
18 | import System.IO | 19 | import System.IO |
19 | import System.IO.Error | 20 | import System.IO.Error |
20 | import System.Timeout | 21 | import System.Timeout |
@@ -26,6 +27,7 @@ import Data.Tox.Relay | |||
26 | import Network.Address (getBindAddress) | 27 | import Network.Address (getBindAddress) |
27 | import Network.StreamServer | 28 | import Network.StreamServer |
28 | import Network.Tox (newCrypto) | 29 | import Network.Tox (newCrypto) |
30 | import 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 | ||
43 | data RelaySession = RelaySession | 45 | data 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 | ||
49 | freshSession :: RelaySession | 51 | freshSession :: 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 | ||
69 | relaySession :: TransportCrypto | 71 | relaySession :: 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 () |
75 | relaySession crypto cons _ conid h = do | 78 | relaySession 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 | ||
134 | data R = R { routingRequest :: PublicKey -> IO ConId | ||
135 | , reply :: RelayPacket -> IO () | ||
136 | , routeOOB :: PublicKey -> IO (Maybe (RelayPacket -> IO ())) | ||
137 | } | ||
138 | |||
139 | handlePacket :: TVar (Map PublicKey (RelayPacket -> IO (), TVar RelaySession)) | 143 | handlePacket :: 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 () |
145 | handlePacket cons me sendToMe session = \case | 152 | handlePacket 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 | ||
54 | packetNumber :: RelayPacket -> Word8 | 54 | packetNumber :: RelayPacket -> Word8 |
55 | packetNumber (RelayData (ConId conid) _) = conid -- 0 to 15 not allowed. | 55 | packetNumber (RelayData _ (ConId conid)) = conid -- 0 to 15 not allowed. |
56 | packetNumber rp = fromIntegral $ pred $ constrIndex $ toConstr rp | 56 | packetNumber rp = fromIntegral $ pred $ constrIndex $ toConstr rp |
57 | 57 | ||
58 | instance Sized RelayPacket where | 58 | instance 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 | ||
76 | instance Serialize RelayPacket where | 76 | instance 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. |
109 | newtype Hello (f :: * -> *) = Hello (Asymm (f HelloData)) | 109 | newtype 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) |
275 | newTox keydb addr onsess suppliedDHTKey = do | 276 | newTox 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) |
287 | newToxOverTransport keydb addr onNewSession suppliedDHTKey udp = do | 289 | newToxOverTransport 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 | ||
55 | import Network.Address (fromSockAddr,toSockAddr,setPort,either4or6,sockAddrPort) | 56 | import Network.Address (fromSockAddr,toSockAddr,setPort,either4or6,sockAddrPort) |
@@ -87,6 +88,8 @@ import qualified Text.ParserCombinators.ReadP as RP | |||
87 | import Data.Hashable | 88 | import Data.Hashable |
88 | import DPut | 89 | import DPut |
89 | import DebugTag | 90 | import DebugTag |
91 | import Data.Word64Map (fitsInInt) | ||
92 | import Data.Bits (shiftR,shiftL) | ||
90 | 93 | ||
91 | type HandleLo a = Maybe (Either String (ByteString, SockAddr)) -> IO a | 94 | type 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 | ||
273 | forwardOnions :: TransportCrypto -> UDPTransport -> UDPTransport | 276 | forwardOnions :: TransportCrypto -> UDPTransport -> (Int -> OnionResponse N1 -> IO ()) {- ^ TCP relay send -} -> UDPTransport |
274 | forwardOnions crypto udp = udp { awaitMessage = forwardAwait crypto udp } | 277 | forwardOnions crypto udp sendTCP = udp { awaitMessage = forwardAwait crypto udp sendTCP } |
275 | 278 | ||
276 | forwardAwait :: TransportCrypto -> UDPTransport -> HandleLo a -> IO a | 279 | forwardAwait :: TransportCrypto -> UDPTransport -> (Int -> OnionResponse N1 -> IO ()) {- ^ TCP relay send -} -> HandleLo a -> IO a |
277 | forwardAwait crypto udp kont = do | 280 | forwardAwait 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 | ||
394 | data Addressed a = Addressed { sockAddr :: SockAddr, unaddressed :: a } | 397 | data Addressed a = Addressed { sockAddr :: SockAddr, unaddressed :: a } |
398 | | TCPIndex { tcpIndex :: Int, unaddressed :: a } | ||
395 | deriving (Eq,Show) | 399 | deriving (Eq,Show) |
396 | 400 | ||
397 | instance Sized a => Sized (Addressed a) where | 401 | instance 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 | ||
426 | addrToIndex :: SockAddr -> Int | ||
427 | addrToIndex (SockAddrInet6 _ _ (lo, hi, _, _) _) = | ||
428 | if fitsInInt (Proxy :: Proxy Word64) | ||
429 | then fromIntegral lo + (fromIntegral hi `shiftL` 32) | ||
430 | else fromIntegral lo | ||
431 | addrToIndex _ = 0 | ||
432 | |||
433 | indexToAddr :: Int -> SockAddr | ||
434 | indexToAddr x = SockAddrInet6 0 0 (fromIntegral x, fromIntegral (x `shiftR` 32),0,0) 0 | ||
435 | |||
422 | instance Serialize a => Serialize (Addressed a) where | 436 | instance 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 | ||
426 | data N0 | 445 | data N0 |
427 | data S n | 446 | data 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 | ||
551 | rewrap :: (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)) | ||
559 | rewrap 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 | |||
532 | handleOnionRequest :: forall a proxy n. | 568 | handleOnionRequest :: 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 |
538 | handleOnionRequest proxy crypto saddr udp kont (OnionRequest nonce msg rpath) = do | 574 | handleOnionRequest 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 | ||
554 | wrapSymmetric :: Serialize (ReturnPath n) => | 597 | wrapSymmetric :: 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) |
556 | wrapSymmetric sym n saddr rpath = ReturnPath n $ encryptSymmetric sym n (encodePlain $ Addressed saddr rpath) | 599 | wrapSymmetric sym n saddr rpath = ReturnPath n $ encryptSymmetric sym n (encodePlain $ saddr rpath) |
557 | 600 | ||
558 | peelSymmetric :: Serialize (Addressed (ReturnPath n)) | 601 | peelSymmetric :: 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)) | |||
568 | peelOnion crypto nonce (Forwarding k fwd) = do | 611 | peelOnion 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 | ||
571 | handleOnionResponse :: (KnownPeanoNat n, Sized (ReturnPath n), Serialize (ReturnPath n)) => proxy (S n) -> TransportCrypto -> SockAddr -> UDPTransport -> IO a -> OnionResponse (S n) -> IO a | 614 | handleOnionResponse :: (KnownPeanoNat n, Sized (ReturnPath n), Serialize (ReturnPath n), Typeable n) => |
572 | handleOnionResponse 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 | ||
623 | handleOnionResponse 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 | ||
585 | data AnnounceRequest = AnnounceRequest | 642 | data 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)) |
30 | toxTransport crypto orouter closeLookup udp = do | 31 | toxTransport 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 |