1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2008-2011 Lennart Poettering
6 Copyright 2014 Tom Gundersen
9 #include "sd-netlink.h"
11 #include "alloc-util.h"
12 #include "local-addresses.h"
14 #include "netlink-util.h"
16 static int address_compare(const void *_a
, const void *_b
) {
17 const struct local_address
*a
= _a
, *b
= _b
;
19 /* Order lowest scope first, IPv4 before IPv6, lowest interface index first */
21 if (a
->family
== AF_INET
&& b
->family
== AF_INET6
)
23 if (a
->family
== AF_INET6
&& b
->family
== AF_INET
)
26 if (a
->scope
< b
->scope
)
28 if (a
->scope
> b
->scope
)
31 if (a
->metric
< b
->metric
)
33 if (a
->metric
> b
->metric
)
36 if (a
->ifindex
< b
->ifindex
)
38 if (a
->ifindex
> b
->ifindex
)
41 return memcmp(&a
->address
, &b
->address
, FAMILY_ADDRESS_SIZE(a
->family
));
44 int local_addresses(sd_netlink
*context
, int ifindex
, int af
, struct local_address
**ret
) {
45 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
, *reply
= NULL
;
46 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
47 _cleanup_free_
struct local_address
*list
= NULL
;
48 size_t n_list
= 0, n_allocated
= 0;
49 sd_netlink_message
*m
;
55 rtnl
= sd_netlink_ref(context
);
57 r
= sd_netlink_open(&rtnl
);
62 r
= sd_rtnl_message_new_addr(rtnl
, &req
, RTM_GETADDR
, 0, af
);
66 r
= sd_netlink_call(rtnl
, req
, 0, &reply
);
70 for (m
= reply
; m
; m
= sd_netlink_message_next(m
)) {
71 struct local_address
*a
;
76 r
= sd_netlink_message_get_errno(m
);
80 r
= sd_netlink_message_get_type(m
, &type
);
83 if (type
!= RTM_NEWADDR
)
86 r
= sd_rtnl_message_addr_get_ifindex(m
, &ifi
);
89 if (ifindex
> 0 && ifi
!= ifindex
)
92 r
= sd_rtnl_message_addr_get_family(m
, &family
);
95 if (af
!= AF_UNSPEC
&& af
!= family
)
98 r
= sd_rtnl_message_addr_get_flags(m
, &flags
);
101 if (flags
& IFA_F_DEPRECATED
)
104 if (!GREEDY_REALLOC0(list
, n_allocated
, n_list
+1))
109 r
= sd_rtnl_message_addr_get_scope(m
, &a
->scope
);
113 if (ifindex
== 0 && IN_SET(a
->scope
, RT_SCOPE_HOST
, RT_SCOPE_NOWHERE
))
119 r
= sd_netlink_message_read_in_addr(m
, IFA_LOCAL
, &a
->address
.in
);
121 r
= sd_netlink_message_read_in_addr(m
, IFA_ADDRESS
, &a
->address
.in
);
128 r
= sd_netlink_message_read_in6_addr(m
, IFA_LOCAL
, &a
->address
.in6
);
130 r
= sd_netlink_message_read_in6_addr(m
, IFA_ADDRESS
, &a
->address
.in6
);
146 qsort_safe(list
, n_list
, sizeof(struct local_address
), address_compare
);
148 *ret
= TAKE_PTR(list
);
153 int local_gateways(sd_netlink
*context
, int ifindex
, int af
, struct local_address
**ret
) {
154 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
, *reply
= NULL
;
155 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
156 _cleanup_free_
struct local_address
*list
= NULL
;
157 sd_netlink_message
*m
= NULL
;
158 size_t n_list
= 0, n_allocated
= 0;
164 rtnl
= sd_netlink_ref(context
);
166 r
= sd_netlink_open(&rtnl
);
171 r
= sd_rtnl_message_new_route(rtnl
, &req
, RTM_GETROUTE
, af
, RTPROT_UNSPEC
);
175 r
= sd_netlink_message_request_dump(req
, true);
179 r
= sd_netlink_call(rtnl
, req
, 0, &reply
);
183 for (m
= reply
; m
; m
= sd_netlink_message_next(m
)) {
184 struct local_address
*a
;
186 unsigned char dst_len
, src_len
;
190 r
= sd_netlink_message_get_errno(m
);
194 r
= sd_netlink_message_get_type(m
, &type
);
197 if (type
!= RTM_NEWROUTE
)
200 /* We only care for default routes */
201 r
= sd_rtnl_message_route_get_dst_prefixlen(m
, &dst_len
);
207 r
= sd_rtnl_message_route_get_src_prefixlen(m
, &src_len
);
213 r
= sd_netlink_message_read_u32(m
, RTA_OIF
, &ifi
);
214 if (r
== -ENODATA
) /* Not all routes have an RTA_OIF attribute (for example nexthop ones) */
218 if (ifindex
> 0 && (int) ifi
!= ifindex
)
221 r
= sd_rtnl_message_route_get_family(m
, &family
);
224 if (af
!= AF_UNSPEC
&& af
!= family
)
227 if (!GREEDY_REALLOC0(list
, n_allocated
, n_list
+ 1))
234 r
= sd_netlink_message_read_in_addr(m
, RTA_GATEWAY
, &a
->address
.in
);
240 r
= sd_netlink_message_read_in6_addr(m
, RTA_GATEWAY
, &a
->address
.in6
);
249 sd_netlink_message_read_u32(m
, RTA_PRIORITY
, &a
->metric
);
258 qsort(list
, n_list
, sizeof(struct local_address
), address_compare
);
260 *ret
= TAKE_PTR(list
);