]>
Commit | Line | Data |
---|---|---|
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 |
11 | static 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 | 36 | int 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 | 145 | int 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 | } |