1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2012 Zbigniew Jędrzejewski-Szmek
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/>.
28 #include <sys/prctl.h>
29 #include <sys/socket.h>
33 #include <gnutls/gnutls.h>
36 #include "sd-daemon.h"
38 #include "conf-parser.h"
40 #include "journal-file.h"
41 #include "journald-native.h"
43 #include "signal-util.h"
44 #include "socket-util.h"
46 #include "journal-remote-write.h"
47 #include "journal-remote.h"
49 #define REMOTE_JOURNAL_PATH "/var/log/journal/remote"
51 #define PRIV_KEY_FILE CERTIFICATE_ROOT "/private/journal-remote.pem"
52 #define CERT_FILE CERTIFICATE_ROOT "/certs/journal-remote.pem"
53 #define TRUST_FILE CERTIFICATE_ROOT "/ca/trusted.pem"
55 static char* arg_url
= NULL
;
56 static char* arg_getter
= NULL
;
57 static char* arg_listen_raw
= NULL
;
58 static char* arg_listen_http
= NULL
;
59 static char* arg_listen_https
= NULL
;
60 static char** arg_files
= NULL
;
61 static int arg_compress
= true;
62 static int arg_seal
= false;
63 static int http_socket
= -1, https_socket
= -1;
64 static char** arg_gnutls_log
= NULL
;
66 static JournalWriteSplitMode arg_split_mode
= JOURNAL_WRITE_SPLIT_HOST
;
67 static char* arg_output
= NULL
;
69 static char *arg_key
= NULL
;
70 static char *arg_cert
= NULL
;
71 static char *arg_trust
= NULL
;
72 static bool arg_trust_all
= false;
74 /**********************************************************************
75 **********************************************************************
76 **********************************************************************/
78 static int spawn_child(const char* child
, char** argv
) {
80 pid_t parent_pid
, child_pid
;
84 return log_error_errno(errno
, "Failed to create pager pipe: %m");
86 parent_pid
= getpid();
90 r
= log_error_errno(errno
, "Failed to fork: %m");
98 (void) reset_all_signal_handlers();
99 (void) reset_signal_mask();
101 r
= dup2(fd
[1], STDOUT_FILENO
);
103 log_error_errno(errno
, "Failed to dup pipe to stdout: %m");
109 /* Make sure the child goes away when the parent dies */
110 if (prctl(PR_SET_PDEATHSIG
, SIGTERM
) < 0)
113 /* Check whether our parent died before we were able
114 * to set the death signal */
115 if (getppid() != parent_pid
)
119 log_error_errno(errno
, "Failed to exec child %s: %m", child
);
125 log_warning_errno(errno
, "Failed to close write end of pipe: %m");
130 static int spawn_curl(const char* url
) {
131 char **argv
= STRV_MAKE("curl",
132 "-HAccept: application/vnd.fdo.journal",
138 r
= spawn_child("curl", argv
);
140 log_error_errno(errno
, "Failed to spawn curl: %m");
144 static int spawn_getter(const char *getter
, const char *url
) {
146 _cleanup_strv_free_
char **words
= NULL
;
149 r
= strv_split_extract(&words
, getter
, WHITESPACE
, EXTRACT_QUOTES
);
151 return log_error_errno(r
, "Failed to split getter option: %m");
153 r
= strv_extend(&words
, url
);
155 return log_error_errno(r
, "Failed to create command line: %m");
157 r
= spawn_child(words
[0], words
);
159 log_error_errno(errno
, "Failed to spawn getter %s: %m", getter
);
164 #define filename_escape(s) xescape((s), "/ ")
166 static int open_output(Writer
*w
, const char* host
) {
167 _cleanup_free_
char *_output
= NULL
;
171 switch (arg_split_mode
) {
172 case JOURNAL_WRITE_SPLIT_NONE
:
173 output
= arg_output
?: REMOTE_JOURNAL_PATH
"/remote.journal";
176 case JOURNAL_WRITE_SPLIT_HOST
: {
177 _cleanup_free_
char *name
;
181 name
= filename_escape(host
);
185 r
= asprintf(&_output
, "%s/remote-%s.journal",
186 arg_output
?: REMOTE_JOURNAL_PATH
,
196 assert_not_reached("what?");
199 r
= journal_file_open_reliably(output
,
200 O_RDWR
|O_CREAT
, 0640,
201 arg_compress
, arg_seal
,
206 log_error_errno(r
, "Failed to open output journal %s: %m",
209 log_debug("Opened output file %s", w
->journal
->path
);
213 /**********************************************************************
214 **********************************************************************
215 **********************************************************************/
217 static int init_writer_hashmap(RemoteServer
*s
) {
218 static const struct hash_ops
*hash_ops
[] = {
219 [JOURNAL_WRITE_SPLIT_NONE
] = NULL
,
220 [JOURNAL_WRITE_SPLIT_HOST
] = &string_hash_ops
,
223 assert(arg_split_mode
>= 0 && arg_split_mode
< (int) ELEMENTSOF(hash_ops
));
225 s
->writers
= hashmap_new(hash_ops
[arg_split_mode
]);
232 static int get_writer(RemoteServer
*s
, const char *host
,
235 _cleanup_writer_unref_ Writer
*w
= NULL
;
238 switch(arg_split_mode
) {
239 case JOURNAL_WRITE_SPLIT_NONE
:
240 key
= "one and only";
243 case JOURNAL_WRITE_SPLIT_HOST
:
249 assert_not_reached("what split mode?");
252 w
= hashmap_get(s
->writers
, key
);
260 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_HOST
) {
261 w
->hashmap_key
= strdup(key
);
266 r
= open_output(w
, host
);
270 r
= hashmap_put(s
->writers
, w
->hashmap_key
?: key
, w
);
280 /**********************************************************************
281 **********************************************************************
282 **********************************************************************/
284 /* This should go away as soon as µhttpd allows state to be passed around. */
285 static RemoteServer
*server
;
287 static int dispatch_raw_source_event(sd_event_source
*event
,
291 static int dispatch_raw_source_until_block(sd_event_source
*event
,
293 static int dispatch_blocking_source_event(sd_event_source
*event
,
295 static int dispatch_raw_connection_event(sd_event_source
*event
,
299 static int dispatch_http_event(sd_event_source
*event
,
304 static int get_source_for_fd(RemoteServer
*s
,
305 int fd
, char *name
, RemoteSource
**source
) {
309 /* This takes ownership of name, but only on success. */
314 if (!GREEDY_REALLOC0(s
->sources
, s
->sources_size
, fd
+ 1))
317 r
= get_writer(s
, name
, &writer
);
319 return log_warning_errno(r
, "Failed to get writer for source %s: %m",
322 if (s
->sources
[fd
] == NULL
) {
323 s
->sources
[fd
] = source_new(fd
, false, name
, writer
);
324 if (!s
->sources
[fd
]) {
325 writer_unref(writer
);
332 *source
= s
->sources
[fd
];
336 static int remove_source(RemoteServer
*s
, int fd
) {
337 RemoteSource
*source
;
340 assert(fd
>= 0 && fd
< (ssize_t
) s
->sources_size
);
342 source
= s
->sources
[fd
];
344 /* this closes fd too */
346 s
->sources
[fd
] = NULL
;
353 static int add_source(RemoteServer
*s
, int fd
, char* name
, bool own_name
) {
355 RemoteSource
*source
= NULL
;
358 /* This takes ownership of name, even on failure, if own_name is true. */
370 r
= get_source_for_fd(s
, fd
, name
, &source
);
372 log_error_errno(r
, "Failed to create source for fd:%d (%s): %m",
378 r
= sd_event_add_io(s
->events
, &source
->event
,
379 fd
, EPOLLIN
|EPOLLRDHUP
|EPOLLPRI
,
380 dispatch_raw_source_event
, source
);
382 /* Add additional source for buffer processing. It will be
384 r
= sd_event_add_defer(s
->events
, &source
->buffer_event
,
385 dispatch_raw_source_until_block
, source
);
387 sd_event_source_set_enabled(source
->buffer_event
, SD_EVENT_OFF
);
388 } else if (r
== -EPERM
) {
389 log_debug("Falling back to sd_event_add_defer for fd:%d (%s)", fd
, name
);
390 r
= sd_event_add_defer(s
->events
, &source
->event
,
391 dispatch_blocking_source_event
, source
);
393 sd_event_source_set_enabled(source
->event
, SD_EVENT_ON
);
396 log_error_errno(r
, "Failed to register event source for fd:%d: %m",
401 r
= sd_event_source_set_description(source
->event
, name
);
403 log_error_errno(r
, "Failed to set source name for fd:%d: %m", fd
);
407 return 1; /* work to do */
410 remove_source(s
, fd
);
414 static int add_raw_socket(RemoteServer
*s
, int fd
) {
416 _cleanup_close_
int fd_
= fd
;
417 char name
[sizeof("raw-socket-")-1 + DECIMAL_STR_MAX(int) + 1];
421 r
= sd_event_add_io(s
->events
, &s
->listen_event
,
423 dispatch_raw_connection_event
, s
);
427 xsprintf(name
, "raw-socket-%d", fd
);
429 r
= sd_event_source_set_description(s
->listen_event
, name
);
438 static int setup_raw_socket(RemoteServer
*s
, const char *address
) {
441 fd
= make_socket_fd(LOG_INFO
, address
, SOCK_STREAM
| SOCK_CLOEXEC
);
445 return add_raw_socket(s
, fd
);
448 /**********************************************************************
449 **********************************************************************
450 **********************************************************************/
452 static int request_meta(void **connection_cls
, int fd
, char *hostname
) {
453 RemoteSource
*source
;
457 assert(connection_cls
);
461 r
= get_writer(server
, hostname
, &writer
);
463 return log_warning_errno(r
, "Failed to get writer for source %s: %m",
466 source
= source_new(fd
, true, hostname
, writer
);
468 writer_unref(writer
);
472 log_debug("Added RemoteSource as connection metadata %p", source
);
474 *connection_cls
= source
;
478 static void request_meta_free(void *cls
,
479 struct MHD_Connection
*connection
,
480 void **connection_cls
,
481 enum MHD_RequestTerminationCode toe
) {
484 assert(connection_cls
);
488 log_debug("Cleaning up connection metadata %p", s
);
490 *connection_cls
= NULL
;
494 static int process_http_upload(
495 struct MHD_Connection
*connection
,
496 const char *upload_data
,
497 size_t *upload_data_size
,
498 RemoteSource
*source
) {
500 bool finished
= false;
506 log_trace("%s: connection %p, %zu bytes",
507 __func__
, connection
, *upload_data_size
);
509 if (*upload_data_size
) {
510 log_trace("Received %zu bytes", *upload_data_size
);
512 r
= push_data(source
, upload_data
, *upload_data_size
);
514 return mhd_respond_oom(connection
);
516 *upload_data_size
= 0;
521 r
= process_source(source
, arg_compress
, arg_seal
);
525 log_warning("Failed to process data for connection %p", connection
);
527 return mhd_respondf(connection
,
528 MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
,
529 "Entry is too large, maximum is %u bytes.\n",
532 return mhd_respondf(connection
,
533 MHD_HTTP_UNPROCESSABLE_ENTITY
,
534 "Processing failed: %s.", strerror(-r
));
541 /* The upload is finished */
543 remaining
= source_non_empty(source
);
545 log_warning("Premature EOFbyte. %zu bytes lost.", remaining
);
546 return mhd_respondf(connection
, MHD_HTTP_EXPECTATION_FAILED
,
547 "Premature EOF. %zu bytes of trailing data not processed.",
551 return mhd_respond(connection
, MHD_HTTP_ACCEPTED
, "OK.\n");
554 static int request_handler(
556 struct MHD_Connection
*connection
,
560 const char *upload_data
,
561 size_t *upload_data_size
,
562 void **connection_cls
) {
566 _cleanup_free_
char *hostname
= NULL
;
569 assert(connection_cls
);
573 log_trace("Handling a connection %s %s %s", method
, url
, version
);
576 return process_http_upload(connection
,
577 upload_data
, upload_data_size
,
580 if (!streq(method
, "POST"))
581 return mhd_respond(connection
, MHD_HTTP_METHOD_NOT_ACCEPTABLE
,
582 "Unsupported method.\n");
584 if (!streq(url
, "/upload"))
585 return mhd_respond(connection
, MHD_HTTP_NOT_FOUND
,
588 header
= MHD_lookup_connection_value(connection
,
589 MHD_HEADER_KIND
, "Content-Type");
590 if (!header
|| !streq(header
, "application/vnd.fdo.journal"))
591 return mhd_respond(connection
, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE
,
592 "Content-Type: application/vnd.fdo.journal"
596 const union MHD_ConnectionInfo
*ci
;
598 ci
= MHD_get_connection_info(connection
,
599 MHD_CONNECTION_INFO_CONNECTION_FD
);
601 log_error("MHD_get_connection_info failed: cannot get remote fd");
602 return mhd_respond(connection
, MHD_HTTP_INTERNAL_SERVER_ERROR
,
603 "Cannot check remote address");
610 if (server
->check_trust
) {
611 r
= check_permissions(connection
, &code
, &hostname
);
615 r
= getnameinfo_pretty(fd
, &hostname
);
617 return mhd_respond(connection
, MHD_HTTP_INTERNAL_SERVER_ERROR
,
618 "Cannot check remote hostname");
623 r
= request_meta(connection_cls
, fd
, hostname
);
625 return respond_oom(connection
);
627 return mhd_respond(connection
, MHD_HTTP_INTERNAL_SERVER_ERROR
,
634 static int setup_microhttpd_server(RemoteServer
*s
,
639 struct MHD_OptionItem opts
[] = {
640 { MHD_OPTION_NOTIFY_COMPLETED
, (intptr_t) request_meta_free
},
641 { MHD_OPTION_EXTERNAL_LOGGER
, (intptr_t) microhttpd_logger
},
642 { MHD_OPTION_LISTEN_SOCKET
, fd
},
650 MHD_USE_PEDANTIC_CHECKS
|
651 MHD_USE_EPOLL_LINUX_ONLY
|
654 const union MHD_DaemonInfo
*info
;
660 r
= fd_nonblock(fd
, true);
662 return log_error_errno(r
, "Failed to make fd:%d nonblocking: %m", fd
);
667 opts
[opts_pos
++] = (struct MHD_OptionItem
)
668 {MHD_OPTION_HTTPS_MEM_KEY
, 0, (char*) key
};
669 opts
[opts_pos
++] = (struct MHD_OptionItem
)
670 {MHD_OPTION_HTTPS_MEM_CERT
, 0, (char*) cert
};
672 flags
|= MHD_USE_SSL
;
675 opts
[opts_pos
++] = (struct MHD_OptionItem
)
676 {MHD_OPTION_HTTPS_MEM_TRUST
, 0, (char*) trust
};
679 d
= new(MHDDaemonWrapper
, 1);
683 d
->fd
= (uint64_t) fd
;
685 d
->daemon
= MHD_start_daemon(flags
, 0,
687 request_handler
, NULL
,
688 MHD_OPTION_ARRAY
, opts
,
691 log_error("Failed to start µhttp daemon");
696 log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)",
697 key
? "HTTPS" : "HTTP", fd
, d
);
700 info
= MHD_get_daemon_info(d
->daemon
, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY
);
702 log_error("µhttp returned NULL daemon info");
707 epoll_fd
= info
->listen_fd
;
709 log_error("µhttp epoll fd is invalid");
714 r
= sd_event_add_io(s
->events
, &d
->event
,
716 dispatch_http_event
, d
);
718 log_error_errno(r
, "Failed to add event callback: %m");
722 r
= sd_event_source_set_description(d
->event
, "epoll-fd");
724 log_error_errno(r
, "Failed to set source name: %m");
728 r
= hashmap_ensure_allocated(&s
->daemons
, &uint64_hash_ops
);
734 r
= hashmap_put(s
->daemons
, &d
->fd
, d
);
736 log_error_errno(r
, "Failed to add daemon to hashmap: %m");
744 MHD_stop_daemon(d
->daemon
);
750 static int setup_microhttpd_socket(RemoteServer
*s
,
757 fd
= make_socket_fd(LOG_DEBUG
, address
, SOCK_STREAM
| SOCK_CLOEXEC
);
761 return setup_microhttpd_server(s
, fd
, key
, cert
, trust
);
764 static int dispatch_http_event(sd_event_source
*event
,
768 MHDDaemonWrapper
*d
= userdata
;
773 r
= MHD_run(d
->daemon
);
775 log_error("MHD_run failed!");
776 // XXX: unregister daemon
780 return 1; /* work to do */
783 /**********************************************************************
784 **********************************************************************
785 **********************************************************************/
787 static int setup_signals(RemoteServer
*s
) {
792 assert_se(sigprocmask_many(SIG_SETMASK
, NULL
, SIGINT
, SIGTERM
, -1) >= 0);
794 r
= sd_event_add_signal(s
->events
, &s
->sigterm_event
, SIGTERM
, NULL
, s
);
798 r
= sd_event_add_signal(s
->events
, &s
->sigint_event
, SIGINT
, NULL
, s
);
805 static int negative_fd(const char *spec
) {
806 /* Return a non-positive number as its inverse, -EINVAL otherwise. */
810 r
= safe_atoi(spec
, &fd
);
820 static int remoteserver_init(RemoteServer
*s
,
829 if ((arg_listen_raw
|| arg_listen_http
) && trust
) {
830 log_error("Option --trust makes all non-HTTPS connections untrusted.");
834 r
= sd_event_default(&s
->events
);
836 return log_error_errno(r
, "Failed to allocate event loop: %m");
840 assert(server
== NULL
);
843 r
= init_writer_hashmap(s
);
847 n
= sd_listen_fds(true);
849 return log_error_errno(n
, "Failed to read listening file descriptors from environment: %m");
851 log_debug("Received %d descriptors", n
);
853 if (MAX(http_socket
, https_socket
) >= SD_LISTEN_FDS_START
+ n
) {
854 log_error("Received fewer sockets than expected");
858 for (fd
= SD_LISTEN_FDS_START
; fd
< SD_LISTEN_FDS_START
+ n
; fd
++) {
859 if (sd_is_socket(fd
, AF_UNSPEC
, 0, true)) {
860 log_debug("Received a listening socket (fd:%d)", fd
);
862 if (fd
== http_socket
)
863 r
= setup_microhttpd_server(s
, fd
, NULL
, NULL
, NULL
);
864 else if (fd
== https_socket
)
865 r
= setup_microhttpd_server(s
, fd
, key
, cert
, trust
);
867 r
= add_raw_socket(s
, fd
);
868 } else if (sd_is_socket(fd
, AF_UNSPEC
, 0, false)) {
871 r
= getnameinfo_pretty(fd
, &hostname
);
873 return log_error_errno(r
, "Failed to retrieve remote name: %m");
875 log_debug("Received a connection socket (fd:%d) from %s", fd
, hostname
);
877 r
= add_source(s
, fd
, hostname
, true);
879 log_error("Unknown socket passed on fd:%d", fd
);
885 return log_error_errno(r
, "Failed to register socket (fd:%d): %m",
890 const char *url
, *hostname
;
892 url
= strjoina(arg_url
, "/entries");
895 log_info("Spawning getter %s...", url
);
896 fd
= spawn_getter(arg_getter
, url
);
898 log_info("Spawning curl %s...", url
);
899 fd
= spawn_curl(url
);
905 startswith(arg_url
, "https://") ?:
906 startswith(arg_url
, "http://") ?:
909 r
= add_source(s
, fd
, (char*) hostname
, false);
914 if (arg_listen_raw
) {
915 log_debug("Listening on a socket...");
916 r
= setup_raw_socket(s
, arg_listen_raw
);
921 if (arg_listen_http
) {
922 r
= setup_microhttpd_socket(s
, arg_listen_http
, NULL
, NULL
, NULL
);
927 if (arg_listen_https
) {
928 r
= setup_microhttpd_socket(s
, arg_listen_https
, key
, cert
, trust
);
933 STRV_FOREACH(file
, arg_files
) {
934 const char *output_name
;
936 if (streq(*file
, "-")) {
937 log_debug("Using standard input as source.");
940 output_name
= "stdin";
942 log_debug("Reading file %s...", *file
);
944 fd
= open(*file
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NONBLOCK
);
946 return log_error_errno(errno
, "Failed to open %s: %m", *file
);
950 r
= add_source(s
, fd
, (char*) output_name
, false);
955 if (s
->active
== 0) {
956 log_error("Zarro sources specified");
960 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_NONE
) {
961 /* In this case we know what the writer will be
962 called, so we can create it and verify that we can
963 create output as expected. */
964 r
= get_writer(s
, NULL
, &s
->_single_writer
);
972 static void server_destroy(RemoteServer
*s
) {
976 while ((d
= hashmap_steal_first(s
->daemons
))) {
977 MHD_stop_daemon(d
->daemon
);
978 sd_event_source_unref(d
->event
);
982 hashmap_free(s
->daemons
);
984 assert(s
->sources_size
== 0 || s
->sources
);
985 for (i
= 0; i
< s
->sources_size
; i
++)
989 writer_unref(s
->_single_writer
);
990 hashmap_free(s
->writers
);
992 sd_event_source_unref(s
->sigterm_event
);
993 sd_event_source_unref(s
->sigint_event
);
994 sd_event_source_unref(s
->listen_event
);
995 sd_event_unref(s
->events
);
997 /* fds that we're listening on remain open... */
1000 /**********************************************************************
1001 **********************************************************************
1002 **********************************************************************/
1004 static int handle_raw_source(sd_event_source
*event
,
1009 RemoteSource
*source
;
1012 /* Returns 1 if there might be more data pending,
1013 * 0 if data is currently exhausted, negative on error.
1016 assert(fd
>= 0 && fd
< (ssize_t
) s
->sources_size
);
1017 source
= s
->sources
[fd
];
1018 assert(source
->fd
== fd
);
1020 r
= process_source(source
, arg_compress
, arg_seal
);
1021 if (source
->state
== STATE_EOF
) {
1024 log_debug("EOF reached with source fd:%d (%s)",
1025 source
->fd
, source
->name
);
1027 remaining
= source_non_empty(source
);
1029 log_notice("Premature EOF. %zu bytes lost.", remaining
);
1030 remove_source(s
, source
->fd
);
1031 log_debug("%zu active sources remaining", s
->active
);
1033 } else if (r
== -E2BIG
) {
1034 log_notice_errno(E2BIG
, "Entry too big, skipped");
1036 } else if (r
== -EAGAIN
) {
1039 log_debug_errno(r
, "Closing connection: %m");
1040 remove_source(server
, fd
);
1046 static int dispatch_raw_source_until_block(sd_event_source
*event
,
1048 RemoteSource
*source
= userdata
;
1051 /* Make sure event stays around even if source is destroyed */
1052 sd_event_source_ref(event
);
1054 r
= handle_raw_source(event
, source
->fd
, EPOLLIN
, server
);
1056 /* No more data for now */
1057 sd_event_source_set_enabled(event
, SD_EVENT_OFF
);
1059 sd_event_source_unref(event
);
1064 static int dispatch_raw_source_event(sd_event_source
*event
,
1068 RemoteSource
*source
= userdata
;
1071 assert(source
->event
);
1072 assert(source
->buffer_event
);
1074 r
= handle_raw_source(event
, fd
, EPOLLIN
, server
);
1076 /* Might have more data. We need to rerun the handler
1077 * until we are sure the buffer is exhausted. */
1078 sd_event_source_set_enabled(source
->buffer_event
, SD_EVENT_ON
);
1083 static int dispatch_blocking_source_event(sd_event_source
*event
,
1085 RemoteSource
*source
= userdata
;
1087 return handle_raw_source(event
, source
->fd
, EPOLLIN
, server
);
1090 static int accept_connection(const char* type
, int fd
,
1091 SocketAddress
*addr
, char **hostname
) {
1094 log_debug("Accepting new %s connection on fd:%d", type
, fd
);
1095 fd2
= accept4(fd
, &addr
->sockaddr
.sa
, &addr
->size
, SOCK_NONBLOCK
|SOCK_CLOEXEC
);
1097 return log_error_errno(errno
, "accept() on fd:%d failed: %m", fd
);
1099 switch(socket_address_family(addr
)) {
1102 _cleanup_free_
char *a
= NULL
;
1105 r
= socket_address_print(addr
, &a
);
1107 log_error_errno(r
, "socket_address_print(): %m");
1112 r
= socknameinfo_pretty(&addr
->sockaddr
, addr
->size
, &b
);
1114 log_error_errno(r
, "Resolving hostname failed: %m");
1119 log_debug("Accepted %s %s connection from %s",
1121 socket_address_family(addr
) == AF_INET
? "IP" : "IPv6",
1129 log_error("Rejected %s connection with unsupported family %d",
1130 type
, socket_address_family(addr
));
1137 static int dispatch_raw_connection_event(sd_event_source
*event
,
1141 RemoteServer
*s
= userdata
;
1143 SocketAddress addr
= {
1144 .size
= sizeof(union sockaddr_union
),
1145 .type
= SOCK_STREAM
,
1147 char *hostname
= NULL
;
1149 fd2
= accept_connection("raw", fd
, &addr
, &hostname
);
1153 return add_source(s
, fd2
, hostname
, true);
1156 /**********************************************************************
1157 **********************************************************************
1158 **********************************************************************/
1160 static const char* const journal_write_split_mode_table
[_JOURNAL_WRITE_SPLIT_MAX
] = {
1161 [JOURNAL_WRITE_SPLIT_NONE
] = "none",
1162 [JOURNAL_WRITE_SPLIT_HOST
] = "host",
1165 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(journal_write_split_mode
, JournalWriteSplitMode
);
1166 static DEFINE_CONFIG_PARSE_ENUM(config_parse_write_split_mode
,
1167 journal_write_split_mode
,
1168 JournalWriteSplitMode
,
1169 "Failed to parse split mode setting");
1171 static int parse_config(void) {
1172 const ConfigTableItem items
[] = {
1173 { "Remote", "SplitMode", config_parse_write_split_mode
, 0, &arg_split_mode
},
1174 { "Remote", "ServerKeyFile", config_parse_path
, 0, &arg_key
},
1175 { "Remote", "ServerCertificateFile", config_parse_path
, 0, &arg_cert
},
1176 { "Remote", "TrustedCertificateFile", config_parse_path
, 0, &arg_trust
},
1179 return config_parse_many(PKGSYSCONFDIR
"/journal-remote.conf",
1180 CONF_DIRS_NULSTR("systemd/journal-remote.conf"),
1181 "Remote\0", config_item_table_lookup
, items
,
1185 static void help(void) {
1186 printf("%s [OPTIONS...] {FILE|-}...\n\n"
1187 "Write external journal events to journal file(s).\n\n"
1188 " -h --help Show this help\n"
1189 " --version Show package version\n"
1190 " --url=URL Read events from systemd-journal-gatewayd at URL\n"
1191 " --getter=COMMAND Read events from the output of COMMAND\n"
1192 " --listen-raw=ADDR Listen for connections at ADDR\n"
1193 " --listen-http=ADDR Listen for HTTP connections at ADDR\n"
1194 " --listen-https=ADDR Listen for HTTPS connections at ADDR\n"
1195 " -o --output=FILE|DIR Write output to FILE or DIR/external-*.journal\n"
1196 " --compress[=BOOL] XZ-compress the output journal (default: yes)\n"
1197 " --seal[=BOOL] Use event sealing (default: no)\n"
1198 " --key=FILENAME SSL key in PEM format (default:\n"
1199 " \"" PRIV_KEY_FILE
"\")\n"
1200 " --cert=FILENAME SSL certificate in PEM format (default:\n"
1201 " \"" CERT_FILE
"\")\n"
1202 " --trust=FILENAME|all SSL CA certificate or disable checking (default:\n"
1203 " \"" TRUST_FILE
"\")\n"
1204 " --gnutls-log=CATEGORY...\n"
1205 " Specify a list of gnutls logging categories\n"
1206 " --split-mode=none|host How many output files to create\n"
1208 "Note: file descriptors from sd_listen_fds() will be consumed, too.\n"
1209 , program_invocation_short_name
);
1212 static int parse_argv(int argc
, char *argv
[]) {
1214 ARG_VERSION
= 0x100,
1229 static const struct option options
[] = {
1230 { "help", no_argument
, NULL
, 'h' },
1231 { "version", no_argument
, NULL
, ARG_VERSION
},
1232 { "url", required_argument
, NULL
, ARG_URL
},
1233 { "getter", required_argument
, NULL
, ARG_GETTER
},
1234 { "listen-raw", required_argument
, NULL
, ARG_LISTEN_RAW
},
1235 { "listen-http", required_argument
, NULL
, ARG_LISTEN_HTTP
},
1236 { "listen-https", required_argument
, NULL
, ARG_LISTEN_HTTPS
},
1237 { "output", required_argument
, NULL
, 'o' },
1238 { "split-mode", required_argument
, NULL
, ARG_SPLIT_MODE
},
1239 { "compress", optional_argument
, NULL
, ARG_COMPRESS
},
1240 { "seal", optional_argument
, NULL
, ARG_SEAL
},
1241 { "key", required_argument
, NULL
, ARG_KEY
},
1242 { "cert", required_argument
, NULL
, ARG_CERT
},
1243 { "trust", required_argument
, NULL
, ARG_TRUST
},
1244 { "gnutls-log", required_argument
, NULL
, ARG_GNUTLS_LOG
},
1249 bool type_a
, type_b
;
1254 while ((c
= getopt_long(argc
, argv
, "ho:", options
, NULL
)) >= 0)
1258 return 0 /* done */;
1265 log_error("cannot currently set more than one --url");
1274 log_error("cannot currently use --getter more than once");
1278 arg_getter
= optarg
;
1281 case ARG_LISTEN_RAW
:
1282 if (arg_listen_raw
) {
1283 log_error("cannot currently use --listen-raw more than once");
1287 arg_listen_raw
= optarg
;
1290 case ARG_LISTEN_HTTP
:
1291 if (arg_listen_http
|| http_socket
>= 0) {
1292 log_error("cannot currently use --listen-http more than once");
1296 r
= negative_fd(optarg
);
1300 arg_listen_http
= optarg
;
1303 case ARG_LISTEN_HTTPS
:
1304 if (arg_listen_https
|| https_socket
>= 0) {
1305 log_error("cannot currently use --listen-https more than once");
1309 r
= negative_fd(optarg
);
1313 arg_listen_https
= optarg
;
1319 log_error("Key file specified twice");
1323 arg_key
= strdup(optarg
);
1331 log_error("Certificate file specified twice");
1335 arg_cert
= strdup(optarg
);
1342 if (arg_trust
|| arg_trust_all
) {
1343 log_error("Confusing trusted CA configuration");
1347 if (streq(optarg
, "all"))
1348 arg_trust_all
= true;
1351 arg_trust
= strdup(optarg
);
1355 log_error("Option --trust is not available.");
1364 log_error("cannot use --output/-o more than once");
1368 arg_output
= optarg
;
1371 case ARG_SPLIT_MODE
:
1372 arg_split_mode
= journal_write_split_mode_from_string(optarg
);
1373 if (arg_split_mode
== _JOURNAL_WRITE_SPLIT_INVALID
) {
1374 log_error("Invalid split mode: %s", optarg
);
1381 r
= parse_boolean(optarg
);
1383 log_error("Failed to parse --compress= parameter.");
1389 arg_compress
= true;
1395 r
= parse_boolean(optarg
);
1397 log_error("Failed to parse --seal= parameter.");
1407 case ARG_GNUTLS_LOG
: {
1409 const char *word
, *state
;
1412 FOREACH_WORD_SEPARATOR(word
, size
, optarg
, ",", state
) {
1415 cat
= strndup(word
, size
);
1419 if (strv_consume(&arg_gnutls_log
, cat
) < 0)
1424 log_error("Option --gnutls-log is not available.");
1433 assert_not_reached("Unknown option code.");
1437 arg_files
= argv
+ optind
;
1439 type_a
= arg_getter
|| !strv_isempty(arg_files
);
1442 || arg_listen_http
|| arg_listen_https
1443 || sd_listen_fds(false) > 0;
1444 if (type_a
&& type_b
) {
1445 log_error("Cannot use file input or --getter with "
1446 "--arg-listen-... or socket activation.");
1451 log_error("Option --output must be specified with file input or --getter.");
1455 arg_split_mode
= JOURNAL_WRITE_SPLIT_NONE
;
1458 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_NONE
1459 && arg_output
&& is_dir(arg_output
, true) > 0) {
1460 log_error("For SplitMode=none, output must be a file.");
1464 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_HOST
1465 && arg_output
&& is_dir(arg_output
, true) <= 0) {
1466 log_error("For SplitMode=host, output must be a directory.");
1470 log_debug("Full config: SplitMode=%s Key=%s Cert=%s Trust=%s",
1471 journal_write_split_mode_to_string(arg_split_mode
),
1476 return 1 /* work to do */;
1479 static int load_certificates(char **key
, char **cert
, char **trust
) {
1482 r
= read_full_file(arg_key
?: PRIV_KEY_FILE
, key
, NULL
);
1484 return log_error_errno(r
, "Failed to read key from file '%s': %m",
1485 arg_key
?: PRIV_KEY_FILE
);
1487 r
= read_full_file(arg_cert
?: CERT_FILE
, cert
, NULL
);
1489 return log_error_errno(r
, "Failed to read certificate from file '%s': %m",
1490 arg_cert
?: CERT_FILE
);
1493 log_info("Certificate checking disabled.");
1495 r
= read_full_file(arg_trust
?: TRUST_FILE
, trust
, NULL
);
1497 return log_error_errno(r
, "Failed to read CA certificate file '%s': %m",
1498 arg_trust
?: TRUST_FILE
);
1504 int main(int argc
, char **argv
) {
1505 RemoteServer s
= {};
1507 _cleanup_free_
char *key
= NULL
, *cert
= NULL
, *trust
= NULL
;
1509 log_show_color(true);
1510 log_parse_environment();
1514 return EXIT_FAILURE
;
1516 r
= parse_argv(argc
, argv
);
1518 return r
== 0 ? EXIT_SUCCESS
: EXIT_FAILURE
;
1521 if (arg_listen_http
|| arg_listen_https
) {
1522 r
= setup_gnutls_logger(arg_gnutls_log
);
1524 return EXIT_FAILURE
;
1527 if (arg_listen_https
|| https_socket
>= 0)
1528 if (load_certificates(&key
, &cert
, &trust
) < 0)
1529 return EXIT_FAILURE
;
1531 if (remoteserver_init(&s
, key
, cert
, trust
) < 0)
1532 return EXIT_FAILURE
;
1534 r
= sd_event_set_watchdog(s
.events
, true);
1536 log_error_errno(r
, "Failed to enable watchdog: %m");
1538 log_debug("Watchdog is %s.", r
> 0 ? "enabled" : "disabled");
1540 log_debug("%s running as pid "PID_FMT
,
1541 program_invocation_short_name
, getpid());
1544 "STATUS=Processing requests...");
1547 r
= sd_event_get_state(s
.events
);
1550 if (r
== SD_EVENT_FINISHED
)
1553 r
= sd_event_run(s
.events
, -1);
1555 log_error_errno(r
, "Failed to run event loop: %m");
1562 "STATUS=Shutting down after writing %" PRIu64
" entries...", s
.event_count
);
1563 log_info("Finishing after writing %" PRIu64
" entries", s
.event_count
);
1571 return r
>= 0 ? EXIT_SUCCESS
: EXIT_FAILURE
;