1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 #include <netinet/ether.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 "string-util.h"
14 #include "socket-util.h"
16 static bool ipv6_proxy_ndp_is_needed(Link
*link
) {
19 if (link
->flags
& IFF_LOOPBACK
)
25 if (link
->network
->ipv6_proxy_ndp
>= 0)
26 return link
->network
->ipv6_proxy_ndp
;
28 if (link
->network
->n_ipv6_proxy_ndp_addresses
== 0)
34 static int ipv6_proxy_ndp_set(Link
*link
) {
40 if (!socket_ipv6_is_supported())
43 v
= ipv6_proxy_ndp_is_needed(link
);
44 p
= strjoina("/proc/sys/net/ipv6/conf/", link
->ifname
, "/proxy_ndp");
46 r
= write_string_file(p
, one_zero(v
), WRITE_STRING_FILE_VERIFY_ON_FAILURE
| WRITE_STRING_FILE_DISABLE_BUFFER
);
48 log_link_warning_errno(link
, r
, "Cannot configure proxy NDP for interface: %m");
53 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 r
= in_addr_is_null(AF_INET6
, &buffer
);
127 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
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
, void *userdata
) {
139 Link
*link
= userdata
;
144 r
= sd_netlink_message_get_errno(m
);
145 if (r
< 0 && r
!= -EEXIST
)
146 log_link_error_errno(link
, r
, "Could not add IPv6 proxy ndp address entry: %m");
151 /* send a request to the kernel to add a IPv6 Proxy entry to the neighbour table */
152 int ipv6_proxy_ndp_address_configure(Link
*link
, IPv6ProxyNDPAddress
*ipv6_proxy_ndp_address
) {
153 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
158 assert(link
->network
);
159 assert(link
->manager
);
160 assert(ipv6_proxy_ndp_address
);
162 rtnl
= link
->manager
->rtnl
;
164 /* create new netlink message */
165 r
= sd_rtnl_message_new_neigh(rtnl
, &req
, RTM_NEWNEIGH
, link
->ifindex
, AF_INET6
);
167 return rtnl_log_create_error(r
);
169 r
= sd_rtnl_message_neigh_set_flags(req
, NLM_F_REQUEST
| NTF_PROXY
);
171 return rtnl_log_create_error(r
);
173 r
= sd_netlink_message_append_in6_addr(req
, NDA_DST
, &ipv6_proxy_ndp_address
->in_addr
);
175 return rtnl_log_create_error(r
);
177 r
= sd_netlink_call_async(rtnl
, NULL
, req
, set_ipv6_proxy_ndp_address_handler
,
178 link_netlink_destroy_callback
, link
, 0, __func__
);
180 return log_link_error_errno(link
, r
, "Could not send rtnetlink message: %m");
187 /* configure all ipv6 proxy ndp addresses */
188 int ipv6_proxy_ndp_addresses_configure(Link
*link
) {
189 IPv6ProxyNDPAddress
*ipv6_proxy_ndp_address
;
194 /* enable or disable proxy_ndp itself depending on whether ipv6_proxy_ndp_addresses are set or not */
195 r
= ipv6_proxy_ndp_set(link
);
199 LIST_FOREACH(ipv6_proxy_ndp_addresses
, ipv6_proxy_ndp_address
, link
->network
->ipv6_proxy_ndp_addresses
) {
200 r
= ipv6_proxy_ndp_address_configure(link
, ipv6_proxy_ndp_address
);