diff options
author | joe <joe@jerkface.net> | 2017-08-31 15:42:27 -0400 |
---|---|---|
committer | joe <joe@jerkface.net> | 2017-08-31 15:42:49 -0400 |
commit | eba3cdcc646211cc152c16d0813cc7e9b1c3111b (patch) | |
tree | e90c45a86d11b16da4eee5f21bb8ee618d7d94d6 /OnionTransport.hs | |
parent | a6b55a29ff656f105ca79c7d4f060920a37c7c70 (diff) |
Separated module OnionTransport from ToxTransport.
Diffstat (limited to 'OnionTransport.hs')
-rw-r--r-- | OnionTransport.hs | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/OnionTransport.hs b/OnionTransport.hs new file mode 100644 index 00000000..804c444e --- /dev/null +++ b/OnionTransport.hs | |||
@@ -0,0 +1,196 @@ | |||
1 | {-# LANGUAGE DataKinds #-} | ||
2 | {-# LANGUAGE GADTs #-} | ||
3 | {-# LANGUAGE GeneralizedNewtypeDeriving #-} | ||
4 | {-# LANGUAGE KindSignatures #-} | ||
5 | {-# LANGUAGE LambdaCase #-} | ||
6 | {-# LANGUAGE ScopedTypeVariables #-} | ||
7 | {-# LANGUAGE TupleSections #-} | ||
8 | {-# LANGUAGE TypeOperators #-} | ||
9 | module OnionTransport | ||
10 | ( parseOnionAddr | ||
11 | , encodeOnionAddr | ||
12 | , forwardOnions | ||
13 | , OnionToOwner(..) | ||
14 | , OnionMessage(..) | ||
15 | , DataToRoute(..) | ||
16 | , AnnounceResponse(..) | ||
17 | , AnnounceRequest(..) | ||
18 | , Forwarding(..) | ||
19 | , ReturnPath(..) | ||
20 | , OnionRequest(..) | ||
21 | , OnionResponse(..) | ||
22 | , Addressed(..) | ||
23 | , UDPTransport | ||
24 | ) where | ||
25 | |||
26 | import Network.QueryResponse | ||
27 | import ToxCrypto | ||
28 | import DHTTransport (NodeInfo(..),NodeId(..),SendNodes,nodeInfo) | ||
29 | |||
30 | import Control.Arrow | ||
31 | import qualified Data.ByteString as B | ||
32 | ;import Data.ByteString (ByteString) | ||
33 | import Data.Serialize as S (Get, Put, Serialize, get, put, runGet) | ||
34 | import Data.Typeable | ||
35 | import Data.Word | ||
36 | import GHC.TypeLits | ||
37 | import Network.Socket | ||
38 | |||
39 | type HandleLo a = Maybe (Either String (ByteString, SockAddr)) -> IO a | ||
40 | |||
41 | type UDPTransport = Transport String SockAddr ByteString | ||
42 | |||
43 | |||
44 | getOnionAssym :: Get (Assym (Encrypted DataToRoute)) | ||
45 | getOnionAssym = _todo | ||
46 | |||
47 | data OnionMessage (f :: * -> *) | ||
48 | = OnionAnnounce (Assym (f (AnnounceRequest,Nonce8))) | ||
49 | | OnionAnnounceResponse Nonce8 Nonce24 (f AnnounceResponse) | ||
50 | | OnionToRoute PublicKey (Assym (f DataToRoute)) -- destination key, aliased Assym | ||
51 | | OnionToRouteResponse (Assym (f DataToRoute)) | ||
52 | |||
53 | data OnionToOwner = OnionToOwner NodeInfo (ReturnPath 3) | ||
54 | | OnionToMe SockAddr -- SockAddr is immediate peer in route | ||
55 | |||
56 | |||
57 | onionToOwner assym ret3 saddr = do | ||
58 | ni <- nodeInfo (NodeId $ senderKey assym) saddr | ||
59 | return $ OnionToOwner ni ret3 | ||
60 | -- data CookieAddress = WithoutCookie NodeInfo | CookieAddress Cookie SockAddr | ||
61 | |||
62 | |||
63 | onion bs saddr getf = do (f,(assym,ret3)) <- runGet ((,) <$> getf <*> getOnionRequest) bs | ||
64 | oaddr <- onionToOwner assym ret3 saddr | ||
65 | return (f assym, oaddr) | ||
66 | |||
67 | |||
68 | parseOnionAddr :: (ByteString, SockAddr) -> Either (OnionMessage Encrypted,OnionToOwner) (ByteString,SockAddr) | ||
69 | parseOnionAddr (msg,saddr) | ||
70 | | Just (typ,bs) <- B.uncons msg | ||
71 | , let right = Right (msg,saddr) | ||
72 | query = either (const right) Left | ||
73 | response = either (const right) (Left . (, OnionToMe saddr)) | ||
74 | = case typ of | ||
75 | 0x83 -> query $ onion bs saddr (pure OnionAnnounce) -- Announce Request | ||
76 | 0x85 -> query $ onion bs saddr (OnionToRoute <$> getPublicKey) -- Onion Data Request | ||
77 | 0x84 -> response $ runGet (OnionAnnounceResponse <$> get <*> get <*> get) bs -- Announce Response | ||
78 | 0x86 -> response $ runGet (OnionToRouteResponse <$> getOnionAssym) bs -- Onion Data Response | ||
79 | _ -> right | ||
80 | |||
81 | encodeOnionAddr :: (OnionMessage Encrypted,OnionToOwner) -> (ByteString, SockAddr) | ||
82 | encodeOnionAddr = _todo | ||
83 | |||
84 | forwardOnions :: TransportCrypto -> UDPTransport -> UDPTransport -- HandleHi a -> IO a -> HandleLo a | ||
85 | forwardOnions crypto udp = udp { awaitMessage = await' } | ||
86 | where | ||
87 | -- forMe :: HandleHi | ||
88 | -- forThem :: handleLo | ||
89 | await' :: HandleLo a -> IO a | ||
90 | await' forThem = awaitMessage udp $ \case | ||
91 | m@(Just (Right (bs,saddr))) -> case B.head bs of | ||
92 | 0x80 -> forward forThem bs $ handleOnionRequest (Proxy :: Proxy 0) crypto saddr (forThem m) | ||
93 | 0x81 -> forward forThem bs $ handleOnionRequest (Proxy :: Proxy 1) crypto saddr (forThem m) | ||
94 | 0x82 -> forward forThem bs $ handleOnionRequest (Proxy :: Proxy 2) crypto saddr (forThem m) | ||
95 | 0x8c -> forward forThem bs $ handleOnionResponse (Proxy :: Proxy 3) crypto saddr (forThem m) | ||
96 | 0x8d -> forward forThem bs $ handleOnionResponse (Proxy :: Proxy 2) crypto saddr (forThem m) | ||
97 | 0x8e -> forward forThem bs $ handleOnionResponse (Proxy :: Proxy 1) crypto saddr (forThem m) | ||
98 | _ -> forThem m | ||
99 | m -> forThem m | ||
100 | |||
101 | forward :: forall c b b1. | ||
102 | Serialize b => | ||
103 | (Maybe (Either String b1) -> c) -> ByteString -> (b -> c) -> c | ||
104 | forward forMe bs f = either (forMe . Just . Left) f $ decode $ B.tail bs | ||
105 | |||
106 | -- n = 0, 1, 2 | ||
107 | data OnionRequest (n :: Nat) = OnionRequest | ||
108 | { onionNonce :: Nonce24 | ||
109 | , onionForward :: Forwarding (3 - n) (OnionMessage Encrypted) | ||
110 | , pathFromOwner :: ReturnPath n | ||
111 | } | ||
112 | |||
113 | instance Serialize (OnionRequest n) where { get = _todo; put = _todo } | ||
114 | instance Serialize (OnionResponse n) where { get = _todo; put = _todo } | ||
115 | |||
116 | -- n = 1, 2, 3 | ||
117 | -- Attributed (Encrypted ( | ||
118 | |||
119 | data OnionResponse (n :: Nat) = OnionResponse | ||
120 | { pathToOwner :: ReturnPath n | ||
121 | , msgToOwner :: OnionMessage Encrypted | ||
122 | } | ||
123 | |||
124 | data Addressed a = Addressed { sockAddr :: SockAddr, unaddressed :: a } | ||
125 | |||
126 | data ReturnPath (n :: Nat) where | ||
127 | NoReturnPath :: ReturnPath 0 | ||
128 | ReturnPath :: Nonce24 -> Encrypted (Addressed (ReturnPath n)) -> ReturnPath (n + 1) | ||
129 | |||
130 | -- instance KnownNat n => Serialize (ReturnPath n) where | ||
131 | -- -- Size: 59 = 1(family) + 16(ip) + 2(port) +16(mac) + 24(nonce) | ||
132 | -- get = ReturnPath <$> getBytes ( 59 * (fromIntegral $ natVal $ Proxy @n) ) | ||
133 | -- put (ReturnPath bs) = putByteString bs | ||
134 | |||
135 | |||
136 | data Forwarding (n :: Nat) msg where | ||
137 | NotForwarded :: msg -> Forwarding 0 msg | ||
138 | Forwarding :: Assym (Encrypted (Addressed (Forwarding n msg))) -> Forwarding (n + 1) msg | ||
139 | |||
140 | handleOnionRequest :: KnownNat n => proxy n -> TransportCrypto -> SockAddr -> IO a -> OnionRequest n -> IO a | ||
141 | handleOnionRequest = _todo | ||
142 | |||
143 | handleOnionResponse :: KnownNat n => proxy n -> TransportCrypto -> SockAddr -> IO a -> OnionResponse n -> IO a | ||
144 | handleOnionResponse = _todo | ||
145 | |||
146 | data AnnounceRequest = AnnounceRequest | ||
147 | { announcePingId :: Nonce32 -- Ping ID | ||
148 | , announceSeeking :: NodeId -- Public key we are searching for | ||
149 | , announceKey :: NodeId -- Public key that we want those sending back data packets to use | ||
150 | } | ||
151 | |||
152 | instance S.Serialize AnnounceRequest where | ||
153 | get = AnnounceRequest <$> S.get <*> S.get <*> S.get | ||
154 | put (AnnounceRequest p s k) = S.put (p,s,k) | ||
155 | |||
156 | getOnionRequest :: Get (Assym (Encrypted msg), ReturnPath 3) | ||
157 | getOnionRequest = _todo | ||
158 | |||
159 | data KeyRecord = NotStored Nonce32 | ||
160 | | SendBackKey PublicKey | ||
161 | | Acknowledged Nonce32 | ||
162 | |||
163 | getPublicKey :: Get PublicKey | ||
164 | getPublicKey = _todo | ||
165 | |||
166 | putPublicKey :: PublicKey -> Put | ||
167 | putPublicKey = _todo | ||
168 | |||
169 | instance S.Serialize KeyRecord where | ||
170 | get = do | ||
171 | is_stored <- S.get :: S.Get Word8 | ||
172 | case is_stored of | ||
173 | 1 -> SendBackKey <$> getPublicKey | ||
174 | 2 -> Acknowledged <$> S.get | ||
175 | _ -> NotStored <$> S.get | ||
176 | put (NotStored n32) = S.put (0 :: Word8) >> S.put n32 | ||
177 | put (SendBackKey key) = S.put (1 :: Word8) >> putPublicKey key | ||
178 | put (Acknowledged n32) = S.put (2 :: Word8) >> S.put n32 | ||
179 | |||
180 | data AnnounceResponse = AnnounceResponse | ||
181 | { is_stored :: KeyRecord | ||
182 | , announceNodes :: SendNodes | ||
183 | } | ||
184 | |||
185 | instance Sized AnnounceResponse where | ||
186 | size = VarSize $ \AnnounceResponse {} -> _todo | ||
187 | |||
188 | instance S.Serialize AnnounceResponse where | ||
189 | get = AnnounceResponse <$> S.get <*> S.get | ||
190 | put (AnnounceResponse st ns) = S.put st >> S.put ns | ||
191 | |||
192 | data DataToRoute = DataToRoute | ||
193 | { dataFromKey :: PublicKey | ||
194 | , dataToRoute :: Encrypted (Word8,ByteString) | ||
195 | } | ||
196 | |||