summaryrefslogtreecommitdiff
path: root/src/Network
diff options
context:
space:
mode:
authorjoe <joe@jerkface.net>2017-07-14 23:52:33 -0400
committerjoe <joe@jerkface.net>2017-07-14 23:52:33 -0400
commit9d5b5512ce3b5b885c0e331d6fcefa0b9d3fc42b (patch)
tree1c83e304b1bf4fb604bb984c6e0e5d0ad54485a2 /src/Network
parent29f369311408b5ed7823c9858257d1c948e24d28 (diff)
Implemented more of the Mainline DHT rewrite.
Diffstat (limited to 'src/Network')
-rw-r--r--src/Network/BitTorrent/DHT/Token.hs58
1 files changed, 54 insertions, 4 deletions
diff --git a/src/Network/BitTorrent/DHT/Token.hs b/src/Network/BitTorrent/DHT/Token.hs
index e3a6b1f6..08079b75 100644
--- a/src/Network/BitTorrent/DHT/Token.hs
+++ b/src/Network/BitTorrent/DHT/Token.hs
@@ -24,6 +24,10 @@ module Network.BitTorrent.DHT.Token
24 24
25 -- * Session tokens 25 -- * Session tokens
26 , TokenMap 26 , TokenMap
27 , SessionTokens
28 , nullSessionTokens
29 , checkToken
30 , grantToken
27 31
28 -- ** Construction 32 -- ** Construction
29 , Network.BitTorrent.DHT.Token.tokens 33 , Network.BitTorrent.DHT.Token.tokens
@@ -52,7 +56,7 @@ import Data.Hashable
52import Data.String 56import Data.String
53import Data.Time 57import Data.Time
54import System.Random 58import System.Random
55 59import Control.Concurrent.STM
56import Network.Address 60import Network.Address
57 61
58-- TODO use ShortByteString 62-- TODO use ShortByteString
@@ -77,7 +81,7 @@ type Secret = Int
77 81
78-- The BitTorrent implementation uses the SHA1 hash of the IP address 82-- The BitTorrent implementation uses the SHA1 hash of the IP address
79-- concatenated onto a secret, we use hashable instead. 83-- concatenated onto a secret, we use hashable instead.
80makeToken :: Hashable a => NodeAddr a -> Secret -> Token 84makeToken :: Hashable a => a -> Secret -> Token
81makeToken n s = Token $ toBS $ hashWithSalt s n 85makeToken n s = Token $ toBS $ hashWithSalt s n
82 where 86 where
83 toBS = toStrict . toLazyByteString . int64BE . fromIntegral 87 toBS = toStrict . toLazyByteString . int64BE . fromIntegral
@@ -104,7 +108,7 @@ tokens seed = (`evalState` mkStdGen seed) $
104-- 'update's. 108-- 'update's.
105-- 109--
106-- Typically used to handle find_peers query. 110-- Typically used to handle find_peers query.
107lookup :: Hashable a => NodeAddr a -> TokenMap -> Token 111lookup :: Hashable a => a -> TokenMap -> Token
108lookup addr TokenMap {..} = makeToken addr curSecret 112lookup addr TokenMap {..} = makeToken addr curSecret
109 113
110-- | Check if token is valid. 114-- | Check if token is valid.
@@ -112,7 +116,7 @@ lookup addr TokenMap {..} = makeToken addr curSecret
112-- Typically used to handle 'Network.DHT.Mainline.Announce' 116-- Typically used to handle 'Network.DHT.Mainline.Announce'
113-- query. If token is invalid the 'Network.KRPC.ProtocolError' should 117-- query. If token is invalid the 'Network.KRPC.ProtocolError' should
114-- be sent back to the malicious node. 118-- be sent back to the malicious node.
115member :: Hashable a => NodeAddr a -> Token -> TokenMap -> Bool 119member :: Hashable a => a -> Token -> TokenMap -> Bool
116member addr token TokenMap {..} = token `L.elem` valid 120member addr token TokenMap {..} = token `L.elem` valid
117 where valid = makeToken addr <$> [curSecret, prevSecret] 121 where valid = makeToken addr <$> [curSecret, prevSecret]
118 122
@@ -130,3 +134,49 @@ update TokenMap {..} = TokenMap
130 } 134 }
131 where 135 where
132 (newSecret, newGen) = next generator 136 (newSecret, newGen) = next generator
137
138data SessionTokens = SessionTokens
139 { tokenMap :: !TokenMap
140 , lastUpdate :: !UTCTime
141 , maxInterval :: !NominalDiffTime
142 }
143
144nullSessionTokens :: IO SessionTokens
145nullSessionTokens = SessionTokens
146 <$> (tokens <$> randomIO)
147 <*> getCurrentTime
148 <*> pure defaultUpdateInterval
149
150-- TODO invalidate *twice* if needed
151invalidateTokens :: UTCTime -> SessionTokens -> SessionTokens
152invalidateTokens curTime ts @ SessionTokens {..}
153 | curTime `diffUTCTime` lastUpdate > maxInterval = SessionTokens
154 { tokenMap = update tokenMap
155 , lastUpdate = curTime
156 , maxInterval = maxInterval
157 }
158 | otherwise = ts
159
160{-----------------------------------------------------------------------
161-- Tokens
162-----------------------------------------------------------------------}
163
164tryUpdateSecret :: TVar SessionTokens -> IO ()
165tryUpdateSecret toks = do
166 curTime <- getCurrentTime
167 atomically $ modifyTVar' toks (invalidateTokens curTime)
168
169grantToken :: Hashable addr => TVar SessionTokens -> addr -> IO Token
170grantToken sessionTokens addr = do
171 tryUpdateSecret sessionTokens
172 toks <- readTVarIO sessionTokens
173 return $ Network.BitTorrent.DHT.Token.lookup addr $ tokenMap toks
174
175-- | Throws 'HandlerError' if the token is invalid or already
176-- expired. See 'TokenMap' for details.
177checkToken :: Hashable addr => TVar SessionTokens -> addr -> Token -> IO Bool
178checkToken sessionTokens addr questionableToken = do
179 tryUpdateSecret sessionTokens
180 toks <- readTVarIO sessionTokens
181 return $ member addr questionableToken (tokenMap toks)
182