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_ERR
, filename
, line
, r
, "Failed to parse IPv6 proxy NDP address, ignoring: %s",
125 if (in_addr_is_null(AF_INET6
, &buffer
)) {
126 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
127 "IPv6 proxy NDP address cannot be the ANY address, ignoring: %s", rvalue
);
131 ipv6_proxy_ndp_address
->in_addr
= buffer
.in6
;
132 ipv6_proxy_ndp_address
= NULL
;
137 static int set_ipv6_proxy_ndp_address_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Link
*link
) {
142 r
= sd_netlink_message_get_errno(m
);
143 if (r
< 0 && r
!= -EEXIST
)
144 log_link_error_errno(link
, r
, "Could not add IPv6 proxy ndp address entry: %m");
149 /* send a request to the kernel to add a IPv6 Proxy entry to the neighbour table */
150 int ipv6_proxy_ndp_address_configure(Link
*link
, IPv6ProxyNDPAddress
*ipv6_proxy_ndp_address
) {
151 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
156 assert(link
->network
);
157 assert(link
->manager
);
158 assert(ipv6_proxy_ndp_address
);
160 rtnl
= link
->manager
->rtnl
;
162 /* create new netlink message */
163 r
= sd_rtnl_message_new_neigh(rtnl
, &req
, RTM_NEWNEIGH
, link
->ifindex
, AF_INET6
);
165 return rtnl_log_create_error(r
);
167 r
= sd_rtnl_message_neigh_set_flags(req
, NLM_F_REQUEST
| NTF_PROXY
);
169 return rtnl_log_create_error(r
);
171 r
= sd_netlink_message_append_in6_addr(req
, NDA_DST
, &ipv6_proxy_ndp_address
->in_addr
);
173 return rtnl_log_create_error(r
);
175 r
= netlink_call_async(rtnl
, NULL
, req
, set_ipv6_proxy_ndp_address_handler
,
176 link_netlink_destroy_callback
, link
);
178 return log_link_error_errno(link
, r
, "Could not send rtnetlink message: %m");
185 /* configure all ipv6 proxy ndp addresses */
186 int ipv6_proxy_ndp_addresses_configure(Link
*link
) {
187 IPv6ProxyNDPAddress
*ipv6_proxy_ndp_address
;
192 /* enable or disable proxy_ndp itself depending on whether ipv6_proxy_ndp_addresses are set or not */
193 r
= ipv6_proxy_ndp_set(link
);
197 LIST_FOREACH(ipv6_proxy_ndp_addresses
, ipv6_proxy_ndp_address
, link
->network
->ipv6_proxy_ndp_addresses
) {
198 r
= ipv6_proxy_ndp_address_configure(link
, ipv6_proxy_ndp_address
);