1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2017 Florian Klink <flokli@flokli.de>
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include <netinet/ether.h>
26 #include "netlink-util.h"
27 #include "networkd-ipv6-proxy-ndp.h"
28 #include "networkd-link.h"
29 #include "networkd-manager.h"
30 #include "networkd-network.h"
31 #include "string-util.h"
32 #include "socket-util.h"
34 static bool ipv6_proxy_ndp_is_needed(Link
*link
) {
37 if (link
->flags
& IFF_LOOPBACK
)
43 if (link
->network
->ipv6_proxy_ndp
>= 0)
44 return link
->network
->ipv6_proxy_ndp
;
46 if (link
->network
->n_ipv6_proxy_ndp_addresses
== 0)
52 static int ipv6_proxy_ndp_set(Link
*link
) {
58 if (!socket_ipv6_is_supported())
61 v
= ipv6_proxy_ndp_is_needed(link
);
62 p
= strjoina("/proc/sys/net/ipv6/conf/", link
->ifname
, "/proxy_ndp");
64 r
= write_string_file(p
, one_zero(v
), WRITE_STRING_FILE_VERIFY_ON_FAILURE
);
66 log_link_warning_errno(link
, r
, "Cannot configure proxy NDP for interface: %m");
71 int ipv6_proxy_ndp_address_new_static(Network
*network
, IPv6ProxyNDPAddress
**ret
) {
72 _cleanup_(ipv6_proxy_ndp_address_freep
) IPv6ProxyNDPAddress
*ipv6_proxy_ndp_address
= NULL
;
77 /* allocate space for IPv6ProxyNDPAddress entry */
78 ipv6_proxy_ndp_address
= new0(IPv6ProxyNDPAddress
, 1);
79 if (!ipv6_proxy_ndp_address
)
82 ipv6_proxy_ndp_address
->network
= network
;
84 LIST_PREPEND(ipv6_proxy_ndp_addresses
, network
->ipv6_proxy_ndp_addresses
, ipv6_proxy_ndp_address
);
85 network
->n_ipv6_proxy_ndp_addresses
++;
87 *ret
= ipv6_proxy_ndp_address
;
88 ipv6_proxy_ndp_address
= NULL
;
93 void ipv6_proxy_ndp_address_free(IPv6ProxyNDPAddress
*ipv6_proxy_ndp_address
) {
94 if (!ipv6_proxy_ndp_address
)
97 if (ipv6_proxy_ndp_address
->network
) {
98 LIST_REMOVE(ipv6_proxy_ndp_addresses
, ipv6_proxy_ndp_address
->network
->ipv6_proxy_ndp_addresses
,
99 ipv6_proxy_ndp_address
);
101 assert(ipv6_proxy_ndp_address
->network
->n_ipv6_proxy_ndp_addresses
> 0);
102 ipv6_proxy_ndp_address
->network
->n_ipv6_proxy_ndp_addresses
--;
105 free(ipv6_proxy_ndp_address
);
108 int config_parse_ipv6_proxy_ndp_address(
110 const char *filename
,
113 unsigned section_line
,
120 Network
*network
= userdata
;
121 _cleanup_(ipv6_proxy_ndp_address_freep
) IPv6ProxyNDPAddress
*ipv6_proxy_ndp_address
= NULL
;
123 union in_addr_union buffer
;
131 r
= ipv6_proxy_ndp_address_new_static(network
, &ipv6_proxy_ndp_address
);
135 r
= in_addr_from_string(AF_INET6
, rvalue
, &buffer
);
137 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse IPv6 proxy NDP address, ignoring: %s",
142 r
= in_addr_is_null(AF_INET6
, &buffer
);
144 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
145 "IPv6 proxy NDP address cannot be the ANY address, ignoring: %s", rvalue
);
149 ipv6_proxy_ndp_address
->in_addr
= buffer
.in6
;
150 ipv6_proxy_ndp_address
= NULL
;
155 static int set_ipv6_proxy_ndp_address_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, void *userdata
) {
156 Link
*link
= userdata
;
161 r
= sd_netlink_message_get_errno(m
);
162 if (r
< 0 && r
!= -EEXIST
)
163 log_link_error_errno(link
, r
, "Could not add IPv6 proxy ndp address entry: %m");
168 /* send a request to the kernel to add a IPv6 Proxy entry to the neighbour table */
169 int ipv6_proxy_ndp_address_configure(Link
*link
, IPv6ProxyNDPAddress
*ipv6_proxy_ndp_address
) {
170 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
175 assert(link
->network
);
176 assert(link
->manager
);
177 assert(ipv6_proxy_ndp_address
);
179 rtnl
= link
->manager
->rtnl
;
181 /* create new netlink message */
182 r
= sd_rtnl_message_new_neigh(rtnl
, &req
, RTM_NEWNEIGH
, link
->ifindex
, AF_INET6
);
184 return rtnl_log_create_error(r
);
186 r
= sd_rtnl_message_neigh_set_flags(req
, NLM_F_REQUEST
| NTF_PROXY
);
188 return rtnl_log_create_error(r
);
190 r
= sd_netlink_message_append_in6_addr(req
, NDA_DST
, &ipv6_proxy_ndp_address
->in_addr
);
192 return rtnl_log_create_error(r
);
194 r
= sd_netlink_call_async(rtnl
, req
, set_ipv6_proxy_ndp_address_handler
, link
, 0, NULL
);
196 return log_link_error_errno(link
, r
, "Could not send rtnetlink message: %m");
201 /* configure all ipv6 proxy ndp addresses */
202 int ipv6_proxy_ndp_addresses_configure(Link
*link
) {
203 IPv6ProxyNDPAddress
*ipv6_proxy_ndp_address
;
208 /* enable or disable proxy_ndp itself depending on whether ipv6_proxy_ndp_addresses are set or not */
209 r
= ipv6_proxy_ndp_set(link
);
213 LIST_FOREACH(ipv6_proxy_ndp_addresses
, ipv6_proxy_ndp_address
, link
->network
->ipv6_proxy_ndp_addresses
) {
214 r
= ipv6_proxy_ndp_address_configure(link
, ipv6_proxy_ndp_address
);