diff options
author | joe <joe@jerkface.net> | 2017-07-14 23:52:33 -0400 |
---|---|---|
committer | joe <joe@jerkface.net> | 2017-07-14 23:52:33 -0400 |
commit | 9d5b5512ce3b5b885c0e331d6fcefa0b9d3fc42b (patch) | |
tree | 1c83e304b1bf4fb604bb984c6e0e5d0ad54485a2 /src/Network/BitTorrent/DHT/Token.hs | |
parent | 29f369311408b5ed7823c9858257d1c948e24d28 (diff) |
Implemented more of the Mainline DHT rewrite.
Diffstat (limited to 'src/Network/BitTorrent/DHT/Token.hs')
-rw-r--r-- | src/Network/BitTorrent/DHT/Token.hs | 58 |
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 | |||
52 | import Data.String | 56 | import Data.String |
53 | import Data.Time | 57 | import Data.Time |
54 | import System.Random | 58 | import System.Random |
55 | 59 | import Control.Concurrent.STM | |
56 | import Network.Address | 60 | import 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. |
80 | makeToken :: Hashable a => NodeAddr a -> Secret -> Token | 84 | makeToken :: Hashable a => a -> Secret -> Token |
81 | makeToken n s = Token $ toBS $ hashWithSalt s n | 85 | makeToken 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. |
107 | lookup :: Hashable a => NodeAddr a -> TokenMap -> Token | 111 | lookup :: Hashable a => a -> TokenMap -> Token |
108 | lookup addr TokenMap {..} = makeToken addr curSecret | 112 | lookup 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. |
115 | member :: Hashable a => NodeAddr a -> Token -> TokenMap -> Bool | 119 | member :: Hashable a => a -> Token -> TokenMap -> Bool |
116 | member addr token TokenMap {..} = token `L.elem` valid | 120 | member 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 | |||
138 | data SessionTokens = SessionTokens | ||
139 | { tokenMap :: !TokenMap | ||
140 | , lastUpdate :: !UTCTime | ||
141 | , maxInterval :: !NominalDiffTime | ||
142 | } | ||
143 | |||
144 | nullSessionTokens :: IO SessionTokens | ||
145 | nullSessionTokens = SessionTokens | ||
146 | <$> (tokens <$> randomIO) | ||
147 | <*> getCurrentTime | ||
148 | <*> pure defaultUpdateInterval | ||
149 | |||
150 | -- TODO invalidate *twice* if needed | ||
151 | invalidateTokens :: UTCTime -> SessionTokens -> SessionTokens | ||
152 | invalidateTokens 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 | |||
164 | tryUpdateSecret :: TVar SessionTokens -> IO () | ||
165 | tryUpdateSecret toks = do | ||
166 | curTime <- getCurrentTime | ||
167 | atomically $ modifyTVar' toks (invalidateTokens curTime) | ||
168 | |||
169 | grantToken :: Hashable addr => TVar SessionTokens -> addr -> IO Token | ||
170 | grantToken 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. | ||
177 | checkToken :: Hashable addr => TVar SessionTokens -> addr -> Token -> IO Bool | ||
178 | checkToken sessionTokens addr questionableToken = do | ||
179 | tryUpdateSecret sessionTokens | ||
180 | toks <- readTVarIO sessionTokens | ||
181 | return $ member addr questionableToken (tokenMap toks) | ||
182 | |||