Files
systemd/src/shared/socket-label.c
T
Daan De Meyer 74d392ed1b tree-wide: standardize header names across src/fundamental, src/basic and src/shared
Drop the -fundamental suffix from src/fundamental/ headers in favor of names
that match their src/basic/ or src/shared/ counterparts (e.g.
macro-fundamental.h -> macro.h, assert-fundamental.h -> assert-util.h,
cleanup-fundamental.h -> cleanup-util.h). Rename src/basic/{btrfs,label}.{c,h}
to use the -util suffix to match the existing shared/btrfs-util and
shared/label-util siblings. Rename src/shared/mkdir-label.{c,h} to mkdir.{c,h}
and src/shared/tmpfile-util-label.{c,h} to tmpfile-util.{c,h} to match the
corresponding src/basic names.

This saves us from having to come up with separate names for files that do
the same thing across tiers, and it makes it easier to move stuff between
src/fundamental, src/basic and src/shared: consumers just #include "foo.h"
and pick up whichever tier their -I path resolves to first, so call sites
don't need to be updated when an API moves between layers.

Where a higher-tier wrapper exists (e.g. src/basic/macro.h wrapping
src/fundamental/macro.h), the wrapper uses an explicit "../fundamental/foo.h"
or "../basic/foo.h" relative include for the lower-tier header. We can't use
GCC's #include_next directive for this — when the wrapper is reachable both
via same-dir-as-source lookup and via -I (e.g. -Isrc/shared) for the
directory it lives in, #include_next advances by exactly one slot in libcpp's
internal directory chain and lands on the same physical directory it was
already in, never reaching the lower-tier sibling (see make_cpp_dir() in
gcc/libcpp/files.cc:1986).

To make sure the right headers are always picked up, the include directories
are reordered so that e.g. src/shared always takes priority over src/basic and
similar for the other directories.

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 10:33:03 +09:00

162 lines
5.3 KiB
C

/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <netinet/in.h>
#include <unistd.h>
#include "errno-util.h"
#include "fd-util.h"
#include "fs-util.h"
#include "log.h"
#include "mkdir.h"
#include "parse-util.h"
#include "selinux-util.h"
#include "smack-util.h"
#include "socket-label.h"
#include "socket-util.h"
#include "string-table.h"
#include "umask-util.h"
static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
[SOCKET_ADDRESS_DEFAULT] = "default",
[SOCKET_ADDRESS_BOTH] = "both",
[SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
};
DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);
SocketAddressBindIPv6Only socket_address_bind_ipv6_only_or_bool_from_string(const char *s) {
int r;
r = parse_boolean(s);
if (r > 0)
return SOCKET_ADDRESS_IPV6_ONLY;
if (r == 0)
return SOCKET_ADDRESS_BOTH;
return socket_address_bind_ipv6_only_from_string(s);
}
int socket_address_listen(
const SocketAddress *a,
int flags,
int backlog,
SocketAddressBindIPv6Only only,
const char *bind_to_device,
bool reuse_port,
bool free_bind,
bool transparent,
mode_t directory_mode,
mode_t socket_mode,
const char *selinux_label,
const char *smack_label) {
_cleanup_close_ int fd = -EBADF;
const char *p;
int r;
assert(a);
r = socket_address_verify(a, true);
if (r < 0)
return r;
if (socket_address_family(a) == AF_INET6 && !socket_ipv6_is_supported())
return -EAFNOSUPPORT;
if (selinux_label) {
r = mac_selinux_create_socket_prepare(selinux_label);
if (r < 0)
return r;
}
fd = RET_NERRNO(socket(socket_address_family(a), a->type | flags, a->protocol));
if (selinux_label)
mac_selinux_create_socket_clear();
if (fd < 0)
return fd;
if (smack_label) {
r = mac_smack_apply_fd(fd, SMACK_ATTR_ACCESS, smack_label);
if (r < 0)
log_warning_errno(r, "Failed to apply SMACK label for socket FD, ignoring: %m");
}
if (socket_address_family(a) == AF_INET6 && only != SOCKET_ADDRESS_DEFAULT) {
r = setsockopt_int(fd, IPPROTO_IPV6, IPV6_V6ONLY, only == SOCKET_ADDRESS_IPV6_ONLY);
if (r < 0)
return r;
}
if (IN_SET(socket_address_family(a), AF_INET, AF_INET6)) {
if (bind_to_device) {
r = socket_bind_to_ifname(fd, bind_to_device);
if (r < 0)
return r;
}
if (reuse_port) {
r = setsockopt_int(fd, SOL_SOCKET, SO_REUSEPORT, true);
if (r < 0)
log_warning_errno(r, "SO_REUSEPORT failed: %m");
}
if (free_bind) {
r = socket_set_freebind(fd, socket_address_family(a), true);
if (r < 0)
log_warning_errno(r, "IP_FREEBIND/IPV6_FREEBIND failed: %m");
}
if (transparent) {
r = socket_set_transparent(fd, socket_address_family(a), true);
if (r < 0)
log_warning_errno(r, "IP_TRANSPARENT/IPV6_TRANSPARENT failed: %m");
}
}
r = setsockopt_int(fd, SOL_SOCKET, SO_REUSEADDR, true);
if (r < 0)
return r;
p = socket_address_get_path(a);
if (p) {
/* Create parents */
(void) mkdir_parents_label(p, directory_mode);
/* Enforce the right access mode for the socket */
WITH_UMASK(~socket_mode) {
r = mac_selinux_bind(fd, &a->sockaddr.sa, a->size);
if (r == -EADDRINUSE) {
/* Unlink and try again */
if (unlink(p) < 0)
return r; /* didn't work, return original error */
r = mac_selinux_bind(fd, &a->sockaddr.sa, a->size);
}
if (r < 0)
return r;
}
if (smack_label) {
r = mac_smack_apply(p, SMACK_ATTR_ACCESS, smack_label);
if (r < 0)
log_warning_errno(r, "Failed to apply SMACK label for socket path, ignoring: %m");
}
} else {
if (bind(fd, &a->sockaddr.sa, a->size) < 0)
return -errno;
}
if (socket_address_can_accept(a))
if (listen(fd, backlog) < 0)
return -errno;
/* Let's trigger an inotify event on the socket node, so that anyone waiting for this socket to be connectable
* gets notified */
if (p)
(void) touch(p);
return TAKE_FD(fd);
}