journald: implement socket forwarding

This commit adds a new way of forwarding journal messages - forwarding
over a socket.

The socket can be any of AF_INET, AF_INET6, AF_UNIUX or AF_VSOCK.

The address to connect to is retrieved from the "journald.forward_address" credential.

It can also be specified in systemd-journald's unit file with ForwardAddress=
This commit is contained in:
Sam Leonard
2024-02-15 14:08:20 +00:00
parent 6813be2eba
commit f31cff849d
13 changed files with 473 additions and 48 deletions
+33 -31
View File
@@ -19,35 +19,37 @@ struct ConfigPerfItem;
%struct-type
%includes
%%
Journal.Storage, config_parse_storage, 0, offsetof(Server, storage)
Journal.Compress, config_parse_compress, 0, offsetof(Server, compress)
Journal.Seal, config_parse_bool, 0, offsetof(Server, seal)
Journal.ReadKMsg, config_parse_bool, 0, offsetof(Server, read_kmsg)
Journal.Audit, config_parse_tristate, 0, offsetof(Server, set_audit)
Journal.SyncIntervalSec, config_parse_sec, 0, offsetof(Server, sync_interval_usec)
Journal.Storage, config_parse_storage, 0, offsetof(Server, storage)
Journal.Compress, config_parse_compress, 0, offsetof(Server, compress)
Journal.Seal, config_parse_bool, 0, offsetof(Server, seal)
Journal.ReadKMsg, config_parse_bool, 0, offsetof(Server, read_kmsg)
Journal.Audit, config_parse_tristate, 0, offsetof(Server, set_audit)
Journal.SyncIntervalSec, config_parse_sec, 0, offsetof(Server, sync_interval_usec)
# The following is a legacy name for compatibility
Journal.RateLimitInterval, config_parse_sec, 0, offsetof(Server, ratelimit_interval)
Journal.RateLimitIntervalSec,config_parse_sec, 0, offsetof(Server, ratelimit_interval)
Journal.RateLimitBurst, config_parse_unsigned, 0, offsetof(Server, ratelimit_burst)
Journal.SystemMaxUse, config_parse_iec_uint64, 0, offsetof(Server, system_storage.metrics.max_use)
Journal.SystemMaxFileSize, config_parse_iec_uint64, 0, offsetof(Server, system_storage.metrics.max_size)
Journal.SystemKeepFree, config_parse_iec_uint64, 0, offsetof(Server, system_storage.metrics.keep_free)
Journal.SystemMaxFiles, config_parse_uint64, 0, offsetof(Server, system_storage.metrics.n_max_files)
Journal.RuntimeMaxUse, config_parse_iec_uint64, 0, offsetof(Server, runtime_storage.metrics.max_use)
Journal.RuntimeMaxFileSize, config_parse_iec_uint64, 0, offsetof(Server, runtime_storage.metrics.max_size)
Journal.RuntimeKeepFree, config_parse_iec_uint64, 0, offsetof(Server, runtime_storage.metrics.keep_free)
Journal.RuntimeMaxFiles, config_parse_uint64, 0, offsetof(Server, runtime_storage.metrics.n_max_files)
Journal.MaxRetentionSec, config_parse_sec, 0, offsetof(Server, max_retention_usec)
Journal.MaxFileSec, config_parse_sec, 0, offsetof(Server, max_file_usec)
Journal.ForwardToSyslog, config_parse_bool, 0, offsetof(Server, forward_to_syslog)
Journal.ForwardToKMsg, config_parse_bool, 0, offsetof(Server, forward_to_kmsg)
Journal.ForwardToConsole, config_parse_bool, 0, offsetof(Server, forward_to_console)
Journal.ForwardToWall, config_parse_bool, 0, offsetof(Server, forward_to_wall)
Journal.TTYPath, config_parse_path, 0, offsetof(Server, tty_path)
Journal.MaxLevelStore, config_parse_log_level, 0, offsetof(Server, max_level_store)
Journal.MaxLevelSyslog, config_parse_log_level, 0, offsetof(Server, max_level_syslog)
Journal.MaxLevelKMsg, config_parse_log_level, 0, offsetof(Server, max_level_kmsg)
Journal.MaxLevelConsole, config_parse_log_level, 0, offsetof(Server, max_level_console)
Journal.MaxLevelWall, config_parse_log_level, 0, offsetof(Server, max_level_wall)
Journal.SplitMode, config_parse_split_mode, 0, offsetof(Server, split_mode)
Journal.LineMax, config_parse_line_max, 0, offsetof(Server, line_max)
Journal.RateLimitInterval, config_parse_sec, 0, offsetof(Server, ratelimit_interval)
Journal.RateLimitIntervalSec,config_parse_sec, 0, offsetof(Server, ratelimit_interval)
Journal.RateLimitBurst, config_parse_unsigned, 0, offsetof(Server, ratelimit_burst)
Journal.SystemMaxUse, config_parse_iec_uint64, 0, offsetof(Server, system_storage.metrics.max_use)
Journal.SystemMaxFileSize, config_parse_iec_uint64, 0, offsetof(Server, system_storage.metrics.max_size)
Journal.SystemKeepFree, config_parse_iec_uint64, 0, offsetof(Server, system_storage.metrics.keep_free)
Journal.SystemMaxFiles, config_parse_uint64, 0, offsetof(Server, system_storage.metrics.n_max_files)
Journal.RuntimeMaxUse, config_parse_iec_uint64, 0, offsetof(Server, runtime_storage.metrics.max_use)
Journal.RuntimeMaxFileSize, config_parse_iec_uint64, 0, offsetof(Server, runtime_storage.metrics.max_size)
Journal.RuntimeKeepFree, config_parse_iec_uint64, 0, offsetof(Server, runtime_storage.metrics.keep_free)
Journal.RuntimeMaxFiles, config_parse_uint64, 0, offsetof(Server, runtime_storage.metrics.n_max_files)
Journal.MaxRetentionSec, config_parse_sec, 0, offsetof(Server, max_retention_usec)
Journal.MaxFileSec, config_parse_sec, 0, offsetof(Server, max_file_usec)
Journal.ForwardToSyslog, config_parse_bool, 0, offsetof(Server, forward_to_syslog)
Journal.ForwardToKMsg, config_parse_bool, 0, offsetof(Server, forward_to_kmsg)
Journal.ForwardToConsole, config_parse_bool, 0, offsetof(Server, forward_to_console)
Journal.ForwardToWall, config_parse_bool, 0, offsetof(Server, forward_to_wall)
Journal.ForwardToSocket, config_parse_forward_to_socket, 0, offsetof(Server, forward_to_socket)
Journal.TTYPath, config_parse_path, 0, offsetof(Server, tty_path)
Journal.MaxLevelStore, config_parse_log_level, 0, offsetof(Server, max_level_store)
Journal.MaxLevelSyslog, config_parse_log_level, 0, offsetof(Server, max_level_syslog)
Journal.MaxLevelKMsg, config_parse_log_level, 0, offsetof(Server, max_level_kmsg)
Journal.MaxLevelConsole, config_parse_log_level, 0, offsetof(Server, max_level_console)
Journal.MaxLevelWall, config_parse_log_level, 0, offsetof(Server, max_level_wall)
Journal.MaxLevelSocket, config_parse_log_level, 0, offsetof(Server, max_level_socket)
Journal.SplitMode, config_parse_split_mode, 0, offsetof(Server, split_mode)
Journal.LineMax, config_parse_line_max, 0, offsetof(Server, line_max)
+76
View File
@@ -18,6 +18,7 @@
#include "audit-util.h"
#include "cgroup-util.h"
#include "conf-parser.h"
#include "creds-util.h"
#include "dirent-util.h"
#include "extract-word.h"
#include "fd-util.h"
@@ -39,6 +40,7 @@
#include "journald-native.h"
#include "journald-rate-limit.h"
#include "journald-server.h"
#include "journald-socket.h"
#include "journald-stream.h"
#include "journald-syslog.h"
#include "log.h"
@@ -51,6 +53,7 @@
#include "rm-rf.h"
#include "selinux-util.h"
#include "signal-util.h"
#include "socket-netlink.h"
#include "socket-util.h"
#include "stdio-util.h"
#include "string-table.h"
@@ -1151,6 +1154,8 @@ static void server_dispatch_message_real(
else
journal_uid = 0;
server_forward_socket(s, iovec, n, priority);
server_write_to_journal(s, journal_uid, iovec, n, priority);
}
@@ -1838,6 +1843,17 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
else
s->max_level_wall = r;
} else if (proc_cmdline_key_streq(key, "systemd.journald.max_level_socket")) {
if (proc_cmdline_value_missing(key, value))
return 0;
r = log_level_from_string(value);
if (r < 0)
log_warning("Failed to parse max level socket value \"%s\". Ignoring.", value);
else
s->max_level_socket = r;
} else if (startswith(key, "systemd.journald"))
log_warning("Unknown journald kernel command line option \"%s\". Ignoring.", key);
@@ -2443,6 +2459,29 @@ static int server_setup_memory_pressure(Server *s) {
return 0;
}
static void server_load_credentials(Server *s) {
_cleanup_free_ void *data = NULL;
int r;
assert(s);
/* if we already have a forward address from config don't load the credential */
if (s->forward_to_socket.sockaddr.sa.sa_family != AF_UNSPEC) {
log_debug("Socket forward address already set not loading journal.forward_to_socket");
return;
}
r = read_credential("journal.forward_to_socket", &data, NULL);
if (r < 0) {
log_debug_errno(r, "Failed to read credential journal.forward_to_socket, ignoring: %m");
return;
}
r = socket_address_parse(&s->forward_to_socket, data);
if (r < 0)
log_debug_errno(r, "Failed to parse credential journal.forward_to_socket, ignoring: %m");
}
int server_new(Server **ret) {
_cleanup_(server_freep) Server *s = NULL;
@@ -2460,6 +2499,7 @@ int server_new(Server **ret) {
.audit_fd = -EBADF,
.hostname_fd = -EBADF,
.notify_fd = -EBADF,
.forward_socket_fd = -EBADF,
.compress.enabled = true,
.compress.threshold_bytes = UINT64_MAX,
@@ -2476,6 +2516,7 @@ int server_new(Server **ret) {
.ratelimit_burst = DEFAULT_RATE_LIMIT_BURST,
.forward_to_wall = true,
.forward_to_socket = { .sockaddr.sa.sa_family = AF_UNSPEC },
.max_file_usec = DEFAULT_MAX_FILE_USEC,
@@ -2484,6 +2525,7 @@ int server_new(Server **ret) {
.max_level_kmsg = LOG_NOTICE,
.max_level_console = LOG_INFO,
.max_level_wall = LOG_EMERG,
.max_level_socket = LOG_DEBUG,
.line_max = DEFAULT_LINE_MAX,
@@ -2524,6 +2566,8 @@ int server_init(Server *s, const char *namespace) {
server_parse_config_file(s);
server_load_credentials(s);
if (!s->namespace) {
/* Parse kernel command line, but only if we are not a namespace instance */
r = proc_cmdline_parse(parse_proc_cmdline_item, s, PROC_CMDLINE_STRIP_RD_PREFIX);
@@ -2796,6 +2840,7 @@ Server* server_free(Server *s) {
safe_close(s->audit_fd);
safe_close(s->hostname_fd);
safe_close(s->notify_fd);
safe_close(s->forward_socket_fd);
if (s->ratelimit)
journal_ratelimit_free(s->ratelimit);
@@ -2931,3 +2976,34 @@ int config_parse_compress(
return 0;
}
int config_parse_forward_to_socket(
const char* unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
SocketAddress* addr = ASSERT_PTR(data);
int r;
assert(unit);
assert(filename);
assert(rvalue);
if (isempty(rvalue))
*addr = (SocketAddress) { .sockaddr.sa.sa_family = AF_UNSPEC };
else {
r = socket_address_parse(addr, rvalue);
if (r < 0)
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse ForwardToSocket= value, ignoring: %s", rvalue);
}
return 0;
}
+5
View File
@@ -5,6 +5,7 @@
#include <sys/types.h>
#include "sd-event.h"
#include "socket-util.h"
typedef struct Server Server;
@@ -78,6 +79,7 @@ struct Server {
int audit_fd;
int hostname_fd;
int notify_fd;
int forward_socket_fd;
sd_event *event;
@@ -123,6 +125,7 @@ struct Server {
bool forward_to_syslog;
bool forward_to_console;
bool forward_to_wall;
SocketAddress forward_to_socket;
unsigned n_forward_syslog_missed;
usec_t last_warn_forward_syslog_missed;
@@ -142,6 +145,7 @@ struct Server {
int max_level_kmsg;
int max_level_console;
int max_level_wall;
int max_level_socket;
Storage storage;
SplitMode split_mode;
@@ -214,6 +218,7 @@ const struct ConfigPerfItem* journald_gperf_lookup(const char *key, GPERF_LEN_TY
CONFIG_PARSER_PROTOTYPE(config_parse_storage);
CONFIG_PARSER_PROTOTYPE(config_parse_line_max);
CONFIG_PARSER_PROTOTYPE(config_parse_compress);
CONFIG_PARSER_PROTOTYPE(config_parse_forward_to_socket);
const char *storage_to_string(Storage s) _const_;
Storage storage_from_string(const char *s) _pure_;
+162
View File
@@ -0,0 +1,162 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <string.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include "fd-util.h"
#include "iovec-util.h"
#include "journald-socket.h"
#include "log.h"
#include "macro.h"
#include "process-util.h"
#include "socket-util.h"
#include "sparse-endian.h"
void server_open_forward_socket(Server *s) {
_cleanup_close_ int socket_fd = -EBADF;
const SocketAddress *addr;
int family;
assert(s);
/* nop if there is nothing to do */
if (s->forward_to_socket.sockaddr.sa.sa_family == AF_UNSPEC || s->namespace || s->forward_socket_fd >= 0)
return;
addr = &s->forward_to_socket;
family = socket_address_family(addr);
if (!IN_SET(family, AF_UNIX, AF_INET, AF_INET6, AF_VSOCK)) {
log_debug("Unsupported socket type for forward socket: %d", family);
return;
}
socket_fd = socket(family, SOCK_STREAM|SOCK_CLOEXEC, 0);
if (socket_fd < 0) {
log_debug_errno(errno, "Failed to create forward socket, ignoring: %m");
return;
}
if (connect(socket_fd, &addr->sockaddr.sa, addr->size) < 0) {
log_debug_errno(errno, "Failed to connect to remote address for forwarding, ignoring: %m");
return;
}
s->forward_socket_fd = TAKE_FD(socket_fd);
log_debug("Successfully connected to remote address for forwarding");
}
static inline bool must_serialise(struct iovec iov) {
/* checks an iovec of the form FIELD=VALUE to see if VALUE needs binary safe serialisation:
* See https://systemd.io/JOURNAL_EXPORT_FORMATS/#journal-export-format for more information
* on binary safe serialisation for the journal export format */
assert(iov.iov_len == 0 || iov.iov_base);
const uint8_t *s = iov.iov_base;
bool before_value = true;
FOREACH_ARRAY(c, s, iov.iov_len) {
if (before_value)
before_value = *c != (uint8_t)'=';
else if (*c < (uint8_t)' ' && *c != (uint8_t)'\t')
return true;
}
return false;
}
void server_forward_socket(
Server *s,
const struct iovec *iovec,
size_t n_iovec,
int priority) {
_cleanup_free_ struct iovec *iov_alloc = NULL;
struct iovec *iov = NULL;
_cleanup_free_ le64_t *len_alloc = NULL;
le64_t *len = NULL;
assert(s);
assert(iovec);
assert(n_iovec > 0);
if (LOG_PRI(priority) > s->max_level_socket)
return;
server_open_forward_socket(s);
/* if we failed to open a socket just return */
if (s->forward_socket_fd < 0)
return;
/* we need a newline after each iovec + 4 for each we have to serialise in a binary safe way
* +1 for the final __REALTIME_TIMESTAMP metadata field */
size_t n = n_iovec * 5 + 1;
if (n < ALLOCA_MAX / (sizeof(struct iovec) + sizeof(le64_t)) / 2) {
iov = newa(struct iovec, n);
len = newa(le64_t, n_iovec);
} else {
iov_alloc = new(struct iovec, n);
if (!iov_alloc) {
log_oom();
return;
}
iov = iov_alloc;
len_alloc = new(le64_t, n_iovec);
if (!len_alloc) {
log_oom();
return;
}
len = len_alloc;
}
struct iovec nl = IOVEC_MAKE_STRING("\n");
size_t iov_idx = 0, len_idx = 0;
FOREACH_ARRAY(i, iovec, n_iovec) {
if (must_serialise(*i)) {
const uint8_t *c;
c = memchr(i->iov_base, '=', i->iov_len);
/* this should never happen */
if (_unlikely_(!c || c == i->iov_base)) {
log_error("Found invalid journal field, refusing to forward.");
return;
}
/* write the field name */
iov[iov_idx++] = IOVEC_MAKE(i->iov_base, c - (uint8_t*) i->iov_base);
iov[iov_idx++] = nl;
/* write the length of the value */
len[len_idx] = htole64(i->iov_len - (c - (uint8_t*) i->iov_base) - 1);
iov[iov_idx++] = IOVEC_MAKE(&len[len_idx++], sizeof(le64_t));
/* write the raw binary value */
iov[iov_idx++] = IOVEC_MAKE(c + 1, i->iov_len - (c - (uint8_t*) i->iov_base) - 1);
} else
/* if it doesn't need special treatment just write the value out */
iov[iov_idx++] = *i;
iov[iov_idx++] = nl;
}
/* synthesise __REALTIME_TIMESTAMP as the last argument so systemd-journal-upload can receive these export messages */
char buf[sizeof("__REALTIME_TIMESTAMP=") + DECIMAL_STR_MAX(usec_t) + 2];
xsprintf(buf, "__REALTIME_TIMESTAMP="USEC_FMT"\n\n", now(CLOCK_REALTIME));
iov[iov_idx++] = IOVEC_MAKE_STRING(buf);
if (writev(s->forward_socket_fd, iov, iov_idx) < 0) {
log_debug_errno(errno, "Failed to forward log message over socket: %m");
/* if we failed to send once we will probably fail again so wait for a new connection to
* establish before attempting to forward again */
s->forward_socket_fd = safe_close(s->forward_socket_fd);
}
}
+8
View File
@@ -0,0 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "journald-server.h"
#include "socket-util.h"
void server_forward_socket(Server *s, const struct iovec *iovec, size_t n, int priority);
void server_open_forward_socket(Server *s);
+1
View File
@@ -44,6 +44,7 @@
#MaxLevelKMsg=notice
#MaxLevelConsole=info
#MaxLevelWall=emerg
#MaxLevelSocket=debug
#LineMax=48K
#ReadKMsg=yes
#Audit=yes
+1
View File
@@ -12,6 +12,7 @@ sources = files(
'journald-stream.c',
'journald-syslog.c',
'journald-wall.c',
'journald-socket.c',
)
sources += custom_target(
+128
View File
@@ -1,8 +1,15 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <netinet/in.h>
#include <stdbool.h>
#include <string.h>
#include <sys/un.h>
#include "journald-server.h"
#include "log.h"
#include "path-util.h"
#include "socket-util.h"
#include "sparse-endian.h"
#include "tests.h"
#define _COMPRESS_PARSE_CHECK(str, enab, thresh, varname) \
@@ -47,4 +54,125 @@ TEST(config_compress) {
COMPRESS_PARSE_CHECK("", true, UINT64_MAX);
}
#define _FORWARD_TO_SOCKET_PARSE_CHECK_FAILS(str, addr, varname) \
do { \
SocketAddress varname = {}; \
config_parse_forward_to_socket("", "", 0, "", 0, "", 0, str, \
&varname, NULL); \
assert_se(socket_address_verify(&varname, true) < 0); \
} while (0)
#define FORWARD_TO_SOCKET_PARSE_CHECK_FAILS(str) \
_FORWARD_TO_SOCKET_PARSE_CHECK_FAILS(str, addr, conf##__COUNTER__)
#define _FORWARD_TO_SOCKET_PARSE_CHECK(str, addr, varname) \
do { \
SocketAddress varname = {}; \
config_parse_forward_to_socket("", "", 0, "", 0, "", 0, str, \
&varname, NULL); \
buf = mfree(buf); \
buf2 = mfree(buf2); \
socket_address_print(&varname, &buf);\
socket_address_print(&addr, &buf2);\
log_info("\"%s\" parsed as \"%s\", should be \"%s\"", str, buf, buf2); \
log_info("socket_address_verify(&addr, false) = %d", socket_address_verify(&addr, false)); \
log_info("socket_address_verify(&varname, false) = %d", socket_address_verify(&varname, false)); \
log_info("socket_address_family(&addr) = %d", socket_address_family(&addr)); \
log_info("socket_address_family(&varname) = %d", socket_address_family(&varname)); \
log_info("addr.size = %u", addr.size); \
log_info("varname.size = %u", varname.size); \
assert_se(socket_address_equal(&varname, &addr)); \
} while (0)
#define FORWARD_TO_SOCKET_PARSE_CHECK(str, addr) \
_FORWARD_TO_SOCKET_PARSE_CHECK(str, addr, conf##__COUNTER__)
TEST(config_forward_to_socket) {
SocketAddress addr;
_cleanup_free_ char *buf = NULL, *buf2 = NULL;
/* Valid AF_UNIX */
addr = (SocketAddress) {
.sockaddr.un = (struct sockaddr_un) {
.sun_family = AF_UNIX,
.sun_path = "/run/host/journal/socket",
},
.size = offsetof(struct sockaddr_un, sun_path) + strlen("/run/host/journal/socket") + 1,
};
FORWARD_TO_SOCKET_PARSE_CHECK("/run/host/journal/socket", addr);
addr.size -= 1;
memcpy(addr.sockaddr.un.sun_path, "\0run/host/journal/socket", sizeof("\0run/host/journal/socket"));
FORWARD_TO_SOCKET_PARSE_CHECK("@run/host/journal/socket", addr);
/* Valid AF_INET */
addr = (SocketAddress) {
.sockaddr.in = (struct sockaddr_in) {
.sin_family = AF_INET,
.sin_addr = { htobe32(0xC0A80001) },
.sin_port = htobe16(1234),
},
.size = sizeof(struct sockaddr_in),
};
FORWARD_TO_SOCKET_PARSE_CHECK("192.168.0.1:1234", addr);
/* Valid AF_INET6 */
addr = (SocketAddress) {
.sockaddr.in6 = (struct sockaddr_in6) {
.sin6_family = AF_INET6,
.sin6_addr = (struct in6_addr) {
.s6_addr16 = {
htobe16(0x2001),
htobe16(0xdb8),
htobe16(0x4006),
htobe16(0x812),
0, 0, 0,
htobe16(0x200e)
}
},
.sin6_port = htobe16(8080),
},
.size = sizeof(struct sockaddr_in6),
};
FORWARD_TO_SOCKET_PARSE_CHECK("[2001:db8:4006:812::200e]:8080", addr);
/* Valid AF_VSOCK */
addr = (SocketAddress) {
.sockaddr.vm = (struct sockaddr_vm) {
.svm_family = AF_VSOCK,
.svm_cid = 123456,
.svm_port = 654321,
},
.size = sizeof(struct sockaddr_vm),
};
FORWARD_TO_SOCKET_PARSE_CHECK("vsock:123456:654321", addr);
/* Invalid IPv4 */
FORWARD_TO_SOCKET_PARSE_CHECK_FAILS("256.123.45.12:1235");
FORWARD_TO_SOCKET_PARSE_CHECK_FAILS("252.123.45.12:123500");
FORWARD_TO_SOCKET_PARSE_CHECK_FAILS("252.123.45.12:0");
FORWARD_TO_SOCKET_PARSE_CHECK_FAILS("252.123.45.12:-1");
FORWARD_TO_SOCKET_PARSE_CHECK_FAILS("-1.123.45.12:22");
/* Invalid IPv6 */
FORWARD_TO_SOCKET_PARSE_CHECK_FAILS("[2001:db8:4006:812::200e]:80800");
FORWARD_TO_SOCKET_PARSE_CHECK_FAILS("[1ffff:db8:4006:812::200e]:8080");
FORWARD_TO_SOCKET_PARSE_CHECK_FAILS("[-1:db8:4006:812::200e]:8080");
FORWARD_TO_SOCKET_PARSE_CHECK_FAILS("[2001:db8:4006:812::200e]:-1");
/* Invalid UNIX */
FORWARD_TO_SOCKET_PARSE_CHECK_FAILS("a/b/c");
/* Invalid VSock */
FORWARD_TO_SOCKET_PARSE_CHECK_FAILS("vsock:4294967296:1234");
FORWARD_TO_SOCKET_PARSE_CHECK_FAILS("vsock:1234:4294967296");
FORWARD_TO_SOCKET_PARSE_CHECK_FAILS("vsock:abcd:1234");
FORWARD_TO_SOCKET_PARSE_CHECK_FAILS("vsock:1234:abcd");
FORWARD_TO_SOCKET_PARSE_CHECK_FAILS("vsock:1234");
/* Invalid Case */
FORWARD_TO_SOCKET_PARSE_CHECK_FAILS("");
FORWARD_TO_SOCKET_PARSE_CHECK_FAILS("ahh yes sockets, mmh");
}
DEFINE_TEST_MAIN(LOG_INFO);