]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/socket-label.c
tree-wide: drop missing.h
[thirdparty/systemd.git] / src / basic / socket-label.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
cc527a47 2
cc527a47 3#include <errno.h>
11c3a366
TA
4#include <netinet/in.h>
5#include <stdbool.h>
cc527a47 6#include <stddef.h>
3ffd4af2 7#include <string.h>
11c3a366 8#include <sys/socket.h>
11c3a366 9#include <sys/un.h>
3ffd4af2 10#include <unistd.h>
cc527a47 11
b5efdb8a 12#include "alloc-util.h"
3ffd4af2 13#include "fd-util.h"
294d46f1 14#include "fs-util.h"
93cc7779 15#include "log.h"
cc527a47 16#include "macro.h"
f5947a5e 17#include "missing_socket.h"
3ffd4af2 18#include "mkdir.h"
d7b8eec7
LP
19#include "selinux-util.h"
20#include "socket-util.h"
825546ef 21#include "umask-util.h"
cc527a47
KS
22
23int socket_address_listen(
24 const SocketAddress *a,
175a3d25 25 int flags,
cc527a47
KS
26 int backlog,
27 SocketAddressBindIPv6Only only,
28 const char *bind_to_device,
54255c64 29 bool reuse_port,
cc527a47
KS
30 bool free_bind,
31 bool transparent,
32 mode_t directory_mode,
33 mode_t socket_mode,
175a3d25
LP
34 const char *label) {
35
36 _cleanup_close_ int fd = -1;
294d46f1 37 const char *p;
6d5e65f6 38 int r;
cc527a47 39
cc527a47 40 assert(a);
cc527a47 41
15dca371 42 r = socket_address_verify(a, true);
175a3d25 43 if (r < 0)
cc527a47
KS
44 return r;
45
46 if (socket_address_family(a) == AF_INET6 && !socket_ipv6_is_supported())
47 return -EAFNOSUPPORT;
48
175a3d25 49 if (label) {
ecabcf8b 50 r = mac_selinux_create_socket_prepare(label);
175a3d25
LP
51 if (r < 0)
52 return r;
53 }
cc527a47 54
175a3d25 55 fd = socket(socket_address_family(a), a->type | flags, a->protocol);
cc527a47
KS
56 r = fd < 0 ? -errno : 0;
57
175a3d25 58 if (label)
ecabcf8b 59 mac_selinux_create_socket_clear();
cc527a47
KS
60
61 if (r < 0)
62 return r;
63
64 if (socket_address_family(a) == AF_INET6 && only != SOCKET_ADDRESS_DEFAULT) {
2ff48e98
LP
65 r = setsockopt_int(fd, IPPROTO_IPV6, IPV6_V6ONLY, only == SOCKET_ADDRESS_IPV6_ONLY);
66 if (r < 0)
67 return r;
cc527a47
KS
68 }
69
5ed272cf 70 if (IN_SET(socket_address_family(a), AF_INET, AF_INET6)) {
953a02d1
LP
71 if (bind_to_device) {
72 r = socket_bind_to_ifname(fd, bind_to_device);
73 if (r < 0)
74 return r;
75 }
cc527a47 76
54255c64 77 if (reuse_port) {
2ff48e98
LP
78 r = setsockopt_int(fd, SOL_SOCKET, SO_REUSEPORT, true);
79 if (r < 0)
80 log_warning_errno(r, "SO_REUSEPORT failed: %m");
54255c64
CT
81 }
82
cc527a47 83 if (free_bind) {
2ff48e98
LP
84 r = setsockopt_int(fd, IPPROTO_IP, IP_FREEBIND, true);
85 if (r < 0)
86 log_warning_errno(r, "IP_FREEBIND failed: %m");
cc527a47
KS
87 }
88
89 if (transparent) {
2ff48e98
LP
90 r = setsockopt_int(fd, IPPROTO_IP, IP_TRANSPARENT, true);
91 if (r < 0)
92 log_warning_errno(r, "IP_TRANSPARENT failed: %m");
cc527a47
KS
93 }
94 }
95
2ff48e98
LP
96 r = setsockopt_int(fd, SOL_SOCKET, SO_REUSEADDR, true);
97 if (r < 0)
98 return r;
cc527a47 99
294d46f1
LP
100 p = socket_address_get_path(a);
101 if (p) {
cc527a47 102 /* Create parents */
294d46f1 103 (void) mkdir_parents_label(p, directory_mode);
cc527a47 104
175a3d25 105 /* Enforce the right access mode for the socket */
825546ef
ZJS
106 RUN_WITH_UMASK(~socket_mode) {
107 r = mac_selinux_bind(fd, &a->sockaddr.sa, a->size);
108 if (r == -EADDRINUSE) {
109 /* Unlink and try again */
706d7c27
LP
110
111 if (unlink(p) < 0)
112 return r; /* didn't work, return original error */
113
114 r = mac_selinux_bind(fd, &a->sockaddr.sa, a->size);
115 }
116 if (r < 0)
825546ef 117 return r;
cc527a47 118 }
825546ef
ZJS
119 } else {
120 if (bind(fd, &a->sockaddr.sa, a->size) < 0)
121 return -errno;
122 }
cc527a47
KS
123
124 if (socket_address_can_accept(a))
125 if (listen(fd, backlog) < 0)
175a3d25 126 return -errno;
cc527a47 127
5b5e6dea
LP
128 /* Let's trigger an inotify event on the socket node, so that anyone waiting for this socket to be connectable
129 * gets notified */
130 if (p)
131 (void) touch(p);
132
175a3d25
LP
133 r = fd;
134 fd = -1;
cc527a47 135
cc527a47
KS
136 return r;
137}
e0aa3726 138
7b7afdfc 139int make_socket_fd(int log_level, const char* address, int type, int flags) {
e0aa3726
ZJS
140 SocketAddress a;
141 int fd, r;
142
143 r = socket_address_parse(&a, address);
e53fc357
LP
144 if (r < 0)
145 return log_error_errno(r, "Failed to parse socket address \"%s\": %m", address);
e0aa3726 146
7b7afdfc
SS
147 a.type = type;
148
149 fd = socket_address_listen(&a, type | flags, SOMAXCONN, SOCKET_ADDRESS_DEFAULT,
54255c64 150 NULL, false, false, false, 0755, 0644, NULL);
e0aa3726 151 if (fd < 0 || log_get_max_level() >= log_level) {
c8b32e11 152 _cleanup_free_ char *p = NULL;
e0aa3726
ZJS
153
154 r = socket_address_print(&a, &p);
f647962d
MS
155 if (r < 0)
156 return log_error_errno(r, "socket_address_print(): %m");
e0aa3726
ZJS
157
158 if (fd < 0)
da927ba9 159 log_error_errno(fd, "Failed to listen on %s: %m", p);
e0aa3726
ZJS
160 else
161 log_full(log_level, "Listening on %s", p);
162 }
163
164 return fd;
165}