]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-netlink/local-addresses.c
tree-wide: sort includes
[thirdparty/systemd.git] / src / libsystemd / sd-netlink / 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
1c4baffc 23#include "sd-netlink.h"
b5efdb8a
LP
24
25#include "alloc-util.h"
e80af1bd 26#include "local-addresses.h"
cf0fbc49
TA
27#include "macro.h"
28#include "netlink-util.h"
8041b5ba 29
5502f0d9 30static int address_compare(const void *_a, const void *_b) {
e80af1bd 31 const struct local_address *a = _a, *b = _b;
5502f0d9
LP
32
33 /* Order lowest scope first, IPv4 before IPv6, lowest interface index first */
34
e9140aff
LP
35 if (a->family == AF_INET && b->family == AF_INET6)
36 return -1;
37 if (a->family == AF_INET6 && b->family == AF_INET)
38 return 1;
39
5502f0d9
LP
40 if (a->scope < b->scope)
41 return -1;
42 if (a->scope > b->scope)
43 return 1;
44
e9140aff 45 if (a->metric < b->metric)
5502f0d9 46 return -1;
e9140aff 47 if (a->metric > b->metric)
5502f0d9
LP
48 return 1;
49
50 if (a->ifindex < b->ifindex)
51 return -1;
52 if (a->ifindex > b->ifindex)
53 return 1;
54
00d75e57 55 return memcmp(&a->address, &b->address, FAMILY_ADDRESS_SIZE(a->family));
5502f0d9
LP
56}
57
1c4baffc
TG
58int local_addresses(sd_netlink *context, int ifindex, int af, struct local_address **ret) {
59 _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL;
60 _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
e80af1bd 61 _cleanup_free_ struct local_address *list = NULL;
5502f0d9 62 size_t n_list = 0, n_allocated = 0;
1c4baffc 63 sd_netlink_message *m;
d1ca51b1 64 int r;
d73c3269 65
e80af1bd
LP
66 assert(ret);
67
ee8c4568 68 if (context)
1c4baffc 69 rtnl = sd_netlink_ref(context);
ee8c4568 70 else {
1c4baffc 71 r = sd_netlink_open(&rtnl);
ee8c4568
LP
72 if (r < 0)
73 return r;
74 }
8041b5ba 75
1d050e1e 76 r = sd_rtnl_message_new_addr(rtnl, &req, RTM_GETADDR, 0, af);
d1ca51b1
TG
77 if (r < 0)
78 return r;
8041b5ba 79
1c4baffc 80 r = sd_netlink_call(rtnl, req, 0, &reply);
d1ca51b1
TG
81 if (r < 0)
82 return r;
d1ca51b1 83
1c4baffc 84 for (m = reply; m; m = sd_netlink_message_next(m)) {
e80af1bd 85 struct local_address *a;
d1ca51b1 86 unsigned char flags;
5502f0d9 87 uint16_t type;
1d050e1e 88 int ifi, family;
d1ca51b1 89
1c4baffc 90 r = sd_netlink_message_get_errno(m);
d1ca51b1
TG
91 if (r < 0)
92 return r;
93
1c4baffc 94 r = sd_netlink_message_get_type(m, &type);
d1ca51b1
TG
95 if (r < 0)
96 return r;
d1ca51b1 97 if (type != RTM_NEWADDR)
8041b5ba
LP
98 continue;
99
ee8c4568
LP
100 r = sd_rtnl_message_addr_get_ifindex(m, &ifi);
101 if (r < 0)
102 return r;
1d050e1e
LP
103 if (ifindex > 0 && ifi != ifindex)
104 continue;
ee8c4568 105
1d050e1e
LP
106 r = sd_rtnl_message_addr_get_family(m, &family);
107 if (r < 0)
108 return r;
109 if (af != AF_UNSPEC && af != family)
ee8c4568
LP
110 continue;
111
5502f0d9 112 r = sd_rtnl_message_addr_get_flags(m, &flags);
d1ca51b1
TG
113 if (r < 0)
114 return r;
5502f0d9 115 if (flags & IFA_F_DEPRECATED)
d73c3269 116 continue;
8041b5ba 117
e9140aff 118 if (!GREEDY_REALLOC0(list, n_allocated, n_list+1))
5502f0d9
LP
119 return -ENOMEM;
120
121 a = list + n_list;
122
123 r = sd_rtnl_message_addr_get_scope(m, &a->scope);
d1ca51b1
TG
124 if (r < 0)
125 return r;
8041b5ba 126
ee8c4568 127 if (ifindex == 0 && (a->scope == RT_SCOPE_HOST || a->scope == RT_SCOPE_NOWHERE))
d73c3269 128 continue;
8041b5ba 129
1d050e1e 130 switch (family) {
5502f0d9 131
d1ca51b1 132 case AF_INET:
1c4baffc 133 r = sd_netlink_message_read_in_addr(m, IFA_LOCAL, &a->address.in);
d1ca51b1 134 if (r < 0) {
1c4baffc 135 r = sd_netlink_message_read_in_addr(m, IFA_ADDRESS, &a->address.in);
d1ca51b1
TG
136 if (r < 0)
137 continue;
138 }
139 break;
5502f0d9 140
d1ca51b1 141 case AF_INET6:
1c4baffc 142 r = sd_netlink_message_read_in6_addr(m, IFA_LOCAL, &a->address.in6);
d1ca51b1 143 if (r < 0) {
1c4baffc 144 r = sd_netlink_message_read_in6_addr(m, IFA_ADDRESS, &a->address.in6);
d1ca51b1
TG
145 if (r < 0)
146 continue;
147 }
148 break;
5502f0d9 149
d1ca51b1 150 default:
d73c3269 151 continue;
d73c3269 152 }
8041b5ba 153
ee8c4568 154 a->ifindex = ifi;
1d050e1e 155 a->family = family;
8041b5ba 156
d1ca51b1 157 n_list++;
5502f0d9 158 };
8041b5ba 159
e9140aff
LP
160 if (n_list > 0)
161 qsort(list, n_list, sizeof(struct local_address), address_compare);
162
163 *ret = list;
164 list = NULL;
165
166 return (int) n_list;
167}
168
1c4baffc
TG
169int local_gateways(sd_netlink *context, int ifindex, int af, struct local_address **ret) {
170 _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL;
171 _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
e9140aff 172 _cleanup_free_ struct local_address *list = NULL;
1c4baffc 173 sd_netlink_message *m = NULL;
e9140aff
LP
174 size_t n_list = 0, n_allocated = 0;
175 int r;
176
177 assert(ret);
178
179 if (context)
1c4baffc 180 rtnl = sd_netlink_ref(context);
e9140aff 181 else {
1c4baffc 182 r = sd_netlink_open(&rtnl);
e9140aff
LP
183 if (r < 0)
184 return r;
185 }
186
1d050e1e 187 r = sd_rtnl_message_new_route(rtnl, &req, RTM_GETROUTE, af, RTPROT_UNSPEC);
e9140aff
LP
188 if (r < 0)
189 return r;
190
1c4baffc 191 r = sd_netlink_message_request_dump(req, true);
e9140aff
LP
192 if (r < 0)
193 return r;
194
1c4baffc 195 r = sd_netlink_call(rtnl, req, 0, &reply);
e9140aff
LP
196 if (r < 0)
197 return r;
198
1c4baffc 199 for (m = reply; m; m = sd_netlink_message_next(m)) {
e9140aff
LP
200 struct local_address *a;
201 uint16_t type;
a98433c0 202 unsigned char dst_len, src_len;
e9140aff 203 uint32_t ifi;
1d050e1e 204 int family;
e9140aff 205
1c4baffc 206 r = sd_netlink_message_get_errno(m);
e9140aff
LP
207 if (r < 0)
208 return r;
209
1c4baffc 210 r = sd_netlink_message_get_type(m, &type);
e9140aff
LP
211 if (r < 0)
212 return r;
e9140aff
LP
213 if (type != RTM_NEWROUTE)
214 continue;
215
a98433c0 216 /* We only care for default routes */
584d0d2a 217 r = sd_rtnl_message_route_get_dst_prefixlen(m, &dst_len);
e9140aff
LP
218 if (r < 0)
219 return r;
e9140aff
LP
220 if (dst_len != 0)
221 continue;
222
584d0d2a 223 r = sd_rtnl_message_route_get_src_prefixlen(m, &src_len);
a98433c0
LP
224 if (r < 0)
225 return r;
226 if (src_len != 0)
227 continue;
228
1c4baffc 229 r = sd_netlink_message_read_u32(m, RTA_OIF, &ifi);
e9140aff
LP
230 if (r < 0)
231 return r;
e9140aff
LP
232 if (ifindex > 0 && (int) ifi != ifindex)
233 continue;
234
1d050e1e
LP
235 r = sd_rtnl_message_route_get_family(m, &family);
236 if (r < 0)
237 return r;
238 if (af != AF_UNSPEC && af != family)
239 continue;
240
e9140aff
LP
241 if (!GREEDY_REALLOC0(list, n_allocated, n_list + 1))
242 return -ENOMEM;
243
244 a = list + n_list;
245
1d050e1e 246 switch (family) {
e9140aff 247 case AF_INET:
1c4baffc 248 r = sd_netlink_message_read_in_addr(m, RTA_GATEWAY, &a->address.in);
e9140aff
LP
249 if (r < 0)
250 continue;
251
252 break;
253 case AF_INET6:
1c4baffc 254 r = sd_netlink_message_read_in6_addr(m, RTA_GATEWAY, &a->address.in6);
e9140aff
LP
255 if (r < 0)
256 continue;
257
258 break;
259 default:
260 continue;
261 }
262
1c4baffc 263 sd_netlink_message_read_u32(m, RTA_PRIORITY, &a->metric);
e9140aff
LP
264
265 a->ifindex = ifi;
1d050e1e 266 a->family = family;
e9140aff 267
1d050e1e 268 n_list++;
e9140aff
LP
269 }
270
271 if (n_list > 0)
e80af1bd 272 qsort(list, n_list, sizeof(struct local_address), address_compare);
d73c3269 273
e80af1bd 274 *ret = list;
d1ca51b1 275 list = NULL;
d73c3269 276
e80af1bd 277 return (int) n_list;
8041b5ba 278}