]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/local-addresses.c
resolved: improve log message when we use TCP a bit
[thirdparty/systemd.git] / src / shared / local-addresses.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
8041b5ba 2
1c4baffc 3#include "sd-netlink.h"
b5efdb8a
LP
4
5#include "alloc-util.h"
e80af1bd 6#include "local-addresses.h"
cf0fbc49
TA
7#include "macro.h"
8#include "netlink-util.h"
760877e9 9#include "sort-util.h"
8041b5ba 10
93bab288
YW
11static int address_compare(const struct local_address *a, const struct local_address *b) {
12 int r;
5502f0d9
LP
13
14 /* Order lowest scope first, IPv4 before IPv6, lowest interface index first */
15
e9140aff
LP
16 if (a->family == AF_INET && b->family == AF_INET6)
17 return -1;
18 if (a->family == AF_INET6 && b->family == AF_INET)
19 return 1;
20
93bab288
YW
21 r = CMP(a->scope, b->scope);
22 if (r != 0)
23 return r;
5502f0d9 24
93bab288
YW
25 r = CMP(a->metric, b->metric);
26 if (r != 0)
27 return r;
5502f0d9 28
93bab288
YW
29 r = CMP(a->ifindex, b->ifindex);
30 if (r != 0)
31 return r;
5502f0d9 32
00d75e57 33 return memcmp(&a->address, &b->address, FAMILY_ADDRESS_SIZE(a->family));
5502f0d9
LP
34}
35
1c4baffc 36int local_addresses(sd_netlink *context, int ifindex, int af, struct local_address **ret) {
4afd3348
LP
37 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
38 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
e80af1bd 39 _cleanup_free_ struct local_address *list = NULL;
5502f0d9 40 size_t n_list = 0, n_allocated = 0;
1c4baffc 41 sd_netlink_message *m;
d1ca51b1 42 int r;
d73c3269 43
e80af1bd
LP
44 assert(ret);
45
ee8c4568 46 if (context)
1c4baffc 47 rtnl = sd_netlink_ref(context);
ee8c4568 48 else {
1c4baffc 49 r = sd_netlink_open(&rtnl);
ee8c4568
LP
50 if (r < 0)
51 return r;
52 }
8041b5ba 53
1d050e1e 54 r = sd_rtnl_message_new_addr(rtnl, &req, RTM_GETADDR, 0, af);
d1ca51b1
TG
55 if (r < 0)
56 return r;
8041b5ba 57
1c4baffc 58 r = sd_netlink_call(rtnl, req, 0, &reply);
d1ca51b1
TG
59 if (r < 0)
60 return r;
d1ca51b1 61
1c4baffc 62 for (m = reply; m; m = sd_netlink_message_next(m)) {
e80af1bd 63 struct local_address *a;
d1ca51b1 64 unsigned char flags;
5502f0d9 65 uint16_t type;
1d050e1e 66 int ifi, family;
d1ca51b1 67
1c4baffc 68 r = sd_netlink_message_get_errno(m);
d1ca51b1
TG
69 if (r < 0)
70 return r;
71
1c4baffc 72 r = sd_netlink_message_get_type(m, &type);
d1ca51b1
TG
73 if (r < 0)
74 return r;
d1ca51b1 75 if (type != RTM_NEWADDR)
8041b5ba
LP
76 continue;
77
ee8c4568
LP
78 r = sd_rtnl_message_addr_get_ifindex(m, &ifi);
79 if (r < 0)
80 return r;
1d050e1e
LP
81 if (ifindex > 0 && ifi != ifindex)
82 continue;
ee8c4568 83
1d050e1e
LP
84 r = sd_rtnl_message_addr_get_family(m, &family);
85 if (r < 0)
86 return r;
87 if (af != AF_UNSPEC && af != family)
ee8c4568
LP
88 continue;
89
5502f0d9 90 r = sd_rtnl_message_addr_get_flags(m, &flags);
d1ca51b1
TG
91 if (r < 0)
92 return r;
5502f0d9 93 if (flags & IFA_F_DEPRECATED)
d73c3269 94 continue;
8041b5ba 95
e9140aff 96 if (!GREEDY_REALLOC0(list, n_allocated, n_list+1))
5502f0d9
LP
97 return -ENOMEM;
98
99 a = list + n_list;
100
101 r = sd_rtnl_message_addr_get_scope(m, &a->scope);
d1ca51b1
TG
102 if (r < 0)
103 return r;
8041b5ba 104
945c2931 105 if (ifindex == 0 && IN_SET(a->scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE))
d73c3269 106 continue;
8041b5ba 107
1d050e1e 108 switch (family) {
5502f0d9 109
d1ca51b1 110 case AF_INET:
1c4baffc 111 r = sd_netlink_message_read_in_addr(m, IFA_LOCAL, &a->address.in);
d1ca51b1 112 if (r < 0) {
1c4baffc 113 r = sd_netlink_message_read_in_addr(m, IFA_ADDRESS, &a->address.in);
d1ca51b1
TG
114 if (r < 0)
115 continue;
116 }
117 break;
5502f0d9 118
d1ca51b1 119 case AF_INET6:
1c4baffc 120 r = sd_netlink_message_read_in6_addr(m, IFA_LOCAL, &a->address.in6);
d1ca51b1 121 if (r < 0) {
1c4baffc 122 r = sd_netlink_message_read_in6_addr(m, IFA_ADDRESS, &a->address.in6);
d1ca51b1
TG
123 if (r < 0)
124 continue;
125 }
126 break;
5502f0d9 127
d1ca51b1 128 default:
d73c3269 129 continue;
d73c3269 130 }
8041b5ba 131
ee8c4568 132 a->ifindex = ifi;
1d050e1e 133 a->family = family;
8041b5ba 134
d1ca51b1 135 n_list++;
5502f0d9 136 };
8041b5ba 137
93bab288 138 typesafe_qsort(list, n_list, address_compare);
e9140aff 139
1cc6c93a 140 *ret = TAKE_PTR(list);
e9140aff
LP
141
142 return (int) n_list;
143}
144
bff94a84
YW
145static int add_local_gateway(
146 struct local_address **list,
147 size_t *n_list,
148 size_t *n_allocated,
149 int af,
150 int ifindex,
151 uint32_t metric,
152 const RouteVia *via) {
153
154 assert(list);
155 assert(n_list);
156 assert(n_allocated);
157 assert(via);
158
159 if (af != AF_UNSPEC && af != via->family)
160 return 0;
161
162 if (!GREEDY_REALLOC(*list, *n_allocated, *n_list + 1))
163 return -ENOMEM;
164
165 (*list)[(*n_list)++] = (struct local_address) {
166 .ifindex = ifindex,
167 .metric = metric,
168 .family = via->family,
169 .address = via->address,
170 };
171
172 return 0;
173}
174
1c4baffc 175int local_gateways(sd_netlink *context, int ifindex, int af, struct local_address **ret) {
4afd3348
LP
176 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
177 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
e9140aff 178 _cleanup_free_ struct local_address *list = NULL;
e9140aff
LP
179 size_t n_list = 0, n_allocated = 0;
180 int r;
181
182 assert(ret);
183
184 if (context)
1c4baffc 185 rtnl = sd_netlink_ref(context);
e9140aff 186 else {
1c4baffc 187 r = sd_netlink_open(&rtnl);
e9140aff
LP
188 if (r < 0)
189 return r;
190 }
191
1d050e1e 192 r = sd_rtnl_message_new_route(rtnl, &req, RTM_GETROUTE, af, RTPROT_UNSPEC);
e9140aff
LP
193 if (r < 0)
194 return r;
195
1c4baffc 196 r = sd_netlink_message_request_dump(req, true);
e9140aff
LP
197 if (r < 0)
198 return r;
199
1c4baffc 200 r = sd_netlink_call(rtnl, req, 0, &reply);
e9140aff
LP
201 if (r < 0)
202 return r;
203
bff94a84
YW
204 for (sd_netlink_message *m = reply; m; m = sd_netlink_message_next(m)) {
205 _cleanup_ordered_set_free_free_ OrderedSet *multipath_routes = NULL;
206 _cleanup_free_ void *rta_multipath = NULL;
207 union in_addr_union gateway;
e9140aff 208 uint16_t type;
d1b014df 209 unsigned char dst_len, src_len, table;
bff94a84
YW
210 uint32_t ifi, metric = 0;
211 size_t rta_len;
1d050e1e 212 int family;
bff94a84 213 RouteVia via;
e9140aff 214
1c4baffc 215 r = sd_netlink_message_get_errno(m);
e9140aff
LP
216 if (r < 0)
217 return r;
218
1c4baffc 219 r = sd_netlink_message_get_type(m, &type);
e9140aff
LP
220 if (r < 0)
221 return r;
e9140aff
LP
222 if (type != RTM_NEWROUTE)
223 continue;
224
a98433c0 225 /* We only care for default routes */
584d0d2a 226 r = sd_rtnl_message_route_get_dst_prefixlen(m, &dst_len);
e9140aff
LP
227 if (r < 0)
228 return r;
e9140aff
LP
229 if (dst_len != 0)
230 continue;
231
584d0d2a 232 r = sd_rtnl_message_route_get_src_prefixlen(m, &src_len);
a98433c0
LP
233 if (r < 0)
234 return r;
235 if (src_len != 0)
236 continue;
237
d1b014df
LP
238 r = sd_rtnl_message_route_get_table(m, &table);
239 if (r < 0)
240 return r;
241 if (table != RT_TABLE_MAIN)
242 continue;
243
bff94a84
YW
244 r = sd_netlink_message_read_u32(m, RTA_PRIORITY, &metric);
245 if (r < 0 && r != -ENODATA)
e9140aff 246 return r;
e9140aff 247
1d050e1e
LP
248 r = sd_rtnl_message_route_get_family(m, &family);
249 if (r < 0)
250 return r;
bff94a84 251 if (!IN_SET(family, AF_INET, AF_INET6))
1d050e1e
LP
252 continue;
253
bff94a84
YW
254 r = sd_netlink_message_read_u32(m, RTA_OIF, &ifi);
255 if (r < 0 && r != -ENODATA)
256 return r;
257 if (r >= 0) {
258 if (ifi <= 0)
259 return -EINVAL;
260 if (ifindex > 0 && (int) ifi != ifindex)
261 continue;
e9140aff 262
bff94a84
YW
263 r = netlink_message_read_in_addr_union(m, RTA_GATEWAY, family, &gateway);
264 if (r < 0 && r != -ENODATA)
265 return r;
266 if (r >= 0) {
267 via.family = family;
268 via.address = gateway;
269 r = add_local_gateway(&list, &n_list, &n_allocated, af, ifi, metric, &via);
270 if (r < 0)
271 return r;
e9140aff 272
e9140aff 273 continue;
bff94a84 274 }
e9140aff 275
bff94a84 276 if (family != AF_INET)
e9140aff
LP
277 continue;
278
bff94a84
YW
279 r = sd_netlink_message_read(m, RTA_VIA, sizeof(via), &via);
280 if (r < 0 && r != -ENODATA)
281 return r;
282 if (r >= 0) {
283 r = add_local_gateway(&list, &n_list, &n_allocated, af, ifi, metric, &via);
284 if (r < 0)
285 return r;
286
287 continue;
288 }
e9140aff
LP
289 }
290
bff94a84
YW
291 r = sd_netlink_message_read_data(m, RTA_MULTIPATH, &rta_len, &rta_multipath);
292 if (r < 0 && r != -ENODATA)
293 return r;
294 if (r >= 0) {
295 MultipathRoute *mr;
e9140aff 296
bff94a84
YW
297 r = rtattr_read_nexthop(rta_multipath, rta_len, family, &multipath_routes);
298 if (r < 0)
299 return r;
e9140aff 300
bff94a84
YW
301 ORDERED_SET_FOREACH(mr, multipath_routes) {
302 if (ifindex > 0 && mr->ifindex != ifindex)
303 continue;
304
305 r = add_local_gateway(&list, &n_list, &n_allocated, af, ifi, metric, &mr->gateway);
306 if (r < 0)
307 return r;
308 }
309 }
e9140aff
LP
310 }
311
93bab288 312 typesafe_qsort(list, n_list, address_compare);
d73c3269 313
1cc6c93a 314 *ret = TAKE_PTR(list);
d73c3269 315
e80af1bd 316 return (int) n_list;
8041b5ba 317}