]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
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" |
3ffd4af2 | 17 | #include "mkdir.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 | ||
35 | _cleanup_close_ int fd = -1; | |
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 | |
175a3d25 | 54 | fd = socket(socket_address_family(a), a->type | flags, a->protocol); |
cc527a47 KS |
55 | r = fd < 0 ? -errno : 0; |
56 | ||
175a3d25 | 57 | if (label) |
ecabcf8b | 58 | mac_selinux_create_socket_clear(); |
cc527a47 KS |
59 | |
60 | if (r < 0) | |
61 | return r; | |
62 | ||
63 | if (socket_address_family(a) == AF_INET6 && only != SOCKET_ADDRESS_DEFAULT) { | |
2ff48e98 LP |
64 | r = setsockopt_int(fd, IPPROTO_IPV6, IPV6_V6ONLY, only == SOCKET_ADDRESS_IPV6_ONLY); |
65 | if (r < 0) | |
66 | return r; | |
cc527a47 KS |
67 | } |
68 | ||
5ed272cf | 69 | if (IN_SET(socket_address_family(a), AF_INET, AF_INET6)) { |
953a02d1 LP |
70 | if (bind_to_device) { |
71 | r = socket_bind_to_ifname(fd, bind_to_device); | |
72 | if (r < 0) | |
73 | return r; | |
74 | } | |
cc527a47 | 75 | |
54255c64 | 76 | if (reuse_port) { |
2ff48e98 LP |
77 | r = setsockopt_int(fd, SOL_SOCKET, SO_REUSEPORT, true); |
78 | if (r < 0) | |
79 | log_warning_errno(r, "SO_REUSEPORT failed: %m"); | |
54255c64 CT |
80 | } |
81 | ||
cc527a47 | 82 | if (free_bind) { |
5d0fe423 | 83 | r = socket_set_freebind(fd, socket_address_family(a), true); |
2ff48e98 | 84 | if (r < 0) |
5d0fe423 | 85 | log_warning_errno(r, "IP_FREEBIND/IPV6_FREEBIND failed: %m"); |
cc527a47 KS |
86 | } |
87 | ||
88 | if (transparent) { | |
5d0fe423 | 89 | r = socket_set_transparent(fd, socket_address_family(a), true); |
2ff48e98 | 90 | if (r < 0) |
5d0fe423 | 91 | log_warning_errno(r, "IP_TRANSPARENT/IPV6_TRANSPARENT failed: %m"); |
cc527a47 KS |
92 | } |
93 | } | |
94 | ||
2ff48e98 LP |
95 | r = setsockopt_int(fd, SOL_SOCKET, SO_REUSEADDR, true); |
96 | if (r < 0) | |
97 | return r; | |
cc527a47 | 98 | |
294d46f1 LP |
99 | p = socket_address_get_path(a); |
100 | if (p) { | |
cc527a47 | 101 | /* Create parents */ |
294d46f1 | 102 | (void) mkdir_parents_label(p, directory_mode); |
cc527a47 | 103 | |
175a3d25 | 104 | /* Enforce the right access mode for the socket */ |
825546ef ZJS |
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 */ | |
706d7c27 LP |
109 | |
110 | if (unlink(p) < 0) | |
111 | return r; /* didn't work, return original error */ | |
112 | ||
113 | r = mac_selinux_bind(fd, &a->sockaddr.sa, a->size); | |
114 | } | |
115 | if (r < 0) | |
825546ef | 116 | return r; |
cc527a47 | 117 | } |
825546ef ZJS |
118 | } else { |
119 | if (bind(fd, &a->sockaddr.sa, a->size) < 0) | |
120 | return -errno; | |
121 | } | |
cc527a47 KS |
122 | |
123 | if (socket_address_can_accept(a)) | |
124 | if (listen(fd, backlog) < 0) | |
175a3d25 | 125 | return -errno; |
cc527a47 | 126 | |
5b5e6dea LP |
127 | /* Let's trigger an inotify event on the socket node, so that anyone waiting for this socket to be connectable |
128 | * gets notified */ | |
129 | if (p) | |
130 | (void) touch(p); | |
131 | ||
d7a0f1f4 | 132 | return TAKE_FD(fd); |
cc527a47 | 133 | } |