forked from ElementsProject/lightning
-
Notifications
You must be signed in to change notification settings - Fork 0
/
connectd.c
2090 lines (1839 loc) · 64.7 KB
/
connectd.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
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*~ Welcome to the connect daemon: maintainer of connectivity!
*
* This is another separate daemon which is responsible for reaching out to
* other peers, and also accepting their incoming connections. It talks to
* them for just long enough to validate their identity using a cryptographic
* handshake, then receive and send supported feature sets; then it hands them
* up to lightningd which will fire up a specific per-peer daemon to talk to
* it.
*/
#include "config.h"
#include <bitcoin/chainparams.h>
#include <ccan/array_size/array_size.h>
#include <ccan/asort/asort.h>
#include <ccan/closefrom/closefrom.h>
#include <ccan/fdpass/fdpass.h>
#include <ccan/noerr/noerr.h>
#include <ccan/tal/str/str.h>
#include <common/bech32.h>
#include <common/bech32_util.h>
#include <common/daemon_conn.h>
#include <common/dev_disconnect.h>
#include <common/ecdh_hsmd.h>
#include <common/gossip_store.h>
#include <common/jsonrpc_errors.h>
#include <common/memleak.h>
#include <common/status.h>
#include <common/subdaemon.h>
#include <common/timeout.h>
#include <common/type_to_string.h>
#include <common/wire_error.h>
#include <connectd/connectd.h>
#include <connectd/connectd_gossipd_wiregen.h>
#include <connectd/connectd_wiregen.h>
#include <connectd/handshake.h>
#include <connectd/multiplex.h>
#include <connectd/netaddress.h>
#include <connectd/onion_message.h>
#include <connectd/peer_exchange_initmsg.h>
#include <connectd/tor.h>
#include <connectd/tor_autoservice.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <signal.h>
#include <sodium.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <wire/wire_io.h>
#include <wire/wire_sync.h>
/*~ We are passed two file descriptors when exec'ed from `lightningd`: the
* first is a connection to `hsmd`, which we need for the cryptographic
* handshake, and the second is to `gossipd`: it gathers network gossip and
* thus may know how to reach certain peers. */
#define HSM_FD 3
#define GOSSIPCTL_FD 4
/* Peers we're trying to reach: we iterate through addrs until we succeed
* or fail. */
struct connecting {
/* daemon->connecting */
struct list_node list;
struct daemon *daemon;
struct io_conn *conn;
/* The ID of the peer (not necessarily unique, in transit!) */
struct node_id id;
/* We iterate through the tal_count(addrs) */
size_t addrnum;
struct wireaddr_internal *addrs;
/* NULL if there wasn't a hint. */
struct wireaddr_internal *addrhint;
/* How far did we get? */
const char *connstate;
/* Accumulated errors */
char *errors;
};
/*~ C programs should generally be written bottom-to-top, with the root
* function at the bottom, and functions it calls above it. That avoids
* us having to pre-declare functions; but in the case of mutual recursion
* pre-declarations are necessary (also, sometimes we do it to avoid making
* a patch hard to review with gratuitous reorganizations). */
static void try_connect_one_addr(struct connecting *connect);
/*~ Some ISP resolvers will reply with a dummy IP to queries that would otherwise
* result in an NXDOMAIN reply. This just checks whether we have one such
* resolver upstream and remembers its reply so we can try to filter future
* dummies out.
*/
static bool broken_resolver(struct daemon *daemon)
{
struct addrinfo *addrinfo;
struct addrinfo hints;
const char *hostname = "nxdomain-test.doesntexist";
int err;
/* If they told us to never do DNS queries, don't even do this one and
* also not if we just say that we don't */
if (!daemon->use_dns || daemon->always_use_proxy) {
daemon->broken_resolver_response = NULL;
return false;
}
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
hints.ai_flags = AI_ADDRCONFIG;
err = getaddrinfo(hostname, tal_fmt(tmpctx, "%d", 42),
&hints, &addrinfo);
/*~ Note the use of tal_dup here: it is a memdup for tal, but it's
* type-aware so it's less error-prone. */
if (err == 0) {
daemon->broken_resolver_response
= tal_dup(daemon, struct sockaddr, addrinfo->ai_addr);
freeaddrinfo(addrinfo);
} else
daemon->broken_resolver_response = NULL;
return daemon->broken_resolver_response != NULL;
}
/*~ Here we see our first tal destructor: in this case the 'struct connect'
* simply removes itself from the list of all 'connect' structs. */
static void destroy_connecting(struct connecting *connect)
{
/*~ We don't *need* the list_head here; `list_del(&connect->list)`
* would work. But we have access to it, and `list_del_from()` is
* clearer for readers, and also does a very brief sanity check that
* the list isn't already empty which catches a surprising number of
* bugs! (If CCAN_LIST_DEBUG were defined, it would perform a
* complete list traverse to check it was in the list before
* deletion). */
list_del_from(&connect->daemon->connecting, &connect->list);
}
/*~ Most simple search functions start with find_; in this case, search
* for an existing attempt to connect the given peer id. */
static struct connecting *find_connecting(struct daemon *daemon,
const struct node_id *id)
{
struct connecting *i;
/*~ Note the node_id_eq function: this is generally preferred over
* doing a memcmp() manually, as it is both typesafe and can handle
* any padding which the C compiler is allowed to insert between
* members (unnecessary here, as there's no padding in a `struct
* node_id`). */
list_for_each(&daemon->connecting, i, list)
if (node_id_eq(id, &i->id))
return i;
return NULL;
}
/*~ Once we've connected out, we disable the callback which would cause us to
* to try the next address. */
static void connected_out_to_peer(struct daemon *daemon,
struct io_conn *conn,
const struct node_id *id)
{
struct connecting *connect = find_connecting(daemon, id);
/* We allocate 'conn' as a child of 'connect': we don't want to free
* it just yet though. tal_steal() it onto the permanent 'daemon'
* struct. */
tal_steal(daemon, conn);
/* We only allow one outgoing attempt at a time */
assert(connect->conn == conn);
/* Don't call destroy_io_conn, since we're done. */
io_set_finish(conn, NULL, NULL);
/* Now free the 'connecting' struct. */
tal_free(connect);
}
/*~ Once they've connected in, stop trying to connect out (if we were). */
static void peer_connected_in(struct daemon *daemon,
struct io_conn *conn,
const struct node_id *id)
{
struct connecting *connect = find_connecting(daemon, id);
if (!connect)
return;
/* Don't call destroy_io_conn, since we're done. */
io_set_finish(connect->conn, NULL, NULL);
/* Now free the 'connecting' struct since we succeeded. */
tal_free(connect);
}
/*~ When we free a peer, we remove it from the daemon's hashtable.
* We also call this manually if we want to elegantly drain peer's
* queues. */
void destroy_peer(struct peer *peer)
{
assert(!peer->draining);
if (!peer_htable_del(peer->daemon->peers, peer))
abort();
/* Tell gossipd to stop asking this peer gossip queries */
daemon_conn_send(peer->daemon->gossipd,
take(towire_gossipd_peer_gone(NULL, &peer->id)));
/* Tell lightningd it's really disconnected */
daemon_conn_send(peer->daemon->master,
take(towire_connectd_peer_disconnect_done(NULL,
&peer->id,
peer->counter)));
/* This makes multiplex.c routines not feed us more, but
* *also* means that if we're freed directly, the ->to_peer
* destructor won't call drain_peer(). */
peer->draining = true;
}
/*~ This is where we create a new peer. */
static struct peer *new_peer(struct daemon *daemon,
const struct node_id *id,
const struct crypto_state *cs,
const u8 *their_features,
struct io_conn *conn STEALS,
int *fd_for_subd)
{
struct peer *peer = tal(daemon, struct peer);
peer->daemon = daemon;
peer->id = *id;
peer->counter = daemon->connection_counter++;
peer->cs = *cs;
peer->subds = tal_arr(peer, struct subd *, 0);
peer->peer_in = NULL;
peer->sent_to_peer = NULL;
peer->urgent = false;
peer->draining = false;
peer->peer_outq = msg_queue_new(peer, false);
peer->last_recv_time = time_now();
#if DEVELOPER
peer->dev_writes_enabled = NULL;
peer->dev_read_enabled = true;
#endif
peer->to_peer = conn;
/* Now we own it */
tal_steal(peer, peer->to_peer);
peer_htable_add(daemon->peers, peer);
tal_add_destructor(peer, destroy_peer);
return peer;
}
/*~ Note the lack of static: this is called by peer_exchange_initmsg.c once the
* INIT messages are exchanged, and also by the retry code above. */
struct io_plan *peer_connected(struct io_conn *conn,
struct daemon *daemon,
const struct node_id *id,
const struct wireaddr_internal *addr,
const struct wireaddr *remote_addr,
struct crypto_state *cs,
const u8 *their_features TAKES,
bool incoming)
{
u8 *msg;
struct peer *peer;
int unsup;
size_t depender, missing;
int subd_fd;
bool option_gossip_queries;
/* We remove any previous connection immediately, on the assumption it's dead */
peer = peer_htable_get(daemon->peers, id);
if (peer)
tal_free(peer);
/* We promised we'd take it by marking it TAKEN above; prepare to free it. */
if (taken(their_features))
tal_steal(tmpctx, their_features);
/* BOLT #1:
*
* The receiving node:
* ...
* - upon receiving unknown _odd_ feature bits that are non-zero:
* - MUST ignore the bit.
* - upon receiving unknown _even_ feature bits that are non-zero:
* - MUST close the connection.
*/
unsup = features_unsupported(daemon->our_features, their_features,
INIT_FEATURE);
if (unsup != -1) {
status_peer_unusual(id, "Unsupported feature %u", unsup);
msg = towire_warningfmt(NULL, NULL, "Unsupported feature %u",
unsup);
msg = cryptomsg_encrypt_msg(NULL, cs, take(msg));
return io_write_wire(conn, take(msg), io_close_cb, NULL);
}
if (!feature_check_depends(their_features, &depender, &missing)) {
status_peer_unusual(id, "Feature %zu requires feature %zu",
depender, missing);
msg = towire_warningfmt(NULL, NULL,
"Feature %zu requires feature %zu",
depender, missing);
msg = cryptomsg_encrypt_msg(NULL, cs, take(msg));
return io_write_wire(conn, take(msg), io_close_cb, NULL);
}
/* We've successfully connected. */
if (incoming)
peer_connected_in(daemon, conn, id);
else
connected_out_to_peer(daemon, conn, id);
if (find_connecting(daemon, id))
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"After %s connection on %p, still trying to connect conn %p?",
incoming ? "incoming" : "outgoing",
conn, find_connecting(daemon, id)->conn);
/* This contains the per-peer state info; gossipd fills in pps->gs */
peer = new_peer(daemon, id, cs, their_features, conn, &subd_fd);
/* Only takes over conn if it succeeds. */
if (!peer)
return io_close(conn);
/* Tell gossipd it can ask query this new peer for gossip */
option_gossip_queries = feature_negotiated(daemon->our_features,
their_features,
OPT_GOSSIP_QUERIES);
msg = towire_gossipd_new_peer(NULL, id, option_gossip_queries);
daemon_conn_send(daemon->gossipd, take(msg));
/* Get ready for streaming gossip from the store */
setup_peer_gossip_store(peer, daemon->our_features, their_features);
/* Create message to tell master peer has connected. */
msg = towire_connectd_peer_connected(NULL, id, peer->counter,
addr, remote_addr,
incoming, their_features);
/*~ daemon_conn is a message queue for inter-daemon communication: we
* queue up the `connect_peer_connected` message to tell lightningd
* we have connected. Once it says something interesting, we tell
* it that, too. */
daemon_conn_send(daemon->master, take(msg));
/*~ Now we set up this connection to read/write from subd */
return multiplex_peer_setup(conn, peer);
}
/*~ handshake.c's handles setting up the crypto state once we get a connection
* in; we hand it straight to peer_exchange_initmsg() to send and receive INIT
* and call peer_connected(). */
static struct io_plan *handshake_in_success(struct io_conn *conn,
const struct pubkey *id_key,
const struct wireaddr_internal *addr,
struct crypto_state *cs,
struct oneshot *timeout,
struct daemon *daemon)
{
struct node_id id;
node_id_from_pubkey(&id, id_key);
status_peer_debug(&id, "Connect IN");
return peer_exchange_initmsg(conn, daemon, daemon->our_features,
cs, &id, addr, timeout, true);
}
/*~ If the timer goes off, we simply free everything, which hangs up. */
static void conn_timeout(struct io_conn *conn)
{
status_debug("conn timed out");
errno = ETIMEDOUT;
io_close(conn);
}
/*~ So, where are you from? */
static bool get_remote_address(struct io_conn *conn,
struct wireaddr_internal *addr)
{
struct sockaddr_storage s = {};
socklen_t len = sizeof(s);
/* The cast here is a weird Berkeley sockets API feature... */
if (getpeername(io_conn_fd(conn), (struct sockaddr *)&s, &len) != 0) {
status_debug("Failed to get peername for incoming conn: %s",
strerror(errno));
return false;
}
if (s.ss_family == AF_INET6) {
struct sockaddr_in6 *s6 = (void *)&s;
addr->itype = ADDR_INTERNAL_WIREADDR;
wireaddr_from_ipv6(&addr->u.wireaddr,
&s6->sin6_addr, ntohs(s6->sin6_port));
} else if (s.ss_family == AF_INET) {
struct sockaddr_in *s4 = (void *)&s;
addr->itype = ADDR_INTERNAL_WIREADDR;
wireaddr_from_ipv4(&addr->u.wireaddr,
&s4->sin_addr, ntohs(s4->sin_port));
} else if (s.ss_family == AF_UNIX) {
struct sockaddr_un *sun = (void *)&s;
addr->itype = ADDR_INTERNAL_SOCKNAME;
memcpy(addr->u.sockname, sun->sun_path, sizeof(sun->sun_path));
} else {
status_broken("Unknown socket type %i for incoming conn",
s.ss_family);
return false;
}
return true;
}
/*~ As so common in C, we need to bundle two args into a callback, so we
* allocate a temporary structure to hold them: */
struct conn_in {
struct wireaddr_internal addr;
struct daemon *daemon;
};
/*~ Once we've got a connection in, we set it up here (whether it's via the
* websocket proxy, or direct). */
static struct io_plan *conn_in(struct io_conn *conn,
struct conn_in *conn_in_arg)
{
struct daemon *daemon = conn_in_arg->daemon;
struct oneshot *timeout;
/* If they don't complete handshake in reasonable time, we hang up */
timeout = new_reltimer(&daemon->timers, conn,
time_from_sec(daemon->timeout_secs),
conn_timeout, conn);
/*~ The crypto handshake differs depending on whether you received or
* initiated the socket connection, so there are two entry points.
* Note, again, the notleak() to avoid our simplistic leak detection
* code from thinking `conn` (which we don't keep a pointer to) is
* leaked */
return responder_handshake(notleak(conn), &daemon->mykey,
&conn_in_arg->addr, timeout,
handshake_in_success, daemon);
}
/*~ When we get a direct connection in we set up its network address
* then call handshake.c to set up the crypto state. */
static struct io_plan *connection_in(struct io_conn *conn,
struct daemon *daemon)
{
struct conn_in conn_in_arg;
if (!get_remote_address(conn, &conn_in_arg.addr))
return io_close(conn);
conn_in_arg.daemon = daemon;
return conn_in(conn, &conn_in_arg);
}
/*~ <hello>I speak web socket</hello>.
*
* Actually that's dumb, websocket (aka rfc6455) looks nothing like that. */
static struct io_plan *websocket_connection_in(struct io_conn *conn,
struct daemon *daemon)
{
int childmsg[2], execfail[2];
pid_t childpid;
int err;
struct conn_in conn_in_arg;
if (!get_remote_address(conn, &conn_in_arg.addr))
return io_close(conn);
status_debug("Websocket connection in from %s",
type_to_string(tmpctx, struct wireaddr_internal,
&conn_in_arg.addr));
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, childmsg) != 0)
goto fail;
if (pipe(execfail) != 0)
goto close_msgfd_fail;
if (fcntl(execfail[1], F_SETFD, fcntl(execfail[1], F_GETFD)
| FD_CLOEXEC) < 0)
goto close_execfail_fail;
childpid = fork();
if (childpid < 0)
goto close_execfail_fail;
if (childpid == 0) {
close(childmsg[0]);
close(execfail[0]);
/* Attach remote socket to stdin. */
if (dup2(io_conn_fd(conn), STDIN_FILENO) == -1)
goto child_errno_fail;
/* Attach our socket to stdout. */
if (dup2(childmsg[1], STDOUT_FILENO) == -1)
goto child_errno_fail;
/* Make (fairly!) sure all other fds are closed. */
closefrom(STDERR_FILENO + 1);
/* Tell websocket helper what we read so far. */
execlp(daemon->websocket_helper, daemon->websocket_helper,
NULL);
child_errno_fail:
err = errno;
/* Gcc's warn-unused-result fail. */
if (write(execfail[1], &err, sizeof(err))) {
;
}
exit(127);
}
close(childmsg[1]);
close(execfail[1]);
/* Child will close this without writing on successful exec. */
if (read(execfail[0], &err, sizeof(err)) == sizeof(err)) {
close(execfail[0]);
waitpid(childpid, NULL, 0);
status_broken("Exec of helper %s failed: %s",
daemon->websocket_helper, strerror(err));
errno = err;
return io_close(conn);
}
close(execfail[0]);
/* New connection actually talks to proxy process. */
conn_in_arg.daemon = daemon;
io_new_conn(tal_parent(conn), childmsg[0], conn_in, &conn_in_arg);
/* Abandon original (doesn't close since child has dup'd fd) */
return io_close(conn);
close_execfail_fail:
close_noerr(execfail[0]);
close_noerr(execfail[1]);
close_msgfd_fail:
close_noerr(childmsg[0]);
close_noerr(childmsg[1]);
fail:
status_broken("Preparation of helper failed: %s",
strerror(errno));
return io_close(conn);
}
/*~ These are the mirror functions for the connecting-out case. */
static struct io_plan *handshake_out_success(struct io_conn *conn,
const struct pubkey *key,
const struct wireaddr_internal *addr,
struct crypto_state *cs,
struct oneshot *timeout,
struct connecting *connect)
{
struct node_id id;
node_id_from_pubkey(&id, key);
connect->connstate = "Exchanging init messages";
status_peer_debug(&id, "Connect OUT");
return peer_exchange_initmsg(conn, connect->daemon,
connect->daemon->our_features,
cs, &id, addr, timeout, false);
}
struct io_plan *connection_out(struct io_conn *conn, struct connecting *connect)
{
struct pubkey outkey;
struct oneshot *timeout;
/* This shouldn't happen: lightningd should not give invalid ids! */
if (!pubkey_from_node_id(&outkey, &connect->id)) {
status_broken("Connection out to invalid id %s",
type_to_string(tmpctx, struct node_id,
&connect->id));
return io_close(conn);
}
/* If they don't complete handshake in reasonable time, hang up */
timeout = new_reltimer(&connect->daemon->timers, conn,
time_from_sec(connect->daemon->timeout_secs),
conn_timeout, conn);
status_peer_debug(&connect->id, "Connected out, starting crypto");
connect->connstate = "Cryptographic handshake";
return initiator_handshake(conn, &connect->daemon->mykey, &outkey,
&connect->addrs[connect->addrnum],
timeout, handshake_out_success, connect);
}
/*~ When we've exhausted all addresses without success, we come here.
*
* Note that gcc gets upset if we put the PRINTF_FMT at the end like this if
* it's an actual function definition, but etags gets confused and ignores the
* rest of the file if we put PRINTF_FMT at the front. So we put it at the
* end, in a gratuitous declaration.
*/
static void connect_failed(struct daemon *daemon,
const struct node_id *id,
const struct wireaddr_internal *addrhint,
enum jsonrpc_errcode errcode,
const char *errfmt, ...)
PRINTF_FMT(5,6);
static void connect_failed(struct daemon *daemon,
const struct node_id *id,
const struct wireaddr_internal *addrhint,
enum jsonrpc_errcode errcode,
const char *errfmt, ...)
{
u8 *msg;
va_list ap;
char *errmsg;
va_start(ap, errfmt);
errmsg = tal_vfmt(tmpctx, errfmt, ap);
va_end(ap);
status_peer_debug(id, "Failed connected out: %s", errmsg);
/* lightningd may have a connect command waiting to know what
* happened. We leave it to lightningd to decide if it wants to try
* again. */
msg = towire_connectd_connect_failed(NULL, id, errcode, errmsg,
addrhint);
daemon_conn_send(daemon->master, take(msg));
}
/* add errors to error list */
void add_errors_to_error_list(struct connecting *connect, const char *error)
{
tal_append_fmt(&connect->errors,
"%s. ", error);
}
/*~ This is the destructor for the (unsuccessful) outgoing connection. We accumulate
* the errors which occurred, so we can report to lightningd properly in case
* they all fail, and try the next address.
*
* This is a specialized form of destructor which takes an extra argument;
* it set up by either the creatively-named tal_add_destructor2(), or by
* the ccan/io's io_set_finish() on a connection. */
static void destroy_io_conn(struct io_conn *conn, struct connecting *connect)
{
/*~ tal_append_fmt appends to a tal string. It's terribly convenient */
const char *errstr = strerror(errno);
/* errno 0 means they hung up on us. */
if (errno == 0) {
errstr = "peer closed connection";
if (streq(connect->connstate, "Cryptographic handshake"))
errstr = "peer closed connection (wrong key?)";
}
add_errors_to_error_list(connect,
tal_fmt(tmpctx, "%s: %s: %s",
type_to_string(tmpctx, struct wireaddr_internal,
&connect->addrs[connect->addrnum]),
connect->connstate, errstr));
connect->addrnum++;
connect->conn = NULL;
try_connect_one_addr(connect);
}
/* This initializes a fresh io_conn by setting it to io_connect to the
* destination */
static struct io_plan *conn_init(struct io_conn *conn,
struct connecting *connect)
{
/*~ I generally dislike the pattern of "set to NULL, assert if NULL at
* bottom". On -O2 and above the compiler will warn you at compile time
* if a there is a path by which the variable is not set, which is always
* preferable to a runtime assertion. In this case, it's the best way
* to use the "enum in a switch" trick to make sure we handle all enum
* cases, so I use it. */
struct addrinfo *ai = NULL;
const struct wireaddr_internal *addr = &connect->addrs[connect->addrnum];
switch (addr->itype) {
case ADDR_INTERNAL_SOCKNAME:
ai = wireaddr_internal_to_addrinfo(tmpctx, addr);
break;
case ADDR_INTERNAL_ALLPROTO:
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Can't connect to all protocols");
break;
case ADDR_INTERNAL_AUTOTOR:
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Can't connect to autotor address");
break;
case ADDR_INTERNAL_STATICTOR:
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Can't connect to statictor address");
break;
case ADDR_INTERNAL_FORPROXY:
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Can't connect to forproxy address");
break;
case ADDR_INTERNAL_WIREADDR:
/* DNS should have been resolved before */
assert(addr->u.wireaddr.type != ADDR_TYPE_DNS);
/* If it was a Tor address, we wouldn't be here. */
assert(!is_toraddr((char*)addr->u.wireaddr.addr));
ai = wireaddr_to_addrinfo(tmpctx, &addr->u.wireaddr);
break;
}
assert(ai);
io_set_finish(conn, destroy_io_conn, connect);
return io_connect(conn, ai, connection_out, connect);
}
/* This initializes a fresh io_conn by setting it to io_connect to the
* SOCKS proxy, as handled in tor.c. */
static struct io_plan *conn_proxy_init(struct io_conn *conn,
struct connecting *connect)
{
const char *host = NULL;
u16 port;
const struct wireaddr_internal *addr = &connect->addrs[connect->addrnum];
switch (addr->itype) {
case ADDR_INTERNAL_FORPROXY:
host = addr->u.unresolved.name;
port = addr->u.unresolved.port;
break;
case ADDR_INTERNAL_WIREADDR:
host = fmt_wireaddr_without_port(tmpctx, &addr->u.wireaddr);
port = addr->u.wireaddr.port;
break;
case ADDR_INTERNAL_SOCKNAME:
case ADDR_INTERNAL_ALLPROTO:
case ADDR_INTERNAL_AUTOTOR:
case ADDR_INTERNAL_STATICTOR:
break;
}
if (!host)
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Can't connect to %u address", addr->itype);
io_set_finish(conn, destroy_io_conn, connect);
return io_tor_connect(conn, connect->daemon->proxyaddr, host, port,
connect);
}
/*~ This is the routine which tries to connect. */
static void try_connect_one_addr(struct connecting *connect)
{
int fd, af;
bool use_proxy = connect->daemon->always_use_proxy;
const struct wireaddr_internal *addr = &connect->addrs[connect->addrnum];
struct io_conn *conn;
bool use_dns = connect->daemon->use_dns;
struct addrinfo hints, *ais, *aii;
struct wireaddr_internal addrhint;
int gai_err;
struct sockaddr_in *sa4;
struct sockaddr_in6 *sa6;
assert(!connect->conn);
/* Out of addresses? */
if (connect->addrnum == tal_count(connect->addrs)) {
connect_failed(connect->daemon, &connect->id,
connect->addrhint, CONNECT_ALL_ADDRESSES_FAILED,
"All addresses failed: %s",
connect->errors);
tal_free(connect);
return;
}
/* Might not even be able to create eg. IPv6 sockets */
af = -1;
switch (addr->itype) {
case ADDR_INTERNAL_SOCKNAME:
af = AF_LOCAL;
/* Local sockets don't use tor proxy */
use_proxy = false;
break;
case ADDR_INTERNAL_ALLPROTO:
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Can't connect ALLPROTO");
case ADDR_INTERNAL_AUTOTOR:
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Can't connect AUTOTOR");
case ADDR_INTERNAL_STATICTOR:
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Can't connect STATICTOR");
case ADDR_INTERNAL_FORPROXY:
use_proxy = true;
break;
case ADDR_INTERNAL_WIREADDR:
switch (addr->u.wireaddr.type) {
case ADDR_TYPE_TOR_V2_REMOVED:
af = -1;
break;
case ADDR_TYPE_TOR_V3:
use_proxy = true;
break;
case ADDR_TYPE_IPV4:
af = AF_INET;
break;
case ADDR_TYPE_IPV6:
af = AF_INET6;
break;
case ADDR_TYPE_DNS:
if (use_proxy) /* hand it to the proxy */
break;
if (!use_dns) { /* ignore DNS when we can't use it */
tal_append_fmt(&connect->errors,
"%s: dns disabled. ",
type_to_string(tmpctx,
struct wireaddr_internal,
addr));
goto next;
}
/* Resolve with getaddrinfo */
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = AF_UNSPEC;
hints.ai_protocol = 0;
hints.ai_flags = AI_ADDRCONFIG;
gai_err = getaddrinfo((char *)addr->u.wireaddr.addr,
tal_fmt(tmpctx, "%d",
addr->u.wireaddr.port),
&hints, &ais);
if (gai_err != 0) {
tal_append_fmt(&connect->errors,
"%s: getaddrinfo error '%s'. ",
type_to_string(tmpctx,
struct wireaddr_internal,
addr),
gai_strerror(gai_err));
goto next;
}
/* create new addrhints on-the-fly per result ... */
for (aii = ais; aii; aii = aii->ai_next) {
addrhint.itype = ADDR_INTERNAL_WIREADDR;
if (aii->ai_family == AF_INET) {
sa4 = (struct sockaddr_in *) aii->ai_addr;
wireaddr_from_ipv4(&addrhint.u.wireaddr,
&sa4->sin_addr,
addr->u.wireaddr.port);
} else if (aii->ai_family == AF_INET6) {
sa6 = (struct sockaddr_in6 *) aii->ai_addr;
wireaddr_from_ipv6(&addrhint.u.wireaddr,
&sa6->sin6_addr,
addr->u.wireaddr.port);
} else {
/* skip unsupported ai_family */
continue;
}
tal_arr_expand(&connect->addrs, addrhint);
/* don't forget to update convenience pointer */
addr = &connect->addrs[connect->addrnum];
}
freeaddrinfo(ais);
goto next;
case ADDR_TYPE_WEBSOCKET:
af = -1;
break;
}
}
/* If we have to use proxy but we don't have one, we fail. */
if (use_proxy) {
if (!connect->daemon->proxyaddr) {
tal_append_fmt(&connect->errors,
"%s: need a proxy. ",
type_to_string(tmpctx,
struct wireaddr_internal,
addr));
goto next;
}
af = connect->daemon->proxyaddr->ai_family;
}
if (af == -1) {
tal_append_fmt(&connect->errors,
"%s: not supported. ",
type_to_string(tmpctx, struct wireaddr_internal,
addr));
goto next;
}
fd = socket(af, SOCK_STREAM, 0);
if (fd < 0) {
tal_append_fmt(&connect->errors,
"%s: opening %i socket gave %s. ",
type_to_string(tmpctx, struct wireaddr_internal,
addr),
af, strerror(errno));
goto next;
}
/* This creates the new connection using our fd, with the initialization
* function one of the above. */
if (use_proxy)
conn = io_new_conn(connect, fd, conn_proxy_init, connect);
else
conn = io_new_conn(connect, fd, conn_init, connect);
/* Careful! io_new_conn can fail (immediate connect() failure), and
* that frees connect. */
if (conn)
connect->conn = conn;
return;
next:
/* This causes very limited recursion. */
connect->addrnum++;
try_connect_one_addr(connect);
}
/*~ Sometimes it's nice to have an explicit enum instead of a bool to make
* arguments clearer: it kind of hacks around C's lack of naming formal
* arguments in callers (e.g. in Python we'd simply call func(websocket=False)).
*/
enum is_websocket {
NORMAL_SOCKET,
WEBSOCKET,
};
/*~ connectd is responsible for incoming connections, but it's the process of
* setting up the listening ports which gives us information we need for startup
* (such as our own address). So we perform setup in two phases: first we bind
* the sockets according to the command line arguments (if any), then we start
* listening for connections to them once lightningd is ready.
*
* This stores the fds we're going to listen on: */
struct listen_fd {
/* This is usually an IPv4/v6 address, but we also support local
* domain sockets (i.e. filesystem) */
struct wireaddr_internal wi;
/* The actual fd, ready to listen() on */
int fd;
/* If we bind() IPv6 then IPv4 to same port, we *may* fail to listen()
* on the IPv4 socket: under Linux, by default, the IPv6 listen()
* covers IPv4 too. Normally we'd consider failing to listen on a
* port to be fatal, so we note this when setting up addresses. */
bool mayfail;
/* Is this a websocket? */
enum is_websocket is_websocket;
};
static struct listen_fd *listen_fd_new(const tal_t *ctx,
const struct wireaddr_internal *wi,
int fd, bool mayfail,
enum is_websocket is_websocket)
{
struct listen_fd *l = tal(ctx, struct listen_fd);
l->wi = *wi;
l->fd = fd;
l->mayfail = mayfail;
l->is_websocket = is_websocket;
return l;
}
/*~ Helper routine to create and bind a socket of a given type; like many
* daemons we set it SO_REUSEADDR so we won't have to wait 2 minutes to reuse
* it on restart.
*
* Note that it's generally an antipattern to have a function which
* returns an allocated object without an explicit tal ctx so the
* caller is aware. */
static struct listen_fd *make_listen_fd(const tal_t *ctx,
const struct wireaddr_internal *wi,
int domain, void *addr, socklen_t len,
bool listen_mayfail,
enum is_websocket is_websocket,
char **errstr)
{
int fd = socket(domain, SOCK_STREAM, 0);
int on = 1;
if (fd < 0) {
const char *es = strerror(errno);
*errstr = tal_fmt(ctx, "Failed to create socket for %s%s: %s",
is_websocket ? "websocket " : "",
type_to_string(tmpctx,