]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
cc527a47 | 2 | |
cc527a47 | 3 | #include <errno.h> |
11c3a366 TA |
4 | #include <netinet/in.h> |
5 | #include <stdbool.h> | |
cc527a47 | 6 | #include <stddef.h> |
3ffd4af2 | 7 | #include <string.h> |
11c3a366 | 8 | #include <sys/un.h> |
3ffd4af2 | 9 | #include <unistd.h> |
cc527a47 | 10 | |
b5efdb8a | 11 | #include "alloc-util.h" |
3ffd4af2 | 12 | #include "fd-util.h" |
294d46f1 | 13 | #include "fs-util.h" |
93cc7779 | 14 | #include "log.h" |
cc527a47 | 15 | #include "macro.h" |
f5947a5e | 16 | #include "missing_socket.h" |
35cd0ba5 | 17 | #include "mkdir-label.h" |
d7b8eec7 LP |
18 | #include "selinux-util.h" |
19 | #include "socket-util.h" | |
825546ef | 20 | #include "umask-util.h" |
cc527a47 KS |
21 | |
22 | int socket_address_listen( | |
23 | const SocketAddress *a, | |
175a3d25 | 24 | int flags, |
cc527a47 KS |
25 | int backlog, |
26 | SocketAddressBindIPv6Only only, | |
27 | const char *bind_to_device, | |
54255c64 | 28 | bool reuse_port, |
cc527a47 KS |
29 | bool free_bind, |
30 | bool transparent, | |
31 | mode_t directory_mode, | |
32 | mode_t socket_mode, | |
175a3d25 LP |
33 | const char *label) { |
34 | ||
254d1313 | 35 | _cleanup_close_ int fd = -EBADF; |
294d46f1 | 36 | const char *p; |
6d5e65f6 | 37 | int r; |
cc527a47 | 38 | |
cc527a47 | 39 | assert(a); |
cc527a47 | 40 | |
15dca371 | 41 | r = socket_address_verify(a, true); |
175a3d25 | 42 | if (r < 0) |
cc527a47 KS |
43 | return r; |
44 | ||
45 | if (socket_address_family(a) == AF_INET6 && !socket_ipv6_is_supported()) | |
46 | return -EAFNOSUPPORT; | |
47 | ||
175a3d25 | 48 | if (label) { |
ecabcf8b | 49 | r = mac_selinux_create_socket_prepare(label); |
175a3d25 LP |
50 | if (r < 0) |
51 | return r; | |
52 | } | |
cc527a47 | 53 | |
7c248223 | 54 | fd = RET_NERRNO(socket(socket_address_family(a), a->type | flags, a->protocol)); |
cc527a47 | 55 | |
175a3d25 | 56 | if (label) |
ecabcf8b | 57 | mac_selinux_create_socket_clear(); |
cc527a47 | 58 | |
7c248223 LP |
59 | if (fd < 0) |
60 | return fd; | |
cc527a47 KS |
61 | |
62 | if (socket_address_family(a) == AF_INET6 && only != SOCKET_ADDRESS_DEFAULT) { | |
2ff48e98 LP |
63 | r = setsockopt_int(fd, IPPROTO_IPV6, IPV6_V6ONLY, only == SOCKET_ADDRESS_IPV6_ONLY); |
64 | if (r < 0) | |
65 | return r; | |
cc527a47 KS |
66 | } |
67 | ||
5ed272cf | 68 | if (IN_SET(socket_address_family(a), AF_INET, AF_INET6)) { |
953a02d1 LP |
69 | if (bind_to_device) { |
70 | r = socket_bind_to_ifname(fd, bind_to_device); | |
71 | if (r < 0) | |
72 | return r; | |
73 | } | |
cc527a47 | 74 | |
54255c64 | 75 | if (reuse_port) { |
2ff48e98 LP |
76 | r = setsockopt_int(fd, SOL_SOCKET, SO_REUSEPORT, true); |
77 | if (r < 0) | |
78 | log_warning_errno(r, "SO_REUSEPORT failed: %m"); | |
54255c64 CT |
79 | } |
80 | ||
cc527a47 | 81 | if (free_bind) { |
5d0fe423 | 82 | r = socket_set_freebind(fd, socket_address_family(a), true); |
2ff48e98 | 83 | if (r < 0) |
5d0fe423 | 84 | log_warning_errno(r, "IP_FREEBIND/IPV6_FREEBIND failed: %m"); |
cc527a47 KS |
85 | } |
86 | ||
87 | if (transparent) { | |
5d0fe423 | 88 | r = socket_set_transparent(fd, socket_address_family(a), true); |
2ff48e98 | 89 | if (r < 0) |
5d0fe423 | 90 | log_warning_errno(r, "IP_TRANSPARENT/IPV6_TRANSPARENT failed: %m"); |
cc527a47 KS |
91 | } |
92 | } | |
93 | ||
2ff48e98 LP |
94 | r = setsockopt_int(fd, SOL_SOCKET, SO_REUSEADDR, true); |
95 | if (r < 0) | |
96 | return r; | |
cc527a47 | 97 | |
294d46f1 LP |
98 | p = socket_address_get_path(a); |
99 | if (p) { | |
cc527a47 | 100 | /* Create parents */ |
294d46f1 | 101 | (void) mkdir_parents_label(p, directory_mode); |
cc527a47 | 102 | |
175a3d25 | 103 | /* Enforce the right access mode for the socket */ |
2053593f | 104 | WITH_UMASK(~socket_mode) { |
825546ef ZJS |
105 | r = mac_selinux_bind(fd, &a->sockaddr.sa, a->size); |
106 | if (r == -EADDRINUSE) { | |
107 | /* Unlink and try again */ | |
706d7c27 LP |
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) | |
825546ef | 115 | return r; |
cc527a47 | 116 | } |
825546ef ZJS |
117 | } else { |
118 | if (bind(fd, &a->sockaddr.sa, a->size) < 0) | |
119 | return -errno; | |
120 | } | |
cc527a47 KS |
121 | |
122 | if (socket_address_can_accept(a)) | |
123 | if (listen(fd, backlog) < 0) | |
175a3d25 | 124 | return -errno; |
cc527a47 | 125 | |
5b5e6dea LP |
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 | ||
d7a0f1f4 | 131 | return TAKE_FD(fd); |
cc527a47 | 132 | } |