]> git.proxmox.com Git - systemd.git/blame - src/libsystemd/sd-netlink/local-addresses.c
New upstream version 242
[systemd.git] / src / libsystemd / sd-netlink / local-addresses.c
CommitLineData
52ad194e 1/* SPDX-License-Identifier: LGPL-2.1+ */
663996b3 2
86f210e9 3#include "sd-netlink.h"
db2df898
MP
4
5#include "alloc-util.h"
5eef597e 6#include "local-addresses.h"
db2df898
MP
7#include "macro.h"
8#include "netlink-util.h"
bb4f798a 9#include "sort-util.h"
663996b3 10
6e866b33
MB
11static int address_compare(const struct local_address *a, const struct local_address *b) {
12 int r;
663996b3 13
5eef597e
MP
14 /* Order lowest scope first, IPv4 before IPv6, lowest interface index first */
15
f47781d8
MP
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
6e866b33
MB
21 r = CMP(a->scope, b->scope);
22 if (r != 0)
23 return r;
5eef597e 24
6e866b33
MB
25 r = CMP(a->metric, b->metric);
26 if (r != 0)
27 return r;
5eef597e 28
6e866b33
MB
29 r = CMP(a->ifindex, b->ifindex);
30 if (r != 0)
31 return r;
5eef597e 32
f47781d8 33 return memcmp(&a->address, &b->address, FAMILY_ADDRESS_SIZE(a->family));
5eef597e
MP
34}
35
86f210e9 36int local_addresses(sd_netlink *context, int ifindex, int af, struct local_address **ret) {
4c89c718
MP
37 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
38 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
5eef597e
MP
39 _cleanup_free_ struct local_address *list = NULL;
40 size_t n_list = 0, n_allocated = 0;
86f210e9 41 sd_netlink_message *m;
60f067b4 42 int r;
663996b3 43
5eef597e
MP
44 assert(ret);
45
46 if (context)
86f210e9 47 rtnl = sd_netlink_ref(context);
5eef597e 48 else {
86f210e9 49 r = sd_netlink_open(&rtnl);
5eef597e
MP
50 if (r < 0)
51 return r;
52 }
663996b3 53
f47781d8 54 r = sd_rtnl_message_new_addr(rtnl, &req, RTM_GETADDR, 0, af);
60f067b4
JS
55 if (r < 0)
56 return r;
663996b3 57
86f210e9 58 r = sd_netlink_call(rtnl, req, 0, &reply);
60f067b4
JS
59 if (r < 0)
60 return r;
60f067b4 61
86f210e9 62 for (m = reply; m; m = sd_netlink_message_next(m)) {
5eef597e 63 struct local_address *a;
60f067b4 64 unsigned char flags;
5eef597e 65 uint16_t type;
f47781d8 66 int ifi, family;
60f067b4 67
86f210e9 68 r = sd_netlink_message_get_errno(m);
60f067b4
JS
69 if (r < 0)
70 return r;
71
86f210e9 72 r = sd_netlink_message_get_type(m, &type);
60f067b4
JS
73 if (r < 0)
74 return r;
60f067b4 75 if (type != RTM_NEWADDR)
663996b3
MS
76 continue;
77
5eef597e 78 r = sd_rtnl_message_addr_get_ifindex(m, &ifi);
60f067b4
JS
79 if (r < 0)
80 return r;
f47781d8
MP
81 if (ifindex > 0 && ifi != ifindex)
82 continue;
663996b3 83
f47781d8
MP
84 r = sd_rtnl_message_addr_get_family(m, &family);
85 if (r < 0)
86 return r;
87 if (af != AF_UNSPEC && af != family)
663996b3
MS
88 continue;
89
60f067b4
JS
90 r = sd_rtnl_message_addr_get_flags(m, &flags);
91 if (r < 0)
92 return r;
60f067b4 93 if (flags & IFA_F_DEPRECATED)
663996b3
MS
94 continue;
95
f47781d8 96 if (!GREEDY_REALLOC0(list, n_allocated, n_list+1))
5eef597e
MP
97 return -ENOMEM;
98
99 a = list + n_list;
100
101 r = sd_rtnl_message_addr_get_scope(m, &a->scope);
60f067b4
JS
102 if (r < 0)
103 return r;
104
f5e65279 105 if (ifindex == 0 && IN_SET(a->scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE))
5eef597e
MP
106 continue;
107
f47781d8 108 switch (family) {
5eef597e 109
60f067b4 110 case AF_INET:
86f210e9 111 r = sd_netlink_message_read_in_addr(m, IFA_LOCAL, &a->address.in);
60f067b4 112 if (r < 0) {
86f210e9 113 r = sd_netlink_message_read_in_addr(m, IFA_ADDRESS, &a->address.in);
60f067b4
JS
114 if (r < 0)
115 continue;
116 }
117 break;
5eef597e 118
60f067b4 119 case AF_INET6:
86f210e9 120 r = sd_netlink_message_read_in6_addr(m, IFA_LOCAL, &a->address.in6);
60f067b4 121 if (r < 0) {
86f210e9 122 r = sd_netlink_message_read_in6_addr(m, IFA_ADDRESS, &a->address.in6);
60f067b4
JS
123 if (r < 0)
124 continue;
125 }
126 break;
5eef597e 127
60f067b4 128 default:
663996b3 129 continue;
663996b3 130 }
663996b3 131
5eef597e 132 a->ifindex = ifi;
f47781d8 133 a->family = family;
663996b3 134
60f067b4 135 n_list++;
5eef597e 136 };
663996b3 137
6e866b33 138 typesafe_qsort(list, n_list, address_compare);
f47781d8 139
b012e921 140 *ret = TAKE_PTR(list);
f47781d8
MP
141
142 return (int) n_list;
143}
144
86f210e9 145int local_gateways(sd_netlink *context, int ifindex, int af, struct local_address **ret) {
4c89c718
MP
146 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
147 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
f47781d8 148 _cleanup_free_ struct local_address *list = NULL;
86f210e9 149 sd_netlink_message *m = NULL;
f47781d8
MP
150 size_t n_list = 0, n_allocated = 0;
151 int r;
152
153 assert(ret);
154
155 if (context)
86f210e9 156 rtnl = sd_netlink_ref(context);
f47781d8 157 else {
86f210e9 158 r = sd_netlink_open(&rtnl);
f47781d8
MP
159 if (r < 0)
160 return r;
161 }
162
163 r = sd_rtnl_message_new_route(rtnl, &req, RTM_GETROUTE, af, RTPROT_UNSPEC);
164 if (r < 0)
165 return r;
166
86f210e9 167 r = sd_netlink_message_request_dump(req, true);
f47781d8
MP
168 if (r < 0)
169 return r;
170
86f210e9 171 r = sd_netlink_call(rtnl, req, 0, &reply);
f47781d8
MP
172 if (r < 0)
173 return r;
174
86f210e9 175 for (m = reply; m; m = sd_netlink_message_next(m)) {
f47781d8
MP
176 struct local_address *a;
177 uint16_t type;
178 unsigned char dst_len, src_len;
179 uint32_t ifi;
180 int family;
181
86f210e9 182 r = sd_netlink_message_get_errno(m);
f47781d8
MP
183 if (r < 0)
184 return r;
185
86f210e9 186 r = sd_netlink_message_get_type(m, &type);
f47781d8
MP
187 if (r < 0)
188 return r;
189 if (type != RTM_NEWROUTE)
190 continue;
191
192 /* We only care for default routes */
193 r = sd_rtnl_message_route_get_dst_prefixlen(m, &dst_len);
194 if (r < 0)
195 return r;
196 if (dst_len != 0)
197 continue;
198
199 r = sd_rtnl_message_route_get_src_prefixlen(m, &src_len);
200 if (r < 0)
201 return r;
202 if (src_len != 0)
203 continue;
204
86f210e9 205 r = sd_netlink_message_read_u32(m, RTA_OIF, &ifi);
1d42b86d
MB
206 if (r == -ENODATA) /* Not all routes have an RTA_OIF attribute (for example nexthop ones) */
207 continue;
f47781d8
MP
208 if (r < 0)
209 return r;
210 if (ifindex > 0 && (int) ifi != ifindex)
211 continue;
212
213 r = sd_rtnl_message_route_get_family(m, &family);
214 if (r < 0)
215 return r;
216 if (af != AF_UNSPEC && af != family)
217 continue;
218
219 if (!GREEDY_REALLOC0(list, n_allocated, n_list + 1))
220 return -ENOMEM;
221
222 a = list + n_list;
223
224 switch (family) {
225 case AF_INET:
86f210e9 226 r = sd_netlink_message_read_in_addr(m, RTA_GATEWAY, &a->address.in);
f47781d8
MP
227 if (r < 0)
228 continue;
229
230 break;
231 case AF_INET6:
86f210e9 232 r = sd_netlink_message_read_in6_addr(m, RTA_GATEWAY, &a->address.in6);
f47781d8
MP
233 if (r < 0)
234 continue;
235
236 break;
237 default:
238 continue;
239 }
240
86f210e9 241 sd_netlink_message_read_u32(m, RTA_PRIORITY, &a->metric);
f47781d8
MP
242
243 a->ifindex = ifi;
244 a->family = family;
245
246 n_list++;
247 }
248
6e866b33 249 typesafe_qsort(list, n_list, address_compare);
663996b3 250
b012e921 251 *ret = TAKE_PTR(list);
663996b3 252
5eef597e 253 return (int) n_list;
663996b3 254}