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