diff options
author | joe <joe@jerkface.net> | 2017-10-01 05:26:36 -0400 |
---|---|---|
committer | joe <joe@jerkface.net> | 2017-10-01 05:26:36 -0400 |
commit | d408e6c3148106c6dbc8afe24a1488619adf34e1 (patch) | |
tree | ca2d7a66b07dba82b6bf236fb234cac75bf87da6 | |
parent | f6f70dcfa25ddf10e3cf16745bdd082cc26b2fd6 (diff) |
Ability to send onion messages when given a path.
-rw-r--r-- | src/Network/QueryResponse.hs | 28 | ||||
-rw-r--r-- | src/Network/Tox.hs | 7 | ||||
-rw-r--r-- | src/Network/Tox/Onion/Handlers.hs | 29 | ||||
-rw-r--r-- | src/Network/Tox/Onion/Transport.hs | 151 | ||||
-rw-r--r-- | src/Network/Tox/Transport.hs | 18 |
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. |
77 | partitionTransport :: ((b,a) -> Either (x,xaddr) (y,yaddr)) | 77 | partitionTransport :: ((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) |
82 | partitionTransport parse encodex encodey tr = | 81 | partitionTransport 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. |
88 | partitionTransportM :: ((b,a) -> IO (Either (x,xaddr) (y,yaddr))) | 87 | partitionTransportM :: ((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) |
93 | partitionTransportM parse encodex encodey tr = do | 91 | partitionTransportM 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 | ||
193 | data Tox = Tox | 193 | data 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 | |||
35 | import Data.Ord | 35 | import Data.Ord |
36 | import Data.Functor.Identity | 36 | import Data.Functor.Identity |
37 | 37 | ||
38 | type Client = QR.Client String PacketKind TransactionId OnionDestination Message | 38 | type Client r = QR.Client String PacketKind TransactionId (OnionDestination r) Message |
39 | type Message = OnionMessage Identity | 39 | type Message = OnionMessage Identity |
40 | 40 | ||
41 | classify :: Message -> MessageClass String PacketKind TransactionId | 41 | classify :: 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. |
62 | announceH :: Routing -> TVar SessionTokens -> TVar AnnouncedKeys -> OnionDestination -> AnnounceRequest -> IO AnnounceResponse | 62 | announceH :: Routing -> TVar SessionTokens -> TVar AnnouncedKeys -> OnionDestination r -> AnnounceRequest -> IO AnnounceResponse |
63 | announceH routing toks keydb (OnionToOwner naddr retpath) req = do | 63 | announceH 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 | ||
99 | dataToRouteH :: | 99 | dataToRouteH :: |
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 | ||
117 | type NodeDistance = NodeId | 117 | type NodeDistance = NodeId |
118 | 118 | ||
119 | data AnnouncedRoute = AnnouncedRoute NodeInfo (ReturnPath N3) | ||
120 | |||
121 | toOnionDestination :: AnnouncedRoute -> OnionDestination r | ||
122 | toOnionDestination (AnnouncedRoute ni rpath) = OnionToOwner ni rpath | ||
123 | |||
119 | data AnnouncedKeys = AnnouncedKeys | 124 | data 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 | ||
125 | insertKey :: POSIXTime -> NodeId -> OnionDestination -> NodeDistance -> AnnouncedKeys -> AnnouncedKeys | 130 | insertKey :: POSIXTime -> NodeId -> AnnouncedRoute -> NodeDistance -> AnnouncedKeys -> AnnouncedKeys |
126 | insertKey tm pub toxpath d keydb = AnnouncedKeys | 131 | insertKey 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 | |||
134 | areq (OnionAnnounce assym) = Right $ fst $ runIdentity $ assymData assym | 139 | areq (OnionAnnounce assym) = Right $ fst $ runIdentity $ assymData assym |
135 | areq _ = Left "Unexpected non-announce OnionMessage" | 140 | areq _ = Left "Unexpected non-announce OnionMessage" |
136 | 141 | ||
137 | handlers :: Transport err OnionDestination Message | 142 | handlers :: 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) |
143 | handlers net routing toks keydb AnnounceType | 148 | handlers 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 | ||
38 | import Network.Address (fromSockAddr,toSockAddr,setPort,either4or6,sockAddrPort) | 40 | import 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 | ||
89 | data OnionDestination = OnionToOwner NodeInfo (ReturnPath N3) -- ^ Somebody else's path to us. | 91 | data 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 | ||
93 | onionKey :: OnionDestination -> Maybe PublicKey | 96 | onionKey :: OnionDestination r -> Maybe PublicKey |
94 | onionKey (OnionToOwner ni _) = Just $ id2key (nodeId ni) | 97 | onionKey (OnionToOwner ni _) = Just $ id2key (nodeId ni) |
95 | onionKey _ = Nothing | 98 | onionKey (OnionDestination ni _) = Just $ id2key (nodeId ni) |
96 | 99 | ||
97 | instance Sized (OnionMessage Encrypted) where | 100 | instance 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 | ||
122 | onionToOwner :: Assym a -> ReturnPath N3 -> SockAddr -> Either String OnionDestination | 124 | onionToOwner :: Assym a -> ReturnPath N3 -> SockAddr -> Either String (OnionDestination r) |
123 | onionToOwner assym ret3 saddr = do | 125 | onionToOwner 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) |
134 | onion bs saddr getf = do (f,(assym,ret3)) <- runGet ((,) <$> getf <*> getOnionRequest) bs | 136 | onion 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 | 140 | parseOnionAddr :: (SockAddr -> Nonce8 -> IO (Maybe (NodeInfo,r))) | |
139 | parseOnionAddr :: (ByteString, SockAddr) -> Either (OnionMessage Encrypted,OnionDestination) (ByteString,SockAddr) | 141 | -> (ByteString, SockAddr) |
140 | parseOnionAddr (msg,saddr) | 142 | -> IO (Either (OnionMessage Encrypted,OnionDestination r) |
143 | (ByteString,SockAddr)) | ||
144 | parseOnionAddr 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. | |
152 | getOnionReply :: Word8 -> Get (OnionMessage Encrypted) | 155 | (return . Left . \(ni,r) -> (msg,OnionDestination ni (Just r))) |
153 | getOnionReply 0x84 = OnionAnnounceResponse <$> get <*> get <*> get | 156 | maddr |
154 | getOnionReply 0x86 = OnionToRouteResponse <$> getOnionAssym | 157 | Just (Right msg@(OnionToRouteResponse asym)) -> do |
155 | 158 | let ni = asymNodeInfo saddr asym | |
156 | replyAlias :: SockAddr -> OnionMessage Encrypted -> OnionDestination | 159 | return $ Left (msg, OnionDestination ni Nothing) |
157 | replyAlias saddr (OnionAnnounceResponse _ _ _) | 160 | _ -> return right |
158 | = OnionDestination | 161 | |
159 | $ either (error "replyAlias: bad protocol") id | 162 | getOnionReply :: Word8 -> Maybe (Get (OnionMessage Encrypted)) |
160 | $ nodeInfo zeroID saddr -- TODO OnionAnnounceResponse has no sender key | 163 | getOnionReply 0x84 = Just $ OnionAnnounceResponse <$> get <*> get <*> get |
161 | replyAlias saddr (OnionToRouteResponse asym) | 164 | getOnionReply 0x86 = Just $ OnionToRouteResponse <$> getOnionAssym |
162 | = OnionDestination $ asymNodeInfo saddr asym | 165 | getOnionReply _ = Nothing |
163 | 166 | ||
164 | putOnionMsg :: OnionMessage Encrypted -> Put | 167 | putOnionMsg :: OnionMessage Encrypted -> Put |
165 | putOnionMsg (OnionAnnounce a) = putOnionAssym 0x83 (return ()) a | 168 | putOnionMsg (OnionAnnounce a) = putOnionAssym 0x83 (return ()) a |
@@ -167,10 +170,18 @@ putOnionMsg (OnionToRoute pubkey a) = putOnionAssym 0x85 (putPublicKey | |||
167 | putOnionMsg (OnionAnnounceResponse n8 n24 x) = put (0x84 :: Word8) >> put n8 >> put n24 >> put x | 170 | putOnionMsg (OnionAnnounceResponse n8 n24 x) = put (0x84 :: Word8) >> put n8 >> put n24 >> put x |
168 | putOnionMsg (OnionToRouteResponse a) = putOnionAssym 0x86 (return ()) a | 171 | putOnionMsg (OnionToRouteResponse a) = putOnionAssym 0x86 (return ()) a |
169 | 172 | ||
170 | encodeOnionAddr :: (OnionMessage Encrypted,OnionDestination) -> (ByteString, SockAddr) | 173 | encodeOnionAddr :: (NodeInfo -> r -> IO (Maybe OnionRoute)) |
171 | encodeOnionAddr (msg,OnionToOwner ni p) = ( runPut $ putResponse (OnionResponse p msg) | 174 | -> (OnionMessage Encrypted,OnionDestination r) |
172 | , nodeAddr ni ) | 175 | -> IO (Maybe (ByteString, SockAddr)) |
173 | encodeOnionAddr (msg,OnionDestination a) = ( runPut (putOnionMsg msg), nodeAddr a) -- TODO: Construct (OnionRequest N0)? | 176 | encodeOnionAddr _ (msg,OnionToOwner ni p) = |
177 | return $ Just ( runPut $ putResponse (OnionResponse p msg) | ||
178 | , nodeAddr ni ) | ||
179 | encodeOnionAddr _ (msg,OnionDestination _ Nothing ) = return Nothing | ||
180 | encodeOnionAddr 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 | ||
175 | forwardOnions :: TransportCrypto -> UDPTransport -> UDPTransport | 186 | forwardOnions :: TransportCrypto -> UDPTransport -> UDPTransport |
176 | forwardOnions crypto udp = udp { awaitMessage = forwardAwait crypto udp } | 187 | forwardOnions crypto udp = udp { awaitMessage = forwardAwait crypto udp } |
@@ -253,7 +264,8 @@ data OnionResponse n = OnionResponse | |||
253 | deriving instance KnownNat (PeanoNat n) => Show (OnionResponse n) | 264 | deriving instance KnownNat (PeanoNat n) => Show (OnionResponse n) |
254 | 265 | ||
255 | instance ( Serialize (ReturnPath n) ) => Serialize (OnionResponse n) where | 266 | instance ( 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 | ||
528 | encrypt :: TransportCrypto -> OnionMessage Identity -> OnionDestination -> (OnionMessage Encrypted, OnionDestination) | 540 | encrypt :: TransportCrypto -> OnionMessage Identity -> OnionDestination r -> (OnionMessage Encrypted, OnionDestination r) |
529 | encrypt crypto msg rpath = ( transcode ( (. (runIdentity . either id assymData)) | 541 | encrypt 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 | ||
548 | decrypt :: TransportCrypto -> OnionMessage Encrypted -> OnionDestination -> Either String (OnionMessage Identity, OnionDestination) | 560 | decrypt :: TransportCrypto -> OnionMessage Encrypted -> OnionDestination r -> Either String (OnionMessage Identity, OnionDestination r) |
549 | decrypt crypto msg addr = (, addr) <$> (sequenceMessage $ transcode (decryptMessage crypto) msg) | 561 | decrypt crypto msg addr = do |
562 | msg <- sequenceMessage $ transcode (\n -> decryptMessage crypto n . left (senderkey addr)) msg | ||
563 | Right (msg, addr) | ||
564 | |||
565 | senderkey :: OnionDestination r -> t -> (Maybe PublicKey, t) | ||
566 | senderkey addr e = (onionKey addr, e) | ||
550 | 567 | ||
551 | decryptMessage :: Serialize x => | 568 | decryptMessage :: 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 |
556 | decryptMessage crypto n (Right assymE) = plain $ ToxCrypto.decrypt secret e | 574 | decryptMessage 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 |
561 | decryptMessage crypto n (Left e) = _todo -- OnionAnnounceResponse has no sender key | 581 | plain = Composed . fmap Identity . (>>= decodePlain) |
562 | 582 | ||
563 | 583 | ||
564 | sequenceMessage :: Applicative m => OnionMessage (m ∘ f) -> m (OnionMessage f) | 584 | sequenceMessage :: Applicative m => OnionMessage (m ∘ f) -> m (OnionMessage f) |
565 | sequenceMessage (OnionAnnounce a) = fmap OnionAnnounce $ sequenceA $ fmap uncomposed a | 585 | sequenceMessage (OnionAnnounce a) = fmap OnionAnnounce $ sequenceA $ fmap uncomposed a |
566 | sequenceMessage (OnionAnnounceResponse n8 n24 dta) = OnionAnnounceResponse n8 n24 <$> uncomposed dta | 586 | sequenceMessage (OnionAnnounceResponse n8 n24 dta) = OnionAnnounceResponse n8 n24 <$> uncomposed dta |
567 | sequenceMessage (OnionToRoute pub a) = pure $ OnionToRoute pub a | 587 | sequenceMessage (OnionToRoute pub a) = pure $ OnionToRoute pub a |
568 | sequenceMessage (OnionToRouteResponse a) = pure $ OnionToRouteResponse a | 588 | sequenceMessage (OnionToRouteResponse a) = pure $ OnionToRouteResponse a |
569 | 589 | ||
570 | transcode :: forall f g. (forall a. Serialize a => Nonce24 -> Either (f a) (Assym (f a)) -> g a) -> OnionMessage f -> OnionMessage g | 590 | transcode :: forall f g. (forall a. Serialize a => Nonce24 -> Either (f a) (Assym (f a)) -> g a) -> OnionMessage f -> OnionMessage g |
571 | transcode f (OnionAnnounce a) = OnionAnnounce $ a { assymData = f (assymNonce a) (Right a) } | 591 | transcode f (OnionAnnounce a) = OnionAnnounce $ a { assymData = f (assymNonce a) (Right a) } |
572 | transcode f (OnionAnnounceResponse n8 n24 dta) = OnionAnnounceResponse n8 n24 $ f n24 $ Left dta | 592 | transcode f (OnionAnnounceResponse n8 n24 dta) = OnionAnnounceResponse n8 n24 $ f n24 $ Left dta |
573 | transcode f (OnionToRoute pub a) = OnionToRoute pub a | 593 | transcode f (OnionToRoute pub a) = OnionToRoute pub a |
574 | transcode f (OnionToRouteResponse a) = OnionToRouteResponse a | 594 | transcode f (OnionToRouteResponse a) = OnionToRouteResponse a |
575 | 595 | ||
596 | |||
597 | data 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 | |||
607 | wrapForRoute :: OnionMessage Encrypted -> NodeInfo -> OnionRoute -> OnionRequest N0 | ||
608 | wrapForRoute 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 | |||
626 | wrapOnion :: Serialize (Forwarding n msg) => | ||
627 | SecretKey | ||
628 | -> Nonce24 | ||
629 | -> PublicKey | ||
630 | -> SockAddr | ||
631 | -> Forwarding n msg | ||
632 | -> Forwarding (S n) msg | ||
633 | wrapOnion 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 #-} |
9 | module Network.Tox.Transport (toxTransport) where | 9 | module Network.Tox.Transport (toxTransport, RouteId) where |
10 | 10 | ||
11 | import Network.QueryResponse | 11 | import Network.QueryResponse |
12 | import Crypto.Tox | 12 | import Crypto.Tox |
@@ -16,16 +16,26 @@ import Network.Tox.Crypto.Transport | |||
16 | 16 | ||
17 | import Network.Socket | 17 | import Network.Socket |
18 | 18 | ||
19 | type RouteId = () -- todo | ||
20 | |||
21 | lookupSender :: SockAddr -> Nonce8 -> IO (Maybe (NodeInfo, RouteId)) | ||
22 | lookupSender _ _ = return Nothing -- todo | ||
23 | |||
24 | lookupRoute :: NodeInfo -> RouteId -> IO (Maybe OnionRoute) | ||
25 | lookupRoute _ _ = return Nothing -- todo | ||
26 | |||
19 | toxTransport :: | 27 | toxTransport :: |
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 ) |
26 | toxTransport crypto closeLookup udp = do | 34 | toxTransport 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 |