1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 David Strauss
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
29 #include <sys/socket.h>
33 #include "sd-daemon.h"
35 #include "sd-resolve.h"
38 #include "path-util.h"
40 #include "socket-util.h"
41 #include "string-util.h"
44 #define BUFFER_SIZE (256 * 1024)
45 #define CONNECTIONS_MAX 256
47 static const char *arg_remote_host
= NULL
;
49 typedef struct Context
{
57 typedef struct Connection
{
60 int server_fd
, client_fd
;
61 int server_to_client_buffer
[2]; /* a pipe */
62 int client_to_server_buffer
[2]; /* a pipe */
64 size_t server_to_client_buffer_full
, client_to_server_buffer_full
;
65 size_t server_to_client_buffer_size
, client_to_server_buffer_size
;
67 sd_event_source
*server_event_source
, *client_event_source
;
69 sd_resolve_query
*resolve_query
;
72 static void connection_free(Connection
*c
) {
76 set_remove(c
->context
->connections
, c
);
78 sd_event_source_unref(c
->server_event_source
);
79 sd_event_source_unref(c
->client_event_source
);
81 safe_close(c
->server_fd
);
82 safe_close(c
->client_fd
);
84 safe_close_pair(c
->server_to_client_buffer
);
85 safe_close_pair(c
->client_to_server_buffer
);
87 sd_resolve_query_unref(c
->resolve_query
);
92 static void context_free(Context
*context
) {
98 while ((es
= set_steal_first(context
->listen
)))
99 sd_event_source_unref(es
);
101 while ((c
= set_first(context
->connections
)))
104 set_free(context
->listen
);
105 set_free(context
->connections
);
107 sd_event_unref(context
->event
);
108 sd_resolve_unref(context
->resolve
);
111 static int connection_create_pipes(Connection
*c
, int buffer
[2], size_t *sz
) {
121 r
= pipe2(buffer
, O_CLOEXEC
|O_NONBLOCK
);
123 return log_error_errno(errno
, "Failed to allocate pipe buffer: %m");
125 (void) fcntl(buffer
[0], F_SETPIPE_SZ
, BUFFER_SIZE
);
127 r
= fcntl(buffer
[0], F_GETPIPE_SZ
);
129 return log_error_errno(errno
, "Failed to get pipe buffer size: %m");
137 static int connection_shovel(
139 int *from
, int buffer
[2], int *to
,
140 size_t *full
, size_t *sz
,
141 sd_event_source
**from_source
, sd_event_source
**to_source
) {
148 assert(buffer
[0] >= 0);
149 assert(buffer
[1] >= 0);
161 if (*full
< *sz
&& *from
>= 0 && *to
>= 0) {
162 z
= splice(*from
, NULL
, buffer
[1], NULL
, *sz
- *full
, SPLICE_F_MOVE
|SPLICE_F_NONBLOCK
);
166 } else if (z
== 0 || errno
== EPIPE
|| errno
== ECONNRESET
) {
167 *from_source
= sd_event_source_unref(*from_source
);
168 *from
= safe_close(*from
);
169 } else if (errno
!= EAGAIN
&& errno
!= EINTR
)
170 return log_error_errno(errno
, "Failed to splice: %m");
173 if (*full
> 0 && *to
>= 0) {
174 z
= splice(buffer
[0], NULL
, *to
, NULL
, *full
, SPLICE_F_MOVE
|SPLICE_F_NONBLOCK
);
178 } else if (z
== 0 || errno
== EPIPE
|| errno
== ECONNRESET
) {
179 *to_source
= sd_event_source_unref(*to_source
);
180 *to
= safe_close(*to
);
181 } else if (errno
!= EAGAIN
&& errno
!= EINTR
)
182 return log_error_errno(errno
, "Failed to splice: %m");
189 static int connection_enable_event_sources(Connection
*c
);
191 static int traffic_cb(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
192 Connection
*c
= userdata
;
199 r
= connection_shovel(c
,
200 &c
->server_fd
, c
->server_to_client_buffer
, &c
->client_fd
,
201 &c
->server_to_client_buffer_full
, &c
->server_to_client_buffer_size
,
202 &c
->server_event_source
, &c
->client_event_source
);
206 r
= connection_shovel(c
,
207 &c
->client_fd
, c
->client_to_server_buffer
, &c
->server_fd
,
208 &c
->client_to_server_buffer_full
, &c
->client_to_server_buffer_size
,
209 &c
->client_event_source
, &c
->server_event_source
);
213 /* EOF on both sides? */
214 if (c
->server_fd
== -1 && c
->client_fd
== -1)
217 /* Server closed, and all data written to client? */
218 if (c
->server_fd
== -1 && c
->server_to_client_buffer_full
<= 0)
221 /* Client closed, and all data written to server? */
222 if (c
->client_fd
== -1 && c
->client_to_server_buffer_full
<= 0)
225 r
= connection_enable_event_sources(c
);
233 return 0; /* ignore errors, continue serving */
236 static int connection_enable_event_sources(Connection
*c
) {
237 uint32_t a
= 0, b
= 0;
242 if (c
->server_to_client_buffer_full
> 0)
244 if (c
->server_to_client_buffer_full
< c
->server_to_client_buffer_size
)
247 if (c
->client_to_server_buffer_full
> 0)
249 if (c
->client_to_server_buffer_full
< c
->client_to_server_buffer_size
)
252 if (c
->server_event_source
)
253 r
= sd_event_source_set_io_events(c
->server_event_source
, a
);
254 else if (c
->server_fd
>= 0)
255 r
= sd_event_add_io(c
->context
->event
, &c
->server_event_source
, c
->server_fd
, a
, traffic_cb
, c
);
260 return log_error_errno(r
, "Failed to set up server event source: %m");
262 if (c
->client_event_source
)
263 r
= sd_event_source_set_io_events(c
->client_event_source
, b
);
264 else if (c
->client_fd
>= 0)
265 r
= sd_event_add_io(c
->context
->event
, &c
->client_event_source
, c
->client_fd
, b
, traffic_cb
, c
);
270 return log_error_errno(r
, "Failed to set up client event source: %m");
275 static int connection_complete(Connection
*c
) {
280 r
= connection_create_pipes(c
, c
->server_to_client_buffer
, &c
->server_to_client_buffer_size
);
284 r
= connection_create_pipes(c
, c
->client_to_server_buffer
, &c
->client_to_server_buffer_size
);
288 r
= connection_enable_event_sources(c
);
296 return 0; /* ignore errors, continue serving */
299 static int connect_cb(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
300 Connection
*c
= userdata
;
308 solen
= sizeof(error
);
309 r
= getsockopt(fd
, SOL_SOCKET
, SO_ERROR
, &error
, &solen
);
311 log_error_errno(errno
, "Failed to issue SO_ERROR: %m");
316 log_error_errno(error
, "Failed to connect to remote host: %m");
320 c
->client_event_source
= sd_event_source_unref(c
->client_event_source
);
322 return connection_complete(c
);
326 return 0; /* ignore errors, continue serving */
329 static int connection_start(Connection
*c
, struct sockaddr
*sa
, socklen_t salen
) {
336 c
->client_fd
= socket(sa
->sa_family
, SOCK_STREAM
|SOCK_NONBLOCK
|SOCK_CLOEXEC
, 0);
337 if (c
->client_fd
< 0) {
338 log_error_errno(errno
, "Failed to get remote socket: %m");
342 r
= connect(c
->client_fd
, sa
, salen
);
344 if (errno
== EINPROGRESS
) {
345 r
= sd_event_add_io(c
->context
->event
, &c
->client_event_source
, c
->client_fd
, EPOLLOUT
, connect_cb
, c
);
347 log_error_errno(r
, "Failed to add connection socket: %m");
351 r
= sd_event_source_set_enabled(c
->client_event_source
, SD_EVENT_ONESHOT
);
353 log_error_errno(r
, "Failed to enable oneshot event source: %m");
357 log_error_errno(errno
, "Failed to connect to remote host: %m");
361 r
= connection_complete(c
);
370 return 0; /* ignore errors, continue serving */
373 static int resolve_cb(sd_resolve_query
*q
, int ret
, const struct addrinfo
*ai
, void *userdata
) {
374 Connection
*c
= userdata
;
380 log_error("Failed to resolve host: %s", gai_strerror(ret
));
384 c
->resolve_query
= sd_resolve_query_unref(c
->resolve_query
);
386 return connection_start(c
, ai
->ai_addr
, ai
->ai_addrlen
);
390 return 0; /* ignore errors, continue serving */
393 static int resolve_remote(Connection
*c
) {
395 static const struct addrinfo hints
= {
396 .ai_family
= AF_UNSPEC
,
397 .ai_socktype
= SOCK_STREAM
,
398 .ai_flags
= AI_ADDRCONFIG
401 union sockaddr_union sa
= {};
402 const char *node
, *service
;
406 if (path_is_absolute(arg_remote_host
)) {
407 sa
.un
.sun_family
= AF_UNIX
;
408 strncpy(sa
.un
.sun_path
, arg_remote_host
, sizeof(sa
.un
.sun_path
)-1);
409 sa
.un
.sun_path
[sizeof(sa
.un
.sun_path
)-1] = 0;
411 salen
= offsetof(union sockaddr_union
, un
.sun_path
) + strlen(sa
.un
.sun_path
);
413 return connection_start(c
, &sa
.sa
, salen
);
416 if (arg_remote_host
[0] == '@') {
417 sa
.un
.sun_family
= AF_UNIX
;
418 sa
.un
.sun_path
[0] = 0;
419 strncpy(sa
.un
.sun_path
+1, arg_remote_host
+1, sizeof(sa
.un
.sun_path
)-2);
420 sa
.un
.sun_path
[sizeof(sa
.un
.sun_path
)-1] = 0;
422 salen
= offsetof(union sockaddr_union
, un
.sun_path
) + 1 + strlen(sa
.un
.sun_path
+ 1);
424 return connection_start(c
, &sa
.sa
, salen
);
427 service
= strrchr(arg_remote_host
, ':');
429 node
= strndupa(arg_remote_host
, service
- arg_remote_host
);
432 node
= arg_remote_host
;
436 log_debug("Looking up address info for %s:%s", node
, service
);
437 r
= sd_resolve_getaddrinfo(c
->context
->resolve
, &c
->resolve_query
, node
, service
, &hints
, resolve_cb
, c
);
439 log_error_errno(r
, "Failed to resolve remote host: %m");
447 return 0; /* ignore errors, continue serving */
450 static int add_connection_socket(Context
*context
, int fd
) {
457 if (set_size(context
->connections
) > CONNECTIONS_MAX
) {
458 log_warning("Hit connection limit, refusing connection.");
463 r
= set_ensure_allocated(&context
->connections
, NULL
);
469 c
= new0(Connection
, 1);
475 c
->context
= context
;
478 c
->server_to_client_buffer
[0] = c
->server_to_client_buffer
[1] = -1;
479 c
->client_to_server_buffer
[0] = c
->client_to_server_buffer
[1] = -1;
481 r
= set_put(context
->connections
, c
);
488 return resolve_remote(c
);
491 static int accept_cb(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
492 _cleanup_free_
char *peer
= NULL
;
493 Context
*context
= userdata
;
498 assert(revents
& EPOLLIN
);
501 nfd
= accept4(fd
, NULL
, NULL
, SOCK_NONBLOCK
|SOCK_CLOEXEC
);
503 if (errno
!= -EAGAIN
)
504 log_warning_errno(errno
, "Failed to accept() socket: %m");
506 getpeername_pretty(nfd
, &peer
);
507 log_debug("New connection from %s", strna(peer
));
509 r
= add_connection_socket(context
, nfd
);
511 log_error_errno(r
, "Failed to accept connection, ignoring: %m");
516 r
= sd_event_source_set_enabled(s
, SD_EVENT_ONESHOT
);
518 log_error_errno(r
, "Error while re-enabling listener with ONESHOT: %m");
519 sd_event_exit(context
->event
, r
);
526 static int add_listen_socket(Context
*context
, int fd
) {
527 sd_event_source
*source
;
533 r
= set_ensure_allocated(&context
->listen
, NULL
);
539 r
= sd_is_socket(fd
, 0, SOCK_STREAM
, 1);
541 return log_error_errno(r
, "Failed to determine socket type: %m");
543 log_error("Passed in socket is not a stream socket.");
547 r
= fd_nonblock(fd
, true);
549 return log_error_errno(r
, "Failed to mark file descriptor non-blocking: %m");
551 r
= sd_event_add_io(context
->event
, &source
, fd
, EPOLLIN
, accept_cb
, context
);
553 return log_error_errno(r
, "Failed to add event source: %m");
555 r
= set_put(context
->listen
, source
);
557 log_error_errno(r
, "Failed to add source to set: %m");
558 sd_event_source_unref(source
);
562 /* Set the watcher to oneshot in case other processes are also
563 * watching to accept(). */
564 r
= sd_event_source_set_enabled(source
, SD_EVENT_ONESHOT
);
566 return log_error_errno(r
, "Failed to enable oneshot mode: %m");
571 static void help(void) {
572 printf("%1$s [HOST:PORT]\n"
574 "Bidirectionally proxy local sockets to another (possibly remote) socket.\n\n"
575 " -h --help Show this help\n"
576 " --version Show package version\n",
577 program_invocation_short_name
);
580 static int parse_argv(int argc
, char *argv
[]) {
587 static const struct option options
[] = {
588 { "help", no_argument
, NULL
, 'h' },
589 { "version", no_argument
, NULL
, ARG_VERSION
},
598 while ((c
= getopt_long(argc
, argv
, "h", options
, NULL
)) >= 0)
613 assert_not_reached("Unhandled option");
616 if (optind
>= argc
) {
617 log_error("Not enough parameters.");
621 if (argc
!= optind
+1) {
622 log_error("Too many parameters.");
626 arg_remote_host
= argv
[optind
];
630 int main(int argc
, char *argv
[]) {
631 Context context
= {};
634 log_parse_environment();
637 r
= parse_argv(argc
, argv
);
641 r
= sd_event_default(&context
.event
);
643 log_error_errno(r
, "Failed to allocate event loop: %m");
647 r
= sd_resolve_default(&context
.resolve
);
649 log_error_errno(r
, "Failed to allocate resolver: %m");
653 r
= sd_resolve_attach_event(context
.resolve
, context
.event
, 0);
655 log_error_errno(r
, "Failed to attach resolver: %m");
659 sd_event_set_watchdog(context
.event
, true);
661 n
= sd_listen_fds(1);
663 log_error("Failed to receive sockets from parent.");
667 log_error("Didn't get any sockets passed in.");
672 for (fd
= SD_LISTEN_FDS_START
; fd
< SD_LISTEN_FDS_START
+ n
; fd
++) {
673 r
= add_listen_socket(&context
, fd
);
678 r
= sd_event_loop(context
.event
);
680 log_error_errno(r
, "Failed to run event loop: %m");
685 context_free(&context
);
687 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;