UNPKG

7.52 kBMarkdownView Raw
1# multiserver
2
3A single interface that can work with multiple protocols,
4and multiple transforms of those protocols (eg, security layer)
5
6## address format
7
8Addresses describe everything needed to connect to a peer.
9each address is divided into protocol sections separated by `~`.
10Each protocol section is divided itself by `:`. A protocol section
11starts with a name for that protocol, and then whatever arguments
12that protocol needs.
13
14For example, the address for my ssb pubserver is:
15```
16net:wx.larpa.net:8008~shs:DTNmX+4SjsgZ7xyDh5xxmNtFqa6pWi5Qtw7cE8aR9TQ=
17```
18That says use the `net` protocol (TCP) to connect to the domain `wx.larpa.net`
19on port `8008`, and then encrypt the session using `shs` ([secret-handshake](https://github.com/auditdrivencrypto/secret-handshake))
20to the public key `DTNmX+4SjsgZ7xyDh5xxmNtFqa6pWi5Qtw7cE8aR9TQ=`.
21
22Usually, the first section is a network protocol, and the rest are transforms,
23such as encryption or compression.
24
25Multiserver makes it easy to use multiple protocols at once. For example,
26my pub server _also_ supports `shs` over websockets.
27
28So, this is another way to connect:
29
30```
31wss://wx.larpa.net~shs:DTNmX+4SjsgZ7xyDh5xxmNtFqa6pWi5Qtw7cE8aR9TQ=
32```
33
34if your server supports multiple protocols, you can concatenate addresses with `;`
35and multiserver will connect to the first address it understands.
36
37```
38net:wx.larpa.net:8008~shs:DTNmX+4SjsgZ7xyDh5xxmNtFqa6pWi5Qtw7cE8aR9TQ=;wss://wx.larpa.net~shs:DTNmX+4SjsgZ7xyDh5xxmNtFqa6pWi5Qtw7cE8aR9TQ=
39```
40This means use net, or wss. In some contexts, you might have a peer that understands
41websockets but not net (for example a browser), as long as a server speaks at least
42one protocol that a peer can understand, then they can communicate.
43
44### net
45
46TCP is a `net:{host}:{port}` port is not optional.
47
48### ws
49
50WebSockets `ws://{host}:{port}?` port defaults to 80 if not provided.
51
52WebSockets over https is `wss://{host}:{port}?` where port is
53443 if not provided.
54
55### onion
56
57Connect over tor using local proxy (9050). Onion is `onion:{host}:{port}` port is not optional.
58
59### reactnative-channel
60
61The [multiserver-rn-channel](http://npm.im/multiserver-rn-channel) module implementes
62a multiserver protocol for use inbetween the reactnative nodejs process and browser process.
63
64### shs
65
66Secret-handshake is `shs:{public_key}:{seed}?`. `seed` is used to create
67a one-time shared private key, that may enable a special access.
68For example, you'll see that ssb invite codes have shs with two sections
69following. Normally, only a single argument (the remote public key) is necessary.
70
71### combined
72
73a network protocol is combined with 1 or more transform protocols,
74for example: `net:{host}:{port}~shs:{key}`
75
76### multi
77
78A server that runs multiple protocols on different ports can simply join them
79with `;` and clients should connect to their preferred protocol.
80clients may try multiple protocols on the same server before giving up,
81but generally it's unlikely that protocols should not fail independently
82(unless there is a bug in one protocol).
83
84an example of a valid multiprotocol:
85`net:{host}:{port}~shs:{key};ws:{host}:{port}~shs:{key}`
86
87
88
89### TODO
90
91A short list of other protocols which could be implemented:
92
93* cjdns
94* other encryption protocols...
95
96## motivation
97
98Developing a p2p system is hard. especially hard is upgrading protocol layers.
99The contemporary approach is to [update code via a backdoor](https://whispersystems.org/blog/the-ecosystem-is-moving/),
100but as easily as security can be added, it can be taken away. We need an approach
101to upgrading that is itself decentralized, and also does not accumulate legacy baggage.
102after upgrading past a version of the protocol, the system should be able to discard that
103without a trace.
104
105Traditionally, protocol versions are upgraded by negioating the version used in a handshake.
106But, how do you upgrade the handshake? You can't. This also tends to accumulate legacy, because
107you never know if you'll meet an old peer.
108
109Some HTTP APIs provide upgradability a better, simpler way.
110By putting a version number within the url. A new version of
111the API can then be used without touching the old one at all.
112
113I propose to adapt this approach to lower level protocols.
114Do not negioate versions/ciphersuits in the handshake.
115Instead, run multiple protocols at once, and "lookup" which
116versions a peer supports currently. Most p2p systems have
117some sort of lookup system to find peers _anyway_
118(might be DHT, a tracker server, or gossip),
119just put version information in there.
120
121There are two main situations where I expect this to be useful:
122upgrading ciphers and bridging across enviroments that are
123otherwise cannot talk to each other (web browser to desktop)
124
125### upgrade
126
127If a peer wants to upgrade from *weak* protocol
128to a *strong* one, they simply start serving *strong* via another port,
129and advertise that in the lookup system.
130Now peers that have support for *strong* can connect via that protocol.
131
132Once most peers have upgraded to strong, support for *weak* can be discontinued.
133
134### bridging
135
136Regular servers can do TCP. Desktop clients can speak TCP,
137but can't create TCP servers reliably. Browsers can
138use WebSockets and WebRTC. WebRTC gives you p2p, but
139needs an introducer. Another option is [utp](https://github.com/mafintosh/utp-native)
140- probably the most convienent, because it doesn't need an introducer
141on _every connection_ (but it does require some bootstrapping),
142but that doesn't work in the browser either.
143
144``` js
145var MultiServer = require('multiserver')
146
147var ms = MultiServer([
148 require('multiserver/plugins/net')({port: 1234}),
149 require('multiserver/plugins/ws')({port: 2345})
150])
151
152//start a server (for both protocols!)
153//returns function to close the server.
154var close = ms.server(function (stream) {
155 //handle incoming connection
156})
157
158//connect to a protocol. uses whichever
159//handler understands the address (in this case, websockets)
160var abort = ms.client('ws://localhost:1234', function (err, stream) {
161 //...
162})
163
164//at any time abort() can be called to cancel the connection attempt.
165//if it's called after the connection is established, it will
166//abort the stream.
167```
168
169### example - server with two security protocols
170
171This is just how some services (eg, github) have an API version
172in their URL scheme. It is now easy to use two different
173versions in parallel. later, they can close down the old API.
174``` js
175var MultiServer = require('multiserver')
176var ms = MultiServer([
177 [ //net + secret-handshake
178 require('multiserver/plugins/net')({port: 3333}),
179 require('secret-handshake-multiserver')({
180 keys: //keypair
181 appKey: //application key
182 auth: //auth function (only needed for server)
183 }),
184 ],
185 [ //net + secret-handshake2
186 //(not implemented yet, but incompatible with shs)
187 require('multiserver/plugins/net')({port: 4444}),
188 require('secret-handshake2-multiserver')({
189 keys: //keypair
190 appKey: //application key
191 auth: //auth function (only needed for server)
192 }),
193 ]
194]
195
196console.log(ms.stringify())
197
198//=> net:<host>:3333~shs:<key>;net:<host>:4444~shs2:<key>
199
200//run two servers on two ports.
201//newer peers can connect directly to 4444 and use shs2.
202//this means the protocol can be _completely_ upgraded.
203ms.server(function (stream) {
204
205})
206
207//connect to legacy protocol
208ms.client('net:<host>:3333~shs:<key>', function (err, stream) {
209 //...
210})
211
212//connect to modern protocol
213ms.client('net:<host>:4444~shs2:<key>', function (err, stream) {
214 //...
215})
216
217```
218
219## License
220
221MIT
222