]>
Commit | Line | Data |
---|---|---|
a032b68d | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
663996b3 | 2 | |
663996b3 | 3 | #include <errno.h> |
4c89c718 MP |
4 | #include <netinet/in.h> |
5 | #include <stdbool.h> | |
663996b3 | 6 | #include <stddef.h> |
db2df898 | 7 | #include <string.h> |
4c89c718 | 8 | #include <sys/un.h> |
db2df898 | 9 | #include <unistd.h> |
663996b3 | 10 | |
db2df898 MP |
11 | #include "alloc-util.h" |
12 | #include "fd-util.h" | |
1d42b86d | 13 | #include "fs-util.h" |
4c89c718 | 14 | #include "log.h" |
663996b3 | 15 | #include "macro.h" |
e1f67bc7 | 16 | #include "missing_socket.h" |
ea0999c9 | 17 | #include "mkdir-label.h" |
e735f4d4 MP |
18 | #include "selinux-util.h" |
19 | #include "socket-util.h" | |
aa27b158 | 20 | #include "umask-util.h" |
663996b3 MS |
21 | |
22 | int socket_address_listen( | |
23 | const SocketAddress *a, | |
60f067b4 | 24 | int flags, |
663996b3 MS |
25 | int backlog, |
26 | SocketAddressBindIPv6Only only, | |
27 | const char *bind_to_device, | |
fb183854 | 28 | bool reuse_port, |
663996b3 MS |
29 | bool free_bind, |
30 | bool transparent, | |
31 | mode_t directory_mode, | |
32 | mode_t socket_mode, | |
60f067b4 JS |
33 | const char *label) { |
34 | ||
35 | _cleanup_close_ int fd = -1; | |
1d42b86d | 36 | const char *p; |
6e866b33 | 37 | int r; |
663996b3 | 38 | |
663996b3 | 39 | assert(a); |
663996b3 | 40 | |
6e866b33 | 41 | r = socket_address_verify(a, true); |
60f067b4 | 42 | if (r < 0) |
663996b3 MS |
43 | return r; |
44 | ||
45 | if (socket_address_family(a) == AF_INET6 && !socket_ipv6_is_supported()) | |
46 | return -EAFNOSUPPORT; | |
47 | ||
60f067b4 | 48 | if (label) { |
5eef597e | 49 | r = mac_selinux_create_socket_prepare(label); |
60f067b4 JS |
50 | if (r < 0) |
51 | return r; | |
52 | } | |
663996b3 | 53 | |
ea0999c9 | 54 | fd = RET_NERRNO(socket(socket_address_family(a), a->type | flags, a->protocol)); |
663996b3 | 55 | |
60f067b4 | 56 | if (label) |
5eef597e | 57 | mac_selinux_create_socket_clear(); |
663996b3 | 58 | |
ea0999c9 MB |
59 | if (fd < 0) |
60 | return fd; | |
663996b3 MS |
61 | |
62 | if (socket_address_family(a) == AF_INET6 && only != SOCKET_ADDRESS_DEFAULT) { | |
6e866b33 MB |
63 | r = setsockopt_int(fd, IPPROTO_IPV6, IPV6_V6ONLY, only == SOCKET_ADDRESS_IPV6_ONLY); |
64 | if (r < 0) | |
65 | return r; | |
663996b3 MS |
66 | } |
67 | ||
f5e65279 | 68 | if (IN_SET(socket_address_family(a), AF_INET, AF_INET6)) { |
bb4f798a MB |
69 | if (bind_to_device) { |
70 | r = socket_bind_to_ifname(fd, bind_to_device); | |
71 | if (r < 0) | |
72 | return r; | |
73 | } | |
663996b3 | 74 | |
fb183854 | 75 | if (reuse_port) { |
6e866b33 MB |
76 | r = setsockopt_int(fd, SOL_SOCKET, SO_REUSEPORT, true); |
77 | if (r < 0) | |
78 | log_warning_errno(r, "SO_REUSEPORT failed: %m"); | |
fb183854 MP |
79 | } |
80 | ||
663996b3 | 81 | if (free_bind) { |
a032b68d | 82 | r = socket_set_freebind(fd, socket_address_family(a), true); |
6e866b33 | 83 | if (r < 0) |
a032b68d | 84 | log_warning_errno(r, "IP_FREEBIND/IPV6_FREEBIND failed: %m"); |
663996b3 MS |
85 | } |
86 | ||
87 | if (transparent) { | |
a032b68d | 88 | r = socket_set_transparent(fd, socket_address_family(a), true); |
6e866b33 | 89 | if (r < 0) |
a032b68d | 90 | log_warning_errno(r, "IP_TRANSPARENT/IPV6_TRANSPARENT failed: %m"); |
663996b3 MS |
91 | } |
92 | } | |
93 | ||
6e866b33 MB |
94 | r = setsockopt_int(fd, SOL_SOCKET, SO_REUSEADDR, true); |
95 | if (r < 0) | |
96 | return r; | |
663996b3 | 97 | |
1d42b86d MB |
98 | p = socket_address_get_path(a); |
99 | if (p) { | |
663996b3 | 100 | /* Create parents */ |
1d42b86d | 101 | (void) mkdir_parents_label(p, directory_mode); |
663996b3 | 102 | |
60f067b4 | 103 | /* Enforce the right access mode for the socket */ |
aa27b158 MP |
104 | RUN_WITH_UMASK(~socket_mode) { |
105 | r = mac_selinux_bind(fd, &a->sockaddr.sa, a->size); | |
106 | if (r == -EADDRINUSE) { | |
107 | /* Unlink and try again */ | |
1d42b86d MB |
108 | |
109 | if (unlink(p) < 0) | |
110 | return r; /* didn't work, return original error */ | |
111 | ||
112 | r = mac_selinux_bind(fd, &a->sockaddr.sa, a->size); | |
113 | } | |
114 | if (r < 0) | |
aa27b158 | 115 | return r; |
663996b3 | 116 | } |
aa27b158 MP |
117 | } else { |
118 | if (bind(fd, &a->sockaddr.sa, a->size) < 0) | |
119 | return -errno; | |
120 | } | |
663996b3 MS |
121 | |
122 | if (socket_address_can_accept(a)) | |
123 | if (listen(fd, backlog) < 0) | |
60f067b4 | 124 | return -errno; |
663996b3 | 125 | |
1d42b86d MB |
126 | /* Let's trigger an inotify event on the socket node, so that anyone waiting for this socket to be connectable |
127 | * gets notified */ | |
128 | if (p) | |
129 | (void) touch(p); | |
130 | ||
a032b68d | 131 | return TAKE_FD(fd); |
663996b3 | 132 | } |