3333#include <connectd/tor.h>
3434#include <connectd/tor_autoservice.h>
3535#include <errno.h>
36+ #include <fcntl.h>
3637#include <netdb.h>
3738#include <netinet/in.h>
3839#include <sodium.h>
40+ #include <sys/types.h>
41+ #include <sys/wait.h>
42+ #include <unistd.h>
3943#include <wire/wire_sync.h>
4044
4145/*~ We are passed two file descriptors when exec'ed from `lightningd`: the
@@ -127,6 +131,12 @@ struct daemon {
127131
128132 /* Our features, as lightningd told us */
129133 struct feature_set * our_features ;
134+
135+ /* Subdaemon to proxy websocket requests. */
136+ char * websocket_helper ;
137+
138+ /* If non-zero, port to listen for websocket connections. */
139+ u16 websocket_port ;
130140};
131141
132142/* Peers we're trying to reach: we iterate through addrs until we succeed
@@ -529,40 +539,55 @@ static void conn_timeout(struct io_conn *conn)
529539 io_close (conn );
530540}
531541
532- /*~ When we get a connection in we set up its network address then call
533- * handshake.c to set up the crypto state. */
534- static struct io_plan * connection_in ( struct io_conn * conn , struct daemon * daemon )
542+ /*~ So, where are you from? */
543+ static bool get_remote_address ( struct io_conn * conn ,
544+ struct wireaddr_internal * addr )
535545{
536- struct wireaddr_internal addr ;
537546 struct sockaddr_storage s = {};
538547 socklen_t len = sizeof (s );
539548
540549 /* The cast here is a weird Berkeley sockets API feature... */
541550 if (getpeername (io_conn_fd (conn ), (struct sockaddr * )& s , & len ) != 0 ) {
542551 status_debug ("Failed to get peername for incoming conn: %s" ,
543552 strerror (errno ));
544- return io_close ( conn ) ;
553+ return false ;
545554 }
546555
547556 if (s .ss_family == AF_INET6 ) {
548557 struct sockaddr_in6 * s6 = (void * )& s ;
549- addr . itype = ADDR_INTERNAL_WIREADDR ;
550- wireaddr_from_ipv6 (& addr . u .wireaddr ,
558+ addr -> itype = ADDR_INTERNAL_WIREADDR ;
559+ wireaddr_from_ipv6 (& addr -> u .wireaddr ,
551560 & s6 -> sin6_addr , ntohs (s6 -> sin6_port ));
552561 } else if (s .ss_family == AF_INET ) {
553562 struct sockaddr_in * s4 = (void * )& s ;
554- addr . itype = ADDR_INTERNAL_WIREADDR ;
555- wireaddr_from_ipv4 (& addr . u .wireaddr ,
563+ addr -> itype = ADDR_INTERNAL_WIREADDR ;
564+ wireaddr_from_ipv4 (& addr -> u .wireaddr ,
556565 & s4 -> sin_addr , ntohs (s4 -> sin_port ));
557566 } else if (s .ss_family == AF_UNIX ) {
558567 struct sockaddr_un * sun = (void * )& s ;
559- addr . itype = ADDR_INTERNAL_SOCKNAME ;
560- memcpy (addr . u .sockname , sun -> sun_path , sizeof (sun -> sun_path ));
568+ addr -> itype = ADDR_INTERNAL_SOCKNAME ;
569+ memcpy (addr -> u .sockname , sun -> sun_path , sizeof (sun -> sun_path ));
561570 } else {
562571 status_broken ("Unknown socket type %i for incoming conn" ,
563572 s .ss_family );
564- return io_close ( conn ) ;
573+ return false ;
565574 }
575+ return true;
576+ }
577+
578+ /*~ As so common in C, we need to bundle two args into a callback, so we
579+ * allocate a temporary structure to hold them: */
580+ struct conn_in {
581+ struct wireaddr_internal addr ;
582+ struct daemon * daemon ;
583+ };
584+
585+ /*~ Once we've got a connection in, we set it up here (whether it's via the
586+ * websocket proxy, or direct). */
587+ static struct io_plan * conn_in (struct io_conn * conn ,
588+ struct conn_in * conn_in_arg )
589+ {
590+ struct daemon * daemon = conn_in_arg -> daemon ;
566591
567592 /* If they don't complete handshake in reasonable time, hang up */
568593 notleak (new_reltimer (& daemon -> timers , conn ,
@@ -574,10 +599,122 @@ static struct io_plan *connection_in(struct io_conn *conn, struct daemon *daemon
574599 * Note, again, the notleak() to avoid our simplistic leak detection
575600 * code from thinking `conn` (which we don't keep a pointer to) is
576601 * leaked */
577- return responder_handshake (notleak (conn ), & daemon -> mykey , & addr ,
602+ return responder_handshake (notleak (conn ), & daemon -> mykey ,
603+ & conn_in_arg -> addr ,
578604 handshake_in_success , daemon );
579605}
580606
607+ /*~ When we get a direct connection in we set up its network address
608+ * then call handshake.c to set up the crypto state. */
609+ static struct io_plan * connection_in (struct io_conn * conn ,
610+ struct daemon * daemon )
611+ {
612+ struct conn_in conn_in_arg ;
613+
614+ if (!get_remote_address (conn , & conn_in_arg .addr ))
615+ return io_close (conn );
616+
617+ conn_in_arg .daemon = daemon ;
618+ return conn_in (conn , & conn_in_arg );
619+ }
620+
621+ /*~ <hello>I speak web socket</hello>.
622+ *
623+ * Actually that's dumb, websocket (aka rfc6455) looks nothing like that. */
624+ static struct io_plan * websocket_connection_in (struct io_conn * conn ,
625+ struct daemon * daemon )
626+ {
627+ int childmsg [2 ], execfail [2 ];
628+ pid_t childpid ;
629+ int err ;
630+ struct conn_in conn_in_arg ;
631+
632+ if (!get_remote_address (conn , & conn_in_arg .addr ))
633+ return io_close (conn );
634+
635+ status_debug ("Websocket connection in from %s" ,
636+ type_to_string (tmpctx , struct wireaddr_internal ,
637+ & conn_in_arg .addr ));
638+
639+ if (socketpair (AF_LOCAL , SOCK_STREAM , 0 , childmsg ) != 0 )
640+ goto fail ;
641+
642+ if (pipe (execfail ) != 0 )
643+ goto close_msgfd_fail ;
644+
645+ if (fcntl (execfail [1 ], F_SETFD , fcntl (execfail [1 ], F_GETFD )
646+ | FD_CLOEXEC ) < 0 )
647+ goto close_execfail_fail ;
648+
649+ childpid = fork ();
650+ if (childpid < 0 )
651+ goto close_execfail_fail ;
652+
653+ if (childpid == 0 ) {
654+ size_t max ;
655+ close (childmsg [0 ]);
656+ close (execfail [0 ]);
657+
658+ /* Attach remote socket to stdin. */
659+ if (dup2 (io_conn_fd (conn ), STDIN_FILENO ) == -1 )
660+ goto child_errno_fail ;
661+
662+ /* Attach our socket to stdout. */
663+ if (dup2 (childmsg [1 ], STDOUT_FILENO ) == -1 )
664+ goto child_errno_fail ;
665+
666+ /* Make (fairly!) sure all other fds are closed. */
667+ max = sysconf (_SC_OPEN_MAX );
668+ for (size_t i = STDERR_FILENO + 1 ; i < max ; i ++ )
669+ close (i );
670+
671+ /* Tell websocket helper what we read so far. */
672+ execlp (daemon -> websocket_helper , daemon -> websocket_helper ,
673+ NULL );
674+
675+ child_errno_fail :
676+ err = errno ;
677+ /* Gcc's warn-unused-result fail. */
678+ if (write (execfail [1 ], & err , sizeof (err ))) {
679+ ;
680+ }
681+ exit (127 );
682+ }
683+
684+ close (childmsg [1 ]);
685+ close (execfail [1 ]);
686+
687+ /* Child will close this without writing on successful exec. */
688+ if (read (execfail [0 ], & err , sizeof (err )) == sizeof (err )) {
689+ close (execfail [0 ]);
690+ waitpid (childpid , NULL , 0 );
691+ status_broken ("Exec of helper %s failed: %s" ,
692+ daemon -> websocket_helper , strerror (err ));
693+ errno = err ;
694+ return io_close (conn );
695+ }
696+
697+ close (execfail [0 ]);
698+
699+ /* New connection actually talks to proxy process. */
700+ conn_in_arg .daemon = daemon ;
701+ io_new_conn (tal_parent (conn ), childmsg [0 ], conn_in , & conn_in_arg );
702+
703+ /* Abandon original (doesn't close since child has dup'd fd) */
704+ return io_close (conn );
705+
706+ close_execfail_fail :
707+ close_noerr (execfail [0 ]);
708+ close_noerr (execfail [1 ]);
709+ close_msgfd_fail :
710+ close_noerr (childmsg [0 ]);
711+ close_noerr (childmsg [1 ]);
712+ fail :
713+ status_broken ("Preparation of helper failed: %s" ,
714+ strerror (errno ));
715+ return io_close (conn );
716+ }
717+
581718/*~ These are the mirror functions for the connecting-out case. */
582719static struct io_plan * handshake_out_success (struct io_conn * conn ,
583720 const struct pubkey * key ,
@@ -906,16 +1043,22 @@ struct listen_fd {
9061043 * covers IPv4 too. Normally we'd consider failing to listen on a
9071044 * port to be fatal, so we note this when setting up addresses. */
9081045 bool mayfail ;
1046+ /* Callback to use for the listening: either connection_in, or for
1047+ * our much-derided WebSocket ability, websocket_connection_in! */
1048+ struct io_plan * (* in_cb )(struct io_conn * conn , struct daemon * daemon );
9091049};
9101050
911- static void add_listen_fd (struct daemon * daemon , int fd , bool mayfail )
1051+ static void add_listen_fd (struct daemon * daemon , int fd , bool mayfail ,
1052+ struct io_plan * (* in_cb )(struct io_conn * ,
1053+ struct daemon * ))
9121054{
9131055 /*~ utils.h contains a convenience macro tal_arr_expand which
9141056 * reallocates a tal_arr to make it one longer, then returns a pointer
9151057 * to the (new) last element. */
9161058 struct listen_fd l ;
9171059 l .fd = fd ;
9181060 l .mayfail = mayfail ;
1061+ l .in_cb = in_cb ;
9191062 tal_arr_expand (& daemon -> listen_fds , l );
9201063}
9211064
@@ -970,11 +1113,18 @@ static int make_listen_fd(int domain, void *addr, socklen_t len, bool mayfail)
9701113/* Return true if it created socket successfully. */
9711114static bool handle_wireaddr_listen (struct daemon * daemon ,
9721115 const struct wireaddr * wireaddr ,
973- bool mayfail )
1116+ bool mayfail ,
1117+ bool websocket )
9741118{
9751119 int fd ;
9761120 struct sockaddr_in addr ;
9771121 struct sockaddr_in6 addr6 ;
1122+ struct io_plan * (* in_cb )(struct io_conn * , struct daemon * );
1123+
1124+ if (websocket )
1125+ in_cb = websocket_connection_in ;
1126+ else
1127+ in_cb = connection_in ;
9781128
9791129 /* Note the use of a switch() over enum here, even though it must be
9801130 * IPv4 or IPv6 here; that will catch future changes. */
@@ -984,19 +1134,21 @@ static bool handle_wireaddr_listen(struct daemon *daemon,
9841134 /* We might fail if IPv6 bound to port first */
9851135 fd = make_listen_fd (AF_INET , & addr , sizeof (addr ), mayfail );
9861136 if (fd >= 0 ) {
987- status_debug ("Created IPv4 listener on port %u" ,
1137+ status_debug ("Created IPv4 %slistener on port %u" ,
1138+ websocket ? "websocket " : "" ,
9881139 wireaddr -> port );
989- add_listen_fd (daemon , fd , mayfail );
1140+ add_listen_fd (daemon , fd , mayfail , in_cb );
9901141 return true;
9911142 }
9921143 return false;
9931144 case ADDR_TYPE_IPV6 :
9941145 wireaddr_to_ipv6 (wireaddr , & addr6 );
9951146 fd = make_listen_fd (AF_INET6 , & addr6 , sizeof (addr6 ), mayfail );
9961147 if (fd >= 0 ) {
997- status_debug ("Created IPv6 listener on port %u" ,
1148+ status_debug ("Created IPv6 %slistener on port %u" ,
1149+ websocket ? "websocket " : "" ,
9981150 wireaddr -> port );
999- add_listen_fd (daemon , fd , mayfail );
1151+ add_listen_fd (daemon , fd , mayfail , in_cb );
10001152 return true;
10011153 }
10021154 return false;
@@ -1122,7 +1274,7 @@ static struct wireaddr_internal *setup_listeners(const tal_t *ctx,
11221274 false);
11231275 status_debug ("Created socket listener on file %s" ,
11241276 addrun .sun_path );
1125- add_listen_fd (daemon , fd , false);
1277+ add_listen_fd (daemon , fd , false, connection_in );
11261278 /* We don't announce socket names, though we allow
11271279 * them to lazily specify --addr=/socket. */
11281280 add_binding (& binding , & wa );
@@ -1147,7 +1299,7 @@ static struct wireaddr_internal *setup_listeners(const tal_t *ctx,
11471299 sizeof (wa .u .wireaddr .addr ));
11481300
11491301 ipv6_ok = handle_wireaddr_listen (daemon , & wa .u .wireaddr ,
1150- true);
1302+ true, false );
11511303 if (ipv6_ok ) {
11521304 add_binding (& binding , & wa );
11531305 if (announce
@@ -1163,7 +1315,7 @@ static struct wireaddr_internal *setup_listeners(const tal_t *ctx,
11631315 sizeof (wa .u .wireaddr .addr ));
11641316 /* OK if this fails, as long as one succeeds! */
11651317 if (handle_wireaddr_listen (daemon , & wa .u .wireaddr ,
1166- ipv6_ok )) {
1318+ ipv6_ok , false )) {
11671319 add_binding (& binding , & wa );
11681320 if (announce
11691321 && public_address (daemon , & wa .u .wireaddr ))
@@ -1174,7 +1326,8 @@ static struct wireaddr_internal *setup_listeners(const tal_t *ctx,
11741326 }
11751327 /* This is a vanilla wireaddr as per BOLT #7 */
11761328 case ADDR_INTERNAL_WIREADDR :
1177- handle_wireaddr_listen (daemon , & wa .u .wireaddr , false);
1329+ handle_wireaddr_listen (daemon , & wa .u .wireaddr ,
1330+ false, false);
11781331 add_binding (& binding , & wa );
11791332 if (announce && public_address (daemon , & wa .u .wireaddr ))
11801333 add_announcable (announcable , & wa .u .wireaddr );
@@ -1188,6 +1341,38 @@ static struct wireaddr_internal *setup_listeners(const tal_t *ctx,
11881341 proposed_wireaddr [i ].itype );
11891342 }
11901343
1344+ /* If we want websockets to match IPv4/v6, set it up now. */
1345+ if (daemon -> websocket_port ) {
1346+ bool announced_some = false;
1347+ struct wireaddr addr ;
1348+
1349+ for (size_t i = 0 ; i < tal_count (binding ); i ++ ) {
1350+ /* Ignore UNIX sockets */
1351+ if (binding [i ].itype != ADDR_INTERNAL_WIREADDR )
1352+ continue ;
1353+
1354+ /* Override with websocket port */
1355+ addr = binding [i ].u .wireaddr ;
1356+ addr .port = daemon -> websocket_port ;
1357+ handle_wireaddr_listen (daemon , & addr , false, true);
1358+ announced_some = true;
1359+ /* FIXME: We don't report these bindings to
1360+ * lightningd, so they don't appear in
1361+ * getinfo. */
1362+ }
1363+
1364+
1365+ /* We add the websocket port to the announcement if it
1366+ * applies to any */
1367+ if (announced_some ) {
1368+ wireaddr_from_websocket (& addr , daemon -> websocket_port );
1369+ add_announcable (announcable , & addr );
1370+ }
1371+ }
1372+
1373+ /* FIXME: Websocket over Tor (difficult for autotor, since we need
1374+ * to use the same onion addr!) */
1375+
11911376 /* Now we have bindings, set up any Tor auto addresses: we will point
11921377 * it at the first bound IPv4 or IPv6 address we have. */
11931378 for (size_t i = 0 ; i < tal_count (proposed_wireaddr ); i ++ ) {
@@ -1294,7 +1479,9 @@ static struct io_plan *connect_init(struct io_conn *conn,
12941479 & daemon -> dev_allow_localhost , & daemon -> use_dns ,
12951480 & tor_password ,
12961481 & daemon -> use_v3_autotor ,
1297- & daemon -> timeout_secs )) {
1482+ & daemon -> timeout_secs ,
1483+ & daemon -> websocket_helper ,
1484+ & daemon -> websocket_port )) {
12981485 /* This is a helper which prints the type expected and the actual
12991486 * message, then exits (it should never be called!). */
13001487 master_badmsg (WIRE_CONNECTD_INIT , msg );
@@ -1367,7 +1554,8 @@ static struct io_plan *connect_activate(struct io_conn *conn,
13671554 }
13681555 notleak (io_new_listener (daemon ,
13691556 daemon -> listen_fds [i ].fd ,
1370- connection_in , daemon ));
1557+ daemon -> listen_fds [i ].in_cb ,
1558+ daemon ));
13711559 }
13721560 }
13731561 /* Free, with NULL assignment just as an extra sanity check. */
0 commit comments