1 /* SPDX-License-Identifier: LGPL-2.1+ */
4 #include <netinet/in.h>
11 #include "alloc-util.h"
16 #include "missing_socket.h"
18 #include "selinux-util.h"
19 #include "socket-util.h"
20 #include "umask-util.h"
22 int socket_address_listen(
23 const SocketAddress
*a
,
26 SocketAddressBindIPv6Only only
,
27 const char *bind_to_device
,
31 mode_t directory_mode
,
35 _cleanup_close_
int fd
= -1;
41 r
= socket_address_verify(a
, true);
45 if (socket_address_family(a
) == AF_INET6
&& !socket_ipv6_is_supported())
49 r
= mac_selinux_create_socket_prepare(label
);
54 fd
= socket(socket_address_family(a
), a
->type
| flags
, a
->protocol
);
55 r
= fd
< 0 ? -errno
: 0;
58 mac_selinux_create_socket_clear();
63 if (socket_address_family(a
) == AF_INET6
&& only
!= SOCKET_ADDRESS_DEFAULT
) {
64 r
= setsockopt_int(fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, only
== SOCKET_ADDRESS_IPV6_ONLY
);
69 if (IN_SET(socket_address_family(a
), AF_INET
, AF_INET6
)) {
71 r
= socket_bind_to_ifname(fd
, bind_to_device
);
77 r
= setsockopt_int(fd
, SOL_SOCKET
, SO_REUSEPORT
, true);
79 log_warning_errno(r
, "SO_REUSEPORT failed: %m");
83 r
= socket_set_freebind(fd
, socket_address_family(a
), true);
85 log_warning_errno(r
, "IP_FREEBIND/IPV6_FREEBIND failed: %m");
89 r
= socket_set_transparent(fd
, socket_address_family(a
), true);
91 log_warning_errno(r
, "IP_TRANSPARENT/IPV6_TRANSPARENT failed: %m");
95 r
= setsockopt_int(fd
, SOL_SOCKET
, SO_REUSEADDR
, true);
99 p
= socket_address_get_path(a
);
102 (void) mkdir_parents_label(p
, directory_mode
);
104 /* Enforce the right access mode for the socket */
105 RUN_WITH_UMASK(~socket_mode
) {
106 r
= mac_selinux_bind(fd
, &a
->sockaddr
.sa
, a
->size
);
107 if (r
== -EADDRINUSE
) {
108 /* Unlink and try again */
111 return r
; /* didn't work, return original error */
113 r
= mac_selinux_bind(fd
, &a
->sockaddr
.sa
, a
->size
);
119 if (bind(fd
, &a
->sockaddr
.sa
, a
->size
) < 0)
123 if (socket_address_can_accept(a
))
124 if (listen(fd
, backlog
) < 0)
127 /* Let's trigger an inotify event on the socket node, so that anyone waiting for this socket to be connectable