1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
4 #include <netinet/in.h>
11 #include "alloc-util.h"
16 #include "missing_socket.h"
17 #include "mkdir-label.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
= -EBADF
;
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
= RET_NERRNO(socket(socket_address_family(a
), a
->type
| flags
, a
->protocol
));
57 mac_selinux_create_socket_clear();
62 if (socket_address_family(a
) == AF_INET6
&& only
!= SOCKET_ADDRESS_DEFAULT
) {
63 r
= setsockopt_int(fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, only
== SOCKET_ADDRESS_IPV6_ONLY
);
68 if (IN_SET(socket_address_family(a
), AF_INET
, AF_INET6
)) {
70 r
= socket_bind_to_ifname(fd
, bind_to_device
);
76 r
= setsockopt_int(fd
, SOL_SOCKET
, SO_REUSEPORT
, true);
78 log_warning_errno(r
, "SO_REUSEPORT failed: %m");
82 r
= socket_set_freebind(fd
, socket_address_family(a
), true);
84 log_warning_errno(r
, "IP_FREEBIND/IPV6_FREEBIND failed: %m");
88 r
= socket_set_transparent(fd
, socket_address_family(a
), true);
90 log_warning_errno(r
, "IP_TRANSPARENT/IPV6_TRANSPARENT failed: %m");
94 r
= setsockopt_int(fd
, SOL_SOCKET
, SO_REUSEADDR
, true);
98 p
= socket_address_get_path(a
);
101 (void) mkdir_parents_label(p
, directory_mode
);
103 /* Enforce the right access mode for the socket */
104 WITH_UMASK(~socket_mode
) {
105 r
= mac_selinux_bind(fd
, &a
->sockaddr
.sa
, a
->size
);
106 if (r
== -EADDRINUSE
) {
107 /* Unlink and try again */
110 return r
; /* didn't work, return original error */
112 r
= mac_selinux_bind(fd
, &a
->sockaddr
.sa
, a
->size
);
118 if (bind(fd
, &a
->sockaddr
.sa
, a
->size
) < 0)
122 if (socket_address_can_accept(a
))
123 if (listen(fd
, backlog
) < 0)
126 /* Let's trigger an inotify event on the socket node, so that anyone waiting for this socket to be connectable