]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-rtnl/local-addresses.c
hwdb: Update database of Bluetooth company identifiers
[thirdparty/systemd.git] / src / libsystemd / sd-rtnl / local-addresses.c
CommitLineData
8041b5ba
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
cbc06dcd 4 This file is part of systemd.
8041b5ba
LP
5
6 Copyright 2008-2011 Lennart Poettering
d1ca51b1 7 Copyright 2014 Tom Gundersen
8041b5ba 8
cbc06dcd
TG
9 systemd is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
8041b5ba 13
cbc06dcd
TG
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
8041b5ba
LP
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
18
cbc06dcd
TG
19 You should have received a copy of the GNU Lesser General Public License
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
8041b5ba
LP
21***/
22
d1ca51b1
TG
23#include "sd-rtnl.h"
24#include "rtnl-util.h"
25#include "macro.h"
e80af1bd 26#include "local-addresses.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
1d050e1e 56int local_addresses(sd_rtnl *context, int ifindex, int af, struct local_address **ret) {
d1ca51b1 57 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
5502f0d9 58 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
e80af1bd 59 _cleanup_free_ struct local_address *list = NULL;
5502f0d9
LP
60 size_t n_list = 0, n_allocated = 0;
61 sd_rtnl_message *m;
d1ca51b1 62 int r;
d73c3269 63
e80af1bd
LP
64 assert(ret);
65
ee8c4568
LP
66 if (context)
67 rtnl = sd_rtnl_ref(context);
68 else {
69 r = sd_rtnl_open(&rtnl, 0);
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
d1ca51b1
TG
78 r = sd_rtnl_call(rtnl, req, 0, &reply);
79 if (r < 0)
80 return r;
d1ca51b1 81
5502f0d9 82 for (m = reply; m; m = sd_rtnl_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
TG
87
88 r = sd_rtnl_message_get_errno(m);
89 if (r < 0)
90 return r;
91
92 r = sd_rtnl_message_get_type(m, &type);
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
ee8c4568 125 if (ifindex == 0 && (a->scope == RT_SCOPE_HOST || a->scope == RT_SCOPE_NOWHERE))
d73c3269 126 continue;
8041b5ba 127
1d050e1e 128 switch (family) {
5502f0d9 129
d1ca51b1 130 case AF_INET:
5502f0d9 131 r = sd_rtnl_message_read_in_addr(m, IFA_LOCAL, &a->address.in);
d1ca51b1 132 if (r < 0) {
5502f0d9 133 r = sd_rtnl_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:
5502f0d9 140 r = sd_rtnl_message_read_in6_addr(m, IFA_LOCAL, &a->address.in6);
d1ca51b1 141 if (r < 0) {
5502f0d9 142 r = sd_rtnl_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
e9140aff
LP
158 if (n_list > 0)
159 qsort(list, n_list, sizeof(struct local_address), address_compare);
160
161 *ret = list;
162 list = NULL;
163
164 return (int) n_list;
165}
166
1d050e1e 167int local_gateways(sd_rtnl *context, int ifindex, int af, struct local_address **ret) {
e9140aff
LP
168 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
169 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
170 _cleanup_free_ struct local_address *list = NULL;
171 sd_rtnl_message *m = NULL;
172 size_t n_list = 0, n_allocated = 0;
173 int r;
174
175 assert(ret);
176
177 if (context)
178 rtnl = sd_rtnl_ref(context);
179 else {
180 r = sd_rtnl_open(&rtnl, 0);
181 if (r < 0)
182 return r;
183 }
184
1d050e1e 185 r = sd_rtnl_message_new_route(rtnl, &req, RTM_GETROUTE, af, RTPROT_UNSPEC);
e9140aff
LP
186 if (r < 0)
187 return r;
188
189 r = sd_rtnl_message_request_dump(req, true);
190 if (r < 0)
191 return r;
192
193 r = sd_rtnl_call(rtnl, req, 0, &reply);
194 if (r < 0)
195 return r;
196
197 for (m = reply; m; m = sd_rtnl_message_next(m)) {
198 struct local_address *a;
199 uint16_t type;
a98433c0 200 unsigned char dst_len, src_len;
e9140aff 201 uint32_t ifi;
1d050e1e 202 int family;
e9140aff
LP
203
204 r = sd_rtnl_message_get_errno(m);
205 if (r < 0)
206 return r;
207
208 r = sd_rtnl_message_get_type(m, &type);
209 if (r < 0)
210 return r;
e9140aff
LP
211 if (type != RTM_NEWROUTE)
212 continue;
213
a98433c0 214 /* We only care for default routes */
e9140aff
LP
215 r = sd_rtnl_message_route_get_dst_len(m, &dst_len);
216 if (r < 0)
217 return r;
e9140aff
LP
218 if (dst_len != 0)
219 continue;
220
a98433c0
LP
221 r = sd_rtnl_message_route_get_src_len(m, &src_len);
222 if (r < 0)
223 return r;
224 if (src_len != 0)
225 continue;
226
e9140aff
LP
227 r = sd_rtnl_message_read_u32(m, RTA_OIF, &ifi);
228 if (r < 0)
229 return r;
e9140aff
LP
230 if (ifindex > 0 && (int) ifi != ifindex)
231 continue;
232
1d050e1e
LP
233 r = sd_rtnl_message_route_get_family(m, &family);
234 if (r < 0)
235 return r;
236 if (af != AF_UNSPEC && af != family)
237 continue;
238
e9140aff
LP
239 if (!GREEDY_REALLOC0(list, n_allocated, n_list + 1))
240 return -ENOMEM;
241
242 a = list + n_list;
243
1d050e1e 244 switch (family) {
e9140aff
LP
245 case AF_INET:
246 r = sd_rtnl_message_read_in_addr(m, RTA_GATEWAY, &a->address.in);
247 if (r < 0)
248 continue;
249
250 break;
251 case AF_INET6:
252 r = sd_rtnl_message_read_in6_addr(m, RTA_GATEWAY, &a->address.in6);
253 if (r < 0)
254 continue;
255
256 break;
257 default:
258 continue;
259 }
260
261 sd_rtnl_message_read_u32(m, RTA_PRIORITY, &a->metric);
262
263 a->ifindex = ifi;
1d050e1e 264 a->family = family;
e9140aff 265
1d050e1e 266 n_list++;
e9140aff
LP
267 }
268
269 if (n_list > 0)
e80af1bd 270 qsort(list, n_list, sizeof(struct local_address), address_compare);
d73c3269 271
e80af1bd 272 *ret = list;
d1ca51b1 273 list = NULL;
d73c3269 274
e80af1bd 275 return (int) n_list;
8041b5ba 276}