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 "alloc-util.h"
39 #include "conf-parser.h"
43 #include "journal-file.h"
44 #include "journal-remote-write.h"
45 #include "journal-remote.h"
46 #include "journald-native.h"
48 #include "parse-util.h"
49 #include "signal-util.h"
50 #include "socket-util.h"
51 #include "stat-util.h"
52 #include "stdio-util.h"
53 #include "string-table.h"
54 #include "string-util.h"
57 #define REMOTE_JOURNAL_PATH "/var/log/journal/remote"
59 #define PRIV_KEY_FILE CERTIFICATE_ROOT "/private/journal-remote.pem"
60 #define CERT_FILE CERTIFICATE_ROOT "/certs/journal-remote.pem"
61 #define TRUST_FILE CERTIFICATE_ROOT "/ca/trusted.pem"
63 static char* arg_url
= NULL
;
64 static char* arg_getter
= NULL
;
65 static char* arg_listen_raw
= NULL
;
66 static char* arg_listen_http
= NULL
;
67 static char* arg_listen_https
= NULL
;
68 static char** arg_files
= NULL
;
69 static int arg_compress
= true;
70 static int arg_seal
= false;
71 static int http_socket
= -1, https_socket
= -1;
72 static char** arg_gnutls_log
= NULL
;
74 static JournalWriteSplitMode arg_split_mode
= JOURNAL_WRITE_SPLIT_HOST
;
75 static char* arg_output
= NULL
;
77 static char *arg_key
= NULL
;
78 static char *arg_cert
= NULL
;
79 static char *arg_trust
= NULL
;
80 static bool arg_trust_all
= false;
82 /**********************************************************************
83 **********************************************************************
84 **********************************************************************/
86 static int spawn_child(const char* child
, char** argv
) {
88 pid_t parent_pid
, child_pid
;
92 return log_error_errno(errno
, "Failed to create pager pipe: %m");
94 parent_pid
= getpid();
98 r
= log_error_errno(errno
, "Failed to fork: %m");
104 if (child_pid
== 0) {
106 (void) reset_all_signal_handlers();
107 (void) reset_signal_mask();
109 r
= dup2(fd
[1], STDOUT_FILENO
);
111 log_error_errno(errno
, "Failed to dup pipe to stdout: %m");
117 /* Make sure the child goes away when the parent dies */
118 if (prctl(PR_SET_PDEATHSIG
, SIGTERM
) < 0)
121 /* Check whether our parent died before we were able
122 * to set the death signal */
123 if (getppid() != parent_pid
)
127 log_error_errno(errno
, "Failed to exec child %s: %m", child
);
133 log_warning_errno(errno
, "Failed to close write end of pipe: %m");
138 static int spawn_curl(const char* url
) {
139 char **argv
= STRV_MAKE("curl",
140 "-HAccept: application/vnd.fdo.journal",
146 r
= spawn_child("curl", argv
);
148 log_error_errno(errno
, "Failed to spawn curl: %m");
152 static int spawn_getter(const char *getter
, const char *url
) {
154 _cleanup_strv_free_
char **words
= NULL
;
157 r
= strv_split_extract(&words
, getter
, WHITESPACE
, EXTRACT_QUOTES
);
159 return log_error_errno(r
, "Failed to split getter option: %m");
161 r
= strv_extend(&words
, url
);
163 return log_error_errno(r
, "Failed to create command line: %m");
165 r
= spawn_child(words
[0], words
);
167 log_error_errno(errno
, "Failed to spawn getter %s: %m", getter
);
172 #define filename_escape(s) xescape((s), "/ ")
174 static int open_output(Writer
*w
, const char* host
) {
175 _cleanup_free_
char *_output
= NULL
;
179 switch (arg_split_mode
) {
180 case JOURNAL_WRITE_SPLIT_NONE
:
181 output
= arg_output
?: REMOTE_JOURNAL_PATH
"/remote.journal";
184 case JOURNAL_WRITE_SPLIT_HOST
: {
185 _cleanup_free_
char *name
;
189 name
= filename_escape(host
);
193 r
= asprintf(&_output
, "%s/remote-%s.journal",
194 arg_output
?: REMOTE_JOURNAL_PATH
,
204 assert_not_reached("what?");
207 r
= journal_file_open_reliably(output
,
208 O_RDWR
|O_CREAT
, 0640,
209 arg_compress
, arg_seal
,
214 log_error_errno(r
, "Failed to open output journal %s: %m",
217 log_debug("Opened output file %s", w
->journal
->path
);
221 /**********************************************************************
222 **********************************************************************
223 **********************************************************************/
225 static int init_writer_hashmap(RemoteServer
*s
) {
226 static const struct hash_ops
*hash_ops
[] = {
227 [JOURNAL_WRITE_SPLIT_NONE
] = NULL
,
228 [JOURNAL_WRITE_SPLIT_HOST
] = &string_hash_ops
,
231 assert(arg_split_mode
>= 0 && arg_split_mode
< (int) ELEMENTSOF(hash_ops
));
233 s
->writers
= hashmap_new(hash_ops
[arg_split_mode
]);
240 static int get_writer(RemoteServer
*s
, const char *host
,
243 _cleanup_writer_unref_ Writer
*w
= NULL
;
246 switch(arg_split_mode
) {
247 case JOURNAL_WRITE_SPLIT_NONE
:
248 key
= "one and only";
251 case JOURNAL_WRITE_SPLIT_HOST
:
257 assert_not_reached("what split mode?");
260 w
= hashmap_get(s
->writers
, key
);
268 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_HOST
) {
269 w
->hashmap_key
= strdup(key
);
274 r
= open_output(w
, host
);
278 r
= hashmap_put(s
->writers
, w
->hashmap_key
?: key
, w
);
288 /**********************************************************************
289 **********************************************************************
290 **********************************************************************/
292 /* This should go away as soon as µhttpd allows state to be passed around. */
293 static RemoteServer
*server
;
295 static int dispatch_raw_source_event(sd_event_source
*event
,
299 static int dispatch_raw_source_until_block(sd_event_source
*event
,
301 static int dispatch_blocking_source_event(sd_event_source
*event
,
303 static int dispatch_raw_connection_event(sd_event_source
*event
,
307 static int dispatch_http_event(sd_event_source
*event
,
312 static int get_source_for_fd(RemoteServer
*s
,
313 int fd
, char *name
, RemoteSource
**source
) {
317 /* This takes ownership of name, but only on success. */
322 if (!GREEDY_REALLOC0(s
->sources
, s
->sources_size
, fd
+ 1))
325 r
= get_writer(s
, name
, &writer
);
327 return log_warning_errno(r
, "Failed to get writer for source %s: %m",
330 if (s
->sources
[fd
] == NULL
) {
331 s
->sources
[fd
] = source_new(fd
, false, name
, writer
);
332 if (!s
->sources
[fd
]) {
333 writer_unref(writer
);
340 *source
= s
->sources
[fd
];
344 static int remove_source(RemoteServer
*s
, int fd
) {
345 RemoteSource
*source
;
348 assert(fd
>= 0 && fd
< (ssize_t
) s
->sources_size
);
350 source
= s
->sources
[fd
];
352 /* this closes fd too */
354 s
->sources
[fd
] = NULL
;
361 static int add_source(RemoteServer
*s
, int fd
, char* name
, bool own_name
) {
363 RemoteSource
*source
= NULL
;
366 /* This takes ownership of name, even on failure, if own_name is true. */
378 r
= get_source_for_fd(s
, fd
, name
, &source
);
380 log_error_errno(r
, "Failed to create source for fd:%d (%s): %m",
386 r
= sd_event_add_io(s
->events
, &source
->event
,
387 fd
, EPOLLIN
|EPOLLRDHUP
|EPOLLPRI
,
388 dispatch_raw_source_event
, source
);
390 /* Add additional source for buffer processing. It will be
392 r
= sd_event_add_defer(s
->events
, &source
->buffer_event
,
393 dispatch_raw_source_until_block
, source
);
395 sd_event_source_set_enabled(source
->buffer_event
, SD_EVENT_OFF
);
396 } else if (r
== -EPERM
) {
397 log_debug("Falling back to sd_event_add_defer for fd:%d (%s)", fd
, name
);
398 r
= sd_event_add_defer(s
->events
, &source
->event
,
399 dispatch_blocking_source_event
, source
);
401 sd_event_source_set_enabled(source
->event
, SD_EVENT_ON
);
404 log_error_errno(r
, "Failed to register event source for fd:%d: %m",
409 r
= sd_event_source_set_description(source
->event
, name
);
411 log_error_errno(r
, "Failed to set source name for fd:%d: %m", fd
);
415 return 1; /* work to do */
418 remove_source(s
, fd
);
422 static int add_raw_socket(RemoteServer
*s
, int fd
) {
424 _cleanup_close_
int fd_
= fd
;
425 char name
[sizeof("raw-socket-")-1 + DECIMAL_STR_MAX(int) + 1];
429 r
= sd_event_add_io(s
->events
, &s
->listen_event
,
431 dispatch_raw_connection_event
, s
);
435 xsprintf(name
, "raw-socket-%d", fd
);
437 r
= sd_event_source_set_description(s
->listen_event
, name
);
446 static int setup_raw_socket(RemoteServer
*s
, const char *address
) {
449 fd
= make_socket_fd(LOG_INFO
, address
, SOCK_STREAM
| SOCK_CLOEXEC
);
453 return add_raw_socket(s
, fd
);
456 /**********************************************************************
457 **********************************************************************
458 **********************************************************************/
460 static int request_meta(void **connection_cls
, int fd
, char *hostname
) {
461 RemoteSource
*source
;
465 assert(connection_cls
);
469 r
= get_writer(server
, hostname
, &writer
);
471 return log_warning_errno(r
, "Failed to get writer for source %s: %m",
474 source
= source_new(fd
, true, hostname
, writer
);
476 writer_unref(writer
);
480 log_debug("Added RemoteSource as connection metadata %p", source
);
482 *connection_cls
= source
;
486 static void request_meta_free(void *cls
,
487 struct MHD_Connection
*connection
,
488 void **connection_cls
,
489 enum MHD_RequestTerminationCode toe
) {
492 assert(connection_cls
);
496 log_debug("Cleaning up connection metadata %p", s
);
498 *connection_cls
= NULL
;
502 static int process_http_upload(
503 struct MHD_Connection
*connection
,
504 const char *upload_data
,
505 size_t *upload_data_size
,
506 RemoteSource
*source
) {
508 bool finished
= false;
514 log_trace("%s: connection %p, %zu bytes",
515 __func__
, connection
, *upload_data_size
);
517 if (*upload_data_size
) {
518 log_trace("Received %zu bytes", *upload_data_size
);
520 r
= push_data(source
, upload_data
, *upload_data_size
);
522 return mhd_respond_oom(connection
);
524 *upload_data_size
= 0;
529 r
= process_source(source
, arg_compress
, arg_seal
);
533 log_warning("Failed to process data for connection %p", connection
);
535 return mhd_respondf(connection
,
536 MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
,
537 "Entry is too large, maximum is %u bytes.\n",
540 return mhd_respondf(connection
,
541 MHD_HTTP_UNPROCESSABLE_ENTITY
,
542 "Processing failed: %s.", strerror(-r
));
549 /* The upload is finished */
551 remaining
= source_non_empty(source
);
553 log_warning("Premature EOFbyte. %zu bytes lost.", remaining
);
554 return mhd_respondf(connection
, MHD_HTTP_EXPECTATION_FAILED
,
555 "Premature EOF. %zu bytes of trailing data not processed.",
559 return mhd_respond(connection
, MHD_HTTP_ACCEPTED
, "OK.\n");
562 static int request_handler(
564 struct MHD_Connection
*connection
,
568 const char *upload_data
,
569 size_t *upload_data_size
,
570 void **connection_cls
) {
574 _cleanup_free_
char *hostname
= NULL
;
577 assert(connection_cls
);
581 log_trace("Handling a connection %s %s %s", method
, url
, version
);
584 return process_http_upload(connection
,
585 upload_data
, upload_data_size
,
588 if (!streq(method
, "POST"))
589 return mhd_respond(connection
, MHD_HTTP_METHOD_NOT_ACCEPTABLE
,
590 "Unsupported method.\n");
592 if (!streq(url
, "/upload"))
593 return mhd_respond(connection
, MHD_HTTP_NOT_FOUND
,
596 header
= MHD_lookup_connection_value(connection
,
597 MHD_HEADER_KIND
, "Content-Type");
598 if (!header
|| !streq(header
, "application/vnd.fdo.journal"))
599 return mhd_respond(connection
, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE
,
600 "Content-Type: application/vnd.fdo.journal"
604 const union MHD_ConnectionInfo
*ci
;
606 ci
= MHD_get_connection_info(connection
,
607 MHD_CONNECTION_INFO_CONNECTION_FD
);
609 log_error("MHD_get_connection_info failed: cannot get remote fd");
610 return mhd_respond(connection
, MHD_HTTP_INTERNAL_SERVER_ERROR
,
611 "Cannot check remote address");
618 if (server
->check_trust
) {
619 r
= check_permissions(connection
, &code
, &hostname
);
623 r
= getnameinfo_pretty(fd
, &hostname
);
625 return mhd_respond(connection
, MHD_HTTP_INTERNAL_SERVER_ERROR
,
626 "Cannot check remote hostname");
631 r
= request_meta(connection_cls
, fd
, hostname
);
633 return respond_oom(connection
);
635 return mhd_respond(connection
, MHD_HTTP_INTERNAL_SERVER_ERROR
,
642 static int setup_microhttpd_server(RemoteServer
*s
,
647 struct MHD_OptionItem opts
[] = {
648 { MHD_OPTION_NOTIFY_COMPLETED
, (intptr_t) request_meta_free
},
649 { MHD_OPTION_EXTERNAL_LOGGER
, (intptr_t) microhttpd_logger
},
650 { MHD_OPTION_LISTEN_SOCKET
, fd
},
659 MHD_USE_EPOLL_LINUX_ONLY
|
660 MHD_USE_PEDANTIC_CHECKS
|
661 MHD_USE_PIPE_FOR_SHUTDOWN
;
663 const union MHD_DaemonInfo
*info
;
669 r
= fd_nonblock(fd
, true);
671 return log_error_errno(r
, "Failed to make fd:%d nonblocking: %m", fd
);
676 opts
[opts_pos
++] = (struct MHD_OptionItem
)
677 {MHD_OPTION_HTTPS_MEM_KEY
, 0, (char*) key
};
678 opts
[opts_pos
++] = (struct MHD_OptionItem
)
679 {MHD_OPTION_HTTPS_MEM_CERT
, 0, (char*) cert
};
681 flags
|= MHD_USE_SSL
;
684 opts
[opts_pos
++] = (struct MHD_OptionItem
)
685 {MHD_OPTION_HTTPS_MEM_TRUST
, 0, (char*) trust
};
688 d
= new(MHDDaemonWrapper
, 1);
692 d
->fd
= (uint64_t) fd
;
694 d
->daemon
= MHD_start_daemon(flags
, 0,
696 request_handler
, NULL
,
697 MHD_OPTION_ARRAY
, opts
,
700 log_error("Failed to start µhttp daemon");
705 log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)",
706 key
? "HTTPS" : "HTTP", fd
, d
);
709 info
= MHD_get_daemon_info(d
->daemon
, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY
);
711 log_error("µhttp returned NULL daemon info");
716 epoll_fd
= info
->listen_fd
;
718 log_error("µhttp epoll fd is invalid");
723 r
= sd_event_add_io(s
->events
, &d
->event
,
725 dispatch_http_event
, d
);
727 log_error_errno(r
, "Failed to add event callback: %m");
731 r
= sd_event_source_set_description(d
->event
, "epoll-fd");
733 log_error_errno(r
, "Failed to set source name: %m");
737 r
= hashmap_ensure_allocated(&s
->daemons
, &uint64_hash_ops
);
743 r
= hashmap_put(s
->daemons
, &d
->fd
, d
);
745 log_error_errno(r
, "Failed to add daemon to hashmap: %m");
753 MHD_stop_daemon(d
->daemon
);
759 static int setup_microhttpd_socket(RemoteServer
*s
,
766 fd
= make_socket_fd(LOG_DEBUG
, address
, SOCK_STREAM
| SOCK_CLOEXEC
);
770 return setup_microhttpd_server(s
, fd
, key
, cert
, trust
);
773 static int dispatch_http_event(sd_event_source
*event
,
777 MHDDaemonWrapper
*d
= userdata
;
782 r
= MHD_run(d
->daemon
);
784 log_error("MHD_run failed!");
785 // XXX: unregister daemon
789 return 1; /* work to do */
792 /**********************************************************************
793 **********************************************************************
794 **********************************************************************/
796 static int setup_signals(RemoteServer
*s
) {
801 assert_se(sigprocmask_many(SIG_SETMASK
, NULL
, SIGINT
, SIGTERM
, -1) >= 0);
803 r
= sd_event_add_signal(s
->events
, &s
->sigterm_event
, SIGTERM
, NULL
, s
);
807 r
= sd_event_add_signal(s
->events
, &s
->sigint_event
, SIGINT
, NULL
, s
);
814 static int negative_fd(const char *spec
) {
815 /* Return a non-positive number as its inverse, -EINVAL otherwise. */
819 r
= safe_atoi(spec
, &fd
);
829 static int remoteserver_init(RemoteServer
*s
,
838 if ((arg_listen_raw
|| arg_listen_http
) && trust
) {
839 log_error("Option --trust makes all non-HTTPS connections untrusted.");
843 r
= sd_event_default(&s
->events
);
845 return log_error_errno(r
, "Failed to allocate event loop: %m");
849 assert(server
== NULL
);
852 r
= init_writer_hashmap(s
);
856 n
= sd_listen_fds(true);
858 return log_error_errno(n
, "Failed to read listening file descriptors from environment: %m");
860 log_debug("Received %d descriptors", n
);
862 if (MAX(http_socket
, https_socket
) >= SD_LISTEN_FDS_START
+ n
) {
863 log_error("Received fewer sockets than expected");
867 for (fd
= SD_LISTEN_FDS_START
; fd
< SD_LISTEN_FDS_START
+ n
; fd
++) {
868 if (sd_is_socket(fd
, AF_UNSPEC
, 0, true)) {
869 log_debug("Received a listening socket (fd:%d)", fd
);
871 if (fd
== http_socket
)
872 r
= setup_microhttpd_server(s
, fd
, NULL
, NULL
, NULL
);
873 else if (fd
== https_socket
)
874 r
= setup_microhttpd_server(s
, fd
, key
, cert
, trust
);
876 r
= add_raw_socket(s
, fd
);
877 } else if (sd_is_socket(fd
, AF_UNSPEC
, 0, false)) {
880 r
= getnameinfo_pretty(fd
, &hostname
);
882 return log_error_errno(r
, "Failed to retrieve remote name: %m");
884 log_debug("Received a connection socket (fd:%d) from %s", fd
, hostname
);
886 r
= add_source(s
, fd
, hostname
, true);
888 log_error("Unknown socket passed on fd:%d", fd
);
894 return log_error_errno(r
, "Failed to register socket (fd:%d): %m",
899 const char *url
, *hostname
;
901 url
= strjoina(arg_url
, "/entries");
904 log_info("Spawning getter %s...", url
);
905 fd
= spawn_getter(arg_getter
, url
);
907 log_info("Spawning curl %s...", url
);
908 fd
= spawn_curl(url
);
914 startswith(arg_url
, "https://") ?:
915 startswith(arg_url
, "http://") ?:
918 r
= add_source(s
, fd
, (char*) hostname
, false);
923 if (arg_listen_raw
) {
924 log_debug("Listening on a socket...");
925 r
= setup_raw_socket(s
, arg_listen_raw
);
930 if (arg_listen_http
) {
931 r
= setup_microhttpd_socket(s
, arg_listen_http
, NULL
, NULL
, NULL
);
936 if (arg_listen_https
) {
937 r
= setup_microhttpd_socket(s
, arg_listen_https
, key
, cert
, trust
);
942 STRV_FOREACH(file
, arg_files
) {
943 const char *output_name
;
945 if (streq(*file
, "-")) {
946 log_debug("Using standard input as source.");
949 output_name
= "stdin";
951 log_debug("Reading file %s...", *file
);
953 fd
= open(*file
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NONBLOCK
);
955 return log_error_errno(errno
, "Failed to open %s: %m", *file
);
959 r
= add_source(s
, fd
, (char*) output_name
, false);
964 if (s
->active
== 0) {
965 log_error("Zero sources specified");
969 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_NONE
) {
970 /* In this case we know what the writer will be
971 called, so we can create it and verify that we can
972 create output as expected. */
973 r
= get_writer(s
, NULL
, &s
->_single_writer
);
981 static void server_destroy(RemoteServer
*s
) {
985 while ((d
= hashmap_steal_first(s
->daemons
))) {
986 MHD_stop_daemon(d
->daemon
);
987 sd_event_source_unref(d
->event
);
991 hashmap_free(s
->daemons
);
993 assert(s
->sources_size
== 0 || s
->sources
);
994 for (i
= 0; i
< s
->sources_size
; i
++)
998 writer_unref(s
->_single_writer
);
999 hashmap_free(s
->writers
);
1001 sd_event_source_unref(s
->sigterm_event
);
1002 sd_event_source_unref(s
->sigint_event
);
1003 sd_event_source_unref(s
->listen_event
);
1004 sd_event_unref(s
->events
);
1006 /* fds that we're listening on remain open... */
1009 /**********************************************************************
1010 **********************************************************************
1011 **********************************************************************/
1013 static int handle_raw_source(sd_event_source
*event
,
1018 RemoteSource
*source
;
1021 /* Returns 1 if there might be more data pending,
1022 * 0 if data is currently exhausted, negative on error.
1025 assert(fd
>= 0 && fd
< (ssize_t
) s
->sources_size
);
1026 source
= s
->sources
[fd
];
1027 assert(source
->fd
== fd
);
1029 r
= process_source(source
, arg_compress
, arg_seal
);
1030 if (source
->state
== STATE_EOF
) {
1033 log_debug("EOF reached with source fd:%d (%s)",
1034 source
->fd
, source
->name
);
1036 remaining
= source_non_empty(source
);
1038 log_notice("Premature EOF. %zu bytes lost.", remaining
);
1039 remove_source(s
, source
->fd
);
1040 log_debug("%zu active sources remaining", s
->active
);
1042 } else if (r
== -E2BIG
) {
1043 log_notice_errno(E2BIG
, "Entry too big, skipped");
1045 } else if (r
== -EAGAIN
) {
1048 log_debug_errno(r
, "Closing connection: %m");
1049 remove_source(server
, fd
);
1055 static int dispatch_raw_source_until_block(sd_event_source
*event
,
1057 RemoteSource
*source
= userdata
;
1060 /* Make sure event stays around even if source is destroyed */
1061 sd_event_source_ref(event
);
1063 r
= handle_raw_source(event
, source
->fd
, EPOLLIN
, server
);
1065 /* No more data for now */
1066 sd_event_source_set_enabled(event
, SD_EVENT_OFF
);
1068 sd_event_source_unref(event
);
1073 static int dispatch_raw_source_event(sd_event_source
*event
,
1077 RemoteSource
*source
= userdata
;
1080 assert(source
->event
);
1081 assert(source
->buffer_event
);
1083 r
= handle_raw_source(event
, fd
, EPOLLIN
, server
);
1085 /* Might have more data. We need to rerun the handler
1086 * until we are sure the buffer is exhausted. */
1087 sd_event_source_set_enabled(source
->buffer_event
, SD_EVENT_ON
);
1092 static int dispatch_blocking_source_event(sd_event_source
*event
,
1094 RemoteSource
*source
= userdata
;
1096 return handle_raw_source(event
, source
->fd
, EPOLLIN
, server
);
1099 static int accept_connection(const char* type
, int fd
,
1100 SocketAddress
*addr
, char **hostname
) {
1103 log_debug("Accepting new %s connection on fd:%d", type
, fd
);
1104 fd2
= accept4(fd
, &addr
->sockaddr
.sa
, &addr
->size
, SOCK_NONBLOCK
|SOCK_CLOEXEC
);
1106 return log_error_errno(errno
, "accept() on fd:%d failed: %m", fd
);
1108 switch(socket_address_family(addr
)) {
1111 _cleanup_free_
char *a
= NULL
;
1114 r
= socket_address_print(addr
, &a
);
1116 log_error_errno(r
, "socket_address_print(): %m");
1121 r
= socknameinfo_pretty(&addr
->sockaddr
, addr
->size
, &b
);
1123 log_error_errno(r
, "Resolving hostname failed: %m");
1128 log_debug("Accepted %s %s connection from %s",
1130 socket_address_family(addr
) == AF_INET
? "IP" : "IPv6",
1138 log_error("Rejected %s connection with unsupported family %d",
1139 type
, socket_address_family(addr
));
1146 static int dispatch_raw_connection_event(sd_event_source
*event
,
1150 RemoteServer
*s
= userdata
;
1152 SocketAddress addr
= {
1153 .size
= sizeof(union sockaddr_union
),
1154 .type
= SOCK_STREAM
,
1156 char *hostname
= NULL
;
1158 fd2
= accept_connection("raw", fd
, &addr
, &hostname
);
1162 return add_source(s
, fd2
, hostname
, true);
1165 /**********************************************************************
1166 **********************************************************************
1167 **********************************************************************/
1169 static const char* const journal_write_split_mode_table
[_JOURNAL_WRITE_SPLIT_MAX
] = {
1170 [JOURNAL_WRITE_SPLIT_NONE
] = "none",
1171 [JOURNAL_WRITE_SPLIT_HOST
] = "host",
1174 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(journal_write_split_mode
, JournalWriteSplitMode
);
1175 static DEFINE_CONFIG_PARSE_ENUM(config_parse_write_split_mode
,
1176 journal_write_split_mode
,
1177 JournalWriteSplitMode
,
1178 "Failed to parse split mode setting");
1180 static int parse_config(void) {
1181 const ConfigTableItem items
[] = {
1182 { "Remote", "SplitMode", config_parse_write_split_mode
, 0, &arg_split_mode
},
1183 { "Remote", "ServerKeyFile", config_parse_path
, 0, &arg_key
},
1184 { "Remote", "ServerCertificateFile", config_parse_path
, 0, &arg_cert
},
1185 { "Remote", "TrustedCertificateFile", config_parse_path
, 0, &arg_trust
},
1188 return config_parse_many(PKGSYSCONFDIR
"/journal-remote.conf",
1189 CONF_DIRS_NULSTR("systemd/journal-remote.conf"),
1190 "Remote\0", config_item_table_lookup
, items
,
1194 static void help(void) {
1195 printf("%s [OPTIONS...] {FILE|-}...\n\n"
1196 "Write external journal events to journal file(s).\n\n"
1197 " -h --help Show this help\n"
1198 " --version Show package version\n"
1199 " --url=URL Read events from systemd-journal-gatewayd at URL\n"
1200 " --getter=COMMAND Read events from the output of COMMAND\n"
1201 " --listen-raw=ADDR Listen for connections at ADDR\n"
1202 " --listen-http=ADDR Listen for HTTP connections at ADDR\n"
1203 " --listen-https=ADDR Listen for HTTPS connections at ADDR\n"
1204 " -o --output=FILE|DIR Write output to FILE or DIR/external-*.journal\n"
1205 " --compress[=BOOL] XZ-compress the output journal (default: yes)\n"
1206 " --seal[=BOOL] Use event sealing (default: no)\n"
1207 " --key=FILENAME SSL key in PEM format (default:\n"
1208 " \"" PRIV_KEY_FILE
"\")\n"
1209 " --cert=FILENAME SSL certificate in PEM format (default:\n"
1210 " \"" CERT_FILE
"\")\n"
1211 " --trust=FILENAME|all SSL CA certificate or disable checking (default:\n"
1212 " \"" TRUST_FILE
"\")\n"
1213 " --gnutls-log=CATEGORY...\n"
1214 " Specify a list of gnutls logging categories\n"
1215 " --split-mode=none|host How many output files to create\n"
1217 "Note: file descriptors from sd_listen_fds() will be consumed, too.\n"
1218 , program_invocation_short_name
);
1221 static int parse_argv(int argc
, char *argv
[]) {
1223 ARG_VERSION
= 0x100,
1238 static const struct option options
[] = {
1239 { "help", no_argument
, NULL
, 'h' },
1240 { "version", no_argument
, NULL
, ARG_VERSION
},
1241 { "url", required_argument
, NULL
, ARG_URL
},
1242 { "getter", required_argument
, NULL
, ARG_GETTER
},
1243 { "listen-raw", required_argument
, NULL
, ARG_LISTEN_RAW
},
1244 { "listen-http", required_argument
, NULL
, ARG_LISTEN_HTTP
},
1245 { "listen-https", required_argument
, NULL
, ARG_LISTEN_HTTPS
},
1246 { "output", required_argument
, NULL
, 'o' },
1247 { "split-mode", required_argument
, NULL
, ARG_SPLIT_MODE
},
1248 { "compress", optional_argument
, NULL
, ARG_COMPRESS
},
1249 { "seal", optional_argument
, NULL
, ARG_SEAL
},
1250 { "key", required_argument
, NULL
, ARG_KEY
},
1251 { "cert", required_argument
, NULL
, ARG_CERT
},
1252 { "trust", required_argument
, NULL
, ARG_TRUST
},
1253 { "gnutls-log", required_argument
, NULL
, ARG_GNUTLS_LOG
},
1259 bool type_a
, type_b
;
1264 while ((c
= getopt_long(argc
, argv
, "ho:", options
, NULL
)) >= 0)
1268 return 0 /* done */;
1275 log_error("cannot currently set more than one --url");
1284 log_error("cannot currently use --getter more than once");
1288 arg_getter
= optarg
;
1291 case ARG_LISTEN_RAW
:
1292 if (arg_listen_raw
) {
1293 log_error("cannot currently use --listen-raw more than once");
1297 arg_listen_raw
= optarg
;
1300 case ARG_LISTEN_HTTP
:
1301 if (arg_listen_http
|| http_socket
>= 0) {
1302 log_error("cannot currently use --listen-http more than once");
1306 r
= negative_fd(optarg
);
1310 arg_listen_http
= optarg
;
1313 case ARG_LISTEN_HTTPS
:
1314 if (arg_listen_https
|| https_socket
>= 0) {
1315 log_error("cannot currently use --listen-https more than once");
1319 r
= negative_fd(optarg
);
1323 arg_listen_https
= optarg
;
1329 log_error("Key file specified twice");
1333 arg_key
= strdup(optarg
);
1341 log_error("Certificate file specified twice");
1345 arg_cert
= strdup(optarg
);
1352 if (arg_trust
|| arg_trust_all
) {
1353 log_error("Confusing trusted CA configuration");
1357 if (streq(optarg
, "all"))
1358 arg_trust_all
= true;
1361 arg_trust
= strdup(optarg
);
1365 log_error("Option --trust is not available.");
1374 log_error("cannot use --output/-o more than once");
1378 arg_output
= optarg
;
1381 case ARG_SPLIT_MODE
:
1382 arg_split_mode
= journal_write_split_mode_from_string(optarg
);
1383 if (arg_split_mode
== _JOURNAL_WRITE_SPLIT_INVALID
) {
1384 log_error("Invalid split mode: %s", optarg
);
1391 r
= parse_boolean(optarg
);
1393 log_error("Failed to parse --compress= parameter.");
1399 arg_compress
= true;
1405 r
= parse_boolean(optarg
);
1407 log_error("Failed to parse --seal= parameter.");
1417 case ARG_GNUTLS_LOG
: {
1421 _cleanup_free_
char *word
= NULL
;
1423 r
= extract_first_word(&p
, &word
, ",", 0);
1425 return log_error_errno(r
, "Failed to parse --gnutls-log= argument: %m");
1430 if (strv_push(&arg_gnutls_log
, word
) < 0)
1437 log_error("Option --gnutls-log is not available.");
1446 assert_not_reached("Unknown option code.");
1450 arg_files
= argv
+ optind
;
1452 type_a
= arg_getter
|| !strv_isempty(arg_files
);
1455 || arg_listen_http
|| arg_listen_https
1456 || sd_listen_fds(false) > 0;
1457 if (type_a
&& type_b
) {
1458 log_error("Cannot use file input or --getter with "
1459 "--arg-listen-... or socket activation.");
1464 log_error("Option --output must be specified with file input or --getter.");
1468 arg_split_mode
= JOURNAL_WRITE_SPLIT_NONE
;
1471 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_NONE
1472 && arg_output
&& is_dir(arg_output
, true) > 0) {
1473 log_error("For SplitMode=none, output must be a file.");
1477 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_HOST
1478 && arg_output
&& is_dir(arg_output
, true) <= 0) {
1479 log_error("For SplitMode=host, output must be a directory.");
1483 log_debug("Full config: SplitMode=%s Key=%s Cert=%s Trust=%s",
1484 journal_write_split_mode_to_string(arg_split_mode
),
1489 return 1 /* work to do */;
1492 static int load_certificates(char **key
, char **cert
, char **trust
) {
1495 r
= read_full_file(arg_key
?: PRIV_KEY_FILE
, key
, NULL
);
1497 return log_error_errno(r
, "Failed to read key from file '%s': %m",
1498 arg_key
?: PRIV_KEY_FILE
);
1500 r
= read_full_file(arg_cert
?: CERT_FILE
, cert
, NULL
);
1502 return log_error_errno(r
, "Failed to read certificate from file '%s': %m",
1503 arg_cert
?: CERT_FILE
);
1506 log_info("Certificate checking disabled.");
1508 r
= read_full_file(arg_trust
?: TRUST_FILE
, trust
, NULL
);
1510 return log_error_errno(r
, "Failed to read CA certificate file '%s': %m",
1511 arg_trust
?: TRUST_FILE
);
1517 int main(int argc
, char **argv
) {
1518 RemoteServer s
= {};
1520 _cleanup_free_
char *key
= NULL
, *cert
= NULL
, *trust
= NULL
;
1522 log_show_color(true);
1523 log_parse_environment();
1527 return EXIT_FAILURE
;
1529 r
= parse_argv(argc
, argv
);
1531 return r
== 0 ? EXIT_SUCCESS
: EXIT_FAILURE
;
1534 if (arg_listen_http
|| arg_listen_https
) {
1535 r
= setup_gnutls_logger(arg_gnutls_log
);
1537 return EXIT_FAILURE
;
1540 if (arg_listen_https
|| https_socket
>= 0)
1541 if (load_certificates(&key
, &cert
, &trust
) < 0)
1542 return EXIT_FAILURE
;
1544 if (remoteserver_init(&s
, key
, cert
, trust
) < 0)
1545 return EXIT_FAILURE
;
1547 r
= sd_event_set_watchdog(s
.events
, true);
1549 log_error_errno(r
, "Failed to enable watchdog: %m");
1551 log_debug("Watchdog is %s.", r
> 0 ? "enabled" : "disabled");
1553 log_debug("%s running as pid "PID_FMT
,
1554 program_invocation_short_name
, getpid());
1557 "STATUS=Processing requests...");
1560 r
= sd_event_get_state(s
.events
);
1563 if (r
== SD_EVENT_FINISHED
)
1566 r
= sd_event_run(s
.events
, -1);
1568 log_error_errno(r
, "Failed to run event loop: %m");
1575 "STATUS=Shutting down after writing %" PRIu64
" entries...", s
.event_count
);
1576 log_info("Finishing after writing %" PRIu64
" entries", s
.event_count
);
1584 return r
>= 0 ? EXIT_SUCCESS
: EXIT_FAILURE
;