2 This file is part of systemd.
4 Copyright 2013 David Strauss
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
27 #include <sys/socket.h>
31 #include "sd-daemon.h"
33 #include "sd-resolve.h"
35 #include "alloc-util.h"
38 #include "path-util.h"
40 #include "socket-util.h"
41 #include "string-util.h"
42 #include "parse-util.h"
45 #define BUFFER_SIZE (256 * 1024)
46 static unsigned arg_connections_max
= 256;
48 static const char *arg_remote_host
= NULL
;
50 typedef struct Context
{
58 typedef struct Connection
{
61 int server_fd
, client_fd
;
62 int server_to_client_buffer
[2]; /* a pipe */
63 int client_to_server_buffer
[2]; /* a pipe */
65 size_t server_to_client_buffer_full
, client_to_server_buffer_full
;
66 size_t server_to_client_buffer_size
, client_to_server_buffer_size
;
68 sd_event_source
*server_event_source
, *client_event_source
;
70 sd_resolve_query
*resolve_query
;
73 static void connection_free(Connection
*c
) {
77 set_remove(c
->context
->connections
, c
);
79 sd_event_source_unref(c
->server_event_source
);
80 sd_event_source_unref(c
->client_event_source
);
82 safe_close(c
->server_fd
);
83 safe_close(c
->client_fd
);
85 safe_close_pair(c
->server_to_client_buffer
);
86 safe_close_pair(c
->client_to_server_buffer
);
88 sd_resolve_query_unref(c
->resolve_query
);
93 static void context_free(Context
*context
) {
99 while ((es
= set_steal_first(context
->listen
)))
100 sd_event_source_unref(es
);
102 while ((c
= set_first(context
->connections
)))
105 set_free(context
->listen
);
106 set_free(context
->connections
);
108 sd_event_unref(context
->event
);
109 sd_resolve_unref(context
->resolve
);
112 static int connection_create_pipes(Connection
*c
, int buffer
[2], size_t *sz
) {
122 r
= pipe2(buffer
, O_CLOEXEC
|O_NONBLOCK
);
124 return log_error_errno(errno
, "Failed to allocate pipe buffer: %m");
126 (void) fcntl(buffer
[0], F_SETPIPE_SZ
, BUFFER_SIZE
);
128 r
= fcntl(buffer
[0], F_GETPIPE_SZ
);
130 return log_error_errno(errno
, "Failed to get pipe buffer size: %m");
138 static int connection_shovel(
140 int *from
, int buffer
[2], int *to
,
141 size_t *full
, size_t *sz
,
142 sd_event_source
**from_source
, sd_event_source
**to_source
) {
149 assert(buffer
[0] >= 0);
150 assert(buffer
[1] >= 0);
162 if (*full
< *sz
&& *from
>= 0 && *to
>= 0) {
163 z
= splice(*from
, NULL
, buffer
[1], NULL
, *sz
- *full
, SPLICE_F_MOVE
|SPLICE_F_NONBLOCK
);
167 } else if (z
== 0 || errno
== EPIPE
|| errno
== ECONNRESET
) {
168 *from_source
= sd_event_source_unref(*from_source
);
169 *from
= safe_close(*from
);
170 } else if (!IN_SET(errno
, EAGAIN
, EINTR
))
171 return log_error_errno(errno
, "Failed to splice: %m");
174 if (*full
> 0 && *to
>= 0) {
175 z
= splice(buffer
[0], NULL
, *to
, NULL
, *full
, SPLICE_F_MOVE
|SPLICE_F_NONBLOCK
);
179 } else if (z
== 0 || errno
== EPIPE
|| errno
== ECONNRESET
) {
180 *to_source
= sd_event_source_unref(*to_source
);
181 *to
= safe_close(*to
);
182 } else if (!IN_SET(errno
, EAGAIN
, EINTR
))
183 return log_error_errno(errno
, "Failed to splice: %m");
190 static int connection_enable_event_sources(Connection
*c
);
192 static int traffic_cb(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
193 Connection
*c
= userdata
;
200 r
= connection_shovel(c
,
201 &c
->server_fd
, c
->server_to_client_buffer
, &c
->client_fd
,
202 &c
->server_to_client_buffer_full
, &c
->server_to_client_buffer_size
,
203 &c
->server_event_source
, &c
->client_event_source
);
207 r
= connection_shovel(c
,
208 &c
->client_fd
, c
->client_to_server_buffer
, &c
->server_fd
,
209 &c
->client_to_server_buffer_full
, &c
->client_to_server_buffer_size
,
210 &c
->client_event_source
, &c
->server_event_source
);
214 /* EOF on both sides? */
215 if (c
->server_fd
== -1 && c
->client_fd
== -1)
218 /* Server closed, and all data written to client? */
219 if (c
->server_fd
== -1 && c
->server_to_client_buffer_full
<= 0)
222 /* Client closed, and all data written to server? */
223 if (c
->client_fd
== -1 && c
->client_to_server_buffer_full
<= 0)
226 r
= connection_enable_event_sources(c
);
234 return 0; /* ignore errors, continue serving */
237 static int connection_enable_event_sources(Connection
*c
) {
238 uint32_t a
= 0, b
= 0;
243 if (c
->server_to_client_buffer_full
> 0)
245 if (c
->server_to_client_buffer_full
< c
->server_to_client_buffer_size
)
248 if (c
->client_to_server_buffer_full
> 0)
250 if (c
->client_to_server_buffer_full
< c
->client_to_server_buffer_size
)
253 if (c
->server_event_source
)
254 r
= sd_event_source_set_io_events(c
->server_event_source
, a
);
255 else if (c
->server_fd
>= 0)
256 r
= sd_event_add_io(c
->context
->event
, &c
->server_event_source
, c
->server_fd
, a
, traffic_cb
, c
);
261 return log_error_errno(r
, "Failed to set up server event source: %m");
263 if (c
->client_event_source
)
264 r
= sd_event_source_set_io_events(c
->client_event_source
, b
);
265 else if (c
->client_fd
>= 0)
266 r
= sd_event_add_io(c
->context
->event
, &c
->client_event_source
, c
->client_fd
, b
, traffic_cb
, c
);
271 return log_error_errno(r
, "Failed to set up client event source: %m");
276 static int connection_complete(Connection
*c
) {
281 r
= connection_create_pipes(c
, c
->server_to_client_buffer
, &c
->server_to_client_buffer_size
);
285 r
= connection_create_pipes(c
, c
->client_to_server_buffer
, &c
->client_to_server_buffer_size
);
289 r
= connection_enable_event_sources(c
);
297 return 0; /* ignore errors, continue serving */
300 static int connect_cb(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
301 Connection
*c
= userdata
;
309 solen
= sizeof(error
);
310 r
= getsockopt(fd
, SOL_SOCKET
, SO_ERROR
, &error
, &solen
);
312 log_error_errno(errno
, "Failed to issue SO_ERROR: %m");
317 log_error_errno(error
, "Failed to connect to remote host: %m");
321 c
->client_event_source
= sd_event_source_unref(c
->client_event_source
);
323 return connection_complete(c
);
327 return 0; /* ignore errors, continue serving */
330 static int connection_start(Connection
*c
, struct sockaddr
*sa
, socklen_t salen
) {
337 c
->client_fd
= socket(sa
->sa_family
, SOCK_STREAM
|SOCK_NONBLOCK
|SOCK_CLOEXEC
, 0);
338 if (c
->client_fd
< 0) {
339 log_error_errno(errno
, "Failed to get remote socket: %m");
343 r
= connect(c
->client_fd
, sa
, salen
);
345 if (errno
== EINPROGRESS
) {
346 r
= sd_event_add_io(c
->context
->event
, &c
->client_event_source
, c
->client_fd
, EPOLLOUT
, connect_cb
, c
);
348 log_error_errno(r
, "Failed to add connection socket: %m");
352 r
= sd_event_source_set_enabled(c
->client_event_source
, SD_EVENT_ONESHOT
);
354 log_error_errno(r
, "Failed to enable oneshot event source: %m");
358 log_error_errno(errno
, "Failed to connect to remote host: %m");
362 r
= connection_complete(c
);
371 return 0; /* ignore errors, continue serving */
374 static int resolve_cb(sd_resolve_query
*q
, int ret
, const struct addrinfo
*ai
, void *userdata
) {
375 Connection
*c
= userdata
;
381 log_error("Failed to resolve host: %s", gai_strerror(ret
));
385 c
->resolve_query
= sd_resolve_query_unref(c
->resolve_query
);
387 return connection_start(c
, ai
->ai_addr
, ai
->ai_addrlen
);
391 return 0; /* ignore errors, continue serving */
394 static int resolve_remote(Connection
*c
) {
396 static const struct addrinfo hints
= {
397 .ai_family
= AF_UNSPEC
,
398 .ai_socktype
= SOCK_STREAM
,
399 .ai_flags
= AI_ADDRCONFIG
402 union sockaddr_union sa
= {};
403 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
));
409 return connection_start(c
, &sa
.sa
, SOCKADDR_UN_LEN(sa
.un
));
412 if (arg_remote_host
[0] == '@') {
413 sa
.un
.sun_family
= AF_UNIX
;
414 sa
.un
.sun_path
[0] = 0;
415 strncpy(sa
.un
.sun_path
+1, arg_remote_host
+1, sizeof(sa
.un
.sun_path
)-1);
416 return connection_start(c
, &sa
.sa
, SOCKADDR_UN_LEN(sa
.un
));
419 service
= strrchr(arg_remote_host
, ':');
421 node
= strndupa(arg_remote_host
, service
- arg_remote_host
);
424 node
= arg_remote_host
;
428 log_debug("Looking up address info for %s:%s", node
, service
);
429 r
= sd_resolve_getaddrinfo(c
->context
->resolve
, &c
->resolve_query
, node
, service
, &hints
, resolve_cb
, c
);
431 log_error_errno(r
, "Failed to resolve remote host: %m");
439 return 0; /* ignore errors, continue serving */
442 static int add_connection_socket(Context
*context
, int fd
) {
449 if (set_size(context
->connections
) > arg_connections_max
) {
450 log_warning("Hit connection limit, refusing connection.");
455 r
= set_ensure_allocated(&context
->connections
, NULL
);
461 c
= new0(Connection
, 1);
467 c
->context
= context
;
470 c
->server_to_client_buffer
[0] = c
->server_to_client_buffer
[1] = -1;
471 c
->client_to_server_buffer
[0] = c
->client_to_server_buffer
[1] = -1;
473 r
= set_put(context
->connections
, c
);
480 return resolve_remote(c
);
483 static int accept_cb(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
484 _cleanup_free_
char *peer
= NULL
;
485 Context
*context
= userdata
;
490 assert(revents
& EPOLLIN
);
493 nfd
= accept4(fd
, NULL
, NULL
, SOCK_NONBLOCK
|SOCK_CLOEXEC
);
495 if (errno
!= -EAGAIN
)
496 log_warning_errno(errno
, "Failed to accept() socket: %m");
498 getpeername_pretty(nfd
, true, &peer
);
499 log_debug("New connection from %s", strna(peer
));
501 r
= add_connection_socket(context
, nfd
);
503 log_error_errno(r
, "Failed to accept connection, ignoring: %m");
508 r
= sd_event_source_set_enabled(s
, SD_EVENT_ONESHOT
);
510 log_error_errno(r
, "Error while re-enabling listener with ONESHOT: %m");
511 sd_event_exit(context
->event
, r
);
518 static int add_listen_socket(Context
*context
, int fd
) {
519 sd_event_source
*source
;
525 r
= set_ensure_allocated(&context
->listen
, NULL
);
531 r
= sd_is_socket(fd
, 0, SOCK_STREAM
, 1);
533 return log_error_errno(r
, "Failed to determine socket type: %m");
535 log_error("Passed in socket is not a stream socket.");
539 r
= fd_nonblock(fd
, true);
541 return log_error_errno(r
, "Failed to mark file descriptor non-blocking: %m");
543 r
= sd_event_add_io(context
->event
, &source
, fd
, EPOLLIN
, accept_cb
, context
);
545 return log_error_errno(r
, "Failed to add event source: %m");
547 r
= set_put(context
->listen
, source
);
549 log_error_errno(r
, "Failed to add source to set: %m");
550 sd_event_source_unref(source
);
554 /* Set the watcher to oneshot in case other processes are also
555 * watching to accept(). */
556 r
= sd_event_source_set_enabled(source
, SD_EVENT_ONESHOT
);
558 return log_error_errno(r
, "Failed to enable oneshot mode: %m");
563 static void help(void) {
564 printf("%1$s [HOST:PORT]\n"
566 "Bidirectionally proxy local sockets to another (possibly remote) socket.\n\n"
567 " -c --connections-max= Set the maximum number of connections to be accepted\n"
568 " -h --help Show this help\n"
569 " --version Show package version\n",
570 program_invocation_short_name
);
573 static int parse_argv(int argc
, char *argv
[]) {
580 static const struct option options
[] = {
581 { "connections-max", required_argument
, NULL
, 'c' },
582 { "help", no_argument
, NULL
, 'h' },
583 { "version", no_argument
, NULL
, ARG_VERSION
},
592 while ((c
= getopt_long(argc
, argv
, "c:h", options
, NULL
)) >= 0)
601 r
= safe_atou(optarg
, &arg_connections_max
);
603 log_error("Failed to parse --connections-max= argument: %s", optarg
);
607 if (arg_connections_max
< 1) {
608 log_error("Connection limit is too low.");
621 assert_not_reached("Unhandled option");
624 if (optind
>= argc
) {
625 log_error("Not enough parameters.");
629 if (argc
!= optind
+1) {
630 log_error("Too many parameters.");
634 arg_remote_host
= argv
[optind
];
638 int main(int argc
, char *argv
[]) {
639 Context context
= {};
642 log_parse_environment();
645 r
= parse_argv(argc
, argv
);
649 r
= sd_event_default(&context
.event
);
651 log_error_errno(r
, "Failed to allocate event loop: %m");
655 r
= sd_resolve_default(&context
.resolve
);
657 log_error_errno(r
, "Failed to allocate resolver: %m");
661 r
= sd_resolve_attach_event(context
.resolve
, context
.event
, 0);
663 log_error_errno(r
, "Failed to attach resolver: %m");
667 sd_event_set_watchdog(context
.event
, true);
669 n
= sd_listen_fds(1);
671 log_error("Failed to receive sockets from parent.");
675 log_error("Didn't get any sockets passed in.");
680 for (fd
= SD_LISTEN_FDS_START
; fd
< SD_LISTEN_FDS_START
+ n
; fd
++) {
681 r
= add_listen_socket(&context
, fd
);
686 r
= sd_event_loop(context
.event
);
688 log_error_errno(r
, "Failed to run event loop: %m");
693 context_free(&context
);
695 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;