diff options
author | joe <joe@jerkface.net> | 2017-08-31 15:19:34 -0400 |
---|---|---|
committer | joe <joe@jerkface.net> | 2017-08-31 15:19:34 -0400 |
commit | a6b55a29ff656f105ca79c7d4f060920a37c7c70 (patch) | |
tree | e7dc6bd7dc066626e5460117384d30ffbcd29971 | |
parent | 74de5c3d86dfdc000f0abab0d465109417932ffe (diff) |
Separated module DHTTransport from ToxTransport.
-rw-r--r-- | DHTTransport.hs | 177 | ||||
-rw-r--r-- | ToxAddress.hs | 30 | ||||
-rw-r--r-- | ToxCrypto.hs | 16 | ||||
-rw-r--r-- | ToxTransport.hs | 84 |
4 files changed, 209 insertions, 98 deletions
diff --git a/DHTTransport.hs b/DHTTransport.hs new file mode 100644 index 00000000..6b3af2fc --- /dev/null +++ b/DHTTransport.hs | |||
@@ -0,0 +1,177 @@ | |||
1 | {-# LANGUAGE GeneralizedNewtypeDeriving #-} | ||
2 | {-# LANGUAGE KindSignatures #-} | ||
3 | module DHTTransport | ||
4 | ( parseDHTAddr | ||
5 | , encodeDHTAddr | ||
6 | , module ToxAddress | ||
7 | , DHTMessage(..) | ||
8 | , Ping | ||
9 | , Pong | ||
10 | , GetNodes | ||
11 | , SendNodes | ||
12 | , CookieRequest | ||
13 | , Cookie | ||
14 | , DHTRequest | ||
15 | ) where | ||
16 | |||
17 | import ToxAddress | ||
18 | import ToxCrypto | ||
19 | |||
20 | import Control.Arrow | ||
21 | import qualified Data.ByteString as B | ||
22 | ;import Data.ByteString (ByteString) | ||
23 | import Data.Serialize as S (Get, Serialize, get, put, runGet) | ||
24 | import Data.Word | ||
25 | import Network.Socket | ||
26 | |||
27 | |||
28 | |||
29 | data DHTMessage (f :: * -> *) | ||
30 | = DHTPing (Assym (f Ping)) | ||
31 | | DHTPong (Assym (f Pong)) | ||
32 | | DHTGetNodes (Assym (f GetNodes)) | ||
33 | | DHTSendNodes (Assym (f SendNodes)) | ||
34 | | DHTCookieRequest (Assym (f CookieRequest)) | ||
35 | | DHTCookie Nonce24 (f Cookie) | ||
36 | | DHTDHTRequest PublicKey (Assym (f DHTRequest)) | ||
37 | |||
38 | instance Sized GetNodes where | ||
39 | size = ConstSize 32 -- TODO This right? | ||
40 | |||
41 | instance Sized SendNodes where | ||
42 | size = VarSize $ \(SendNodes ns) -> _nodeFormatSize * length ns | ||
43 | |||
44 | instance Sized Ping where size = ConstSize 1 | ||
45 | instance Sized Pong where size = ConstSize 1 | ||
46 | |||
47 | parseDHTAddr :: (ByteString, SockAddr) -> Either (DHTMessage Encrypted8,NodeInfo) (ByteString,SockAddr) | ||
48 | parseDHTAddr (msg,saddr) | ||
49 | | Just (typ,bs) <- B.uncons msg | ||
50 | , let right = Right (msg,saddr) | ||
51 | left = either (const right) Left | ||
52 | = case typ of | ||
53 | 0x00 -> left $ direct bs saddr DHTPing | ||
54 | 0x01 -> left $ direct bs saddr DHTPong | ||
55 | 0x02 -> left $ direct bs saddr DHTGetNodes | ||
56 | 0x04 -> left $ direct bs saddr DHTSendNodes | ||
57 | 0x18 -> left $ direct bs saddr DHTCookieRequest | ||
58 | 0x19 -> left $ fanGet bs getCookie (uncurry DHTCookie) (const $ noReplyAddr saddr) | ||
59 | 0x20 -> left $ fanGet bs getDHTReqest (uncurry DHTDHTRequest) (asymNodeInfo saddr . snd) | ||
60 | _ -> right | ||
61 | |||
62 | encodeDHTAddr :: (DHTMessage Encrypted8,NodeInfo) -> (ByteString, SockAddr) | ||
63 | encodeDHTAddr = _todo | ||
64 | |||
65 | getCookie :: Get (Nonce24, Encrypted8 Cookie) | ||
66 | getCookie = get | ||
67 | |||
68 | getDHTReqest :: Get (PublicKey, Assym (Encrypted8 DHTRequest)) | ||
69 | getDHTReqest = _todo | ||
70 | |||
71 | getDHT :: Sized a => Get (Assym (Encrypted8 a)) | ||
72 | getDHT = _todo | ||
73 | |||
74 | |||
75 | -- Throws an error if called with a non-internet socket. | ||
76 | direct :: Sized a => ByteString | ||
77 | -> SockAddr | ||
78 | -> (Assym (Encrypted8 a) | ||
79 | -> DHTMessage Encrypted8) | ||
80 | -> Either String (DHTMessage Encrypted8, NodeInfo) | ||
81 | direct bs saddr f = fanGet bs getDHT f (asymNodeInfo saddr) | ||
82 | |||
83 | -- Throws an error if called with a non-internet socket. | ||
84 | asymNodeInfo saddr asym = either (error . mappend "asymNodeInfo: ") id $ nodeInfo (NodeId $ senderKey asym) saddr | ||
85 | |||
86 | |||
87 | fanGet :: ByteString -> Get x -> (x -> a) -> (x -> b) -> Either String (a,b) | ||
88 | fanGet bs getIt f nid = fmap (f &&& nid) $ runGet getIt bs | ||
89 | |||
90 | -- Throws an error if called with a non-internet socket. | ||
91 | noReplyAddr saddr = either (error . mappend "noReplyAddr: ") id $ nodeInfo zeroID saddr | ||
92 | |||
93 | |||
94 | -- ## DHT Request packets | ||
95 | -- | ||
96 | -- | Length | Contents | | ||
97 | -- |:-------|:--------------------------| | ||
98 | -- | `1` | `uint8_t` (0x20) | | ||
99 | -- | `32` | receiver's DHT public key | | ||
100 | -- ... ... | ||
101 | |||
102 | data DHTRequestPacket = DHTRequestPacket | ||
103 | { requestTarget :: PublicKey | ||
104 | , request :: Assym (Encrypted DHTRequest) | ||
105 | } | ||
106 | |||
107 | instance Serialize DHTRequestPacket where | ||
108 | get = _todo | ||
109 | put = _todo | ||
110 | |||
111 | |||
112 | data DHTRequest | ||
113 | = NATPing Nonce8 | ||
114 | | NATPong Nonce8 | ||
115 | | DHTPK DHTPublicKey | ||
116 | |||
117 | -- | Length | Contents | | ||
118 | -- |:------------|:------------------------------------| | ||
119 | -- | `1` | `uint8_t` (0x9c) | | ||
120 | -- | `8` | `uint64_t` `no_replay` | | ||
121 | -- | `32` | Our DHT public key | | ||
122 | -- | `[39, 204]` | Maximum of 4 nodes in packed format | | ||
123 | data DHTPublicKey = DHTPublicKey | ||
124 | { dhtpkNonce :: Nonce8 | ||
125 | , dhtpk :: PublicKey | ||
126 | , dhtpkNodes :: SendNodes | ||
127 | } | ||
128 | |||
129 | newtype GetNodes = GetNodes NodeId | ||
130 | deriving (Eq,Ord,Show,Read,S.Serialize) | ||
131 | |||
132 | newtype SendNodes = SendNodes [NodeInfo] | ||
133 | deriving (Eq,Ord,Show,Read) | ||
134 | |||
135 | instance S.Serialize SendNodes where | ||
136 | get = do | ||
137 | cnt <- S.get :: S.Get Word8 | ||
138 | ns <- sequence $ replicate (fromIntegral cnt) S.get | ||
139 | return $ SendNodes ns | ||
140 | |||
141 | put (SendNodes ns) = do | ||
142 | let ns' = take 4 ns | ||
143 | S.put (fromIntegral (length ns') :: Word8) | ||
144 | mapM_ S.put ns' | ||
145 | |||
146 | data Ping = Ping deriving Show | ||
147 | data Pong = Pong deriving Show | ||
148 | |||
149 | instance S.Serialize Ping where | ||
150 | get = do w8 <- S.get | ||
151 | if (w8 :: Word8) /= 0 | ||
152 | then fail "Malformed ping." | ||
153 | else return Ping | ||
154 | put Ping = S.put (0 :: Word8) | ||
155 | |||
156 | instance S.Serialize Pong where | ||
157 | get = do w8 <- S.get | ||
158 | if (w8 :: Word8) /= 1 | ||
159 | then fail "Malformed pong." | ||
160 | else return Pong | ||
161 | put Pong = S.put (1 :: Word8) | ||
162 | |||
163 | newtype CookieRequest = CookieRequest PublicKey | ||
164 | newtype CookieResponse = CookieResponse Cookie | ||
165 | |||
166 | data Cookie = Cookie Nonce24 (Encrypted CookieData) | ||
167 | |||
168 | instance Sized Cookie where size = ConstSize 112 -- 24 byte nonce + 88 byte cookie data | ||
169 | |||
170 | data CookieData = CookieData -- 16 (mac) | ||
171 | { cookieTime :: Word64 -- 8 | ||
172 | , longTermKey :: PublicKey -- 32 | ||
173 | , dhtKey :: PublicKey -- + 32 | ||
174 | } -- = 88 bytes when encrypted. | ||
175 | |||
176 | instance Sized CookieRequest where | ||
177 | size = ConstSize 64 -- 32 byte key + 32 byte padding | ||
diff --git a/ToxAddress.hs b/ToxAddress.hs index a0d5345d..9aa7a575 100644 --- a/ToxAddress.hs +++ b/ToxAddress.hs | |||
@@ -13,16 +13,18 @@ | |||
13 | {-# LANGUAGE ScopedTypeVariables #-} | 13 | {-# LANGUAGE ScopedTypeVariables #-} |
14 | {-# LANGUAGE TupleSections #-} | 14 | {-# LANGUAGE TupleSections #-} |
15 | {-# LANGUAGE TypeApplications #-} | 15 | {-# LANGUAGE TypeApplications #-} |
16 | module ToxAddress where | 16 | module ToxAddress (NodeInfo(..),NodeId(..),nodeInfo) where |
17 | 17 | ||
18 | import Control.Applicative | 18 | import Control.Applicative |
19 | import Control.Monad | 19 | import Control.Monad |
20 | import Crypto.Error.Types (CryptoFailable (..), | ||
21 | throwCryptoError) | ||
22 | import Crypto.PubKey.Curve25519 | ||
20 | import qualified Data.Aeson as JSON | 23 | import qualified Data.Aeson as JSON |
21 | ;import Data.Aeson (FromJSON, ToJSON, (.=)) | 24 | ;import Data.Aeson (FromJSON, ToJSON, (.=)) |
22 | import Data.Bits | ||
23 | import Data.Bits.ByteString () | 25 | import Data.Bits.ByteString () |
24 | import Data.ByteArray as BA (ByteArrayAccess, Bytes) | 26 | import qualified Data.ByteArray as BA |
25 | import qualified Data.ByteArray as BA | 27 | ;import Data.ByteArray as BA (ByteArrayAccess) |
26 | import qualified Data.ByteString as B | 28 | import qualified Data.ByteString as B |
27 | ;import Data.ByteString (ByteString) | 29 | ;import Data.ByteString (ByteString) |
28 | import qualified Data.ByteString.Base16 as Base16 | 30 | import qualified Data.ByteString.Base16 as Base16 |
@@ -33,18 +35,12 @@ import Data.Hashable | |||
33 | import Data.IP | 35 | import Data.IP |
34 | import Data.Serialize as S | 36 | import Data.Serialize as S |
35 | import Data.Word | 37 | import Data.Word |
38 | import Foreign.Storable | ||
39 | import GHC.TypeLits | ||
36 | import Network.Address hiding (nodePort) | 40 | import Network.Address hiding (nodePort) |
37 | import Network.Socket | 41 | import System.IO.Unsafe (unsafeDupablePerformIO) |
38 | import qualified Text.ParserCombinators.ReadP as RP | 42 | import qualified Text.ParserCombinators.ReadP as RP |
39 | import Text.Read | 43 | import Text.Read |
40 | import GHC.TypeLits | ||
41 | import Crypto.PubKey.Curve25519 | ||
42 | import Crypto.Error.Types (CryptoFailable(..)) | ||
43 | |||
44 | data Address | ||
45 | = DHTNode NodeInfo -- A direct DHT exchange. | ||
46 | | OnionFromOwner NodeInfo (ForwardPath 3) -- Your own created onion path. | ||
47 | | OnionToOwner NodeInfo (ReturnPath 3) -- An onion path end point. | ||
48 | 44 | ||
49 | -- | perform io for hashes that do allocation and ffi. | 45 | -- | perform io for hashes that do allocation and ffi. |
50 | -- unsafeDupablePerformIO is used when possible as the | 46 | -- unsafeDupablePerformIO is used when possible as the |
@@ -363,14 +359,6 @@ zeroID = PubKey $ B.replicate 32 0 | |||
363 | 359 | ||
364 | -} | 360 | -} |
365 | 361 | ||
366 | newtype ReturnPath (n::Nat) = ReturnPath ByteString | ||
367 | deriving (Eq, Ord,Data) | ||
368 | |||
369 | instance KnownNat n => Serialize (ReturnPath n) where | ||
370 | -- Size: 59 = 1(family) + 16(ip) + 2(port) +16(mac) + 24(nonce) | ||
371 | get = ReturnPath <$> getBytes ( 59 * (fromIntegral $ natVal $ Proxy @n) ) | ||
372 | put (ReturnPath bs) = putByteString bs | ||
373 | |||
374 | newtype ForwardPath (n::Nat) = ForwardPath ByteString | 362 | newtype ForwardPath (n::Nat) = ForwardPath ByteString |
375 | deriving (Eq, Ord,Data) | 363 | deriving (Eq, Ord,Data) |
376 | 364 | ||
diff --git a/ToxCrypto.hs b/ToxCrypto.hs index cae7e251..6f0fcf1a 100644 --- a/ToxCrypto.hs +++ b/ToxCrypto.hs | |||
@@ -7,6 +7,8 @@ module ToxCrypto | |||
7 | , publicKey | 7 | , publicKey |
8 | , SecretKey | 8 | , SecretKey |
9 | , Encrypted | 9 | , Encrypted |
10 | , Encrypted8 | ||
11 | , Assym(..) | ||
10 | , Plain | 12 | , Plain |
11 | , computeSharedSecret | 13 | , computeSharedSecret |
12 | , encrypt | 14 | , encrypt |
@@ -47,6 +49,10 @@ import qualified Data.ByteString.Internal | |||
47 | newtype Encrypted a = Encrypted ByteString | 49 | newtype Encrypted a = Encrypted ByteString |
48 | deriving (Eq,Ord,Data) | 50 | deriving (Eq,Ord,Data) |
49 | 51 | ||
52 | newtype Encrypted8 a = E8 (Encrypted (a,Nonce8)) | ||
53 | deriving Serialize | ||
54 | |||
55 | |||
50 | newtype Auth = Auth Poly1305.Auth deriving (Eq, ByteArrayAccess) | 56 | newtype Auth = Auth Poly1305.Auth deriving (Eq, ByteArrayAccess) |
51 | instance Ord Auth where | 57 | instance Ord Auth where |
52 | compare (Auth a) (Auth b) = comparing (BA.convert :: Poly1305.Auth -> Bytes) a b | 58 | compare (Auth a) (Auth b) = comparing (BA.convert :: Poly1305.Auth -> Bytes) a b |
@@ -210,3 +216,13 @@ zeros32 = Nonce32 $ BA.replicate 32 0 | |||
210 | 216 | ||
211 | zeros24 :: ByteString | 217 | zeros24 :: ByteString |
212 | zeros24 = BA.take 24 zs where Nonce32 zs = zeros32 | 218 | zeros24 = BA.take 24 zs where Nonce32 zs = zeros32 |
219 | |||
220 | -- | `32` | sender's DHT public key | | ||
221 | -- | `24` | nonce | | ||
222 | -- | `?` | encrypted message | | ||
223 | data Assym a = Assym | ||
224 | { senderKey :: PublicKey | ||
225 | , assymNonce :: Nonce24 | ||
226 | , assymData :: a | ||
227 | } | ||
228 | |||
diff --git a/ToxTransport.hs b/ToxTransport.hs index 694d9d79..3e442d49 100644 --- a/ToxTransport.hs +++ b/ToxTransport.hs | |||
@@ -15,16 +15,6 @@ module ToxTransport | |||
15 | 15 | ||
16 | , UDPTransport | 16 | , UDPTransport |
17 | 17 | ||
18 | -- DHTTransport | ||
19 | , DHTMessage(..) | ||
20 | , Ping | ||
21 | , Pong | ||
22 | , GetNodes | ||
23 | , SendNodes | ||
24 | , CookieRequest | ||
25 | , Cookie | ||
26 | , DHTRequest | ||
27 | |||
28 | -- OnionTransport | 18 | -- OnionTransport |
29 | , OnionToOwner(..) | 19 | , OnionToOwner(..) |
30 | , OnionMessage(..) | 20 | , OnionMessage(..) |
@@ -48,9 +38,8 @@ module ToxTransport | |||
48 | ) where | 38 | ) where |
49 | 39 | ||
50 | import Network.QueryResponse | 40 | import Network.QueryResponse |
51 | import ToxAddress as Tox hiding (OnionToOwner, ReturnPath) | ||
52 | import ToxCrypto | 41 | import ToxCrypto |
53 | import ToxPacket | 42 | import DHTTransport |
54 | 43 | ||
55 | import Control.Applicative | 44 | import Control.Applicative |
56 | import Control.Arrow | 45 | import Control.Arrow |
@@ -98,76 +87,11 @@ toxTransport crypto closeLookup udp = do | |||
98 | type HandleHi a = Maybe (Either String (DHTMessage Encrypted8, NodeInfo)) -> IO a | 87 | type HandleHi a = Maybe (Either String (DHTMessage Encrypted8, NodeInfo)) -> IO a |
99 | type HandleLo a = Maybe (Either String (ByteString, SockAddr)) -> IO a | 88 | type HandleLo a = Maybe (Either String (ByteString, SockAddr)) -> IO a |
100 | 89 | ||
101 | data DHTMessage (f :: * -> *) | ||
102 | = DHTPing (Assym (f Ping)) | ||
103 | | DHTPong (Assym (f Pong)) | ||
104 | | DHTGetNodes (Assym (f GetNodes)) | ||
105 | | DHTSendNodes (Assym (f SendNodes)) | ||
106 | | DHTCookieRequest (Assym (f CookieRequest)) | ||
107 | | DHTCookie Nonce24 (f Cookie) | ||
108 | | DHTDHTRequest PublicKey (Assym (f DHTRequest)) | ||
109 | |||
110 | instance Sized GetNodes where | ||
111 | size = ConstSize 32 -- TODO This right? | ||
112 | |||
113 | instance Sized SendNodes where | ||
114 | size = VarSize $ \(SendNodes ns) -> _nodeFormatSize * length ns | ||
115 | |||
116 | instance Sized Ping where size = ConstSize 1 | ||
117 | instance Sized Pong where size = ConstSize 1 | ||
118 | |||
119 | newtype Encrypted8 a = E8 (Encrypted (a,Nonce8)) | ||
120 | deriving Serialize | ||
121 | |||
122 | -- instance (Sized a, Sized b) => Sized (a,b) where size = _todo | 90 | -- instance (Sized a, Sized b) => Sized (a,b) where size = _todo |
123 | 91 | ||
124 | getDHT :: Sized a => Get (Assym (Encrypted8 a)) | ||
125 | getDHT = _todo | ||
126 | |||
127 | getOnionAssym :: Get (Assym (Encrypted DataToRoute)) | 92 | getOnionAssym :: Get (Assym (Encrypted DataToRoute)) |
128 | getOnionAssym = _todo | 93 | getOnionAssym = _todo |
129 | 94 | ||
130 | getCookie :: Get (Nonce24, Encrypted8 Cookie) | ||
131 | getCookie = get | ||
132 | |||
133 | getDHTReqest :: Get (PublicKey, Assym (Encrypted8 DHTRequest)) | ||
134 | getDHTReqest = _todo | ||
135 | |||
136 | fanGet :: ByteString -> Get x -> (x -> a) -> (x -> b) -> Either String (a,b) | ||
137 | fanGet bs getIt f nid = fmap (f &&& nid) $ runGet getIt bs | ||
138 | |||
139 | -- Throws an error if called with a non-internet socket. | ||
140 | direct :: Sized a => ByteString | ||
141 | -> SockAddr | ||
142 | -> (Assym (Encrypted8 a) | ||
143 | -> DHTMessage Encrypted8) | ||
144 | -> Either String (DHTMessage Encrypted8, NodeInfo) | ||
145 | direct bs saddr f = fanGet bs getDHT f (asymNodeInfo saddr) | ||
146 | |||
147 | -- Throws an error if called with a non-internet socket. | ||
148 | asymNodeInfo saddr asym = either (error . mappend "asymNodeInfo: ") id $ nodeInfo (NodeId $ senderKey asym) saddr | ||
149 | |||
150 | -- Throws an error if called with a non-internet socket. | ||
151 | noReplyAddr saddr = either (error . mappend "noReplyAddr: ") id $ nodeInfo zeroID saddr | ||
152 | |||
153 | parseDHTAddr :: (ByteString, SockAddr) -> Either (DHTMessage Encrypted8,NodeInfo) (ByteString,SockAddr) | ||
154 | parseDHTAddr (msg,saddr) | ||
155 | | Just (typ,bs) <- B.uncons msg | ||
156 | , let right = Right (msg,saddr) | ||
157 | left = either (const right) Left | ||
158 | = case typ of | ||
159 | 0x00 -> left $ direct bs saddr DHTPing | ||
160 | 0x01 -> left $ direct bs saddr DHTPong | ||
161 | 0x02 -> left $ direct bs saddr DHTGetNodes | ||
162 | 0x04 -> left $ direct bs saddr DHTSendNodes | ||
163 | 0x18 -> left $ direct bs saddr DHTCookieRequest | ||
164 | 0x19 -> left $ fanGet bs getCookie (uncurry DHTCookie) (const $ noReplyAddr saddr) | ||
165 | 0x20 -> left $ fanGet bs getDHTReqest (uncurry DHTDHTRequest) (asymNodeInfo saddr . snd) | ||
166 | _ -> right | ||
167 | |||
168 | encodeDHTAddr :: (DHTMessage Encrypted8,NodeInfo) -> (ByteString, SockAddr) | ||
169 | encodeDHTAddr = _todo | ||
170 | |||
171 | 95 | ||
172 | data OnionMessage (f :: * -> *) | 96 | data OnionMessage (f :: * -> *) |
173 | = OnionAnnounce (Assym (f (AnnounceRequest,Nonce8))) | 97 | = OnionAnnounce (Assym (f (AnnounceRequest,Nonce8))) |
@@ -396,6 +320,12 @@ data ReturnPath (n :: Nat) where | |||
396 | NoReturnPath :: ReturnPath 0 | 320 | NoReturnPath :: ReturnPath 0 |
397 | ReturnPath :: Nonce24 -> Encrypted (Addressed (ReturnPath n)) -> ReturnPath (n + 1) | 321 | ReturnPath :: Nonce24 -> Encrypted (Addressed (ReturnPath n)) -> ReturnPath (n + 1) |
398 | 322 | ||
323 | -- instance KnownNat n => Serialize (ReturnPath n) where | ||
324 | -- -- Size: 59 = 1(family) + 16(ip) + 2(port) +16(mac) + 24(nonce) | ||
325 | -- get = ReturnPath <$> getBytes ( 59 * (fromIntegral $ natVal $ Proxy @n) ) | ||
326 | -- put (ReturnPath bs) = putByteString bs | ||
327 | |||
328 | |||
399 | data Forwarding (n :: Nat) msg where | 329 | data Forwarding (n :: Nat) msg where |
400 | NotForwarded :: msg -> Forwarding 0 msg | 330 | NotForwarded :: msg -> Forwarding 0 msg |
401 | Forwarding :: Assym (Encrypted (Addressed (Forwarding n msg))) -> Forwarding (n + 1) msg | 331 | Forwarding :: Assym (Encrypted (Addressed (Forwarding n msg))) -> Forwarding (n + 1) msg |