summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjoe <joe@jerkface.net>2017-10-01 05:26:36 -0400
committerjoe <joe@jerkface.net>2017-10-01 05:26:36 -0400
commitd408e6c3148106c6dbc8afe24a1488619adf34e1 (patch)
treeca2d7a66b07dba82b6bf236fb234cac75bf87da6
parentf6f70dcfa25ddf10e3cf16745bdd082cc26b2fd6 (diff)
Ability to send onion messages when given a path.
-rw-r--r--src/Network/QueryResponse.hs28
-rw-r--r--src/Network/Tox.hs7
-rw-r--r--src/Network/Tox/Onion/Handlers.hs29
-rw-r--r--src/Network/Tox/Onion/Transport.hs151
-rw-r--r--src/Network/Tox/Transport.hs18
5 files changed, 153 insertions, 80 deletions
diff --git a/src/Network/QueryResponse.hs b/src/Network/QueryResponse.hs
index d467d302..0fa1a05a 100644
--- a/src/Network/QueryResponse.hs
+++ b/src/Network/QueryResponse.hs
@@ -74,23 +74,21 @@ layerTransport parse encode tr =
74-- | Paritions a 'Transport' into two higher-level transports. Note: An 'MVar' 74-- | Paritions a 'Transport' into two higher-level transports. Note: An 'MVar'
75-- is used to share the same underlying socket, so be sure to fork a thread for 75-- is used to share the same underlying socket, so be sure to fork a thread for
76-- both returned 'Transport's to avoid hanging. 76-- both returned 'Transport's to avoid hanging.
77partitionTransport :: ((b,a) -> Either (x,xaddr) (y,yaddr)) 77partitionTransport :: ((b,a) -> Either (x,xaddr) (b,a))
78 -> ((x,xaddr) -> (b,a)) 78 -> ((x,xaddr) -> Maybe (b,a))
79 -> ((y,yaddr) -> (b,a))
80 -> Transport err a b 79 -> Transport err a b
81 -> IO (Transport err xaddr x, Transport err yaddr y) 80 -> IO (Transport err xaddr x, Transport err a b)
82partitionTransport parse encodex encodey tr = 81partitionTransport parse encodex tr =
83 partitionTransportM (return . parse) (return . encodex) (return . encodey) tr 82 partitionTransportM (return . parse) (return . encodex) tr
84 83
85-- | Paritions a 'Transport' into two higher-level transports. Note: An 'MVar' 84-- | Paritions a 'Transport' into two higher-level transports. Note: An 'MVar'
86-- is used to share the same underlying socket, so be sure to fork a thread for 85-- is used to share the same underlying socket, so be sure to fork a thread for
87-- both returned 'Transport's to avoid hanging. 86-- both returned 'Transport's to avoid hanging.
88partitionTransportM :: ((b,a) -> IO (Either (x,xaddr) (y,yaddr))) 87partitionTransportM :: ((b,a) -> IO (Either (x,xaddr) (b,a)))
89 -> ((x,xaddr) -> IO (b,a)) 88 -> ((x,xaddr) -> IO (Maybe (b,a)))
90 -> ((y,yaddr) -> IO (b,a))
91 -> Transport err a b 89 -> Transport err a b
92 -> IO (Transport err xaddr x, Transport err yaddr y) 90 -> IO (Transport err xaddr x, Transport err a b)
93partitionTransportM parse encodex encodey tr = do 91partitionTransportM parse encodex tr = do
94 mvar <- newEmptyMVar 92 mvar <- newEmptyMVar
95 let xtr = tr { awaitMessage = \kont -> fix $ \again -> do 93 let xtr = tr { awaitMessage = \kont -> fix $ \again -> do
96 awaitMessage tr $ \m -> case m of 94 awaitMessage tr $ \m -> case m of
@@ -100,14 +98,12 @@ partitionTransportM parse encodex encodey tr = do
100 Just (Left e) -> kont $ Just (Left e) 98 Just (Left e) -> kont $ Just (Left e)
101 Nothing -> kont Nothing 99 Nothing -> kont Nothing
102 , sendMessage = \addr' msg' -> do 100 , sendMessage = \addr' msg' -> do
103 (msg,addr) <- encodex (msg',addr') 101 msg_addr <- encodex (msg',addr')
104 sendMessage tr addr msg 102 mapM_ (uncurry . flip $ sendMessage tr) msg_addr
105 } 103 }
106 ytr = Transport 104 ytr = Transport
107 { awaitMessage = \kont -> takeMVar mvar >>= kont . Just . Right 105 { awaitMessage = \kont -> takeMVar mvar >>= kont . Just . Right
108 , sendMessage = \addr' msg' -> do 106 , sendMessage = sendMessage tr
109 (msg,addr) <- encodey (msg',addr')
110 sendMessage tr addr msg
111 , closeTransport = return () 107 , closeTransport = return ()
112 } 108 }
113 return (xtr, ytr) 109 return (xtr, ytr)
diff --git a/src/Network/Tox.hs b/src/Network/Tox.hs
index 8df1a09d..3c5fc955 100644
--- a/src/Network/Tox.hs
+++ b/src/Network/Tox.hs
@@ -192,7 +192,7 @@ newClient drg net classify selfAddr handlers modifynet = do
192 192
193data Tox = Tox 193data Tox = Tox
194 { toxDHT :: DHT.Client 194 { toxDHT :: DHT.Client
195 , toxOnion :: Onion.Client 195 , toxOnion :: Onion.Client RouteId
196 , toxCrypto :: Transport String SockAddr NetCrypto 196 , toxCrypto :: Transport String SockAddr NetCrypto
197 , toxRouting :: DHT.Routing 197 , toxRouting :: DHT.Routing
198 , toxTokens :: TVar SessionTokens 198 , toxTokens :: TVar SessionTokens
@@ -237,7 +237,10 @@ newTox keydb addr = do
237 oniondrg <- drgNew 237 oniondrg <- drgNew
238 let onionnet = layerTransport (Onion.decrypt crypto) (Onion.encrypt crypto) onioncrypt 238 let onionnet = layerTransport (Onion.decrypt crypto) (Onion.encrypt crypto) onioncrypt
239 onionclient <- newClient oniondrg onionnet Onion.classify 239 onionclient <- newClient oniondrg onionnet Onion.classify
240 (const $ return $ either (const $ error "bad sockaddr") Onion.OnionDestination $ nodeInfo zeroID addr) 240 (const $ return
241 $ either (const $ error "bad sockaddr")
242 (flip Onion.OnionDestination Nothing)
243 $ nodeInfo zeroID addr)
241 (Onion.handlers onionnet routing toks keydb) 244 (Onion.handlers onionnet routing toks keydb)
242 (const id) 245 (const id)
243 return Tox 246 return Tox
diff --git a/src/Network/Tox/Onion/Handlers.hs b/src/Network/Tox/Onion/Handlers.hs
index 72398735..08f5cabd 100644
--- a/src/Network/Tox/Onion/Handlers.hs
+++ b/src/Network/Tox/Onion/Handlers.hs
@@ -35,7 +35,7 @@ import Data.Bits
35import Data.Ord 35import Data.Ord
36import Data.Functor.Identity 36import Data.Functor.Identity
37 37
38type Client = QR.Client String PacketKind TransactionId OnionDestination Message 38type Client r = QR.Client String PacketKind TransactionId (OnionDestination r) Message
39type Message = OnionMessage Identity 39type Message = OnionMessage Identity
40 40
41classify :: Message -> MessageClass String PacketKind TransactionId 41classify :: Message -> MessageClass String PacketKind TransactionId
@@ -59,7 +59,7 @@ classify msg = go msg
59-- The reason for this 20 second timeout in toxcore is that it gives a reasonable 59-- The reason for this 20 second timeout in toxcore is that it gives a reasonable
60-- time (20 to 40 seconds) for a peer to announce himself while taking in count 60-- time (20 to 40 seconds) for a peer to announce himself while taking in count
61-- all the possible delays with some extra seconds. 61-- all the possible delays with some extra seconds.
62announceH :: Routing -> TVar SessionTokens -> TVar AnnouncedKeys -> OnionDestination -> AnnounceRequest -> IO AnnounceResponse 62announceH :: Routing -> TVar SessionTokens -> TVar AnnouncedKeys -> OnionDestination r -> AnnounceRequest -> IO AnnounceResponse
63announceH routing toks keydb (OnionToOwner naddr retpath) req = do 63announceH routing toks keydb (OnionToOwner naddr retpath) req = do
64 case () of 64 case () of
65 _ | announcePingId req == zeros32 65 _ | announcePingId req == zeros32
@@ -76,7 +76,7 @@ announceH routing toks keydb (OnionToOwner naddr retpath) req = do
76 let storing = (nodeId naddr == announceSeeking req) 76 let storing = (nodeId naddr == announceSeeking req)
77 record <- atomically $ do 77 record <- atomically $ do
78 when (withTok && storing) $ do 78 when (withTok && storing) $ do
79 let toxpath = OnionToOwner naddr{ nodeId = announceKey req } retpath 79 let toxpath = AnnouncedRoute naddr{ nodeId = announceKey req } retpath
80 -- Note: The following distance calculation assumes that 80 -- Note: The following distance calculation assumes that
81 -- our nodeid doesn't change and is the same for both 81 -- our nodeid doesn't change and is the same for both
82 -- routing4 and routing6. 82 -- routing4 and routing6.
@@ -89,16 +89,16 @@ announceH routing toks keydb (OnionToOwner naddr retpath) req = do
89 then Nonce32 . toPaddedByteString 32 <$> grantToken toks naddr 89 then Nonce32 . toPaddedByteString 32 <$> grantToken toks naddr
90 else return $ zeros32 90 else return $ zeros32
91 let k = case record of 91 let k = case record of
92 Nothing -> NotStored newtok 92 Nothing -> NotStored newtok
93 Just (OnionDestination {}) | storing -> Acknowledged newtok 93 Just _ | storing -> Acknowledged newtok
94 Just (OnionToOwner ni _) -> SendBackKey $ id2key (nodeId ni) 94 Just (AnnouncedRoute ni _) -> SendBackKey $ id2key (nodeId ni)
95 let response = AnnounceResponse k ns 95 let response = AnnounceResponse k ns
96 hPutStrLn stderr $ unwords ["Announce:", show req, "-reply->", show response] 96 hPutStrLn stderr $ unwords ["Announce:", show req, "-reply->", show response]
97 return response 97 return response
98 98
99dataToRouteH :: 99dataToRouteH ::
100 TVar AnnouncedKeys 100 TVar AnnouncedKeys
101 -> Transport err OnionDestination (OnionMessage f) 101 -> Transport err (OnionDestination r) (OnionMessage f)
102 -> addr 102 -> addr
103 -> OnionMessage f 103 -> OnionMessage f
104 -> IO () 104 -> IO ()
@@ -111,18 +111,23 @@ dataToRouteH keydb udp _ (OnionToRoute pub assym) = do
111 return rpath 111 return rpath
112 forM_ mb $ \rpath -> do 112 forM_ mb $ \rpath -> do
113 -- forward 113 -- forward
114 sendMessage udp rpath $ OnionToRouteResponse assym 114 sendMessage udp (toOnionDestination rpath) $ OnionToRouteResponse assym
115 hPutStrLn stderr $ "Forwarding data-to-route -->"++show k 115 hPutStrLn stderr $ "Forwarding data-to-route -->"++show k
116 116
117type NodeDistance = NodeId 117type NodeDistance = NodeId
118 118
119data AnnouncedRoute = AnnouncedRoute NodeInfo (ReturnPath N3)
120
121toOnionDestination :: AnnouncedRoute -> OnionDestination r
122toOnionDestination (AnnouncedRoute ni rpath) = OnionToOwner ni rpath
123
119data AnnouncedKeys = AnnouncedKeys 124data AnnouncedKeys = AnnouncedKeys
120 { keyByAge :: !(PSQ NodeId (Down POSIXTime)) -- timeout of 300 seconds 125 { keyByAge :: !(PSQ NodeId (Down POSIXTime)) -- timeout of 300 seconds
121 , keyAssoc :: !(MinMaxPSQ' NodeId NodeDistance (Int,OnionDestination)) 126 , keyAssoc :: !(MinMaxPSQ' NodeId NodeDistance (Int,AnnouncedRoute))
122 } 127 }
123 128
124 129
125insertKey :: POSIXTime -> NodeId -> OnionDestination -> NodeDistance -> AnnouncedKeys -> AnnouncedKeys 130insertKey :: POSIXTime -> NodeId -> AnnouncedRoute -> NodeDistance -> AnnouncedKeys -> AnnouncedKeys
126insertKey tm pub toxpath d keydb = AnnouncedKeys 131insertKey tm pub toxpath d keydb = AnnouncedKeys
127 { keyByAge = PSQ.insert pub (Down tm) (keyByAge keydb) 132 { keyByAge = PSQ.insert pub (Down tm) (keyByAge keydb)
128 , keyAssoc = case MinMaxPSQ.lookup' pub (keyAssoc keydb) of 133 , keyAssoc = case MinMaxPSQ.lookup' pub (keyAssoc keydb) of
@@ -134,12 +139,12 @@ areq :: Message -> Either String AnnounceRequest
134areq (OnionAnnounce assym) = Right $ fst $ runIdentity $ assymData assym 139areq (OnionAnnounce assym) = Right $ fst $ runIdentity $ assymData assym
135areq _ = Left "Unexpected non-announce OnionMessage" 140areq _ = Left "Unexpected non-announce OnionMessage"
136 141
137handlers :: Transport err OnionDestination Message 142handlers :: Transport err (OnionDestination r) Message
138 -> Routing 143 -> Routing
139 -> TVar SessionTokens 144 -> TVar SessionTokens
140 -> TVar AnnouncedKeys 145 -> TVar AnnouncedKeys
141 -> PacketKind 146 -> PacketKind
142 -> Maybe (MethodHandler String TransactionId OnionDestination Message) 147 -> Maybe (MethodHandler String TransactionId (OnionDestination r) Message)
143handlers net routing toks keydb AnnounceType 148handlers net routing toks keydb AnnounceType
144 = Just 149 = Just
145 $ MethodHandler areq (\(TransactionId n8 n24) src dst -> OnionAnnounceResponse n8 n24 . Identity) 150 $ MethodHandler areq (\(TransactionId n8 n24) src dst -> OnionAnnounceResponse n8 n24 . Identity)
diff --git a/src/Network/Tox/Onion/Transport.hs b/src/Network/Tox/Onion/Transport.hs
index 0e6e4954..a3c1950f 100644
--- a/src/Network/Tox/Onion/Transport.hs
+++ b/src/Network/Tox/Onion/Transport.hs
@@ -33,6 +33,8 @@ module Network.Tox.Onion.Transport
33 , encrypt 33 , encrypt
34 , decrypt 34 , decrypt
35 , peelSymmetric 35 , peelSymmetric
36 , OnionRoute(..)
37 , N3
36 ) where 38 ) where
37 39
38import Network.Address (fromSockAddr,toSockAddr,setPort,either4or6,sockAddrPort) 40import Network.Address (fromSockAddr,toSockAddr,setPort,either4or6,sockAddrPort)
@@ -86,13 +88,14 @@ deriving instance ( Show (f (AnnounceRequest, Nonce8))
86 , Show (f DataToRoute) 88 , Show (f DataToRoute)
87 ) => Show (OnionMessage f) 89 ) => Show (OnionMessage f)
88 90
89data OnionDestination = OnionToOwner NodeInfo (ReturnPath N3) -- ^ Somebody else's path to us. 91data OnionDestination r
90 | OnionDestination NodeInfo -- ^ Our own onion-path. 92 = OnionToOwner NodeInfo (ReturnPath N3) -- ^ Somebody else's path to us.
93 | OnionDestination NodeInfo (Maybe r) -- ^ Our own onion-path.
91 deriving Show 94 deriving Show
92 95
93onionKey :: OnionDestination -> Maybe PublicKey 96onionKey :: OnionDestination r -> Maybe PublicKey
94onionKey (OnionToOwner ni _) = Just $ id2key (nodeId ni) 97onionKey (OnionToOwner ni _) = Just $ id2key (nodeId ni)
95onionKey _ = Nothing 98onionKey (OnionDestination ni _) = Just $ id2key (nodeId ni)
96 99
97instance Sized (OnionMessage Encrypted) where 100instance Sized (OnionMessage Encrypted) where
98 size = VarSize $ \case 101 size = VarSize $ \case
@@ -111,15 +114,14 @@ instance Serialize (OnionMessage Encrypted) where
111 case typ :: Word8 of 114 case typ :: Word8 of
112 0x83 -> OnionAnnounce <$> getAliasedAssym 115 0x83 -> OnionAnnounce <$> getAliasedAssym
113 0x85 -> OnionToRoute <$> getPublicKey <*> getAliasedAssym 116 0x85 -> OnionToRoute <$> getPublicKey <*> getAliasedAssym
114 0x84 -> getOnionReply typ 117 t -> fail ("Unknown onion payload: " ++ show t)
115 0x86 -> getOnionReply typ 118 `fromMaybe` getOnionReply t
116 t -> fail $ "Unknown onion payload: " ++ show t
117 put (OnionAnnounce a) = putWord8 0x83 >> putAliasedAssym a 119 put (OnionAnnounce a) = putWord8 0x83 >> putAliasedAssym a
118 put (OnionToRoute k a) = putWord8 0x85 >> putPublicKey k >> putAliasedAssym a 120 put (OnionToRoute k a) = putWord8 0x85 >> putPublicKey k >> putAliasedAssym a
119 put (OnionAnnounceResponse n8 n24 x) = putWord8 0x84 >> put n8 >> put n24 >> put x 121 put (OnionAnnounceResponse n8 n24 x) = putWord8 0x84 >> put n8 >> put n24 >> put x
120 put (OnionToRouteResponse a) = putWord8 0x86 >> putAliasedAssym a 122 put (OnionToRouteResponse a) = putWord8 0x86 >> putAliasedAssym a
121 123
122onionToOwner :: Assym a -> ReturnPath N3 -> SockAddr -> Either String OnionDestination 124onionToOwner :: Assym a -> ReturnPath N3 -> SockAddr -> Either String (OnionDestination r)
123onionToOwner assym ret3 saddr = do 125onionToOwner assym ret3 saddr = do
124 ni <- nodeInfo (key2id $ senderKey assym) saddr 126 ni <- nodeInfo (key2id $ senderKey assym) saddr
125 return $ OnionToOwner ni ret3 127 return $ OnionToOwner ni ret3
@@ -130,36 +132,37 @@ onion :: Sized msg =>
130 ByteString 132 ByteString
131 -> SockAddr 133 -> SockAddr
132 -> Get (Assym (Encrypted msg) -> t) 134 -> Get (Assym (Encrypted msg) -> t)
133 -> Either String (t, OnionDestination) 135 -> Either String (t, OnionDestination r)
134onion bs saddr getf = do (f,(assym,ret3)) <- runGet ((,) <$> getf <*> getOnionRequest) bs 136onion bs saddr getf = do (f,(assym,ret3)) <- runGet ((,) <$> getf <*> getOnionRequest) bs
135 oaddr <- onionToOwner assym ret3 saddr 137 oaddr <- onionToOwner assym ret3 saddr
136 return (f assym, oaddr) 138 return (f assym, oaddr)
137 139
138 140parseOnionAddr :: (SockAddr -> Nonce8 -> IO (Maybe (NodeInfo,r)))
139parseOnionAddr :: (ByteString, SockAddr) -> Either (OnionMessage Encrypted,OnionDestination) (ByteString,SockAddr) 141 -> (ByteString, SockAddr)
140parseOnionAddr (msg,saddr) 142 -> IO (Either (OnionMessage Encrypted,OnionDestination r)
143 (ByteString,SockAddr))
144parseOnionAddr lookupSender (msg,saddr)
141 | Just (typ,bs) <- B.uncons msg 145 | Just (typ,bs) <- B.uncons msg
142 , let right = Right (msg,saddr) 146 , let right = Right (msg,saddr)
143 query = either (const right) Left 147 query = return . either (const right) Left
144 response = either (const right) (Left . \msg -> ( msg , replyAlias saddr msg ))
145 = case typ of 148 = case typ of
146 0x83 -> query $ onion bs saddr (pure OnionAnnounce) -- Announce Request 149 0x83 -> query $ onion bs saddr (pure OnionAnnounce) -- Announce Request
147 0x85 -> query $ onion bs saddr (OnionToRoute <$> getPublicKey) -- Onion Data Request 150 0x85 -> query $ onion bs saddr (OnionToRoute <$> getPublicKey) -- Onion Data Request
148 0x84 -> response $ runGet (getOnionReply 0x84) bs -- Announce Response 151 _ -> case flip runGet bs <$> getOnionReply typ of
149 0x86 -> response $ runGet (getOnionReply 0x86) bs -- Onion Data Response 152 Just (Right msg@(OnionAnnounceResponse n8 _ _)) -> do
150 _ -> right 153 maddr <- lookupSender saddr n8
151 154 maybe (return right) -- Response unsolicited or too late.
152getOnionReply :: Word8 -> Get (OnionMessage Encrypted) 155 (return . Left . \(ni,r) -> (msg,OnionDestination ni (Just r)))
153getOnionReply 0x84 = OnionAnnounceResponse <$> get <*> get <*> get 156 maddr
154getOnionReply 0x86 = OnionToRouteResponse <$> getOnionAssym 157 Just (Right msg@(OnionToRouteResponse asym)) -> do
155 158 let ni = asymNodeInfo saddr asym
156replyAlias :: SockAddr -> OnionMessage Encrypted -> OnionDestination 159 return $ Left (msg, OnionDestination ni Nothing)
157replyAlias saddr (OnionAnnounceResponse _ _ _) 160 _ -> return right
158 = OnionDestination 161
159 $ either (error "replyAlias: bad protocol") id 162getOnionReply :: Word8 -> Maybe (Get (OnionMessage Encrypted))
160 $ nodeInfo zeroID saddr -- TODO OnionAnnounceResponse has no sender key 163getOnionReply 0x84 = Just $ OnionAnnounceResponse <$> get <*> get <*> get
161replyAlias saddr (OnionToRouteResponse asym) 164getOnionReply 0x86 = Just $ OnionToRouteResponse <$> getOnionAssym
162 = OnionDestination $ asymNodeInfo saddr asym 165getOnionReply _ = Nothing
163 166
164putOnionMsg :: OnionMessage Encrypted -> Put 167putOnionMsg :: OnionMessage Encrypted -> Put
165putOnionMsg (OnionAnnounce a) = putOnionAssym 0x83 (return ()) a 168putOnionMsg (OnionAnnounce a) = putOnionAssym 0x83 (return ()) a
@@ -167,10 +170,18 @@ putOnionMsg (OnionToRoute pubkey a) = putOnionAssym 0x85 (putPublicKey
167putOnionMsg (OnionAnnounceResponse n8 n24 x) = put (0x84 :: Word8) >> put n8 >> put n24 >> put x 170putOnionMsg (OnionAnnounceResponse n8 n24 x) = put (0x84 :: Word8) >> put n8 >> put n24 >> put x
168putOnionMsg (OnionToRouteResponse a) = putOnionAssym 0x86 (return ()) a 171putOnionMsg (OnionToRouteResponse a) = putOnionAssym 0x86 (return ()) a
169 172
170encodeOnionAddr :: (OnionMessage Encrypted,OnionDestination) -> (ByteString, SockAddr) 173encodeOnionAddr :: (NodeInfo -> r -> IO (Maybe OnionRoute))
171encodeOnionAddr (msg,OnionToOwner ni p) = ( runPut $ putResponse (OnionResponse p msg) 174 -> (OnionMessage Encrypted,OnionDestination r)
172 , nodeAddr ni ) 175 -> IO (Maybe (ByteString, SockAddr))
173encodeOnionAddr (msg,OnionDestination a) = ( runPut (putOnionMsg msg), nodeAddr a) -- TODO: Construct (OnionRequest N0)? 176encodeOnionAddr _ (msg,OnionToOwner ni p) =
177 return $ Just ( runPut $ putResponse (OnionResponse p msg)
178 , nodeAddr ni )
179encodeOnionAddr _ (msg,OnionDestination _ Nothing ) = return Nothing
180encodeOnionAddr getRoute (msg,OnionDestination ni (Just rid)) = do
181 let go route = do
182 return (runPut $ putRequest $ wrapForRoute msg ni route, nodeAddr ni)
183 getRoute ni rid >>= mapM go
184
174 185
175forwardOnions :: TransportCrypto -> UDPTransport -> UDPTransport 186forwardOnions :: TransportCrypto -> UDPTransport -> UDPTransport
176forwardOnions crypto udp = udp { awaitMessage = forwardAwait crypto udp } 187forwardOnions crypto udp = udp { awaitMessage = forwardAwait crypto udp }
@@ -253,7 +264,8 @@ data OnionResponse n = OnionResponse
253deriving instance KnownNat (PeanoNat n) => Show (OnionResponse n) 264deriving instance KnownNat (PeanoNat n) => Show (OnionResponse n)
254 265
255instance ( Serialize (ReturnPath n) ) => Serialize (OnionResponse n) where 266instance ( Serialize (ReturnPath n) ) => Serialize (OnionResponse n) where
256 get = OnionResponse <$> get <*> (get >>= getOnionReply) 267 get = OnionResponse <$> get <*> (get >>= fromMaybe (fail "illegal onion forwarding")
268 . getOnionReply)
257 put (OnionResponse p m) = put p >> putOnionMsg m 269 put (OnionResponse p m) = put p >> putOnionMsg m
258 270
259 271
@@ -525,7 +537,7 @@ instance Sized OnionData where
525 -- should be treated as variable sized. 537 -- should be treated as variable sized.
526 VarSize f -> f dhtpk 538 VarSize f -> f dhtpk
527 539
528encrypt :: TransportCrypto -> OnionMessage Identity -> OnionDestination -> (OnionMessage Encrypted, OnionDestination) 540encrypt :: TransportCrypto -> OnionMessage Identity -> OnionDestination r -> (OnionMessage Encrypted, OnionDestination r)
529encrypt crypto msg rpath = ( transcode ( (. (runIdentity . either id assymData)) 541encrypt crypto msg rpath = ( transcode ( (. (runIdentity . either id assymData))
530 . encryptMessage skey okey) 542 . encryptMessage skey okey)
531 msg 543 msg
@@ -545,31 +557,78 @@ encryptMessage skey destKey n a = ToxCrypto.encrypt secret plain
545 secret = computeSharedSecret skey destKey n 557 secret = computeSharedSecret skey destKey n
546 plain = encodePlain a 558 plain = encodePlain a
547 559
548decrypt :: TransportCrypto -> OnionMessage Encrypted -> OnionDestination -> Either String (OnionMessage Identity, OnionDestination) 560decrypt :: TransportCrypto -> OnionMessage Encrypted -> OnionDestination r -> Either String (OnionMessage Identity, OnionDestination r)
549decrypt crypto msg addr = (, addr) <$> (sequenceMessage $ transcode (decryptMessage crypto) msg) 561decrypt crypto msg addr = do
562 msg <- sequenceMessage $ transcode (\n -> decryptMessage crypto n . left (senderkey addr)) msg
563 Right (msg, addr)
564
565senderkey :: OnionDestination r -> t -> (Maybe PublicKey, t)
566senderkey addr e = (onionKey addr, e)
550 567
551decryptMessage :: Serialize x => 568decryptMessage :: Serialize x =>
552 TransportCrypto 569 TransportCrypto
553 -> Nonce24 570 -> Nonce24
554 -> Either (Encrypted x) (Assym (Encrypted x)) 571 -> Either (Maybe PublicKey, Encrypted x)
572 (Assym (Encrypted x))
555 -> (Either String ∘ Identity) x 573 -> (Either String ∘ Identity) x
556decryptMessage crypto n (Right assymE) = plain $ ToxCrypto.decrypt secret e 574decryptMessage crypto n arg
575 | Just secret <- msecret = plain $ ToxCrypto.decrypt secret e
576 | otherwise = Composed $ Left "decryptMessage: Unknown sender"
557 where 577 where
558 secret = computeSharedSecret (transportSecret crypto) (senderKey assymE) n 578 msecret = do sender <- mkey
559 e = assymData assymE 579 Just $ computeSharedSecret (transportSecret crypto) sender n
560 plain = Composed . fmap Identity . (>>= decodePlain) 580 (mkey,e) = either id (Just . senderKey &&& assymData) arg
561decryptMessage crypto n (Left e) = _todo -- OnionAnnounceResponse has no sender key 581 plain = Composed . fmap Identity . (>>= decodePlain)
562 582
563 583
564sequenceMessage :: Applicative m => OnionMessage (m ∘ f) -> m (OnionMessage f) 584sequenceMessage :: Applicative m => OnionMessage (m ∘ f) -> m (OnionMessage f)
565sequenceMessage (OnionAnnounce a) = fmap OnionAnnounce $ sequenceA $ fmap uncomposed a 585sequenceMessage (OnionAnnounce a) = fmap OnionAnnounce $ sequenceA $ fmap uncomposed a
566sequenceMessage (OnionAnnounceResponse n8 n24 dta) = OnionAnnounceResponse n8 n24 <$> uncomposed dta 586sequenceMessage (OnionAnnounceResponse n8 n24 dta) = OnionAnnounceResponse n8 n24 <$> uncomposed dta
567sequenceMessage (OnionToRoute pub a) = pure $ OnionToRoute pub a 587sequenceMessage (OnionToRoute pub a) = pure $ OnionToRoute pub a
568sequenceMessage (OnionToRouteResponse a) = pure $ OnionToRouteResponse a 588sequenceMessage (OnionToRouteResponse a) = pure $ OnionToRouteResponse a
569 589
570transcode :: forall f g. (forall a. Serialize a => Nonce24 -> Either (f a) (Assym (f a)) -> g a) -> OnionMessage f -> OnionMessage g 590transcode :: forall f g. (forall a. Serialize a => Nonce24 -> Either (f a) (Assym (f a)) -> g a) -> OnionMessage f -> OnionMessage g
571transcode f (OnionAnnounce a) = OnionAnnounce $ a { assymData = f (assymNonce a) (Right a) } 591transcode f (OnionAnnounce a) = OnionAnnounce $ a { assymData = f (assymNonce a) (Right a) }
572transcode f (OnionAnnounceResponse n8 n24 dta) = OnionAnnounceResponse n8 n24 $ f n24 $ Left dta 592transcode f (OnionAnnounceResponse n8 n24 dta) = OnionAnnounceResponse n8 n24 $ f n24 $ Left dta
573transcode f (OnionToRoute pub a) = OnionToRoute pub a 593transcode f (OnionToRoute pub a) = OnionToRoute pub a
574transcode f (OnionToRouteResponse a) = OnionToRouteResponse a 594transcode f (OnionToRouteResponse a) = OnionToRouteResponse a
575 595
596
597data OnionRoute = OnionRoute
598 { routeNonce :: Nonce24
599 , routeAliasA :: SecretKey
600 , routeAliasB :: SecretKey
601 , routeAliasC :: SecretKey
602 , routeNodeA :: NodeInfo
603 , routeNodeB :: NodeInfo
604 , routeNodeC :: NodeInfo
605 }
606
607wrapForRoute :: OnionMessage Encrypted -> NodeInfo -> OnionRoute -> OnionRequest N0
608wrapForRoute msg ni r = OnionRequest
609 { onionNonce = routeNonce r
610 , onionForward = wrapOnion (routeAliasA r)
611 (routeNonce r)
612 (id2key . nodeId $ routeNodeA r)
613 (nodeAddr $ routeNodeB r)
614 $ wrapOnion (routeAliasB r)
615 (routeNonce r)
616 (id2key . nodeId $ routeNodeB r)
617 (nodeAddr $ routeNodeC r)
618 $ wrapOnion (routeAliasC r)
619 (routeNonce r)
620 (id2key . nodeId $ routeNodeC r)
621 (nodeAddr ni)
622 $ NotForwarded msg
623 , pathFromOwner = NoReturnPath
624 }
625
626wrapOnion :: Serialize (Forwarding n msg) =>
627 SecretKey
628 -> Nonce24
629 -> PublicKey
630 -> SockAddr
631 -> Forwarding n msg
632 -> Forwarding (S n) msg
633wrapOnion skey nonce destkey saddr fwd =
634 Forwarding (toPublic skey) $ encryptMessage skey destkey nonce (Addressed saddr fwd)
diff --git a/src/Network/Tox/Transport.hs b/src/Network/Tox/Transport.hs
index d99b6713..d441dc0a 100644
--- a/src/Network/Tox/Transport.hs
+++ b/src/Network/Tox/Transport.hs
@@ -6,7 +6,7 @@
6{-# LANGUAGE ScopedTypeVariables #-} 6{-# LANGUAGE ScopedTypeVariables #-}
7{-# LANGUAGE TupleSections #-} 7{-# LANGUAGE TupleSections #-}
8{-# LANGUAGE TypeOperators #-} 8{-# LANGUAGE TypeOperators #-}
9module Network.Tox.Transport (toxTransport) where 9module Network.Tox.Transport (toxTransport, RouteId) where
10 10
11import Network.QueryResponse 11import Network.QueryResponse
12import Crypto.Tox 12import Crypto.Tox
@@ -16,16 +16,26 @@ import Network.Tox.Crypto.Transport
16 16
17import Network.Socket 17import Network.Socket
18 18
19type RouteId = () -- todo
20
21lookupSender :: SockAddr -> Nonce8 -> IO (Maybe (NodeInfo, RouteId))
22lookupSender _ _ = return Nothing -- todo
23
24lookupRoute :: NodeInfo -> RouteId -> IO (Maybe OnionRoute)
25lookupRoute _ _ = return Nothing -- todo
26
19toxTransport :: 27toxTransport ::
20 TransportCrypto 28 TransportCrypto
21 -> (PublicKey -> IO (Maybe NodeInfo)) 29 -> (PublicKey -> IO (Maybe NodeInfo))
22 -> UDPTransport 30 -> UDPTransport
23 -> IO ( Transport String NodeInfo (DHTMessage Encrypted8) 31 -> IO ( Transport String NodeInfo (DHTMessage Encrypted8)
24 , Transport String OnionDestination (OnionMessage Encrypted) 32 , Transport String (OnionDestination RouteId) (OnionMessage Encrypted)
25 , Transport String SockAddr NetCrypto ) 33 , Transport String SockAddr NetCrypto )
26toxTransport crypto closeLookup udp = do 34toxTransport crypto closeLookup udp = do
27 (dht,udp1) <- partitionTransport parseDHTAddr encodeDHTAddr id $ forwardOnions crypto udp 35 (dht,udp1) <- partitionTransport parseDHTAddr (Just . encodeDHTAddr) $ forwardOnions crypto udp
28 (onion,udp2) <- partitionTransport parseOnionAddr encodeOnionAddr id udp1 36 (onion,udp2) <- partitionTransportM (parseOnionAddr lookupSender)
37 (encodeOnionAddr lookupRoute)
38 udp1
29 let netcrypto = layerTransport parseNetCrypto encodeNetCrypto udp2 39 let netcrypto = layerTransport parseNetCrypto encodeNetCrypto udp2
30 return ( forwardDHTRequests crypto closeLookup dht 40 return ( forwardDHTRequests crypto closeLookup dht
31 , onion 41 , onion