forked from ElementsProject/lightning
-
Notifications
You must be signed in to change notification settings - Fork 0
/
peer_exchange_initmsg.c
303 lines (266 loc) · 8.64 KB
/
peer_exchange_initmsg.c
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
#include "config.h"
#include <bitcoin/chainparams.h>
#include <ccan/io/io.h>
#include <common/dev_disconnect.h>
#include <common/memleak.h>
#include <common/status.h>
#include <common/wire_error.h>
#include <connectd/connectd.h>
#include <connectd/connectd_wiregen.h>
#include <connectd/netaddress.h>
#include <connectd/peer_exchange_initmsg.h>
#include <wire/peer_wire.h>
/* Temporary structure for us to read peer message in */
struct early_peer {
struct daemon *daemon;
/* The ID of the peer */
struct node_id id;
/* Where it's connected to/from. */
struct wireaddr_internal addr;
/* Crypto state for writing/reading peer initmsg */
struct crypto_state cs;
/* Buffer for reading/writing message. */
u8 *msg;
/* Are we connected via a websocket? */
enum is_websocket is_websocket;
bool incoming;
};
static bool contains_common_chain(struct bitcoin_blkid *chains)
{
for (size_t i = 0; i < tal_count(chains); i++) {
if (bitcoin_blkid_eq(&chains[i], &chainparams->genesis_blockhash))
return true;
}
return false;
}
/* Here in case we need to read another message. */
static struct io_plan *read_init(struct io_conn *conn, struct early_peer *peer);
static struct io_plan *peer_init_received(struct io_conn *conn,
struct early_peer *peer)
{
u8 *msg = cryptomsg_decrypt_body(tmpctx, &peer->cs, peer->msg);
u8 *globalfeatures, *features;
struct tlv_init_tlvs *tlvs;
struct wireaddr *remote_addr;
if (!msg)
return io_close(conn);
status_peer_io(LOG_IO_IN, &peer->id, msg);
/* BOLT #1:
*
* A receiving node:
* - upon receiving a message of _odd_, unknown type:
* - MUST ignore the received message.
*/
if (unlikely(is_unknown_msg_discardable(msg)))
return read_init(conn, peer);
if (!fromwire_init(tmpctx, msg, &globalfeatures, &features, &tlvs)) {
status_peer_debug(&peer->id,
"bad fromwire_init '%s', closing",
tal_hex(tmpctx, msg));
return io_close(conn);
}
/* BOLT #1:
* The receiving node:
* ...
* - upon receiving `networks` containing no common chains
* - MAY close the connection.
*/
if (tlvs->networks) {
if (!contains_common_chain(tlvs->networks)) {
status_peer_debug(&peer->id,
"No common chain with this peer '%s', closing",
tal_hex(tmpctx, msg));
msg = towire_warningfmt(NULL, NULL, "No common network");
msg = cryptomsg_encrypt_msg(NULL, &peer->cs, take(msg));
return io_write(conn, msg, tal_count(msg), io_close_cb, NULL);
}
}
/* fetch optional tlv `remote_addr` */
remote_addr = NULL;
/* BOLT #1:
* The receiving node:
* ...
* - MAY use the `remote_addr` to update its `node_announcement`
*/
if (tlvs->remote_addr) {
const u8 *cursor = tlvs->remote_addr;
size_t len = tal_bytelen(tlvs->remote_addr);
remote_addr = tal(peer, struct wireaddr);
if (fromwire_wireaddr(&cursor, &len, remote_addr)) {
switch (remote_addr->type) {
case ADDR_TYPE_IPV4:
case ADDR_TYPE_IPV6:
/* Drop non-public addresses when not testing */
if (!address_routable(remote_addr,
IFDEV(peer->daemon->dev_allow_localhost,
false)))
remote_addr = tal_free(remote_addr);
break;
/* We are only interested in IP addresses */
case ADDR_TYPE_TOR_V2_REMOVED:
case ADDR_TYPE_TOR_V3:
case ADDR_TYPE_DNS:
remote_addr = tal_free(remote_addr);
break;
}
} else
remote_addr = tal_free(remote_addr);
}
/* The globalfeatures field is now unused, but there was a
* window where it was: combine the two. */
features = featurebits_or(tmpctx, take(features), globalfeatures);
/* We can dispose of peer after next call. */
tal_steal(tmpctx, peer);
/* Usually return io_close_taken_fd, but may wait for old peer to
* be disconnected if it's a reconnect. */
return peer_connected(conn, peer->daemon, &peer->id,
&peer->addr,
remote_addr,
&peer->cs,
take(features),
peer->is_websocket,
peer->incoming);
}
static struct io_plan *peer_init_hdr_received(struct io_conn *conn,
struct early_peer *peer)
{
u16 len;
if (!cryptomsg_decrypt_header(&peer->cs, peer->msg, &len))
return io_close(conn);
tal_free(peer->msg);
peer->msg = tal_arr(peer, u8, (u32)len + CRYPTOMSG_BODY_OVERHEAD);
return io_read(conn, peer->msg, tal_count(peer->msg),
peer_init_received, peer);
}
static struct io_plan *read_init(struct io_conn *conn, struct early_peer *peer)
{
/* Free our sent init msg. */
tal_free(peer->msg);
/* BOLT #1:
*
* The receiving node:
* - MUST wait to receive `init` before sending any other messages.
*/
peer->msg = tal_arr(peer, u8, CRYPTOMSG_HDR_SIZE);
return io_read(conn, peer->msg, tal_bytelen(peer->msg),
peer_init_hdr_received, peer);
}
#if DEVELOPER
static struct io_plan *peer_write_postclose(struct io_conn *conn,
struct early_peer *peer)
{
dev_sabotage_fd(io_conn_fd(conn), true);
return read_init(conn, peer);
}
static struct io_plan *peer_write_post_sabotage(struct io_conn *conn,
struct early_peer *peer)
{
dev_sabotage_fd(io_conn_fd(conn), false);
return read_init(conn, peer);
}
#endif
struct io_plan *peer_exchange_initmsg(struct io_conn *conn,
struct daemon *daemon,
const struct feature_set *our_features,
const struct crypto_state *cs,
const struct node_id *id,
const struct wireaddr_internal *addr,
struct oneshot *timeout,
enum is_websocket is_websocket,
bool incoming)
{
/* If conn is closed, forget peer */
struct early_peer *peer = tal(conn, struct early_peer);
struct io_plan *(*next)(struct io_conn *, struct early_peer *);
struct tlv_init_tlvs *tlvs;
peer->daemon = daemon;
peer->id = *id;
peer->addr = *addr;
peer->cs = *cs;
peer->incoming = incoming;
peer->is_websocket = is_websocket;
/* Attach timer to early peer, so it gets freed with it. */
notleak(tal_steal(peer, timeout));
/* BOLT #1:
*
* The sending node:
* - MUST send `init` as the first Lightning message for any
* connection.
* ...
* - SHOULD set `networks` to all chains it will gossip or open
* channels for.
*/
tlvs = tlv_init_tlvs_new(tmpctx);
tlvs->networks = tal_dup_arr(tlvs, struct bitcoin_blkid,
&chainparams->genesis_blockhash, 1, 0);
/* set optional tlv `remote_addr` on incoming IP connections */
tlvs->remote_addr = NULL;
/* BOLT #1:
* The sending node:
* ...
* - SHOULD set `remote_addr` to reflect the remote IP address (and port) of an
* incoming connection, if the node is the receiver and the connection was done
* via IP.
*/
if (incoming
&& addr->itype == ADDR_INTERNAL_WIREADDR
&& !addr->u.wireaddr.is_websocket
&& address_routable(&addr->u.wireaddr.wireaddr, true)) {
switch (addr->u.wireaddr.wireaddr.type) {
case ADDR_TYPE_IPV4:
case ADDR_TYPE_IPV6:
tlvs->remote_addr = tal_arr(tlvs, u8, 0);
towire_wireaddr(&tlvs->remote_addr, &addr->u.wireaddr.wireaddr);
break;
/* Only report IP addresses back for now */
case ADDR_TYPE_TOR_V2_REMOVED:
case ADDR_TYPE_TOR_V3:
case ADDR_TYPE_DNS:
break;
}
}
/* Initially, there were two sets of feature bits: global and local.
* Local affected peer nodes only, global affected everyone. Both were
* sent in the `init` message, but node_announcement only advertized
* globals.
*
* But we didn't have any globals for a long time, and it turned out
* that people wanted us to broadcast local features so they could do
* peer selection. We agreed that the number spaces should be distinct,
* but debate still raged on how to handle them.
*
* Meanwhile, we finally added a global bit to the spec, so now it
* matters. And LND v0.8 decided to make option_static_remotekey a
* GLOBAL bit, not a local bit, so we need to send that as a global
* bit here.
*
* Finally, we agreed that bits below 13 could be put in both, but
* from now on they'll all go in initfeatures. */
peer->msg = towire_init(NULL,
our_features->bits[GLOBAL_INIT_FEATURE],
our_features->bits[INIT_FEATURE],
tlvs);
status_peer_io(LOG_IO_OUT, &peer->id, peer->msg);
peer->msg = cryptomsg_encrypt_msg(peer, &peer->cs, take(peer->msg));
next = read_init;
#if DEVELOPER
switch (dev_disconnect(&peer->id, WIRE_INIT)) {
case DEV_DISCONNECT_BEFORE:
dev_sabotage_fd(io_conn_fd(conn), true);
break;
case DEV_DISCONNECT_AFTER:
next = peer_write_postclose;
break;
case DEV_DISCONNECT_BLACKHOLE:
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Blackhole not supported during handshake");
break;
case DEV_DISCONNECT_NORMAL:
break;
case DEV_DISCONNECT_DISABLE_AFTER:
next = peer_write_post_sabotage;
break;
}
#endif /* DEVELOPER */
return io_write(conn, peer->msg, tal_bytelen(peer->msg), next, peer);
}