1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 #include <netinet/in.h>
8 #include "netlink-util.h"
9 #include "networkd-ipv6-proxy-ndp.h"
10 #include "networkd-link.h"
11 #include "networkd-manager.h"
12 #include "networkd-network.h"
13 #include "socket-util.h"
14 #include "string-util.h"
15 #include "sysctl-util.h"
17 static bool ipv6_proxy_ndp_is_needed(Link
*link
) {
20 if (link
->flags
& IFF_LOOPBACK
)
26 if (link
->network
->ipv6_proxy_ndp
>= 0)
27 return link
->network
->ipv6_proxy_ndp
;
29 if (link
->network
->n_ipv6_proxy_ndp_addresses
== 0)
35 static int ipv6_proxy_ndp_set(Link
*link
) {
41 if (!socket_ipv6_is_supported())
44 v
= ipv6_proxy_ndp_is_needed(link
);
46 r
= sysctl_write_ip_property_boolean(AF_INET6
, link
->ifname
, "proxy_ndp", v
);
48 log_link_warning_errno(link
, r
, "Cannot configure proxy NDP for interface: %m");
53 static int ipv6_proxy_ndp_address_new_static(Network
*network
, IPv6ProxyNDPAddress
**ret
) {
54 _cleanup_(ipv6_proxy_ndp_address_freep
) IPv6ProxyNDPAddress
*ipv6_proxy_ndp_address
= NULL
;
59 /* allocate space for IPv6ProxyNDPAddress entry */
60 ipv6_proxy_ndp_address
= new(IPv6ProxyNDPAddress
, 1);
61 if (!ipv6_proxy_ndp_address
)
64 *ipv6_proxy_ndp_address
= (IPv6ProxyNDPAddress
) {
68 LIST_PREPEND(ipv6_proxy_ndp_addresses
, network
->ipv6_proxy_ndp_addresses
, ipv6_proxy_ndp_address
);
69 network
->n_ipv6_proxy_ndp_addresses
++;
71 *ret
= TAKE_PTR(ipv6_proxy_ndp_address
);
76 void ipv6_proxy_ndp_address_free(IPv6ProxyNDPAddress
*ipv6_proxy_ndp_address
) {
77 if (!ipv6_proxy_ndp_address
)
80 if (ipv6_proxy_ndp_address
->network
) {
81 LIST_REMOVE(ipv6_proxy_ndp_addresses
, ipv6_proxy_ndp_address
->network
->ipv6_proxy_ndp_addresses
,
82 ipv6_proxy_ndp_address
);
84 assert(ipv6_proxy_ndp_address
->network
->n_ipv6_proxy_ndp_addresses
> 0);
85 ipv6_proxy_ndp_address
->network
->n_ipv6_proxy_ndp_addresses
--;
88 free(ipv6_proxy_ndp_address
);
91 int config_parse_ipv6_proxy_ndp_address(
96 unsigned section_line
,
103 Network
*network
= userdata
;
104 _cleanup_(ipv6_proxy_ndp_address_freep
) IPv6ProxyNDPAddress
*ipv6_proxy_ndp_address
= NULL
;
106 union in_addr_union buffer
;
114 r
= ipv6_proxy_ndp_address_new_static(network
, &ipv6_proxy_ndp_address
);
118 r
= in_addr_from_string(AF_INET6
, rvalue
, &buffer
);
120 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
121 "Failed to parse IPv6 proxy NDP address, ignoring: %s",
126 if (in_addr_is_null(AF_INET6
, &buffer
)) {
127 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
128 "IPv6 proxy NDP address cannot be the ANY address, ignoring: %s", rvalue
);
132 ipv6_proxy_ndp_address
->in_addr
= buffer
.in6
;
133 ipv6_proxy_ndp_address
= NULL
;
138 static int set_ipv6_proxy_ndp_address_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Link
*link
) {
143 r
= sd_netlink_message_get_errno(m
);
144 if (r
< 0 && r
!= -EEXIST
)
145 log_link_message_warning_errno(link
, m
, r
, "Could not add IPv6 proxy ndp address entry, ignoring");
150 /* send a request to the kernel to add a IPv6 Proxy entry to the neighbour table */
151 int ipv6_proxy_ndp_address_configure(Link
*link
, IPv6ProxyNDPAddress
*ipv6_proxy_ndp_address
) {
152 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
157 assert(link
->network
);
158 assert(link
->manager
);
159 assert(ipv6_proxy_ndp_address
);
161 rtnl
= link
->manager
->rtnl
;
163 /* create new netlink message */
164 r
= sd_rtnl_message_new_neigh(rtnl
, &req
, RTM_NEWNEIGH
, link
->ifindex
, AF_INET6
);
166 return log_link_error_errno(link
, r
, "Could not create RTM_NEWNEIGH message: %m");
168 r
= sd_rtnl_message_neigh_set_flags(req
, NLM_F_REQUEST
| NTF_PROXY
);
170 return log_link_error_errno(link
, r
, "Could not set neighbor flags: %m");
172 r
= sd_netlink_message_append_in6_addr(req
, NDA_DST
, &ipv6_proxy_ndp_address
->in_addr
);
174 return log_link_error_errno(link
, r
, "Could not append NDA_DST attribute: %m");
176 r
= netlink_call_async(rtnl
, NULL
, req
, set_ipv6_proxy_ndp_address_handler
,
177 link_netlink_destroy_callback
, link
);
179 return log_link_error_errno(link
, r
, "Could not send rtnetlink message: %m");
186 /* configure all ipv6 proxy ndp addresses */
187 int ipv6_proxy_ndp_addresses_configure(Link
*link
) {
188 IPv6ProxyNDPAddress
*ipv6_proxy_ndp_address
;
193 /* enable or disable proxy_ndp itself depending on whether ipv6_proxy_ndp_addresses are set or not */
194 r
= ipv6_proxy_ndp_set(link
);
198 LIST_FOREACH(ipv6_proxy_ndp_addresses
, ipv6_proxy_ndp_address
, link
->network
->ipv6_proxy_ndp_addresses
) {
199 r
= ipv6_proxy_ndp_address_configure(link
, ipv6_proxy_ndp_address
);