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
);
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
= new0(IPv6ProxyNDPAddress
, 1);
61 if (!ipv6_proxy_ndp_address
)
64 ipv6_proxy_ndp_address
->network
= network
;
66 LIST_PREPEND(ipv6_proxy_ndp_addresses
, network
->ipv6_proxy_ndp_addresses
, ipv6_proxy_ndp_address
);
67 network
->n_ipv6_proxy_ndp_addresses
++;
69 *ret
= ipv6_proxy_ndp_address
;
70 ipv6_proxy_ndp_address
= NULL
;
75 void ipv6_proxy_ndp_address_free(IPv6ProxyNDPAddress
*ipv6_proxy_ndp_address
) {
76 if (!ipv6_proxy_ndp_address
)
79 if (ipv6_proxy_ndp_address
->network
) {
80 LIST_REMOVE(ipv6_proxy_ndp_addresses
, ipv6_proxy_ndp_address
->network
->ipv6_proxy_ndp_addresses
,
81 ipv6_proxy_ndp_address
);
83 assert(ipv6_proxy_ndp_address
->network
->n_ipv6_proxy_ndp_addresses
> 0);
84 ipv6_proxy_ndp_address
->network
->n_ipv6_proxy_ndp_addresses
--;
87 free(ipv6_proxy_ndp_address
);
90 int config_parse_ipv6_proxy_ndp_address(
95 unsigned section_line
,
102 Network
*network
= userdata
;
103 _cleanup_(ipv6_proxy_ndp_address_freep
) IPv6ProxyNDPAddress
*ipv6_proxy_ndp_address
= NULL
;
105 union in_addr_union buffer
;
113 r
= ipv6_proxy_ndp_address_new_static(network
, &ipv6_proxy_ndp_address
);
117 r
= in_addr_from_string(AF_INET6
, rvalue
, &buffer
);
119 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse IPv6 proxy NDP address, ignoring: %s",
124 r
= in_addr_is_null(AF_INET6
, &buffer
);
126 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
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
, void *userdata
) {
138 Link
*link
= userdata
;
143 r
= sd_netlink_message_get_errno(m
);
144 if (r
< 0 && r
!= -EEXIST
)
145 log_link_error_errno(link
, r
, "Could not add IPv6 proxy ndp address entry: %m");
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 rtnl_log_create_error(r
);
168 r
= sd_rtnl_message_neigh_set_flags(req
, NLM_F_REQUEST
| NTF_PROXY
);
170 return rtnl_log_create_error(r
);
172 r
= sd_netlink_message_append_in6_addr(req
, NDA_DST
, &ipv6_proxy_ndp_address
->in_addr
);
174 return rtnl_log_create_error(r
);
176 r
= sd_netlink_call_async(rtnl
, NULL
, req
, set_ipv6_proxy_ndp_address_handler
,
177 link_netlink_destroy_callback
, link
, 0, __func__
);
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
);