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/>.
27 #include <sys/prctl.h>
28 #include <sys/socket.h>
32 #include "sd-daemon.h"
33 #include "signal-util.h"
34 #include "journal-file.h"
35 #include "journald-native.h"
36 #include "socket-util.h"
41 #include "conf-parser.h"
44 #include <gnutls/gnutls.h>
47 #include "journal-remote.h"
48 #include "journal-remote-write.h"
50 #define REMOTE_JOURNAL_PATH "/var/log/journal/remote"
52 #define PRIV_KEY_FILE CERTIFICATE_ROOT "/private/journal-remote.pem"
53 #define CERT_FILE CERTIFICATE_ROOT "/certs/journal-remote.pem"
54 #define TRUST_FILE CERTIFICATE_ROOT "/ca/trusted.pem"
56 static char* arg_url
= NULL
;
57 static char* arg_getter
= NULL
;
58 static char* arg_listen_raw
= NULL
;
59 static char* arg_listen_http
= NULL
;
60 static char* arg_listen_https
= NULL
;
61 static char** arg_files
= NULL
;
62 static int arg_compress
= true;
63 static int arg_seal
= false;
64 static int http_socket
= -1, https_socket
= -1;
65 static char** arg_gnutls_log
= NULL
;
67 static JournalWriteSplitMode arg_split_mode
= JOURNAL_WRITE_SPLIT_HOST
;
68 static char* arg_output
= NULL
;
70 static char *arg_key
= NULL
;
71 static char *arg_cert
= NULL
;
72 static char *arg_trust
= NULL
;
73 static bool arg_trust_all
= false;
75 /**********************************************************************
76 **********************************************************************
77 **********************************************************************/
79 static int spawn_child(const char* child
, char** argv
) {
81 pid_t parent_pid
, child_pid
;
85 return log_error_errno(errno
, "Failed to create pager pipe: %m");
87 parent_pid
= getpid();
91 r
= log_error_errno(errno
, "Failed to fork: %m");
99 (void) reset_all_signal_handlers();
100 (void) reset_signal_mask();
102 r
= dup2(fd
[1], STDOUT_FILENO
);
104 log_error_errno(errno
, "Failed to dup pipe to stdout: %m");
110 /* Make sure the child goes away when the parent dies */
111 if (prctl(PR_SET_PDEATHSIG
, SIGTERM
) < 0)
114 /* Check whether our parent died before we were able
115 * to set the death signal */
116 if (getppid() != parent_pid
)
120 log_error_errno(errno
, "Failed to exec child %s: %m", child
);
126 log_warning_errno(errno
, "Failed to close write end of pipe: %m");
131 static int spawn_curl(const char* url
) {
132 char **argv
= STRV_MAKE("curl",
133 "-HAccept: application/vnd.fdo.journal",
139 r
= spawn_child("curl", argv
);
141 log_error_errno(errno
, "Failed to spawn curl: %m");
145 static int spawn_getter(const char *getter
, const char *url
) {
147 _cleanup_strv_free_
char **words
= NULL
;
150 r
= strv_split_extract(&words
, getter
, WHITESPACE
, EXTRACT_QUOTES
);
152 return log_error_errno(r
, "Failed to split getter option: %m");
154 r
= strv_extend(&words
, url
);
156 return log_error_errno(r
, "Failed to create command line: %m");
158 r
= spawn_child(words
[0], words
);
160 log_error_errno(errno
, "Failed to spawn getter %s: %m", getter
);
165 #define filename_escape(s) xescape((s), "/ ")
167 static int open_output(Writer
*w
, const char* host
) {
168 _cleanup_free_
char *_output
= NULL
;
172 switch (arg_split_mode
) {
173 case JOURNAL_WRITE_SPLIT_NONE
:
174 output
= arg_output
?: REMOTE_JOURNAL_PATH
"/remote.journal";
177 case JOURNAL_WRITE_SPLIT_HOST
: {
178 _cleanup_free_
char *name
;
182 name
= filename_escape(host
);
186 r
= asprintf(&_output
, "%s/remote-%s.journal",
187 arg_output
?: REMOTE_JOURNAL_PATH
,
197 assert_not_reached("what?");
200 r
= journal_file_open_reliably(output
,
201 O_RDWR
|O_CREAT
, 0640,
202 arg_compress
, arg_seal
,
207 log_error_errno(r
, "Failed to open output journal %s: %m",
210 log_debug("Opened output file %s", w
->journal
->path
);
214 /**********************************************************************
215 **********************************************************************
216 **********************************************************************/
218 static int init_writer_hashmap(RemoteServer
*s
) {
219 static const struct hash_ops
*hash_ops
[] = {
220 [JOURNAL_WRITE_SPLIT_NONE
] = NULL
,
221 [JOURNAL_WRITE_SPLIT_HOST
] = &string_hash_ops
,
224 assert(arg_split_mode
>= 0 && arg_split_mode
< (int) ELEMENTSOF(hash_ops
));
226 s
->writers
= hashmap_new(hash_ops
[arg_split_mode
]);
233 static int get_writer(RemoteServer
*s
, const char *host
,
236 _cleanup_writer_unref_ Writer
*w
= NULL
;
239 switch(arg_split_mode
) {
240 case JOURNAL_WRITE_SPLIT_NONE
:
241 key
= "one and only";
244 case JOURNAL_WRITE_SPLIT_HOST
:
250 assert_not_reached("what split mode?");
253 w
= hashmap_get(s
->writers
, key
);
261 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_HOST
) {
262 w
->hashmap_key
= strdup(key
);
267 r
= open_output(w
, host
);
271 r
= hashmap_put(s
->writers
, w
->hashmap_key
?: key
, w
);
281 /**********************************************************************
282 **********************************************************************
283 **********************************************************************/
285 /* This should go away as soon as µhttpd allows state to be passed around. */
286 static RemoteServer
*server
;
288 static int dispatch_raw_source_event(sd_event_source
*event
,
292 static int dispatch_raw_source_until_block(sd_event_source
*event
,
294 static int dispatch_blocking_source_event(sd_event_source
*event
,
296 static int dispatch_raw_connection_event(sd_event_source
*event
,
300 static int dispatch_http_event(sd_event_source
*event
,
305 static int get_source_for_fd(RemoteServer
*s
,
306 int fd
, char *name
, RemoteSource
**source
) {
310 /* This takes ownership of name, but only on success. */
315 if (!GREEDY_REALLOC0(s
->sources
, s
->sources_size
, fd
+ 1))
318 r
= get_writer(s
, name
, &writer
);
320 return log_warning_errno(r
, "Failed to get writer for source %s: %m",
323 if (s
->sources
[fd
] == NULL
) {
324 s
->sources
[fd
] = source_new(fd
, false, name
, writer
);
325 if (!s
->sources
[fd
]) {
326 writer_unref(writer
);
333 *source
= s
->sources
[fd
];
337 static int remove_source(RemoteServer
*s
, int fd
) {
338 RemoteSource
*source
;
341 assert(fd
>= 0 && fd
< (ssize_t
) s
->sources_size
);
343 source
= s
->sources
[fd
];
345 /* this closes fd too */
347 s
->sources
[fd
] = NULL
;
354 static int add_source(RemoteServer
*s
, int fd
, char* name
, bool own_name
) {
356 RemoteSource
*source
= NULL
;
359 /* This takes ownership of name, even on failure, if own_name is true. */
371 r
= get_source_for_fd(s
, fd
, name
, &source
);
373 log_error_errno(r
, "Failed to create source for fd:%d (%s): %m",
379 r
= sd_event_add_io(s
->events
, &source
->event
,
380 fd
, EPOLLIN
|EPOLLRDHUP
|EPOLLPRI
,
381 dispatch_raw_source_event
, source
);
383 /* Add additional source for buffer processing. It will be
385 r
= sd_event_add_defer(s
->events
, &source
->buffer_event
,
386 dispatch_raw_source_until_block
, source
);
388 sd_event_source_set_enabled(source
->buffer_event
, SD_EVENT_OFF
);
389 } else if (r
== -EPERM
) {
390 log_debug("Falling back to sd_event_add_defer for fd:%d (%s)", fd
, name
);
391 r
= sd_event_add_defer(s
->events
, &source
->event
,
392 dispatch_blocking_source_event
, source
);
394 sd_event_source_set_enabled(source
->event
, SD_EVENT_ON
);
397 log_error_errno(r
, "Failed to register event source for fd:%d: %m",
402 r
= sd_event_source_set_description(source
->event
, name
);
404 log_error_errno(r
, "Failed to set source name for fd:%d: %m", fd
);
408 return 1; /* work to do */
411 remove_source(s
, fd
);
415 static int add_raw_socket(RemoteServer
*s
, int fd
) {
417 _cleanup_close_
int fd_
= fd
;
418 char name
[sizeof("raw-socket-")-1 + DECIMAL_STR_MAX(int) + 1];
422 r
= sd_event_add_io(s
->events
, &s
->listen_event
,
424 dispatch_raw_connection_event
, s
);
428 xsprintf(name
, "raw-socket-%d", fd
);
430 r
= sd_event_source_set_description(s
->listen_event
, name
);
439 static int setup_raw_socket(RemoteServer
*s
, const char *address
) {
442 fd
= make_socket_fd(LOG_INFO
, address
, SOCK_STREAM
| SOCK_CLOEXEC
);
446 return add_raw_socket(s
, fd
);
449 /**********************************************************************
450 **********************************************************************
451 **********************************************************************/
453 static int request_meta(void **connection_cls
, int fd
, char *hostname
) {
454 RemoteSource
*source
;
458 assert(connection_cls
);
462 r
= get_writer(server
, hostname
, &writer
);
464 return log_warning_errno(r
, "Failed to get writer for source %s: %m",
467 source
= source_new(fd
, true, hostname
, writer
);
469 writer_unref(writer
);
473 log_debug("Added RemoteSource as connection metadata %p", source
);
475 *connection_cls
= source
;
479 static void request_meta_free(void *cls
,
480 struct MHD_Connection
*connection
,
481 void **connection_cls
,
482 enum MHD_RequestTerminationCode toe
) {
485 assert(connection_cls
);
489 log_debug("Cleaning up connection metadata %p", s
);
491 *connection_cls
= NULL
;
495 static int process_http_upload(
496 struct MHD_Connection
*connection
,
497 const char *upload_data
,
498 size_t *upload_data_size
,
499 RemoteSource
*source
) {
501 bool finished
= false;
507 log_trace("%s: connection %p, %zu bytes",
508 __func__
, connection
, *upload_data_size
);
510 if (*upload_data_size
) {
511 log_trace("Received %zu bytes", *upload_data_size
);
513 r
= push_data(source
, upload_data
, *upload_data_size
);
515 return mhd_respond_oom(connection
);
517 *upload_data_size
= 0;
522 r
= process_source(source
, arg_compress
, arg_seal
);
526 log_warning("Failed to process data for connection %p", connection
);
528 return mhd_respondf(connection
,
529 MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
,
530 "Entry is too large, maximum is %u bytes.\n",
533 return mhd_respondf(connection
,
534 MHD_HTTP_UNPROCESSABLE_ENTITY
,
535 "Processing failed: %s.", strerror(-r
));
542 /* The upload is finished */
544 remaining
= source_non_empty(source
);
546 log_warning("Premature EOFbyte. %zu bytes lost.", remaining
);
547 return mhd_respondf(connection
, MHD_HTTP_EXPECTATION_FAILED
,
548 "Premature EOF. %zu bytes of trailing data not processed.",
552 return mhd_respond(connection
, MHD_HTTP_ACCEPTED
, "OK.\n");
555 static int request_handler(
557 struct MHD_Connection
*connection
,
561 const char *upload_data
,
562 size_t *upload_data_size
,
563 void **connection_cls
) {
567 _cleanup_free_
char *hostname
= NULL
;
570 assert(connection_cls
);
574 log_trace("Handling a connection %s %s %s", method
, url
, version
);
577 return process_http_upload(connection
,
578 upload_data
, upload_data_size
,
581 if (!streq(method
, "POST"))
582 return mhd_respond(connection
, MHD_HTTP_METHOD_NOT_ACCEPTABLE
,
583 "Unsupported method.\n");
585 if (!streq(url
, "/upload"))
586 return mhd_respond(connection
, MHD_HTTP_NOT_FOUND
,
589 header
= MHD_lookup_connection_value(connection
,
590 MHD_HEADER_KIND
, "Content-Type");
591 if (!header
|| !streq(header
, "application/vnd.fdo.journal"))
592 return mhd_respond(connection
, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE
,
593 "Content-Type: application/vnd.fdo.journal"
597 const union MHD_ConnectionInfo
*ci
;
599 ci
= MHD_get_connection_info(connection
,
600 MHD_CONNECTION_INFO_CONNECTION_FD
);
602 log_error("MHD_get_connection_info failed: cannot get remote fd");
603 return mhd_respond(connection
, MHD_HTTP_INTERNAL_SERVER_ERROR
,
604 "Cannot check remote address");
611 if (server
->check_trust
) {
612 r
= check_permissions(connection
, &code
, &hostname
);
616 r
= getnameinfo_pretty(fd
, &hostname
);
618 return mhd_respond(connection
, MHD_HTTP_INTERNAL_SERVER_ERROR
,
619 "Cannot check remote hostname");
625 r
= request_meta(connection_cls
, fd
, hostname
);
627 return respond_oom(connection
);
629 return mhd_respond(connection
, MHD_HTTP_INTERNAL_SERVER_ERROR
,
636 static int setup_microhttpd_server(RemoteServer
*s
,
641 struct MHD_OptionItem opts
[] = {
642 { MHD_OPTION_NOTIFY_COMPLETED
, (intptr_t) request_meta_free
},
643 { MHD_OPTION_EXTERNAL_LOGGER
, (intptr_t) microhttpd_logger
},
644 { MHD_OPTION_LISTEN_SOCKET
, fd
},
652 MHD_USE_PEDANTIC_CHECKS
|
653 MHD_USE_EPOLL_LINUX_ONLY
|
656 const union MHD_DaemonInfo
*info
;
662 r
= fd_nonblock(fd
, true);
664 return log_error_errno(r
, "Failed to make fd:%d nonblocking: %m", fd
);
669 opts
[opts_pos
++] = (struct MHD_OptionItem
)
670 {MHD_OPTION_HTTPS_MEM_KEY
, 0, (char*) key
};
671 opts
[opts_pos
++] = (struct MHD_OptionItem
)
672 {MHD_OPTION_HTTPS_MEM_CERT
, 0, (char*) cert
};
674 flags
|= MHD_USE_SSL
;
677 opts
[opts_pos
++] = (struct MHD_OptionItem
)
678 {MHD_OPTION_HTTPS_MEM_TRUST
, 0, (char*) trust
};
681 d
= new(MHDDaemonWrapper
, 1);
685 d
->fd
= (uint64_t) fd
;
687 d
->daemon
= MHD_start_daemon(flags
, 0,
689 request_handler
, NULL
,
690 MHD_OPTION_ARRAY
, opts
,
693 log_error("Failed to start µhttp daemon");
698 log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)",
699 key
? "HTTPS" : "HTTP", fd
, d
);
702 info
= MHD_get_daemon_info(d
->daemon
, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY
);
704 log_error("µhttp returned NULL daemon info");
709 epoll_fd
= info
->listen_fd
;
711 log_error("µhttp epoll fd is invalid");
716 r
= sd_event_add_io(s
->events
, &d
->event
,
718 dispatch_http_event
, d
);
720 log_error_errno(r
, "Failed to add event callback: %m");
724 r
= sd_event_source_set_description(d
->event
, "epoll-fd");
726 log_error_errno(r
, "Failed to set source name: %m");
730 r
= hashmap_ensure_allocated(&s
->daemons
, &uint64_hash_ops
);
736 r
= hashmap_put(s
->daemons
, &d
->fd
, d
);
738 log_error_errno(r
, "Failed to add daemon to hashmap: %m");
746 MHD_stop_daemon(d
->daemon
);
752 static int setup_microhttpd_socket(RemoteServer
*s
,
759 fd
= make_socket_fd(LOG_DEBUG
, address
, SOCK_STREAM
| SOCK_CLOEXEC
);
763 return setup_microhttpd_server(s
, fd
, key
, cert
, trust
);
766 static int dispatch_http_event(sd_event_source
*event
,
770 MHDDaemonWrapper
*d
= userdata
;
775 r
= MHD_run(d
->daemon
);
777 log_error("MHD_run failed!");
778 // XXX: unregister daemon
782 return 1; /* work to do */
785 /**********************************************************************
786 **********************************************************************
787 **********************************************************************/
789 static int setup_signals(RemoteServer
*s
) {
794 assert_se(sigprocmask_many(SIG_SETMASK
, NULL
, SIGINT
, SIGTERM
, -1) >= 0);
796 r
= sd_event_add_signal(s
->events
, &s
->sigterm_event
, SIGTERM
, NULL
, s
);
800 r
= sd_event_add_signal(s
->events
, &s
->sigint_event
, SIGINT
, NULL
, s
);
807 static int negative_fd(const char *spec
) {
808 /* Return a non-positive number as its inverse, -EINVAL otherwise. */
812 r
= safe_atoi(spec
, &fd
);
822 static int remoteserver_init(RemoteServer
*s
,
831 if ((arg_listen_raw
|| arg_listen_http
) && trust
) {
832 log_error("Option --trust makes all non-HTTPS connections untrusted.");
836 r
= sd_event_default(&s
->events
);
838 return log_error_errno(r
, "Failed to allocate event loop: %m");
842 assert(server
== NULL
);
845 r
= init_writer_hashmap(s
);
849 n
= sd_listen_fds(true);
851 return log_error_errno(n
, "Failed to read listening file descriptors from environment: %m");
853 log_debug("Received %d descriptors", n
);
855 if (MAX(http_socket
, https_socket
) >= SD_LISTEN_FDS_START
+ n
) {
856 log_error("Received fewer sockets than expected");
860 for (fd
= SD_LISTEN_FDS_START
; fd
< SD_LISTEN_FDS_START
+ n
; fd
++) {
861 if (sd_is_socket(fd
, AF_UNSPEC
, 0, true)) {
862 log_debug("Received a listening socket (fd:%d)", fd
);
864 if (fd
== http_socket
)
865 r
= setup_microhttpd_server(s
, fd
, NULL
, NULL
, NULL
);
866 else if (fd
== https_socket
)
867 r
= setup_microhttpd_server(s
, fd
, key
, cert
, trust
);
869 r
= add_raw_socket(s
, fd
);
870 } else if (sd_is_socket(fd
, AF_UNSPEC
, 0, false)) {
873 r
= getnameinfo_pretty(fd
, &hostname
);
875 return log_error_errno(r
, "Failed to retrieve remote name: %m");
877 log_debug("Received a connection socket (fd:%d) from %s", fd
, hostname
);
879 r
= add_source(s
, fd
, hostname
, true);
881 log_error("Unknown socket passed on fd:%d", fd
);
887 return log_error_errno(r
, "Failed to register socket (fd:%d): %m",
892 const char *url
, *hostname
;
894 url
= strjoina(arg_url
, "/entries");
897 log_info("Spawning getter %s...", url
);
898 fd
= spawn_getter(arg_getter
, url
);
900 log_info("Spawning curl %s...", url
);
901 fd
= spawn_curl(url
);
907 startswith(arg_url
, "https://") ?:
908 startswith(arg_url
, "http://") ?:
911 r
= add_source(s
, fd
, (char*) hostname
, false);
916 if (arg_listen_raw
) {
917 log_debug("Listening on a socket...");
918 r
= setup_raw_socket(s
, arg_listen_raw
);
923 if (arg_listen_http
) {
924 r
= setup_microhttpd_socket(s
, arg_listen_http
, NULL
, NULL
, NULL
);
929 if (arg_listen_https
) {
930 r
= setup_microhttpd_socket(s
, arg_listen_https
, key
, cert
, trust
);
935 STRV_FOREACH(file
, arg_files
) {
936 const char *output_name
;
938 if (streq(*file
, "-")) {
939 log_debug("Using standard input as source.");
942 output_name
= "stdin";
944 log_debug("Reading file %s...", *file
);
946 fd
= open(*file
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NONBLOCK
);
948 return log_error_errno(errno
, "Failed to open %s: %m", *file
);
952 r
= add_source(s
, fd
, (char*) output_name
, false);
957 if (s
->active
== 0) {
958 log_error("Zarro sources specified");
962 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_NONE
) {
963 /* In this case we know what the writer will be
964 called, so we can create it and verify that we can
965 create output as expected. */
966 r
= get_writer(s
, NULL
, &s
->_single_writer
);
974 static void server_destroy(RemoteServer
*s
) {
978 while ((d
= hashmap_steal_first(s
->daemons
))) {
979 MHD_stop_daemon(d
->daemon
);
980 sd_event_source_unref(d
->event
);
984 hashmap_free(s
->daemons
);
986 assert(s
->sources_size
== 0 || s
->sources
);
987 for (i
= 0; i
< s
->sources_size
; i
++)
991 writer_unref(s
->_single_writer
);
992 hashmap_free(s
->writers
);
994 sd_event_source_unref(s
->sigterm_event
);
995 sd_event_source_unref(s
->sigint_event
);
996 sd_event_source_unref(s
->listen_event
);
997 sd_event_unref(s
->events
);
999 /* fds that we're listening on remain open... */
1002 /**********************************************************************
1003 **********************************************************************
1004 **********************************************************************/
1006 static int handle_raw_source(sd_event_source
*event
,
1011 RemoteSource
*source
;
1014 /* Returns 1 if there might be more data pending,
1015 * 0 if data is currently exhausted, negative on error.
1018 assert(fd
>= 0 && fd
< (ssize_t
) s
->sources_size
);
1019 source
= s
->sources
[fd
];
1020 assert(source
->fd
== fd
);
1022 r
= process_source(source
, arg_compress
, arg_seal
);
1023 if (source
->state
== STATE_EOF
) {
1026 log_debug("EOF reached with source fd:%d (%s)",
1027 source
->fd
, source
->name
);
1029 remaining
= source_non_empty(source
);
1031 log_notice("Premature EOF. %zu bytes lost.", remaining
);
1032 remove_source(s
, source
->fd
);
1033 log_debug("%zu active sources remaining", s
->active
);
1035 } else if (r
== -E2BIG
) {
1036 log_notice_errno(E2BIG
, "Entry too big, skipped");
1038 } else if (r
== -EAGAIN
) {
1041 log_debug_errno(r
, "Closing connection: %m");
1042 remove_source(server
, fd
);
1048 static int dispatch_raw_source_until_block(sd_event_source
*event
,
1050 RemoteSource
*source
= userdata
;
1053 /* Make sure event stays around even if source is destroyed */
1054 sd_event_source_ref(event
);
1056 r
= handle_raw_source(event
, source
->fd
, EPOLLIN
, server
);
1058 /* No more data for now */
1059 sd_event_source_set_enabled(event
, SD_EVENT_OFF
);
1061 sd_event_source_unref(event
);
1066 static int dispatch_raw_source_event(sd_event_source
*event
,
1070 RemoteSource
*source
= userdata
;
1073 assert(source
->event
);
1074 assert(source
->buffer_event
);
1076 r
= handle_raw_source(event
, fd
, EPOLLIN
, server
);
1078 /* Might have more data. We need to rerun the handler
1079 * until we are sure the buffer is exhausted. */
1080 sd_event_source_set_enabled(source
->buffer_event
, SD_EVENT_ON
);
1085 static int dispatch_blocking_source_event(sd_event_source
*event
,
1087 RemoteSource
*source
= userdata
;
1089 return handle_raw_source(event
, source
->fd
, EPOLLIN
, server
);
1092 static int accept_connection(const char* type
, int fd
,
1093 SocketAddress
*addr
, char **hostname
) {
1096 log_debug("Accepting new %s connection on fd:%d", type
, fd
);
1097 fd2
= accept4(fd
, &addr
->sockaddr
.sa
, &addr
->size
, SOCK_NONBLOCK
|SOCK_CLOEXEC
);
1099 return log_error_errno(errno
, "accept() on fd:%d failed: %m", fd
);
1101 switch(socket_address_family(addr
)) {
1104 _cleanup_free_
char *a
= NULL
;
1107 r
= socket_address_print(addr
, &a
);
1109 log_error_errno(r
, "socket_address_print(): %m");
1114 r
= socknameinfo_pretty(&addr
->sockaddr
, addr
->size
, &b
);
1116 log_error_errno(r
, "Resolving hostname failed: %m");
1121 log_debug("Accepted %s %s connection from %s",
1123 socket_address_family(addr
) == AF_INET
? "IP" : "IPv6",
1131 log_error("Rejected %s connection with unsupported family %d",
1132 type
, socket_address_family(addr
));
1139 static int dispatch_raw_connection_event(sd_event_source
*event
,
1143 RemoteServer
*s
= userdata
;
1145 SocketAddress addr
= {
1146 .size
= sizeof(union sockaddr_union
),
1147 .type
= SOCK_STREAM
,
1149 char *hostname
= NULL
;
1151 fd2
= accept_connection("raw", fd
, &addr
, &hostname
);
1155 return add_source(s
, fd2
, hostname
, true);
1158 /**********************************************************************
1159 **********************************************************************
1160 **********************************************************************/
1162 static const char* const journal_write_split_mode_table
[_JOURNAL_WRITE_SPLIT_MAX
] = {
1163 [JOURNAL_WRITE_SPLIT_NONE
] = "none",
1164 [JOURNAL_WRITE_SPLIT_HOST
] = "host",
1167 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(journal_write_split_mode
, JournalWriteSplitMode
);
1168 static DEFINE_CONFIG_PARSE_ENUM(config_parse_write_split_mode
,
1169 journal_write_split_mode
,
1170 JournalWriteSplitMode
,
1171 "Failed to parse split mode setting");
1173 static int parse_config(void) {
1174 const ConfigTableItem items
[] = {
1175 { "Remote", "SplitMode", config_parse_write_split_mode
, 0, &arg_split_mode
},
1176 { "Remote", "ServerKeyFile", config_parse_path
, 0, &arg_key
},
1177 { "Remote", "ServerCertificateFile", config_parse_path
, 0, &arg_cert
},
1178 { "Remote", "TrustedCertificateFile", config_parse_path
, 0, &arg_trust
},
1181 return config_parse_many(PKGSYSCONFDIR
"/journal-remote.conf",
1182 CONF_DIRS_NULSTR("systemd/journal-remote.conf"),
1183 "Remote\0", config_item_table_lookup
, items
,
1187 static void help(void) {
1188 printf("%s [OPTIONS...] {FILE|-}...\n\n"
1189 "Write external journal events to journal file(s).\n\n"
1190 " -h --help Show this help\n"
1191 " --version Show package version\n"
1192 " --url=URL Read events from systemd-journal-gatewayd at URL\n"
1193 " --getter=COMMAND Read events from the output of COMMAND\n"
1194 " --listen-raw=ADDR Listen for connections at ADDR\n"
1195 " --listen-http=ADDR Listen for HTTP connections at ADDR\n"
1196 " --listen-https=ADDR Listen for HTTPS connections at ADDR\n"
1197 " -o --output=FILE|DIR Write output to FILE or DIR/external-*.journal\n"
1198 " --compress[=BOOL] XZ-compress the output journal (default: yes)\n"
1199 " --seal[=BOOL] Use event sealing (default: no)\n"
1200 " --key=FILENAME SSL key in PEM format (default:\n"
1201 " \"" PRIV_KEY_FILE
"\")\n"
1202 " --cert=FILENAME SSL certificate in PEM format (default:\n"
1203 " \"" CERT_FILE
"\")\n"
1204 " --trust=FILENAME|all SSL CA certificate or disable checking (default:\n"
1205 " \"" TRUST_FILE
"\")\n"
1206 " --gnutls-log=CATEGORY...\n"
1207 " Specify a list of gnutls logging categories\n"
1208 " --split-mode=none|host How many output files to create\n"
1210 "Note: file descriptors from sd_listen_fds() will be consumed, too.\n"
1211 , program_invocation_short_name
);
1214 static int parse_argv(int argc
, char *argv
[]) {
1216 ARG_VERSION
= 0x100,
1231 static const struct option options
[] = {
1232 { "help", no_argument
, NULL
, 'h' },
1233 { "version", no_argument
, NULL
, ARG_VERSION
},
1234 { "url", required_argument
, NULL
, ARG_URL
},
1235 { "getter", required_argument
, NULL
, ARG_GETTER
},
1236 { "listen-raw", required_argument
, NULL
, ARG_LISTEN_RAW
},
1237 { "listen-http", required_argument
, NULL
, ARG_LISTEN_HTTP
},
1238 { "listen-https", required_argument
, NULL
, ARG_LISTEN_HTTPS
},
1239 { "output", required_argument
, NULL
, 'o' },
1240 { "split-mode", required_argument
, NULL
, ARG_SPLIT_MODE
},
1241 { "compress", optional_argument
, NULL
, ARG_COMPRESS
},
1242 { "seal", optional_argument
, NULL
, ARG_SEAL
},
1243 { "key", required_argument
, NULL
, ARG_KEY
},
1244 { "cert", required_argument
, NULL
, ARG_CERT
},
1245 { "trust", required_argument
, NULL
, ARG_TRUST
},
1246 { "gnutls-log", required_argument
, NULL
, ARG_GNUTLS_LOG
},
1251 bool type_a
, type_b
;
1256 while ((c
= getopt_long(argc
, argv
, "ho:", options
, NULL
)) >= 0)
1260 return 0 /* done */;
1263 puts(PACKAGE_STRING
);
1264 puts(SYSTEMD_FEATURES
);
1265 return 0 /* done */;
1269 log_error("cannot currently set more than one --url");
1278 log_error("cannot currently use --getter more than once");
1282 arg_getter
= optarg
;
1285 case ARG_LISTEN_RAW
:
1286 if (arg_listen_raw
) {
1287 log_error("cannot currently use --listen-raw more than once");
1291 arg_listen_raw
= optarg
;
1294 case ARG_LISTEN_HTTP
:
1295 if (arg_listen_http
|| http_socket
>= 0) {
1296 log_error("cannot currently use --listen-http more than once");
1300 r
= negative_fd(optarg
);
1304 arg_listen_http
= optarg
;
1307 case ARG_LISTEN_HTTPS
:
1308 if (arg_listen_https
|| https_socket
>= 0) {
1309 log_error("cannot currently use --listen-https more than once");
1313 r
= negative_fd(optarg
);
1317 arg_listen_https
= optarg
;
1323 log_error("Key file specified twice");
1327 arg_key
= strdup(optarg
);
1335 log_error("Certificate file specified twice");
1339 arg_cert
= strdup(optarg
);
1346 if (arg_trust
|| arg_trust_all
) {
1347 log_error("Confusing trusted CA configuration");
1351 if (streq(optarg
, "all"))
1352 arg_trust_all
= true;
1355 arg_trust
= strdup(optarg
);
1359 log_error("Option --trust is not available.");
1368 log_error("cannot use --output/-o more than once");
1372 arg_output
= optarg
;
1375 case ARG_SPLIT_MODE
:
1376 arg_split_mode
= journal_write_split_mode_from_string(optarg
);
1377 if (arg_split_mode
== _JOURNAL_WRITE_SPLIT_INVALID
) {
1378 log_error("Invalid split mode: %s", optarg
);
1385 r
= parse_boolean(optarg
);
1387 log_error("Failed to parse --compress= parameter.");
1393 arg_compress
= true;
1399 r
= parse_boolean(optarg
);
1401 log_error("Failed to parse --seal= parameter.");
1411 case ARG_GNUTLS_LOG
: {
1413 const char *word
, *state
;
1416 FOREACH_WORD_SEPARATOR(word
, size
, optarg
, ",", state
) {
1419 cat
= strndup(word
, size
);
1423 if (strv_consume(&arg_gnutls_log
, cat
) < 0)
1428 log_error("Option --gnutls-log is not available.");
1437 assert_not_reached("Unknown option code.");
1441 arg_files
= argv
+ optind
;
1443 type_a
= arg_getter
|| !strv_isempty(arg_files
);
1446 || arg_listen_http
|| arg_listen_https
1447 || sd_listen_fds(false) > 0;
1448 if (type_a
&& type_b
) {
1449 log_error("Cannot use file input or --getter with "
1450 "--arg-listen-... or socket activation.");
1455 log_error("Option --output must be specified with file input or --getter.");
1459 arg_split_mode
= JOURNAL_WRITE_SPLIT_NONE
;
1462 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_NONE
1463 && arg_output
&& is_dir(arg_output
, true) > 0) {
1464 log_error("For SplitMode=none, output must be a file.");
1468 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_HOST
1469 && arg_output
&& is_dir(arg_output
, true) <= 0) {
1470 log_error("For SplitMode=host, output must be a directory.");
1474 log_debug("Full config: SplitMode=%s Key=%s Cert=%s Trust=%s",
1475 journal_write_split_mode_to_string(arg_split_mode
),
1480 return 1 /* work to do */;
1483 static int load_certificates(char **key
, char **cert
, char **trust
) {
1486 r
= read_full_file(arg_key
?: PRIV_KEY_FILE
, key
, NULL
);
1488 return log_error_errno(r
, "Failed to read key from file '%s': %m",
1489 arg_key
?: PRIV_KEY_FILE
);
1491 r
= read_full_file(arg_cert
?: CERT_FILE
, cert
, NULL
);
1493 return log_error_errno(r
, "Failed to read certificate from file '%s': %m",
1494 arg_cert
?: CERT_FILE
);
1497 log_info("Certificate checking disabled.");
1499 r
= read_full_file(arg_trust
?: TRUST_FILE
, trust
, NULL
);
1501 return log_error_errno(r
, "Failed to read CA certificate file '%s': %m",
1502 arg_trust
?: TRUST_FILE
);
1508 int main(int argc
, char **argv
) {
1509 RemoteServer s
= {};
1511 _cleanup_free_
char *key
= NULL
, *cert
= NULL
, *trust
= NULL
;
1513 log_show_color(true);
1514 log_parse_environment();
1518 return EXIT_FAILURE
;
1520 r
= parse_argv(argc
, argv
);
1522 return r
== 0 ? EXIT_SUCCESS
: EXIT_FAILURE
;
1525 if (arg_listen_http
|| arg_listen_https
) {
1526 r
= setup_gnutls_logger(arg_gnutls_log
);
1528 return EXIT_FAILURE
;
1531 if (arg_listen_https
|| https_socket
>= 0)
1532 if (load_certificates(&key
, &cert
, &trust
) < 0)
1533 return EXIT_FAILURE
;
1535 if (remoteserver_init(&s
, key
, cert
, trust
) < 0)
1536 return EXIT_FAILURE
;
1538 r
= sd_event_set_watchdog(s
.events
, true);
1540 log_error_errno(r
, "Failed to enable watchdog: %m");
1542 log_debug("Watchdog is %s.", r
> 0 ? "enabled" : "disabled");
1544 log_debug("%s running as pid "PID_FMT
,
1545 program_invocation_short_name
, getpid());
1548 "STATUS=Processing requests...");
1551 r
= sd_event_get_state(s
.events
);
1554 if (r
== SD_EVENT_FINISHED
)
1557 r
= sd_event_run(s
.events
, -1);
1559 log_error_errno(r
, "Failed to run event loop: %m");
1566 "STATUS=Shutting down after writing %" PRIu64
" entries...", s
.event_count
);
1567 log_info("Finishing after writing %" PRIu64
" entries", s
.event_count
);
1575 return r
>= 0 ? EXIT_SUCCESS
: EXIT_FAILURE
;