]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-netlink/local-addresses.c
Merge pull request #7388 from keszybz/doc-tweak
[thirdparty/systemd.git] / src / libsystemd / sd-netlink / local-addresses.c
CommitLineData
8041b5ba 1/***
cbc06dcd 2 This file is part of systemd.
8041b5ba
LP
3
4 Copyright 2008-2011 Lennart Poettering
d1ca51b1 5 Copyright 2014 Tom Gundersen
8041b5ba 6
cbc06dcd
TG
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
8041b5ba 11
cbc06dcd
TG
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
8041b5ba
LP
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
cbc06dcd
TG
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
8041b5ba
LP
19***/
20
1c4baffc 21#include "sd-netlink.h"
b5efdb8a
LP
22
23#include "alloc-util.h"
e80af1bd 24#include "local-addresses.h"
cf0fbc49
TA
25#include "macro.h"
26#include "netlink-util.h"
8041b5ba 27
5502f0d9 28static int address_compare(const void *_a, const void *_b) {
e80af1bd 29 const struct local_address *a = _a, *b = _b;
5502f0d9
LP
30
31 /* Order lowest scope first, IPv4 before IPv6, lowest interface index first */
32
e9140aff
LP
33 if (a->family == AF_INET && b->family == AF_INET6)
34 return -1;
35 if (a->family == AF_INET6 && b->family == AF_INET)
36 return 1;
37
5502f0d9
LP
38 if (a->scope < b->scope)
39 return -1;
40 if (a->scope > b->scope)
41 return 1;
42
e9140aff 43 if (a->metric < b->metric)
5502f0d9 44 return -1;
e9140aff 45 if (a->metric > b->metric)
5502f0d9
LP
46 return 1;
47
48 if (a->ifindex < b->ifindex)
49 return -1;
50 if (a->ifindex > b->ifindex)
51 return 1;
52
00d75e57 53 return memcmp(&a->address, &b->address, FAMILY_ADDRESS_SIZE(a->family));
5502f0d9
LP
54}
55
1c4baffc 56int local_addresses(sd_netlink *context, int ifindex, int af, struct local_address **ret) {
4afd3348
LP
57 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
58 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
e80af1bd 59 _cleanup_free_ struct local_address *list = NULL;
5502f0d9 60 size_t n_list = 0, n_allocated = 0;
1c4baffc 61 sd_netlink_message *m;
d1ca51b1 62 int r;
d73c3269 63
e80af1bd
LP
64 assert(ret);
65
ee8c4568 66 if (context)
1c4baffc 67 rtnl = sd_netlink_ref(context);
ee8c4568 68 else {
1c4baffc 69 r = sd_netlink_open(&rtnl);
ee8c4568
LP
70 if (r < 0)
71 return r;
72 }
8041b5ba 73
1d050e1e 74 r = sd_rtnl_message_new_addr(rtnl, &req, RTM_GETADDR, 0, af);
d1ca51b1
TG
75 if (r < 0)
76 return r;
8041b5ba 77
1c4baffc 78 r = sd_netlink_call(rtnl, req, 0, &reply);
d1ca51b1
TG
79 if (r < 0)
80 return r;
d1ca51b1 81
1c4baffc 82 for (m = reply; m; m = sd_netlink_message_next(m)) {
e80af1bd 83 struct local_address *a;
d1ca51b1 84 unsigned char flags;
5502f0d9 85 uint16_t type;
1d050e1e 86 int ifi, family;
d1ca51b1 87
1c4baffc 88 r = sd_netlink_message_get_errno(m);
d1ca51b1
TG
89 if (r < 0)
90 return r;
91
1c4baffc 92 r = sd_netlink_message_get_type(m, &type);
d1ca51b1
TG
93 if (r < 0)
94 return r;
d1ca51b1 95 if (type != RTM_NEWADDR)
8041b5ba
LP
96 continue;
97
ee8c4568
LP
98 r = sd_rtnl_message_addr_get_ifindex(m, &ifi);
99 if (r < 0)
100 return r;
1d050e1e
LP
101 if (ifindex > 0 && ifi != ifindex)
102 continue;
ee8c4568 103
1d050e1e
LP
104 r = sd_rtnl_message_addr_get_family(m, &family);
105 if (r < 0)
106 return r;
107 if (af != AF_UNSPEC && af != family)
ee8c4568
LP
108 continue;
109
5502f0d9 110 r = sd_rtnl_message_addr_get_flags(m, &flags);
d1ca51b1
TG
111 if (r < 0)
112 return r;
5502f0d9 113 if (flags & IFA_F_DEPRECATED)
d73c3269 114 continue;
8041b5ba 115
e9140aff 116 if (!GREEDY_REALLOC0(list, n_allocated, n_list+1))
5502f0d9
LP
117 return -ENOMEM;
118
119 a = list + n_list;
120
121 r = sd_rtnl_message_addr_get_scope(m, &a->scope);
d1ca51b1
TG
122 if (r < 0)
123 return r;
8041b5ba 124
945c2931 125 if (ifindex == 0 && IN_SET(a->scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE))
d73c3269 126 continue;
8041b5ba 127
1d050e1e 128 switch (family) {
5502f0d9 129
d1ca51b1 130 case AF_INET:
1c4baffc 131 r = sd_netlink_message_read_in_addr(m, IFA_LOCAL, &a->address.in);
d1ca51b1 132 if (r < 0) {
1c4baffc 133 r = sd_netlink_message_read_in_addr(m, IFA_ADDRESS, &a->address.in);
d1ca51b1
TG
134 if (r < 0)
135 continue;
136 }
137 break;
5502f0d9 138
d1ca51b1 139 case AF_INET6:
1c4baffc 140 r = sd_netlink_message_read_in6_addr(m, IFA_LOCAL, &a->address.in6);
d1ca51b1 141 if (r < 0) {
1c4baffc 142 r = sd_netlink_message_read_in6_addr(m, IFA_ADDRESS, &a->address.in6);
d1ca51b1
TG
143 if (r < 0)
144 continue;
145 }
146 break;
5502f0d9 147
d1ca51b1 148 default:
d73c3269 149 continue;
d73c3269 150 }
8041b5ba 151
ee8c4568 152 a->ifindex = ifi;
1d050e1e 153 a->family = family;
8041b5ba 154
d1ca51b1 155 n_list++;
5502f0d9 156 };
8041b5ba 157
68a9c7c4 158 qsort_safe(list, n_list, sizeof(struct local_address), address_compare);
e9140aff
LP
159
160 *ret = list;
161 list = NULL;
162
163 return (int) n_list;
164}
165
1c4baffc 166int local_gateways(sd_netlink *context, int ifindex, int af, struct local_address **ret) {
4afd3348
LP
167 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
168 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
e9140aff 169 _cleanup_free_ struct local_address *list = NULL;
1c4baffc 170 sd_netlink_message *m = NULL;
e9140aff
LP
171 size_t n_list = 0, n_allocated = 0;
172 int r;
173
174 assert(ret);
175
176 if (context)
1c4baffc 177 rtnl = sd_netlink_ref(context);
e9140aff 178 else {
1c4baffc 179 r = sd_netlink_open(&rtnl);
e9140aff
LP
180 if (r < 0)
181 return r;
182 }
183
1d050e1e 184 r = sd_rtnl_message_new_route(rtnl, &req, RTM_GETROUTE, af, RTPROT_UNSPEC);
e9140aff
LP
185 if (r < 0)
186 return r;
187
1c4baffc 188 r = sd_netlink_message_request_dump(req, true);
e9140aff
LP
189 if (r < 0)
190 return r;
191
1c4baffc 192 r = sd_netlink_call(rtnl, req, 0, &reply);
e9140aff
LP
193 if (r < 0)
194 return r;
195
1c4baffc 196 for (m = reply; m; m = sd_netlink_message_next(m)) {
e9140aff
LP
197 struct local_address *a;
198 uint16_t type;
a98433c0 199 unsigned char dst_len, src_len;
e9140aff 200 uint32_t ifi;
1d050e1e 201 int family;
e9140aff 202
1c4baffc 203 r = sd_netlink_message_get_errno(m);
e9140aff
LP
204 if (r < 0)
205 return r;
206
1c4baffc 207 r = sd_netlink_message_get_type(m, &type);
e9140aff
LP
208 if (r < 0)
209 return r;
e9140aff
LP
210 if (type != RTM_NEWROUTE)
211 continue;
212
a98433c0 213 /* We only care for default routes */
584d0d2a 214 r = sd_rtnl_message_route_get_dst_prefixlen(m, &dst_len);
e9140aff
LP
215 if (r < 0)
216 return r;
e9140aff
LP
217 if (dst_len != 0)
218 continue;
219
584d0d2a 220 r = sd_rtnl_message_route_get_src_prefixlen(m, &src_len);
a98433c0
LP
221 if (r < 0)
222 return r;
223 if (src_len != 0)
224 continue;
225
1c4baffc 226 r = sd_netlink_message_read_u32(m, RTA_OIF, &ifi);
e9140aff
LP
227 if (r < 0)
228 return r;
e9140aff
LP
229 if (ifindex > 0 && (int) ifi != ifindex)
230 continue;
231
1d050e1e
LP
232 r = sd_rtnl_message_route_get_family(m, &family);
233 if (r < 0)
234 return r;
235 if (af != AF_UNSPEC && af != family)
236 continue;
237
e9140aff
LP
238 if (!GREEDY_REALLOC0(list, n_allocated, n_list + 1))
239 return -ENOMEM;
240
241 a = list + n_list;
242
1d050e1e 243 switch (family) {
e9140aff 244 case AF_INET:
1c4baffc 245 r = sd_netlink_message_read_in_addr(m, RTA_GATEWAY, &a->address.in);
e9140aff
LP
246 if (r < 0)
247 continue;
248
249 break;
250 case AF_INET6:
1c4baffc 251 r = sd_netlink_message_read_in6_addr(m, RTA_GATEWAY, &a->address.in6);
e9140aff
LP
252 if (r < 0)
253 continue;
254
255 break;
256 default:
257 continue;
258 }
259
1c4baffc 260 sd_netlink_message_read_u32(m, RTA_PRIORITY, &a->metric);
e9140aff
LP
261
262 a->ifindex = ifi;
1d050e1e 263 a->family = family;
e9140aff 264
1d050e1e 265 n_list++;
e9140aff
LP
266 }
267
268 if (n_list > 0)
e80af1bd 269 qsort(list, n_list, sizeof(struct local_address), address_compare);
d73c3269 270
e80af1bd 271 *ret = list;
d1ca51b1 272 list = NULL;
d73c3269 273
e80af1bd 274 return (int) n_list;
8041b5ba 275}