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/>.
22 #include <arpa/inet.h>
29 #include <sys/fcntl.h>
30 #include <sys/socket.h>
35 #include "sd-daemon.h"
37 #include "socket-util.h"
40 #define BUFFER_SIZE 16384
41 #define _cleanup_freeaddrinfo_ _cleanup_(freeaddrinfop)
43 unsigned int total_clients = 0;
45 DEFINE_TRIVIAL_CLEANUP_FUNC(struct addrinfo *, freeaddrinfo);
51 const char *remote_host;
52 const char *remote_service;
57 sd_event_source *w_recv;
58 sd_event_source *w_send;
59 struct connection *c_destination;
60 size_t buffer_filled_len;
61 size_t buffer_sent_len;
62 char buffer[BUFFER_SIZE];
65 static void free_connection(struct connection *c) {
66 log_debug("Freeing fd=%d (conn %p).", c->fd, c);
67 sd_event_source_unref(c->w_recv);
68 sd_event_source_unref(c->w_send);
73 static int send_buffer(struct connection *sender) {
74 struct connection *receiver = sender->c_destination;
78 /* We cannot assume that even a partial send() indicates that
79 * the next send() will block. Loop until it does. */
80 while (sender->buffer_filled_len > sender->buffer_sent_len) {
81 len = send(receiver->fd, sender->buffer + sender->buffer_sent_len, sender->buffer_filled_len - sender->buffer_sent_len, 0);
82 log_debug("send(%d, ...)=%ld", receiver->fd, len);
84 if (errno != EWOULDBLOCK && errno != EAGAIN) {
85 log_error("Error %d in send to fd=%d: %m", errno, receiver->fd);
89 /* send() is in a blocking state. */
94 /* len < 0 can't occur here. len == 0 is possible but
95 * undefined behavior for nonblocking send(). */
97 sender->buffer_sent_len += len;
100 log_debug("send(%d, ...) completed with %lu bytes still buffered.", receiver->fd, sender->buffer_filled_len - sender->buffer_sent_len);
102 /* Detect a would-block state or partial send. */
103 if (sender->buffer_filled_len > sender->buffer_sent_len) {
105 /* If the buffer is full, disable events coming for recv. */
106 if (sender->buffer_filled_len == BUFFER_SIZE) {
107 r = sd_event_source_set_enabled(sender->w_recv, SD_EVENT_OFF);
109 log_error("Error %d disabling recv for fd=%d: %s", r, sender->fd, strerror(-r));
114 /* Watch for when the recipient can be sent data again. */
115 r = sd_event_source_set_enabled(receiver->w_send, SD_EVENT_ON);
117 log_error("Error %d enabling send for fd=%d: %s", r, receiver->fd, strerror(-r));
120 log_debug("Done with recv for fd=%d. Waiting on send for fd=%d.", sender->fd, receiver->fd);
124 /* If we sent everything without blocking, the buffer is now empty. */
125 sender->buffer_filled_len = 0;
126 sender->buffer_sent_len = 0;
128 /* Unmute the sender, in case the buffer was full. */
129 r = sd_event_source_set_enabled(sender->w_recv, SD_EVENT_ON);
131 log_error("Error %d enabling recv for fd=%d: %s", r, sender->fd, strerror(-r));
135 /* Mute the recipient, as we have no data to send now. */
136 r = sd_event_source_set_enabled(receiver->w_send, SD_EVENT_OFF);
138 log_error("Error %d disabling send for fd=%d: %s", r, receiver->fd, strerror(-r));
145 static int transfer_data_cb(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
146 struct connection *c = (struct connection *) userdata;
150 assert(revents & (EPOLLIN | EPOLLOUT));
153 log_debug("Got event revents=%d from fd=%d (conn %p).", revents, fd, c);
155 if (revents & EPOLLIN) {
156 log_debug("About to recv up to %lu bytes from fd=%d (%lu/BUFFER_SIZE).", BUFFER_SIZE - c->buffer_filled_len, fd, c->buffer_filled_len);
158 assert(s == c->w_recv);
160 /* Receive until the buffer's full, there's no more data,
161 * or the client/server disconnects. */
162 while (c->buffer_filled_len < BUFFER_SIZE) {
163 len = recv(fd, c->buffer + c->buffer_filled_len, BUFFER_SIZE - c->buffer_filled_len, 0);
164 log_debug("recv(%d, ...)=%ld", fd, len);
166 if (errno != EWOULDBLOCK && errno != EAGAIN) {
167 log_error("Error %d in recv from fd=%d: %m", errno, fd);
171 /* recv() is in a blocking state. */
176 log_debug("Clean disconnection from fd=%d", fd);
178 free_connection(c->c_destination);
184 log_debug("Recording that the buffer got %ld more bytes full.", len);
185 c->buffer_filled_len += len;
186 log_debug("Buffer now has %ld bytes full.", c->buffer_filled_len);
189 /* Try sending the data immediately. */
190 return send_buffer(c);
193 assert(s == c->w_send);
194 return send_buffer(c->c_destination);
200 /* Once sending to the server is unblocked, set up the real watchers. */
201 static int connected_to_server_cb(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
202 struct sd_event *e = NULL;
203 struct connection *c_server_to_client = (struct connection *) userdata;
204 struct connection *c_client_to_server = c_server_to_client->c_destination;
207 assert(revents & EPOLLOUT);
211 /* Cancel the initial write watcher for the server. */
212 sd_event_source_unref(s);
214 log_debug("Connected to server. Initializing watchers for receiving data.");
216 /* A disabled send watcher for the server. */
217 r = sd_event_add_io(e, c_server_to_client->fd, EPOLLOUT, transfer_data_cb, c_server_to_client, &c_server_to_client->w_send);
219 log_error("Error %d creating send watcher for fd=%d: %s", r, c_server_to_client->fd, strerror(-r));
222 r = sd_event_source_set_enabled(c_server_to_client->w_send, SD_EVENT_OFF);
224 log_error("Error %d muting send for fd=%d: %s", r, c_server_to_client->fd, strerror(-r));
228 /* A recv watcher for the server. */
229 r = sd_event_add_io(e, c_server_to_client->fd, EPOLLIN, transfer_data_cb, c_server_to_client, &c_server_to_client->w_recv);
231 log_error("Error %d creating recv watcher for fd=%d: %s", r, c_server_to_client->fd, strerror(-r));
235 /* A disabled send watcher for the client. */
236 r = sd_event_add_io(e, c_client_to_server->fd, EPOLLOUT, transfer_data_cb, c_client_to_server, &c_client_to_server->w_send);
238 log_error("Error %d creating send watcher for fd=%d: %s", r, c_client_to_server->fd, strerror(-r));
241 r = sd_event_source_set_enabled(c_client_to_server->w_send, SD_EVENT_OFF);
243 log_error("Error %d muting send for fd=%d: %s", r, c_client_to_server->fd, strerror(-r));
247 /* A recv watcher for the client. */
248 r = sd_event_add_io(e, c_client_to_server->fd, EPOLLIN, transfer_data_cb, c_client_to_server, &c_client_to_server->w_recv);
250 log_error("Error %d creating recv watcher for fd=%d: %s", r, c_client_to_server->fd, strerror(-r));
257 free_connection(c_client_to_server);
258 free_connection(c_server_to_client);
264 static int get_server_connection_fd(const struct proxy *proxy) {
269 if (proxy->remote_is_inet) {
271 _cleanup_freeaddrinfo_ struct addrinfo *result = NULL;
272 struct addrinfo hints = {.ai_family = AF_UNSPEC,
273 .ai_socktype = SOCK_STREAM,
274 .ai_flags = AI_PASSIVE};
276 log_debug("Looking up address info for %s:%s", proxy->remote_host, proxy->remote_service);
277 s = getaddrinfo(proxy->remote_host, proxy->remote_service, &hints, &result);
279 log_error("getaddrinfo error (%d): %s", s, gai_strerror(s));
283 if (result == NULL) {
284 log_error("getaddrinfo: no result");
288 /* @TODO: Try connecting to all results instead of just the first. */
289 server_fd = socket(result->ai_family, result->ai_socktype | SOCK_NONBLOCK, result->ai_protocol);
291 log_error("Error %d creating socket: %m", errno);
295 r = connect(server_fd, result->ai_addr, result->ai_addrlen);
296 /* Ignore EINPROGRESS errors because they're expected for a nonblocking socket. */
297 if (r < 0 && errno != EINPROGRESS) {
298 log_error("Error %d while connecting to socket %s:%s: %m", errno, proxy->remote_host, proxy->remote_service);
303 struct sockaddr_un remote;
305 server_fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0);
307 log_error("Error %d creating socket: %m", errno);
311 remote.sun_family = AF_UNIX;
312 strncpy(remote.sun_path, proxy->remote_host, sizeof(remote.sun_path));
313 len = strlen(remote.sun_path) + sizeof(remote.sun_family);
314 r = connect(server_fd, (struct sockaddr *) &remote, len);
315 if (r < 0 && errno != EINPROGRESS) {
316 log_error("Error %d while connecting to Unix domain socket %s: %m", errno, proxy->remote_host);
321 log_debug("Server connection is fd=%d", server_fd);
325 static int accept_cb(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
326 struct proxy *proxy = (struct proxy *) userdata;
327 struct connection *c_server_to_client;
328 struct connection *c_client_to_server;
330 union sockaddr_union sa;
331 socklen_t salen = sizeof(sa);
333 assert(revents & EPOLLIN);
335 c_server_to_client = malloc0(sizeof(struct connection));
336 if (c_server_to_client == NULL) {
341 c_client_to_server = malloc0(sizeof(struct connection));
342 if (c_client_to_server == NULL) {
347 c_server_to_client->fd = get_server_connection_fd(proxy);
348 if (c_server_to_client->fd < 0) {
349 log_error("Error initiating server connection.");
353 c_client_to_server->fd = accept(fd, (struct sockaddr *) &sa, &salen);
354 if (c_client_to_server->fd < 0) {
355 log_error("Error accepting client connection.");
359 /* Unlike on BSD, client sockets do not inherit nonblocking status
360 * from the listening socket. */
361 r = fd_nonblock(c_client_to_server->fd, true);
363 log_error("Error %d marking client connection as nonblocking: %s", r, strerror(-r));
367 if (sa.sa.sa_family == AF_INET || sa.sa.sa_family == AF_INET6) {
368 char sa_str[INET6_ADDRSTRLEN];
371 success = inet_ntop(sa.sa.sa_family, &sa.in6.sin6_addr, sa_str, INET6_ADDRSTRLEN);
373 log_warning("Error %d calling inet_ntop: %m", errno);
375 log_debug("Accepted client connection from %s as fd=%d", sa_str, c_client_to_server->fd);
378 log_debug("Accepted client connection (non-IP) as fd=%d", c_client_to_server->fd);
382 log_debug("Client fd=%d (conn %p) successfully connected. Total clients: %u", c_client_to_server->fd, c_client_to_server, total_clients);
383 log_debug("Server fd=%d (conn %p) successfully initialized.", c_server_to_client->fd, c_server_to_client);
385 /* Initialize watcher for send to server; this shows connectivity. */
386 r = sd_event_add_io(sd_event_get(s), c_server_to_client->fd, EPOLLOUT, connected_to_server_cb, c_server_to_client, &c_server_to_client->w_send);
388 log_error("Error %d creating connectivity watcher for fd=%d: %s", r, c_server_to_client->fd, strerror(-r));
392 /* Allow lookups of the opposite connection. */
393 c_server_to_client->c_destination = c_client_to_server;
394 c_client_to_server->c_destination = c_server_to_client;
399 log_warning("Accepting a client connection or connecting to the server failed.");
400 free_connection(c_client_to_server);
401 free_connection(c_server_to_client);
404 /* Preserve the main loop even if a single proxy setup fails. */
408 static int run_main_loop(struct proxy *proxy) {
409 int r = EXIT_SUCCESS;
410 struct sd_event *e = NULL;
411 sd_event_source *w_accept = NULL;
413 r = sd_event_new(&e);
417 r = fd_nonblock(proxy->listen_fd, true);
421 log_debug("Initializing main listener fd=%d", proxy->listen_fd);
423 sd_event_add_io(e, proxy->listen_fd, EPOLLIN, accept_cb, proxy, &w_accept);
425 log_debug("Initialized main listener. Entering loop.");
430 sd_event_source_unref(w_accept);
436 static int help(void) {
438 printf("%s hostname-or-ip port-or-service\n"
439 "%s unix-domain-socket-path\n\n"
440 "Inherit a socket. Bidirectionally proxy.\n\n"
441 " -h --help Show this help\n"
442 " --version Print version and exit\n"
443 " --ignore-env Ignore expected systemd environment\n",
444 program_invocation_short_name,
445 program_invocation_short_name);
450 static void version(void) {
451 puts(PACKAGE_STRING " saproxy");
454 static int parse_argv(int argc, char *argv[], struct proxy *p) {
461 static const struct option options[] = {
462 { "help", no_argument, NULL, 'h' },
463 { "version", no_argument, NULL, ARG_VERSION },
464 { "ignore-env", no_argument, NULL, ARG_IGNORE_ENV},
473 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
489 p->ignore_env = true;
493 log_error("Unknown option code %c", c);
498 if (optind + 1 != argc && optind + 2 != argc) {
499 log_error("Incorrect number of positional arguments.");
504 p->remote_host = argv[optind];
505 assert(p->remote_host);
507 p->remote_is_inet = p->remote_host[0] != '/';
509 if (optind == argc - 2) {
510 if (!p->remote_is_inet) {
511 log_error("A port or service is not allowed for Unix socket destinations.");
515 p->remote_service = argv[optind + 1];
516 assert(p->remote_service);
517 } else if (p->remote_is_inet) {
518 log_error("A port or service is required for IP destinations.");
526 int main(int argc, char *argv[]) {
530 log_parse_environment();
533 r = parse_argv(argc, argv, &p);
537 p.listen_fd = SD_LISTEN_FDS_START;
541 n = sd_listen_fds(1);
543 log_error("Found zero inheritable sockets. Are you sure this is running as a socket-activated service?");
547 log_error("Error %d while finding inheritable sockets: %s", n, strerror(-n));
551 log_error("Can't listen on more than one socket.");
557 /* @TODO: Check if this proxy can work with datagram sockets. */
558 r = sd_is_socket(p.listen_fd, 0, SOCK_STREAM, 1);
560 log_error("Error %d while checking inherited socket: %s", r, strerror(-r));
564 log_info("Starting the socket activation proxy with listener fd=%d.", p.listen_fd);
566 r = run_main_loop(&p);
568 log_error("Error %d from main loop.", r);
574 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;