summaryrefslogtreecommitdiff
path: root/dht/src/Network/Tox/Onion/Transport.hs
blob: 6319ed2f0b70d027ca6d2b3b158cca2bfa17d613 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
module Network.Tox.Onion.Transport
    ( parseOnionAddr
    , encodeOnionAddr
    , parseDataToRoute
    , encodeDataToRoute
    , forwardOnions
    , AliasSelector(..)
    , OnionDestination(..)
    , OnionMessage(..)
    , Rendezvous(..)
    , DataToRoute(..)
    , OnionData(..)
    , AnnouncedRendezvous(..)
    , AnnounceResponse(..)
    , AnnounceRequest(..)
    , Forwarding(..)
    , ReturnPath(..)
    , OnionRequest(..)
    , OnionResponse(..)
    , Addressed(..)
    , UDPTransport
    , KeyRecord(..)
    , encrypt
    , decrypt
    , peelSymmetric
    , OnionRoute(..)
    , dummyRoute
    , N0
    , N1
    , N2
    , N3
    , onionKey
    , onionAliasSelector
    , selectAlias
    , RouteId(..)
    , routeId
    , putRequest
    , wrapForRoute
    , wrapSymmetric
    , wrapOnion
    , wrapOnionPure
    , unwrapAnnounceResponse
    , wrapIndirectHops
    ) where

import qualified Data.ByteString as B
         ;import Data.ByteString (ByteString)
import Data.Maybe
import Data.Serialize
import Network.Socket

import Crypto.Tox hiding (encrypt,decrypt)
import Network.Tox.TCP.NodeId (udpNodeInfo)
import qualified Data.Tox.Relay as TCP
import Data.Tox.Onion
import Network.Address (nullAddress4)
import Network.Tox.DHT.Transport (SendNodes(..))
import Network.Tox.NodeId
import Network.QueryResponse

encodeOnionAddr :: TransportCrypto
                   -> (NodeInfo -> RouteId -> IO (Maybe OnionRoute))
                   -> (OnionMessage Encrypted,OnionDestination RouteId)
                   -> IO (Maybe (ByteString, SockAddr))
encodeOnionAddr crypto _ (msg,OnionToOwner ni p) =
    return $ Just ( runPut $ putResponse (OnionResponse p msg)
                  , nodeAddr ni )
encodeOnionAddr crypto getRoute (msg,OnionDestination x ni Nothing) = do
    encodeOnionAddr crypto getRoute (msg,OnionDestination x ni (Just $ routeId $ nodeId ni) )
encodeOnionAddr crypto getRoute (msg,OnionDestination _ ni (Just rid)) = do
    let go route = do
            req <- wrapForRoute crypto msg ni route
            return ( runPut $ putRequest req , nodeAddr $ routeNodeA route)
    m <- {-# SCC "encodeOnionAddr.getRoute" #-} getRoute ni rid
    x <- {-# SCC "encodeOnionAddr.wrapForRoute" #-} mapM go m
    return x

wrapForRoute :: TransportCrypto
                      -> OnionMessage Encrypted
                      -> NodeInfo
                      -> OnionRoute
                      -> IO (OnionRequest N0)
wrapForRoute crypto msg ni r =
    wrapIndirectHops crypto msg ni r $ \nonce saddr msg' -> do
        fwd <- wrapOnion crypto (routeAliasA r)
                                nonce
                                (id2key . nodeId $ routeNodeA r)
                                saddr
                                msg'
        return $ OnionRequest { onionNonce    = nonce
                              , onionForward  = fwd
                              , pathFromOwner = NoReturnPath
                              }

wrapIndirectHops :: TransportCrypto
                      -> OnionMessage Encrypted
                      -> NodeInfo
                      -> OnionRoute
                      -> (Nonce24 -> SockAddr -> Forwarding N2 (OnionMessage Encrypted) -> IO a)
                      -> IO a
wrapIndirectHops crypto msg ni r fin = do
    let nonce = msgNonce msg
    fwd <- wrapOnion crypto (routeAliasB r)
                             nonce
                             (id2key . nodeId $ routeNodeB r)
                             (nodeAddr $ routeNodeC r)
        =<< wrapOnion crypto (routeAliasC r)
                             nonce
                             (id2key . nodeId $ routeNodeC r)
                             (nodeAddr ni)
                             (NotForwarded msg)
    fin nonce (nodeAddr $ routeNodeB r) fwd

unwrapAnnounceResponse :: Maybe NodeId -> NodeInfo -> AnnounceResponse -> ([NodeInfo], [Rendezvous], Maybe Nonce32)
unwrapAnnounceResponse alias ni (AnnounceResponse is_stored (SendNodes ns0)) | let ns = map udpNodeInfo ns0
    = case is_stored of
        NotStored n32    -> ( ns , []                                                        , Just n32)
        SendBackKey k    -> ( ns , [Rendezvous k ni]                                         , Nothing )
        Acknowledged n32 -> ( ns , maybeToList $ fmap (\k -> Rendezvous (id2key k) ni) alias , Just n32)