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