ftnet_utils/
protocol.rs

1/// why are we handling protocols ourselves and not using the built-in APNS feature?
2/// ================================================================================
3///
4/// first, I would re-emphasize that we could have used APNS feature of iroh[1], they have built
5/// in protocol handling support. but it does not work because if you want to use more than one
6/// protocol, you have to create more than one connection with the peer.
7///
8/// [1]: https://docs.rs/iroh/latest/iroh/endpoint/struct.Builder.html#method.alpns
9///
10/// why would we want that? say a peer wants to do multiple types of things at the same time. for
11/// example, do a ping to check if connection is open, or to send both http and tcp proxy at the
12/// same time. consider I am on call with you but also browsing a folder you have shared.
13///
14/// from the docs it is not clear if creating another connection, after one connection is already
15/// established is a cheap operation or not. in my opinion, it cannot be cheap because ALPN is used
16/// as part of TLS connection handshake process.
17///
18/// this is how the `client hello` message looks like during initial TLS connection handshake:
19///
20/// > Handshake Type: Client Hello (1)
21/// >  Length: 141
22/// >  Version: TLS 1.2 (0x0303)
23/// >  Random: dd67b5943e5efd0740519f38071008b59efbd68ab3114587...
24/// >  Session ID Length: 0
25/// >  Cipher Suites Length: 10
26/// >  Cipher Suites (5 suites)
27/// >  Compression Methods Length: 1
28/// >  Compression Methods (1 method)
29/// >  Extensions Length: 90
30/// >  [other extensions omitted]
31/// >  Extension: application_layer_protocol_negotiation (len=14)
32/// >      Type: application_layer_protocol_negotiation (16)
33/// >      Length: 14
34/// >      ALPN Extension Length: 12
35/// >      ALPN Protocol
36/// >          ALPN string length: 2
37/// >          ALPN Next Protocol: h2
38/// >          ALPN string length: 8
39/// >          ALPN Next Protocol: http/1.1
40///
41/// as you see, the ALPN is part of the `client hello` message, and it is sent during the initial
42/// connection handshake. so if we want to use more than one protocol, we have to do one more
43/// `client hello` hand-shake proces.
44///
45/// so we are using multiple [bidirectional][3] streams over a single connection. each new stream
46/// con be used for a same or different protocol.
47///
48/// [3]: https://docs.rs/iroh/latest/iroh/endpoint/struct.Connection.html#method.open_bi
49///
50/// note: this is not a settled decision. if we are doing audio video streaming, we may not get the
51/// optimal performance, and we may have to use multiple connections; this approach is to be
52/// verified in the future.
53///
54/// the protocol "protocol"
55/// =======================
56///
57/// the protocol: the peer / side that wants to communicate will be considered the "client", and
58/// will initiate the bidirectional stream using `iroh::Connection::open_bi()` method. the server
59/// will have an infinite loop to accept incoming bidirectional streams. for the loop to end, the
60/// client must send a "quit" message and wait for ack from the server before closing the connection.
61///
62/// the bidirectional stream will contain new line terminal JSON text indicating the protocol, and
63/// the rest of the message will be handled by the protocol-specific handler.
64///
65/// the protocol JSON line will be called header line, or stream header.
66///
67/// the stream header can contain protocol-specific information also, e.g., the request to proxy to
68/// a server may include information about the server to proxy to in the protocol header. so that
69/// the lower level protocol handler need not worry about further ways to extract protocol-specific
70/// data.
71///
72/// security philosophy: more protocols, more liabilities
73/// =====================================================
74///
75/// the goal of the FTNet is to make sure there are only a few protocols. all protocol
76/// handlers are security risk, they are written in Rust, possibly using C and other libraries.
77/// their code has to be reviewed for potential security issues.
78///
79/// this is why fastn is a full stack web application. fastn programs are compiled in JS code, and
80/// in future to webassembly, and JS engines have decent security sandbox. we do not allow npm/deno
81/// etc., and only run the most sandboxed, browser like JS code. fastn applications can also use
82/// webassembly compiled code, which again is sandboxed.
83#[derive(Debug, serde::Serialize, serde::Deserialize)]
84pub enum Protocol {
85    /// client can send this message to check if the connection is open / healthy.
86    Ping,
87    /// client may not be using NTP, or may only have p2p access and no other internet access, in
88    /// which case it can ask for the time from the peers and try to create a consensus.
89    WhatTimeIsIt,
90    /// client is done and want to end close the connection
91    Quit,
92    /// connect with the identity server. this means connect with the fastn service as part of the
93    /// identity server.
94    Identity,
95    /// client wants to make an HTTP request to a device whose ID is specified. note that the exact
96    /// ip:port is not known to peers, they only the "device id" for the service. server will figure
97    /// out the ip:port from the device id.
98    Http {
99        id: String,
100    },
101    /// if the client wants their traffic to route via this server, they can send this. for this to
102    /// work, the person owning the device must have created a SOCKS5 device, and allowed this peer
103    /// to access it.
104    Socks5 {
105        id: String,
106    },
107    Tcp {
108        id: String,
109    },
110    // TODO: RTP/"RTCP" for audio video streaming
111}
112
113/// Iroh supports multiple protocols, and we do need multiple protocols, lets say one for proxying
114/// TCP connection, another for proxying HTTP connection, and so on. But if we use different APNS
115/// to handle them, we will end up creating more connections than minimally required (one connection
116/// can only talk one APNS). So, we use a single APNS for all the protocols, and we use the first
117/// line of the input to determine the protocol.
118pub const APNS_IDENTITY: &[u8] = b"/FTNet/identity/0.1";