]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/socket-label.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / basic / socket-label.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
cc527a47
KS
2/***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
cc527a47
KS
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 15 Lesser General Public License for more details.
cc527a47 16
5430f7f2 17 You should have received a copy of the GNU Lesser General Public License
cc527a47
KS
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
cc527a47 21#include <errno.h>
11c3a366
TA
22#include <netinet/in.h>
23#include <stdbool.h>
cc527a47 24#include <stddef.h>
3ffd4af2 25#include <string.h>
11c3a366 26#include <sys/socket.h>
11c3a366 27#include <sys/un.h>
3ffd4af2 28#include <unistd.h>
cc527a47 29
b5efdb8a 30#include "alloc-util.h"
3ffd4af2 31#include "fd-util.h"
93cc7779 32#include "log.h"
cc527a47 33#include "macro.h"
cc527a47 34#include "missing.h"
3ffd4af2 35#include "mkdir.h"
d7b8eec7
LP
36#include "selinux-util.h"
37#include "socket-util.h"
825546ef 38#include "umask-util.h"
cc527a47
KS
39
40int socket_address_listen(
41 const SocketAddress *a,
175a3d25 42 int flags,
cc527a47
KS
43 int backlog,
44 SocketAddressBindIPv6Only only,
45 const char *bind_to_device,
54255c64 46 bool reuse_port,
cc527a47
KS
47 bool free_bind,
48 bool transparent,
49 mode_t directory_mode,
50 mode_t socket_mode,
175a3d25
LP
51 const char *label) {
52
53 _cleanup_close_ int fd = -1;
54 int r, one;
cc527a47 55
cc527a47 56 assert(a);
cc527a47 57
175a3d25
LP
58 r = socket_address_verify(a);
59 if (r < 0)
cc527a47
KS
60 return r;
61
62 if (socket_address_family(a) == AF_INET6 && !socket_ipv6_is_supported())
63 return -EAFNOSUPPORT;
64
175a3d25 65 if (label) {
ecabcf8b 66 r = mac_selinux_create_socket_prepare(label);
175a3d25
LP
67 if (r < 0)
68 return r;
69 }
cc527a47 70
175a3d25 71 fd = socket(socket_address_family(a), a->type | flags, a->protocol);
cc527a47
KS
72 r = fd < 0 ? -errno : 0;
73
175a3d25 74 if (label)
ecabcf8b 75 mac_selinux_create_socket_clear();
cc527a47
KS
76
77 if (r < 0)
78 return r;
79
80 if (socket_address_family(a) == AF_INET6 && only != SOCKET_ADDRESS_DEFAULT) {
81 int flag = only == SOCKET_ADDRESS_IPV6_ONLY;
82
83 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag)) < 0)
175a3d25 84 return -errno;
cc527a47
KS
85 }
86
5ed272cf 87 if (IN_SET(socket_address_family(a), AF_INET, AF_INET6)) {
cc527a47
KS
88 if (bind_to_device)
89 if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, bind_to_device, strlen(bind_to_device)+1) < 0)
175a3d25 90 return -errno;
cc527a47 91
54255c64
CT
92 if (reuse_port) {
93 one = 1;
94 if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) < 0)
95 log_warning_errno(errno, "SO_REUSEPORT failed: %m");
96 }
97
cc527a47
KS
98 if (free_bind) {
99 one = 1;
100 if (setsockopt(fd, IPPROTO_IP, IP_FREEBIND, &one, sizeof(one)) < 0)
56f64d95 101 log_warning_errno(errno, "IP_FREEBIND failed: %m");
cc527a47
KS
102 }
103
104 if (transparent) {
105 one = 1;
106 if (setsockopt(fd, IPPROTO_IP, IP_TRANSPARENT, &one, sizeof(one)) < 0)
56f64d95 107 log_warning_errno(errno, "IP_TRANSPARENT failed: %m");
cc527a47
KS
108 }
109 }
110
111 one = 1;
112 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
175a3d25 113 return -errno;
cc527a47
KS
114
115 if (socket_address_family(a) == AF_UNIX && a->sockaddr.un.sun_path[0] != 0) {
cc527a47 116 /* Create parents */
825546ef 117 (void) mkdir_parents_label(a->sockaddr.un.sun_path, directory_mode);
cc527a47 118
175a3d25 119 /* Enforce the right access mode for the socket */
825546ef
ZJS
120 RUN_WITH_UMASK(~socket_mode) {
121 r = mac_selinux_bind(fd, &a->sockaddr.sa, a->size);
122 if (r == -EADDRINUSE) {
123 /* Unlink and try again */
124 unlink(a->sockaddr.un.sun_path);
125 if (bind(fd, &a->sockaddr.sa, a->size) < 0)
126 return -errno;
127 } else if (r < 0)
128 return r;
cc527a47 129 }
825546ef
ZJS
130 } else {
131 if (bind(fd, &a->sockaddr.sa, a->size) < 0)
132 return -errno;
133 }
cc527a47
KS
134
135 if (socket_address_can_accept(a))
136 if (listen(fd, backlog) < 0)
175a3d25 137 return -errno;
cc527a47 138
175a3d25
LP
139 r = fd;
140 fd = -1;
cc527a47 141
cc527a47
KS
142 return r;
143}
e0aa3726 144
7b7afdfc 145int make_socket_fd(int log_level, const char* address, int type, int flags) {
e0aa3726
ZJS
146 SocketAddress a;
147 int fd, r;
148
149 r = socket_address_parse(&a, address);
e53fc357
LP
150 if (r < 0)
151 return log_error_errno(r, "Failed to parse socket address \"%s\": %m", address);
e0aa3726 152
7b7afdfc
SS
153 a.type = type;
154
155 fd = socket_address_listen(&a, type | flags, SOMAXCONN, SOCKET_ADDRESS_DEFAULT,
54255c64 156 NULL, false, false, false, 0755, 0644, NULL);
e0aa3726 157 if (fd < 0 || log_get_max_level() >= log_level) {
c8b32e11 158 _cleanup_free_ char *p = NULL;
e0aa3726
ZJS
159
160 r = socket_address_print(&a, &p);
f647962d
MS
161 if (r < 0)
162 return log_error_errno(r, "socket_address_print(): %m");
e0aa3726
ZJS
163
164 if (fd < 0)
da927ba9 165 log_error_errno(fd, "Failed to listen on %s: %m", p);
e0aa3726
ZJS
166 else
167 log_full(log_level, "Listening on %s", p);
168 }
169
170 return fd;
171}