]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-rtnl/local-addresses.c
nss-myhostname: always resolve the host name "gateway" to the local default gateway
[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
53 return 0;
54}
55
ee8c4568 56int local_addresses(sd_rtnl *context, int ifindex, 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
d1ca51b1
TG
74 r = sd_rtnl_message_new_addr(rtnl, &req, RTM_GETADDR, 0, AF_UNSPEC);
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;
ee8c4568 86 int ifi;
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;
95
96 if (type != RTM_NEWADDR)
8041b5ba
LP
97 continue;
98
ee8c4568
LP
99 r = sd_rtnl_message_addr_get_ifindex(m, &ifi);
100 if (r < 0)
101 return r;
102
103 if (ifindex != 0 && ifi != ifindex)
104 continue;
105
5502f0d9 106 r = sd_rtnl_message_addr_get_flags(m, &flags);
d1ca51b1
TG
107 if (r < 0)
108 return r;
8041b5ba 109
5502f0d9 110 if (flags & IFA_F_DEPRECATED)
d73c3269 111 continue;
8041b5ba 112
e9140aff 113 if (!GREEDY_REALLOC0(list, n_allocated, n_list+1))
5502f0d9
LP
114 return -ENOMEM;
115
116 a = list + n_list;
117
118 r = sd_rtnl_message_addr_get_scope(m, &a->scope);
d1ca51b1
TG
119 if (r < 0)
120 return r;
8041b5ba 121
ee8c4568 122 if (ifindex == 0 && (a->scope == RT_SCOPE_HOST || a->scope == RT_SCOPE_NOWHERE))
d73c3269 123 continue;
8041b5ba 124
5502f0d9 125 r = sd_rtnl_message_addr_get_family(m, &a->family);
d1ca51b1
TG
126 if (r < 0)
127 return r;
128
5502f0d9
LP
129 switch (a->family) {
130
d1ca51b1 131 case AF_INET:
5502f0d9 132 r = sd_rtnl_message_read_in_addr(m, IFA_LOCAL, &a->address.in);
d1ca51b1 133 if (r < 0) {
5502f0d9 134 r = sd_rtnl_message_read_in_addr(m, IFA_ADDRESS, &a->address.in);
d1ca51b1
TG
135 if (r < 0)
136 continue;
137 }
138 break;
5502f0d9 139
d1ca51b1 140 case AF_INET6:
5502f0d9 141 r = sd_rtnl_message_read_in6_addr(m, IFA_LOCAL, &a->address.in6);
d1ca51b1 142 if (r < 0) {
5502f0d9 143 r = sd_rtnl_message_read_in6_addr(m, IFA_ADDRESS, &a->address.in6);
d1ca51b1
TG
144 if (r < 0)
145 continue;
146 }
147 break;
5502f0d9 148
d1ca51b1 149 default:
d73c3269 150 continue;
d73c3269 151 }
8041b5ba 152
ee8c4568 153 a->ifindex = ifi;
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
167int local_gateways(sd_rtnl *context, int ifindex, struct local_address **ret) {
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
185 r = sd_rtnl_message_new_route(rtnl, &req, RTM_GETROUTE, AF_UNSPEC, RTPROT_UNSPEC);
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;
200 unsigned char dst_len;
201 uint32_t ifi;
202
203 r = sd_rtnl_message_get_errno(m);
204 if (r < 0)
205 return r;
206
207 r = sd_rtnl_message_get_type(m, &type);
208 if (r < 0)
209 return r;
210
211 if (type != RTM_NEWROUTE)
212 continue;
213
214 r = sd_rtnl_message_route_get_dst_len(m, &dst_len);
215 if (r < 0)
216 return r;
217
218 /* We only care for default routes */
219 if (dst_len != 0)
220 continue;
221
222 r = sd_rtnl_message_read_u32(m, RTA_OIF, &ifi);
223 if (r < 0)
224 return r;
225
226 if (ifindex > 0 && (int) ifi != ifindex)
227 continue;
228
229 if (!GREEDY_REALLOC0(list, n_allocated, n_list + 1))
230 return -ENOMEM;
231
232 a = list + n_list;
233
234 r = sd_rtnl_message_route_get_family(m, &a->family);
235 if (r < 0)
236 return r;
237
238 switch (a->family) {
239 case AF_INET:
240 r = sd_rtnl_message_read_in_addr(m, RTA_GATEWAY, &a->address.in);
241 if (r < 0)
242 continue;
243
244 break;
245 case AF_INET6:
246 r = sd_rtnl_message_read_in6_addr(m, RTA_GATEWAY, &a->address.in6);
247 if (r < 0)
248 continue;
249
250 break;
251 default:
252 continue;
253 }
254
255 sd_rtnl_message_read_u32(m, RTA_PRIORITY, &a->metric);
256
257 a->ifindex = ifi;
258 n_list++;
259
260 }
261
262 if (n_list > 0)
e80af1bd 263 qsort(list, n_list, sizeof(struct local_address), address_compare);
d73c3269 264
e80af1bd 265 *ret = list;
d1ca51b1 266 list = NULL;
d73c3269 267
e80af1bd 268 return (int) n_list;
8041b5ba 269}