summaryrefslogtreecommitdiff
path: root/src/Network/Tox
diff options
context:
space:
mode:
Diffstat (limited to 'src/Network/Tox')
-rw-r--r--src/Network/Tox/Onion/Transport.hs73
-rw-r--r--src/Network/Tox/Relay.hs15
-rw-r--r--src/Network/Tox/TCP.hs75
-rw-r--r--src/Network/Tox/Transport.hs2
4 files changed, 134 insertions, 31 deletions
diff --git a/src/Network/Tox/Onion/Transport.hs b/src/Network/Tox/Onion/Transport.hs
index 0cb03718..8918f913 100644
--- a/src/Network/Tox/Onion/Transport.hs
+++ b/src/Network/Tox/Onion/Transport.hs
@@ -44,14 +44,18 @@ module Network.Tox.Onion.Transport
44 , OnionRoute(..) 44 , OnionRoute(..)
45 , N0 45 , N0
46 , N1 46 , N1
47 , N2
47 , N3 48 , N3
48 , onionKey 49 , onionKey
49 , onionAliasSelector 50 , onionAliasSelector
50 , selectAlias 51 , selectAlias
51 , RouteId(..) 52 , RouteId(..)
52 , routeId 53 , routeId
53 , rewrap
54 , putRequest 54 , putRequest
55 , wrapForRoute
56 , wrapSymmetric
57 , wrapOnion
58 , wrapOnionPure
55 ) where 59 ) where
56 60
57import Network.Address (fromSockAddr,toSockAddr,setPort,either4or6,sockAddrPort) 61import Network.Address (fromSockAddr,toSockAddr,setPort,either4or6,sockAddrPort)
@@ -91,6 +95,7 @@ import DPut
91import DebugTag 95import DebugTag
92import Data.Word64Map (fitsInInt) 96import Data.Word64Map (fitsInInt)
93import Data.Bits (shiftR,shiftL) 97import Data.Bits (shiftR,shiftL)
98import qualified Rank2
94 99
95type HandleLo a = Maybe (Either String (ByteString, SockAddr)) -> IO a 100type HandleLo a = Maybe (Either String (ByteString, SockAddr)) -> IO a
96 101
@@ -124,6 +129,26 @@ deriving instance ( Show (f (AnnounceRequest, Nonce8))
124 , Show (f DataToRoute) 129 , Show (f DataToRoute)
125 ) => Show (OnionMessage f) 130 ) => Show (OnionMessage f)
126 131
132instance Data (OnionMessage Encrypted) where
133 gfoldl f z txt = z (either error id . S.decode) `f` S.encode txt
134 toConstr _ = error "OnionMessage.toConstr"
135 gunfold _ _ = error "OnionMessage.gunfold"
136#if MIN_VERSION_base(4,2,0)
137 dataTypeOf _ = mkNoRepType "Network.Tox.Onion.Transport.OnionMessage"
138#else
139 dataTypeOf _ = mkNorepType "Network.Tox.Onion.Transport.OnionMessage"
140#endif
141
142instance Rank2.Functor OnionMessage where
143 f <$> m = mapPayload (Proxy :: Proxy Serialize) f m
144
145instance Payload Serialize OnionMessage where
146 mapPayload _ f (OnionAnnounce a) = OnionAnnounce (fmap f a)
147 mapPayload _ f (OnionAnnounceResponse n8 n24 a) = OnionAnnounceResponse n8 n24 (f a)
148 mapPayload _ f (OnionToRoute k a) = OnionToRoute k a
149 mapPayload _ f (OnionToRouteResponse a) = OnionToRouteResponse a
150
151
127msgNonce :: OnionMessage f -> Nonce24 152msgNonce :: OnionMessage f -> Nonce24
128msgNonce (OnionAnnounce a) = asymmNonce a 153msgNonce (OnionAnnounce a) = asymmNonce a
129msgNonce (OnionAnnounceResponse _ n24 _) = n24 154msgNonce (OnionAnnounceResponse _ n24 _) = n24
@@ -274,10 +299,10 @@ encodeOnionAddr crypto getRoute (msg,OnionDestination _ ni (Just rid)) = do
274 return x 299 return x
275 300
276 301
277forwardOnions :: TransportCrypto -> UDPTransport -> (Int -> OnionResponse N1 -> IO ()) {- ^ TCP relay send -} -> UDPTransport 302forwardOnions :: TransportCrypto -> UDPTransport -> (Int -> OnionMessage Encrypted -> IO ()) {- ^ TCP relay send -} -> UDPTransport
278forwardOnions crypto udp sendTCP = udp { awaitMessage = forwardAwait crypto udp sendTCP } 303forwardOnions crypto udp sendTCP = udp { awaitMessage = forwardAwait crypto udp sendTCP }
279 304
280forwardAwait :: TransportCrypto -> UDPTransport -> (Int -> OnionResponse N1 -> IO ()) {- ^ TCP relay send -} -> HandleLo a -> IO a 305forwardAwait :: TransportCrypto -> UDPTransport -> (Int -> OnionMessage Encrypted -> IO ()) {- ^ TCP relay send -} -> HandleLo a -> IO a
281forwardAwait crypto udp sendTCP kont = do 306forwardAwait crypto udp sendTCP kont = do
282 fix $ \another -> do 307 fix $ \another -> do
283 awaitMessage udp $ \case 308 awaitMessage udp $ \case
@@ -325,6 +350,7 @@ data OnionRequest n = OnionRequest
325 deriving (Eq,Ord) 350 deriving (Eq,Ord)
326 351
327 352
353{-
328instance (Typeable n, Sized (ReturnPath n), Serialize (ReturnPath n) 354instance (Typeable n, Sized (ReturnPath n), Serialize (ReturnPath n)
329 , Serialize (Forwarding (ThreeMinus n) (OnionMessage Encrypted)) 355 , Serialize (Forwarding (ThreeMinus n) (OnionMessage Encrypted))
330 ) => Data (OnionRequest n) where 356 ) => Data (OnionRequest n) where
@@ -336,6 +362,8 @@ instance (Typeable n, Sized (ReturnPath n), Serialize (ReturnPath n)
336#else 362#else
337 dataTypeOf _ = mkNorepType "Network.Tox.Onion.Transport.OnionRequest" 363 dataTypeOf _ = mkNorepType "Network.Tox.Onion.Transport.OnionRequest"
338#endif 364#endif
365-}
366
339 367
340instance (Typeable n, Serialize (ReturnPath n)) => Data (OnionResponse n) where 368instance (Typeable n, Serialize (ReturnPath n)) => Data (OnionResponse n) where
341 gfoldl f z txt = z (either error id . S.decode) `f` S.encode txt 369 gfoldl f z txt = z (either error id . S.decode) `f` S.encode txt
@@ -397,7 +425,17 @@ instance (Sized (ReturnPath n)) => Sized (OnionResponse (S n)) where
397 425
398data Addressed a = Addressed { sockAddr :: SockAddr, unaddressed :: a } 426data Addressed a = Addressed { sockAddr :: SockAddr, unaddressed :: a }
399 | TCPIndex { tcpIndex :: Int, unaddressed :: a } 427 | TCPIndex { tcpIndex :: Int, unaddressed :: a }
400 deriving (Eq,Show) 428 deriving (Eq,Ord,Show)
429
430instance (Typeable a, Serialize a) => Data (Addressed a) where
431 gfoldl f z a = z (either error id . S.decode) `f` S.encode a
432 toConstr _ = error "Addressed.toConstr"
433 gunfold _ _ = error "Addressed.gunfold"
434#if MIN_VERSION_base(4,2,0)
435 dataTypeOf _ = mkNoRepType "Network.Tox.Onion.Transport.Addressed"
436#else
437 dataTypeOf _ = mkNorepType "Network.Tox.Onion.Transport.Addressed"
438#endif
401 439
402instance Sized a => Sized (Addressed a) where 440instance Sized a => Sized (Addressed a) where
403 size = case size :: Size a of 441 size = case size :: Size a of
@@ -434,6 +472,10 @@ addrToIndex _ = 0
434indexToAddr :: Int -> SockAddr 472indexToAddr :: Int -> SockAddr
435indexToAddr x = SockAddrInet6 0 0 (fromIntegral x, fromIntegral (x `shiftR` 32),0,0) 0 473indexToAddr x = SockAddrInet6 0 0 (fromIntegral x, fromIntegral (x `shiftR` 32),0,0) 0
436 474
475-- Note, toxcore would check an address family byte here to detect a TCP-bound
476-- packet, but we instead use the IPv6 id and rely on the port number being
477-- zero. Since it will be symmetrically encrypted for our eyes only, it's not
478-- important to conform on this point.
437instance Serialize a => Serialize (Addressed a) where 479instance Serialize a => Serialize (Addressed a) where
438 get = do saddr <- getForwardAddr 480 get = do saddr <- getForwardAddr
439 a <- get 481 a <- get
@@ -549,6 +591,7 @@ instance (Serialize (Encrypted (Addressed (Forwarding n msg)))) => Serialize (Fo
549 get = Forwarding <$> getPublicKey <*> get 591 get = Forwarding <$> getPublicKey <*> get
550 put (Forwarding k x) = putPublicKey k >> put x 592 put (Forwarding k x) = putPublicKey k >> put x
551 593
594{-
552rewrap :: (ThreeMinus n ~ S (ThreeMinus (S n)), 595rewrap :: (ThreeMinus n ~ S (ThreeMinus (S n)),
553 Serialize (ReturnPath n), 596 Serialize (ReturnPath n),
554 Serialize 597 Serialize
@@ -565,6 +608,7 @@ rewrap crypto saddr (OnionRequest nonce msg rpath) = do
565 Addressed dst msg' 608 Addressed dst msg'
566 -> Right (OnionRequest nonce msg' $ wrapSymmetric sym snonce saddr rpath, dst) 609 -> Right (OnionRequest nonce msg' $ wrapSymmetric sym snonce saddr rpath, dst)
567 _ -> Left "Onion forward to TCP client?" 610 _ -> Left "Onion forward to TCP client?"
611-}
568 612
569handleOnionRequest :: forall a proxy n. 613handleOnionRequest :: forall a proxy n.
570 ( LessThanThree n 614 ( LessThanThree n
@@ -584,7 +628,6 @@ handleOnionRequest proxy crypto saddr udp kont (OnionRequest nonce msg rpath) =
584 628
585 case peeled of 629 case peeled of
586 Left e -> do 630 Left e -> do
587 -- todo report encryption error
588 dput XOnion $ unwords [ "peelOnion:", show n, showDestination, e] 631 dput XOnion $ unwords [ "peelOnion:", show n, showDestination, e]
589 kont 632 kont
590 Right (Addressed dst msg') -> do 633 Right (Addressed dst msg') -> do
@@ -617,7 +660,7 @@ handleOnionResponse :: (KnownPeanoNat n, Sized (ReturnPath n), Serialize (Return
617 -> TransportCrypto 660 -> TransportCrypto
618 -> SockAddr 661 -> SockAddr
619 -> UDPTransport 662 -> UDPTransport
620 -> (Int -> OnionResponse N1 -> IO ()) -- ^ TCP-relay onion send. 663 -> (Int -> OnionMessage Encrypted -> IO ()) -- ^ TCP-relay onion send.
621 -> IO a 664 -> IO a
622 -> OnionResponse (S n) 665 -> OnionResponse (S n)
623 -> IO a 666 -> IO a
@@ -633,10 +676,9 @@ handleOnionResponse proxy crypto saddr udp sendTCP kont (OnionResponse path msg)
633 sendMessage udp dst (runPut $ putResponse $ OnionResponse path' msg) 676 sendMessage udp dst (runPut $ putResponse $ OnionResponse path' msg)
634 kont 677 kont
635 Right (TCPIndex dst path') -> do 678 Right (TCPIndex dst path') -> do
636 -- This should only occur for OnionResponse N1 679 case peanoVal path' of
637 case gcast (OnionResponse path' msg) of 680 0 -> sendTCP dst msg
638 Just supported -> sendTCP dst supported 681 n -> dput XUnexpected $ "handleOnionResponse: TCP-bound OnionResponse" ++ show n ++ " not supported."
639 Nothing -> dput XUnexpected "handleOnionResponse: TCP-bound message not supported."
640 kont 682 kont
641 683
642 684
@@ -900,6 +942,17 @@ wrapOnion crypto skey nonce destkey saddr fwd = do
900 secret <- lookupSharedSecret crypto skey destkey nonce 942 secret <- lookupSharedSecret crypto skey destkey nonce
901 return $ Forwarding (toPublic skey) $ ToxCrypto.encrypt secret plain 943 return $ Forwarding (toPublic skey) $ ToxCrypto.encrypt secret plain
902 944
945wrapOnionPure :: Serialize (Forwarding n msg) =>
946 SecretKey
947 -> ToxCrypto.State
948 -> SockAddr
949 -> Forwarding n msg
950 -> Forwarding (S n) msg
951wrapOnionPure skey st saddr fwd = Forwarding (toPublic skey) (ToxCrypto.encrypt st plain)
952 where
953 plain = encodePlain $ Addressed saddr fwd
954
955
903 956
904-- TODO 957-- TODO
905-- Two types of packets may be sent to Rendezvous via OnionToRoute requests. 958-- Two types of packets may be sent to Rendezvous via OnionToRoute requests.
diff --git a/src/Network/Tox/Relay.hs b/src/Network/Tox/Relay.hs
index 7af14ed6..2842fcc2 100644
--- a/src/Network/Tox/Relay.hs
+++ b/src/Network/Tox/Relay.hs
@@ -201,22 +201,23 @@ handlePacket cons thistcp me crypto sendOnion sendToMe session = \case
201 sendToThem' <- IntMap.lookup i $ associated mySession 201 sendToThem' <- IntMap.lookup i $ associated mySession
202 return $ sendToThem' $ RelayData bs 202 return $ sendToThem' $ RelayData bs
203 203
204 OnionPacket p -> do 204 OnionPacket n24 (Addressed addr req) -> do
205 mp <- rewrap crypto (TCPIndex thistcp) p 205 rpath <- atomically $ do
206 case mp of 206 sym <- transportSymmetric crypto
207 Right (p',addr) -> sendOnion addr p' 207 n <- transportNewNonce crypto
208 _ -> return () 208 return $ wrapSymmetric sym n (TCPIndex thistcp) NoReturnPath
209 sendOnion addr $ OnionRequest n24 req rpath
209 210
210 _ -> return () 211 _ -> return ()
211 212
212 213
213sendTCP_ :: TVar (IntMap (RelayPacket -> IO ())) -> Int -> OnionResponse N1 -> IO () 214sendTCP_ :: TVar (IntMap (RelayPacket -> IO ())) -> Int -> OnionMessage Encrypted -> IO ()
214sendTCP_ st addr x = join $ atomically 215sendTCP_ st addr x = join $ atomically
215 $ IntMap.lookup addr <$> readTVar st >>= \case 216 $ IntMap.lookup addr <$> readTVar st >>= \case
216 Nothing -> return $ return () 217 Nothing -> return $ return ()
217 Just send -> return $ send $ OnionPacketResponse x 218 Just send -> return $ send $ OnionPacketResponse x
218 219
219tcpRelay :: SockAddr -> (SockAddr -> OnionRequest N1 -> IO ()) -> IO (ServerHandle, Int -> OnionResponse N1 -> IO ()) 220tcpRelay :: SockAddr -> (SockAddr -> OnionRequest N1 -> IO ()) -> IO (ServerHandle, Int -> OnionMessage Encrypted -> IO ())
220tcpRelay udp_addr sendOnion = do 221tcpRelay udp_addr sendOnion = do
221 crypto <- newCrypto 222 crypto <- newCrypto
222 cons <- newTVarIO Map.empty 223 cons <- newTVarIO Map.empty
diff --git a/src/Network/Tox/TCP.hs b/src/Network/Tox/TCP.hs
index 608becc3..c9c3d9a6 100644
--- a/src/Network/Tox/TCP.hs
+++ b/src/Network/Tox/TCP.hs
@@ -7,6 +7,7 @@ module Network.Tox.TCP where
7import Control.Arrow 7import Control.Arrow
8import Control.Concurrent 8import Control.Concurrent
9import Control.Concurrent.STM 9import Control.Concurrent.STM
10import Control.Monad
10import Crypto.Random 11import Crypto.Random
11import Data.Functor.Contravariant 12import Data.Functor.Contravariant
12import Data.Functor.Identity 13import Data.Functor.Identity
@@ -22,11 +23,12 @@ import DebugTag
22import DPut 23import DPut
23import Network.Address (setPort,PortNumber) 24import Network.Address (setPort,PortNumber)
24import Network.Kademlia.Routing 25import Network.Kademlia.Routing
25import Network.Kademlia.Search 26import Network.Kademlia.Search hiding (sendQuery)
26import Network.QueryResponse 27import Network.QueryResponse
27import Network.QueryResponse.TCP 28import Network.QueryResponse.TCP
28import Network.Tox.DHT.Handlers (toxSpace) 29import Network.Tox.DHT.Handlers (toxSpace)
29import Network.Tox.Onion.Transport (OnionMessage(..),OnionResponse(..),N1) 30import Network.Tox.Onion.Transport hiding (encrypt,decrypt)
31import Network.Tox.Onion.Handlers (unwrapAnnounceResponse)
30import qualified Network.Tox.NodeId as UDP 32import qualified Network.Tox.NodeId as UDP
31 33
32 34
@@ -103,30 +105,77 @@ toxTCP crypto = tcpTransport 30 (tcpStream crypto)
103tcpSpace :: KademliaSpace NodeId NodeInfo 105tcpSpace :: KademliaSpace NodeId NodeInfo
104tcpSpace = contramap udpNodeInfo toxSpace 106tcpSpace = contramap udpNodeInfo toxSpace
105 107
106nodeSearch :: Client err meth tid NodeInfo RelayPacket -> Search NodeId (IP, PortNumber) () NodeInfo NodeInfo 108nodeSearch :: TCPClient err () Nonce8 -> Search NodeId (IP, PortNumber) () NodeInfo NodeInfo
107nodeSearch client = Search 109nodeSearch tcp = Search
108 { searchSpace = tcpSpace 110 { searchSpace = tcpSpace
109 , searchNodeAddress = nodeIP &&& tcpPort 111 , searchNodeAddress = nodeIP &&& tcpPort
110 , searchQuery = getNodes client 112 , searchQuery = getTCPNodes tcp
111 } 113 }
112 114
113getNodes :: Client err meth tid NodeInfo RelayPacket -> NodeId -> NodeInfo -> IO (Maybe ([NodeInfo], [NodeInfo], Maybe ())) 115data TCPClient err meth tid = TCPClient
114getNodes client seeking dst = do 116 { tcpCrypto :: TransportCrypto
115 return Nothing -- TODO 117 , tcpClient :: Client err () tid NodeInfo RelayPacket
118 , tcpGetGateway :: UDP.NodeInfo -> STM (Maybe NodeInfo)
119 }
120
121getTCPNodes :: TCPClient err () Nonce8 -> NodeId -> NodeInfo -> IO (Maybe ([NodeInfo],[NodeInfo],Maybe ()))
122getTCPNodes tcp seeking dst = do
123 r <- getUDPNodes tcp seeking (udpNodeInfo dst)
124 let tcps (ns,_,mb) = (ns',ns',mb)
125 where ns' = do
126 n <- ns
127 [ NodeInfo n (fromIntegral 443) , NodeInfo n (fromIntegral 80) , NodeInfo n (UDP.nodePort n) ]
128 return $ tcps <$> r
129
130getUDPNodes :: TCPClient err () Nonce8 -> NodeId -> UDP.NodeInfo -> IO (Maybe ([UDP.NodeInfo], [UDP.NodeInfo], Maybe ()))
131getUDPNodes tcp seeking dst = do
132 mgateway <- atomically $ tcpGetGateway tcp dst
133 fmap join $ forM mgateway $ \gateway -> do
134 (b,c,n24) <- atomically $ do
135 b <- transportNewKey (tcpCrypto tcp)
136 c <- transportNewKey (tcpCrypto tcp)
137 n24 <- transportNewNonce (tcpCrypto tcp)
138 return (b,c,n24)
139 wrap2 <- lookupNonceFunction (tcpCrypto tcp) b (UDP.id2key $ UDP.nodeId dst)
140 wrap1 <- lookupNonceFunction (tcpCrypto tcp) c (UDP.id2key $ nodeId gateway)
141 wrap0 <- lookupNonceFunction (tcpCrypto tcp) (transportSecret $ tcpCrypto tcp) (UDP.id2key $ UDP.nodeId dst)
142 let meth = MethodSerializer -- MethodSerializer Nonce8 NodeInfo RelayPacket meth AnnounceRequest (Either String AnnounceResponse)
143 { methodTimeout = \tid addr -> return (addr,8000000) -- 8 second timeout
144 , method = () -- meth
145 , wrapQuery = \n8 src dst x ->
146 OnionPacket n24 $ Addressed (UDP.nodeAddr $ udpNodeInfo dst)
147 $ wrapOnionPure b (wrap2 n24) (UDP.nodeAddr $ udpNodeInfo dst)
148 $ wrapOnionPure c (wrap1 n24) (nodeAddr gateway)
149 $ NotForwarded $ encryptPayload (wrap0 n24)
150 $ OnionAnnounce Asymm
151 { senderKey = transportPublic (tcpCrypto tcp)
152 , asymmNonce = n24
153 , asymmData = pure (x,n8)
154 }
155 , unwrapResponse = \case
156 OnionPacketResponse (OnionAnnounceResponse _ n24' r)
157 -> decrypt (wrap0 n24') r >>= decodePlain
158 x -> Left $ "getUDPNodes: unwrapResponse fail " ++ show x
159 }
160 r <- sendQuery (tcpClient tcp) meth (AnnounceRequest zeros32 seeking UDP.zeroID) gateway
161 forM r $ \response -> do
162 let (ns,_,mb) = either (const ([],[],Nothing)) (unwrapAnnounceResponse Nothing dst) $ response
163 return (ns,ns, const () <$> mb)
164
116 165
117handleOOB :: PublicKey -> ByteString -> NodeInfo -> NodeInfo -> IO (Maybe (RelayPacket -> RelayPacket)) 166handleOOB :: PublicKey -> ByteString -> NodeInfo -> NodeInfo -> IO (Maybe (RelayPacket -> RelayPacket))
118handleOOB k bs src dst = do 167handleOOB k bs src dst = do
119 dput XMisc $ "TODO: handleOOB " ++ show src 168 dput XMisc $ "TODO: handleOOB " ++ show src
120 return Nothing 169 return Nothing
121 170
122handle2route :: OnionResponse N1 -> NodeInfo -> NodeInfo -> IO (Maybe (RelayPacket -> RelayPacket)) 171handle2route :: OnionMessage Encrypted -> NodeInfo -> NodeInfo -> IO (Maybe (RelayPacket -> RelayPacket))
123handle2route o src dst = do 172handle2route o src dst = do
124 dput XMisc $ "TODO: handle2route " ++ show src 173 dput XMisc $ "TODO: handle2route " ++ show src
125 return Nothing 174 return Nothing
126 175
127 176
128tcpClient :: TransportCrypto -> IO (Client String () Nonce8 NodeInfo RelayPacket) 177newClient :: TransportCrypto -> IO (Client String () Nonce8 NodeInfo RelayPacket)
129tcpClient crypto = do 178newClient crypto = do
130 net <- toxTCP crypto 179 net <- toxTCP crypto
131 drg <- drgNew 180 drg <- drgNew
132 map_var <- atomically $ newTVar (drg, Data.Word64Map.empty) 181 map_var <- atomically $ newTVar (drg, Data.Word64Map.empty)
@@ -136,8 +185,8 @@ tcpClient crypto = do
136 { classifyInbound = \case 185 { classifyInbound = \case
137 RelayPing n -> IsQuery () n 186 RelayPing n -> IsQuery () n
138 RelayPong n -> IsResponse n 187 RelayPong n -> IsResponse n
139 OnionPacketResponse (OnionResponse _ (OnionAnnounceResponse n8 n24 ciphered)) -> IsResponse n8 188 OnionPacketResponse (OnionAnnounceResponse n8 n24 ciphered) -> IsResponse n8
140 OnionPacketResponse o@(OnionResponse _ (OnionToRouteResponse _)) -> IsUnsolicited $ handle2route o 189 OnionPacketResponse o@(OnionToRouteResponse _) -> IsUnsolicited $ handle2route o
141 OOBRecv k bs -> IsUnsolicited $ handleOOB k bs 190 OOBRecv k bs -> IsUnsolicited $ handleOOB k bs
142 , lookupHandler = \() -> Just MethodHandler 191 , lookupHandler = \() -> Just MethodHandler
143 { methodParse = \(RelayPing n8) -> Right () 192 { methodParse = \(RelayPing n8) -> Right ()
diff --git a/src/Network/Tox/Transport.hs b/src/Network/Tox/Transport.hs
index 0b34e8f8..e79e4d8b 100644
--- a/src/Network/Tox/Transport.hs
+++ b/src/Network/Tox/Transport.hs
@@ -22,7 +22,7 @@ toxTransport ::
22 -> OnionRouter 22 -> OnionRouter
23 -> (PublicKey -> IO (Maybe NodeInfo)) 23 -> (PublicKey -> IO (Maybe NodeInfo))
24 -> UDPTransport 24 -> UDPTransport
25 -> (Int -> OnionResponse N1 -> IO ()) -- ^ TCP-bound callback. 25 -> (Int -> OnionMessage Encrypted -> IO ()) -- ^ TCP-bound callback.
26 -> IO ( Transport String SockAddr (CryptoPacket Encrypted) 26 -> IO ( Transport String SockAddr (CryptoPacket Encrypted)
27 , Transport String NodeInfo (DHTMessage Encrypted8) 27 , Transport String NodeInfo (DHTMessage Encrypted8)
28 , Transport String (OnionDestination RouteId) (OnionMessage Encrypted) 28 , Transport String (OnionDestination RouteId) (OnionMessage Encrypted)