]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal-remote/journal-remote.c
journal-remote: set a limit on the number of fields in a message
[thirdparty/systemd.git] / src / journal-remote / journal-remote.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
fdfccdbc
ZJS
2
3#include <errno.h>
4#include <fcntl.h>
fdfccdbc
ZJS
5#include <stdio.h>
6#include <stdlib.h>
7#include <string.h>
8#include <sys/prctl.h>
9#include <sys/socket.h>
5e38eb93 10#include <stdint.h>
3f6fd1ba 11
fdfccdbc 12#include "sd-daemon.h"
3f6fd1ba 13
b5efdb8a 14#include "alloc-util.h"
a0f29c76 15#include "def.h"
4f5dd394 16#include "escape.h"
3ffd4af2 17#include "fd-util.h"
fdfccdbc 18#include "journal-file.h"
4f5dd394 19#include "journal-remote-write.h"
3ffd4af2 20#include "journal-remote.h"
fdfccdbc 21#include "journald-native.h"
fdfccdbc 22#include "macro.h"
6bedfcbb 23#include "parse-util.h"
dccca82b 24#include "process-util.h"
3f6fd1ba 25#include "socket-util.h"
15a5e950 26#include "stdio-util.h"
07630cea 27#include "string-util.h"
fdfccdbc 28#include "strv.h"
fdfccdbc 29
8201af08 30#define REMOTE_JOURNAL_PATH "/var/log/journal/remote"
fdfccdbc 31
9ff48d09 32#define filename_escape(s) xescape((s), "/ ")
8201af08 33
c064d8db
ZJS
34static int open_output(RemoteServer *s, Writer *w, const char* host) {
35 _cleanup_free_ char *_filename = NULL;
36 const char *filename;
fdfccdbc
ZJS
37 int r;
38
c064d8db 39 switch (s->split_mode) {
8201af08 40 case JOURNAL_WRITE_SPLIT_NONE:
c064d8db 41 filename = s->output;
8201af08 42 break;
fdfccdbc 43
8201af08
ZJS
44 case JOURNAL_WRITE_SPLIT_HOST: {
45 _cleanup_free_ char *name;
fdfccdbc 46
8201af08 47 assert(host);
fdfccdbc 48
8201af08
ZJS
49 name = filename_escape(host);
50 if (!name)
51 return log_oom();
52
c064d8db 53 r = asprintf(&_filename, "%s/remote-%s.journal", s->output, name);
fdfccdbc
ZJS
54 if (r < 0)
55 return log_oom();
8201af08 56
c064d8db 57 filename = _filename;
8201af08
ZJS
58 break;
59 }
60
61 default:
62 assert_not_reached("what?");
fdfccdbc
ZJS
63 }
64
c064d8db 65 r = journal_file_open_reliably(filename,
fdfccdbc 66 O_RDWR|O_CREAT, 0640,
c064d8db 67 s->compress, (uint64_t) -1, s->seal,
8201af08 68 &w->metrics,
b58c888f 69 w->mmap, NULL,
8201af08 70 NULL, &w->journal);
fdfccdbc 71 if (r < 0)
c064d8db
ZJS
72 return log_error_errno(r, "Failed to open output journal %s: %m", filename);
73
74 log_debug("Opened output file %s", w->journal->path);
75 return 0;
fdfccdbc
ZJS
76}
77
cc64d017
ZJS
78/**********************************************************************
79 **********************************************************************
80 **********************************************************************/
81
9ff48d09 82static int init_writer_hashmap(RemoteServer *s) {
c064d8db 83 static const struct hash_ops* const hash_ops[] = {
d5099efc
MS
84 [JOURNAL_WRITE_SPLIT_NONE] = NULL,
85 [JOURNAL_WRITE_SPLIT_HOST] = &string_hash_ops,
9ff48d09
ZJS
86 };
87
c064d8db
ZJS
88 assert(s);
89 assert(s->split_mode >= 0 && s->split_mode < (int) ELEMENTSOF(hash_ops));
cc64d017 90
c064d8db 91 s->writers = hashmap_new(hash_ops[s->split_mode]);
9ff48d09
ZJS
92 if (!s->writers)
93 return log_oom();
94
95 return 0;
96}
97
c064d8db 98int journal_remote_get_writer(RemoteServer *s, const char *host, Writer **writer) {
8e766630 99 _cleanup_(writer_unrefp) Writer *w = NULL;
9ff48d09 100 const void *key;
9ff48d09
ZJS
101 int r;
102
c064d8db 103 switch(s->split_mode) {
9ff48d09
ZJS
104 case JOURNAL_WRITE_SPLIT_NONE:
105 key = "one and only";
106 break;
107
108 case JOURNAL_WRITE_SPLIT_HOST:
109 assert(host);
110 key = host;
111 break;
112
113 default:
114 assert_not_reached("what split mode?");
115 }
116
117 w = hashmap_get(s->writers, key);
118 if (w)
119 writer_ref(w);
120 else {
121 w = writer_new(s);
122 if (!w)
123 return log_oom();
124
c064d8db 125 if (s->split_mode == JOURNAL_WRITE_SPLIT_HOST) {
9ff48d09
ZJS
126 w->hashmap_key = strdup(key);
127 if (!w->hashmap_key)
128 return log_oom();
129 }
cc64d017 130
c064d8db 131 r = open_output(s, w, host);
9ff48d09
ZJS
132 if (r < 0)
133 return r;
fdfccdbc 134
9ff48d09
ZJS
135 r = hashmap_put(s->writers, w->hashmap_key ?: key, w);
136 if (r < 0)
137 return r;
138 }
fdfccdbc 139
1cc6c93a
YW
140 *writer = TAKE_PTR(w);
141
9ff48d09
ZJS
142 return 0;
143}
cc64d017 144
9ff48d09
ZJS
145/**********************************************************************
146 **********************************************************************
147 **********************************************************************/
fdfccdbc 148
cc64d017 149/* This should go away as soon as µhttpd allows state to be passed around. */
c064d8db 150RemoteServer *journal_remote_server_global;
cc64d017 151
fdfccdbc
ZJS
152static int dispatch_raw_source_event(sd_event_source *event,
153 int fd,
154 uint32_t revents,
155 void *userdata);
043945b9
ZJS
156static int dispatch_raw_source_until_block(sd_event_source *event,
157 void *userdata);
70f1b2dd
ZJS
158static int dispatch_blocking_source_event(sd_event_source *event,
159 void *userdata);
fdfccdbc
ZJS
160static int dispatch_raw_connection_event(sd_event_source *event,
161 int fd,
162 uint32_t revents,
163 void *userdata);
164
9ff48d09
ZJS
165static int get_source_for_fd(RemoteServer *s,
166 int fd, char *name, RemoteSource **source) {
167 Writer *writer;
168 int r;
169
1f8af042
ZJS
170 /* This takes ownership of name, but only on success. */
171
fdfccdbc
ZJS
172 assert(fd >= 0);
173 assert(source);
174
ca2d3784 175 if (!GREEDY_REALLOC0(s->sources, s->sources_size, fd + 1))
fdfccdbc
ZJS
176 return log_oom();
177
c064d8db 178 r = journal_remote_get_writer(s, name, &writer);
eb56eb9b
MS
179 if (r < 0)
180 return log_warning_errno(r, "Failed to get writer for source %s: %m",
181 name);
9ff48d09 182
fdfccdbc 183 if (s->sources[fd] == NULL) {
9ff48d09
ZJS
184 s->sources[fd] = source_new(fd, false, name, writer);
185 if (!s->sources[fd]) {
186 writer_unref(writer);
fdfccdbc 187 return log_oom();
9ff48d09
ZJS
188 }
189
fdfccdbc
ZJS
190 s->active++;
191 }
192
193 *source = s->sources[fd];
194 return 0;
195}
196
197static int remove_source(RemoteServer *s, int fd) {
198 RemoteSource *source;
199
200 assert(s);
ca2d3784 201 assert(fd >= 0 && fd < (ssize_t) s->sources_size);
fdfccdbc
ZJS
202
203 source = s->sources[fd];
204 if (source) {
8201af08 205 /* this closes fd too */
fdfccdbc
ZJS
206 source_free(source);
207 s->sources[fd] = NULL;
208 s->active--;
209 }
210
fdfccdbc
ZJS
211 return 0;
212}
213
c064d8db 214int journal_remote_add_source(RemoteServer *s, int fd, char* name, bool own_name) {
a7f7d1bd 215 RemoteSource *source = NULL;
fdfccdbc
ZJS
216 int r;
217
1f8af042
ZJS
218 /* This takes ownership of name, even on failure, if own_name is true. */
219
fdfccdbc
ZJS
220 assert(s);
221 assert(fd >= 0);
9ff48d09 222 assert(name);
fdfccdbc 223
9ff48d09
ZJS
224 if (!own_name) {
225 name = strdup(name);
226 if (!name)
227 return log_oom();
228 }
fdfccdbc 229
9ff48d09 230 r = get_source_for_fd(s, fd, name, &source);
fdfccdbc 231 if (r < 0) {
c33b3297
MS
232 log_error_errno(r, "Failed to create source for fd:%d (%s): %m",
233 fd, name);
1f8af042 234 free(name);
fdfccdbc
ZJS
235 return r;
236 }
8201af08 237
fdfccdbc 238 r = sd_event_add_io(s->events, &source->event,
8201af08 239 fd, EPOLLIN|EPOLLRDHUP|EPOLLPRI,
043945b9
ZJS
240 dispatch_raw_source_event, source);
241 if (r == 0) {
242 /* Add additional source for buffer processing. It will be
243 * enabled later. */
244 r = sd_event_add_defer(s->events, &source->buffer_event,
245 dispatch_raw_source_until_block, source);
246 if (r == 0)
247 sd_event_source_set_enabled(source->buffer_event, SD_EVENT_OFF);
248 } else if (r == -EPERM) {
70f1b2dd
ZJS
249 log_debug("Falling back to sd_event_add_defer for fd:%d (%s)", fd, name);
250 r = sd_event_add_defer(s->events, &source->event,
251 dispatch_blocking_source_event, source);
252 if (r == 0)
253 sd_event_source_set_enabled(source->event, SD_EVENT_ON);
254 }
fdfccdbc 255 if (r < 0) {
c33b3297
MS
256 log_error_errno(r, "Failed to register event source for fd:%d: %m",
257 fd);
fdfccdbc
ZJS
258 goto error;
259 }
260
356779df 261 r = sd_event_source_set_description(source->event, name);
43300d9d 262 if (r < 0) {
da927ba9 263 log_error_errno(r, "Failed to set source name for fd:%d: %m", fd);
43300d9d
ZJS
264 goto error;
265 }
266
fdfccdbc
ZJS
267 return 1; /* work to do */
268
269 error:
270 remove_source(s, fd);
271 return r;
272}
273
c064d8db 274int journal_remote_add_raw_socket(RemoteServer *s, int fd) {
8a8d55f2 275 int r;
43300d9d 276 _cleanup_close_ int fd_ = fd;
fbd0b64f 277 char name[STRLEN("raw-socket-") + DECIMAL_STR_MAX(int) + 1];
43300d9d
ZJS
278
279 assert(fd >= 0);
fdfccdbc 280
8201af08
ZJS
281 r = sd_event_add_io(s->events, &s->listen_event,
282 fd, EPOLLIN,
fdfccdbc 283 dispatch_raw_connection_event, s);
43300d9d 284 if (r < 0)
fdfccdbc 285 return r;
fdfccdbc 286
5ffa8c81 287 xsprintf(name, "raw-socket-%d", fd);
43300d9d 288
356779df 289 r = sd_event_source_set_description(s->listen_event, name);
43300d9d
ZJS
290 if (r < 0)
291 return r;
292
293 fd_ = -1;
313cefa1 294 s->active++;
fdfccdbc
ZJS
295 return 0;
296}
297
8201af08
ZJS
298/**********************************************************************
299 **********************************************************************
300 **********************************************************************/
301
c064d8db
ZJS
302int journal_remote_server_init(
303 RemoteServer *s,
304 const char *output,
305 JournalWriteSplitMode split_mode,
306 bool compress,
307 bool seal) {
cc64d017 308
fdfccdbc
ZJS
309 int r;
310
311 assert(s);
312
c064d8db
ZJS
313 assert(journal_remote_server_global == NULL);
314 journal_remote_server_global = s;
fdfccdbc 315
c064d8db
ZJS
316 s->split_mode = split_mode;
317 s->compress = compress;
318 s->seal = seal;
43300d9d 319
c064d8db
ZJS
320 if (output)
321 s->output = output;
322 else if (split_mode == JOURNAL_WRITE_SPLIT_NONE)
323 s->output = REMOTE_JOURNAL_PATH "/remote.journal";
324 else if (split_mode == JOURNAL_WRITE_SPLIT_HOST)
325 s->output = REMOTE_JOURNAL_PATH;
42b6bf75 326 else
c064d8db 327 assert_not_reached("bad split mode");
ad95fd1d 328
b1604b34 329 r = sd_event_default(&s->events);
23bbb0de
MS
330 if (r < 0)
331 return log_error_errno(r, "Failed to allocate event loop: %m");
fdfccdbc 332
22259a00
JL
333 r = init_writer_hashmap(s);
334 if (r < 0)
335 return r;
336
8201af08 337 return 0;
fdfccdbc
ZJS
338}
339
63e2ebcd 340#if HAVE_MICROHTTPD
1599f593
ZJS
341static void MHDDaemonWrapper_free(MHDDaemonWrapper *d) {
342 MHD_stop_daemon(d->daemon);
343 sd_event_source_unref(d->io_event);
344 sd_event_source_unref(d->timer_event);
345 free(d);
346}
63e2ebcd 347#endif
1599f593 348
94952201 349void journal_remote_server_destroy(RemoteServer *s) {
ca2d3784 350 size_t i;
cc64d017 351
63e2ebcd 352#if HAVE_MICROHTTPD
1599f593 353 hashmap_free_with_destructor(s->daemons, MHDDaemonWrapper_free);
63e2ebcd 354#endif
cc64d017 355
fdfccdbc 356 assert(s->sources_size == 0 || s->sources);
cc64d017 357 for (i = 0; i < s->sources_size; i++)
fdfccdbc 358 remove_source(s, i);
fdfccdbc
ZJS
359 free(s->sources);
360
9ff48d09
ZJS
361 writer_unref(s->_single_writer);
362 hashmap_free(s->writers);
363
fdfccdbc
ZJS
364 sd_event_source_unref(s->sigterm_event);
365 sd_event_source_unref(s->sigint_event);
366 sd_event_source_unref(s->listen_event);
367 sd_event_unref(s->events);
368
c064d8db
ZJS
369 if (s == journal_remote_server_global)
370 journal_remote_server_global = NULL;
371
fdfccdbc 372 /* fds that we're listening on remain open... */
fdfccdbc
ZJS
373}
374
375/**********************************************************************
376 **********************************************************************
377 **********************************************************************/
378
864876ec
ZJS
379int journal_remote_handle_raw_source(
380 sd_event_source *event,
381 int fd,
382 uint32_t revents,
383 RemoteServer *s) {
fdfccdbc 384
fdfccdbc
ZJS
385 RemoteSource *source;
386 int r;
387
043945b9
ZJS
388 /* Returns 1 if there might be more data pending,
389 * 0 if data is currently exhausted, negative on error.
390 */
391
ca2d3784 392 assert(fd >= 0 && fd < (ssize_t) s->sources_size);
fdfccdbc 393 source = s->sources[fd];
b18453ed 394 assert(source->importer.fd == fd);
fdfccdbc 395
c064d8db 396 r = process_source(source, s->compress, s->seal);
b18453ed 397 if (journal_importer_eof(&source->importer)) {
4a0a6ac0
ZJS
398 size_t remaining;
399
b18453ed
ZJS
400 log_debug("EOF reached with source %s (fd=%d)",
401 source->importer.name, source->importer.fd);
4a0a6ac0 402
b18453ed 403 remaining = journal_importer_bytes_remaining(&source->importer);
4a0a6ac0 404 if (remaining > 0)
0e72da6f 405 log_notice("Premature EOF. %zu bytes lost.", remaining);
b18453ed 406 remove_source(s, source->importer.fd);
0e72da6f 407 log_debug("%zu active sources remaining", s->active);
8201af08 408 return 0;
fdfccdbc 409 } else if (r == -E2BIG) {
ef4d6abe
ZJS
410 log_notice("Entry with too many fields, skipped");
411 return 1;
412 } else if (r == -ENOBUFS) {
d4e98880 413 log_notice("Entry too big, skipped");
8201af08 414 return 1;
ff55c3c7 415 } else if (r == -EAGAIN) {
8201af08
ZJS
416 return 0;
417 } else if (r < 0) {
0e72da6f 418 log_debug_errno(r, "Closing connection: %m");
c064d8db 419 remove_source(s, fd);
8201af08
ZJS
420 return 0;
421 } else
422 return 1;
fdfccdbc
ZJS
423}
424
043945b9
ZJS
425static int dispatch_raw_source_until_block(sd_event_source *event,
426 void *userdata) {
427 RemoteSource *source = userdata;
428 int r;
429
430 /* Make sure event stays around even if source is destroyed */
431 sd_event_source_ref(event);
432
864876ec 433 r = journal_remote_handle_raw_source(event, source->importer.fd, EPOLLIN, journal_remote_server_global);
043945b9
ZJS
434 if (r != 1)
435 /* No more data for now */
436 sd_event_source_set_enabled(event, SD_EVENT_OFF);
437
438 sd_event_source_unref(event);
439
440 return r;
441}
442
443static int dispatch_raw_source_event(sd_event_source *event,
444 int fd,
445 uint32_t revents,
446 void *userdata) {
447 RemoteSource *source = userdata;
448 int r;
449
450 assert(source->event);
451 assert(source->buffer_event);
452
864876ec 453 r = journal_remote_handle_raw_source(event, fd, EPOLLIN, journal_remote_server_global);
043945b9
ZJS
454 if (r == 1)
455 /* Might have more data. We need to rerun the handler
456 * until we are sure the buffer is exhausted. */
457 sd_event_source_set_enabled(source->buffer_event, SD_EVENT_ON);
458
459 return r;
460}
461
70f1b2dd
ZJS
462static int dispatch_blocking_source_event(sd_event_source *event,
463 void *userdata) {
464 RemoteSource *source = userdata;
465
864876ec 466 return journal_remote_handle_raw_source(event, source->importer.fd, EPOLLIN, journal_remote_server_global);
70f1b2dd
ZJS
467}
468
8201af08
ZJS
469static int accept_connection(const char* type, int fd,
470 SocketAddress *addr, char **hostname) {
fdfccdbc
ZJS
471 int fd2, r;
472
cc64d017
ZJS
473 log_debug("Accepting new %s connection on fd:%d", type, fd);
474 fd2 = accept4(fd, &addr->sockaddr.sa, &addr->size, SOCK_NONBLOCK|SOCK_CLOEXEC);
4a62c710
MS
475 if (fd2 < 0)
476 return log_error_errno(errno, "accept() on fd:%d failed: %m", fd);
fdfccdbc 477
cc64d017 478 switch(socket_address_family(addr)) {
fdfccdbc
ZJS
479 case AF_INET:
480 case AF_INET6: {
8201af08
ZJS
481 _cleanup_free_ char *a = NULL;
482 char *b;
fdfccdbc 483
cc64d017 484 r = socket_address_print(addr, &a);
fdfccdbc 485 if (r < 0) {
da927ba9 486 log_error_errno(r, "socket_address_print(): %m");
fdfccdbc
ZJS
487 close(fd2);
488 return r;
489 }
490
8201af08
ZJS
491 r = socknameinfo_pretty(&addr->sockaddr, addr->size, &b);
492 if (r < 0) {
1938ac51 493 log_error_errno(r, "Resolving hostname failed: %m");
8201af08
ZJS
494 close(fd2);
495 return r;
496 }
497
0e72da6f
ZJS
498 log_debug("Accepted %s %s connection from %s",
499 type,
500 socket_address_family(addr) == AF_INET ? "IP" : "IPv6",
501 a);
cc64d017 502
8201af08
ZJS
503 *hostname = b;
504
cc64d017 505 return fd2;
fdfccdbc
ZJS
506 };
507 default:
cc64d017
ZJS
508 log_error("Rejected %s connection with unsupported family %d",
509 type, socket_address_family(addr));
fdfccdbc 510 close(fd2);
cc64d017 511
fdfccdbc
ZJS
512 return -EINVAL;
513 }
cc64d017 514}
fdfccdbc 515
cc64d017
ZJS
516static int dispatch_raw_connection_event(sd_event_source *event,
517 int fd,
518 uint32_t revents,
519 void *userdata) {
520 RemoteServer *s = userdata;
1f8af042 521 int fd2;
cc64d017
ZJS
522 SocketAddress addr = {
523 .size = sizeof(union sockaddr_union),
524 .type = SOCK_STREAM,
525 };
a7f7d1bd 526 char *hostname = NULL;
fdfccdbc 527
8201af08 528 fd2 = accept_connection("raw", fd, &addr, &hostname);
cc64d017
ZJS
529 if (fd2 < 0)
530 return fd2;
fdfccdbc 531
c064d8db 532 return journal_remote_add_source(s, fd2, hostname, true);
fdfccdbc 533}