2 This file is part of systemd.
4 Copyright 2010 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include <netinet/in.h>
25 #include <sys/socket.h>
29 #include "alloc-util.h"
35 #include "selinux-util.h"
36 #include "socket-util.h"
37 #include "umask-util.h"
39 int socket_address_listen(
40 const SocketAddress
*a
,
43 SocketAddressBindIPv6Only only
,
44 const char *bind_to_device
,
48 mode_t directory_mode
,
52 _cleanup_close_
int fd
= -1;
57 r
= socket_address_verify(a
);
61 if (socket_address_family(a
) == AF_INET6
&& !socket_ipv6_is_supported())
65 r
= mac_selinux_create_socket_prepare(label
);
70 fd
= socket(socket_address_family(a
), a
->type
| flags
, a
->protocol
);
71 r
= fd
< 0 ? -errno
: 0;
74 mac_selinux_create_socket_clear();
79 if (socket_address_family(a
) == AF_INET6
&& only
!= SOCKET_ADDRESS_DEFAULT
) {
80 int flag
= only
== SOCKET_ADDRESS_IPV6_ONLY
;
82 if (setsockopt(fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &flag
, sizeof(flag
)) < 0)
86 if (socket_address_family(a
) == AF_INET
|| socket_address_family(a
) == AF_INET6
) {
88 if (setsockopt(fd
, SOL_SOCKET
, SO_BINDTODEVICE
, bind_to_device
, strlen(bind_to_device
)+1) < 0)
93 if (setsockopt(fd
, SOL_SOCKET
, SO_REUSEPORT
, &one
, sizeof(one
)) < 0)
94 log_warning_errno(errno
, "SO_REUSEPORT failed: %m");
99 if (setsockopt(fd
, IPPROTO_IP
, IP_FREEBIND
, &one
, sizeof(one
)) < 0)
100 log_warning_errno(errno
, "IP_FREEBIND failed: %m");
105 if (setsockopt(fd
, IPPROTO_IP
, IP_TRANSPARENT
, &one
, sizeof(one
)) < 0)
106 log_warning_errno(errno
, "IP_TRANSPARENT failed: %m");
111 if (setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof(one
)) < 0)
114 if (socket_address_family(a
) == AF_UNIX
&& a
->sockaddr
.un
.sun_path
[0] != 0) {
116 (void) mkdir_parents_label(a
->sockaddr
.un
.sun_path
, directory_mode
);
118 /* Enforce the right access mode for the socket */
119 RUN_WITH_UMASK(~socket_mode
) {
120 r
= mac_selinux_bind(fd
, &a
->sockaddr
.sa
, a
->size
);
121 if (r
== -EADDRINUSE
) {
122 /* Unlink and try again */
123 unlink(a
->sockaddr
.un
.sun_path
);
124 if (bind(fd
, &a
->sockaddr
.sa
, a
->size
) < 0)
130 if (bind(fd
, &a
->sockaddr
.sa
, a
->size
) < 0)
134 if (socket_address_can_accept(a
))
135 if (listen(fd
, backlog
) < 0)
144 int make_socket_fd(int log_level
, const char* address
, int type
, int flags
) {
148 r
= socket_address_parse(&a
, address
);
150 return log_error_errno(r
, "Failed to parse socket address \"%s\": %m", address
);
154 fd
= socket_address_listen(&a
, type
| flags
, SOMAXCONN
, SOCKET_ADDRESS_DEFAULT
,
155 NULL
, false, false, false, 0755, 0644, NULL
);
156 if (fd
< 0 || log_get_max_level() >= log_level
) {
157 _cleanup_free_
char *p
= NULL
;
159 r
= socket_address_print(&a
, &p
);
161 return log_error_errno(r
, "socket_address_print(): %m");
164 log_error_errno(fd
, "Failed to listen on %s: %m", p
);
166 log_full(log_level
, "Listening on %s", p
);