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"
33 static bool ipv6_proxy_ndp_is_needed(Link
*link
) {
36 if (link
->flags
& IFF_LOOPBACK
)
42 if (link
->network
->ipv6_proxy_ndp
!= -1)
43 return link
->network
->ipv6_proxy_ndp
;
45 if (link
->network
->n_ipv6_proxy_ndp_addresses
== 0)
51 static int ipv6_proxy_ndp_set(Link
*link
) {
57 v
= ipv6_proxy_ndp_is_needed(link
);
58 p
= strjoina("/proc/sys/net/ipv6/conf/", link
->ifname
, "/proxy_ndp");
60 r
= write_string_file(p
, one_zero(v
), WRITE_STRING_FILE_VERIFY_ON_FAILURE
);
62 log_link_warning_errno(link
, r
, "Cannot configure proxy NDP for interface: %m");
67 int ipv6_proxy_ndp_address_new_static(Network
*network
, IPv6ProxyNDPAddress
**ret
) {
68 _cleanup_(ipv6_proxy_ndp_address_freep
) IPv6ProxyNDPAddress
*ipv6_proxy_ndp_address
= NULL
;
73 /* allocate space for IPv6ProxyNDPAddress entry */
74 ipv6_proxy_ndp_address
= new0(IPv6ProxyNDPAddress
, 1);
75 if (!ipv6_proxy_ndp_address
)
78 ipv6_proxy_ndp_address
->network
= network
;
80 LIST_PREPEND(ipv6_proxy_ndp_addresses
, network
->ipv6_proxy_ndp_addresses
, ipv6_proxy_ndp_address
);
81 network
->n_ipv6_proxy_ndp_addresses
++;
83 *ret
= ipv6_proxy_ndp_address
;
84 ipv6_proxy_ndp_address
= NULL
;
89 void ipv6_proxy_ndp_address_free(IPv6ProxyNDPAddress
*ipv6_proxy_ndp_address
) {
90 if (!ipv6_proxy_ndp_address
)
93 if (ipv6_proxy_ndp_address
->network
) {
94 LIST_REMOVE(ipv6_proxy_ndp_addresses
, ipv6_proxy_ndp_address
->network
->ipv6_proxy_ndp_addresses
,
95 ipv6_proxy_ndp_address
);
97 assert(ipv6_proxy_ndp_address
->network
->n_ipv6_proxy_ndp_addresses
> 0);
98 ipv6_proxy_ndp_address
->network
->n_ipv6_proxy_ndp_addresses
--;
101 free(ipv6_proxy_ndp_address
);
104 int config_parse_ipv6_proxy_ndp_address(
106 const char *filename
,
109 unsigned section_line
,
116 Network
*network
= userdata
;
117 _cleanup_(ipv6_proxy_ndp_address_freep
) IPv6ProxyNDPAddress
*ipv6_proxy_ndp_address
= NULL
;
119 union in_addr_union buffer
;
127 r
= ipv6_proxy_ndp_address_new_static(network
, &ipv6_proxy_ndp_address
);
131 r
= in_addr_from_string(AF_INET6
, rvalue
, &buffer
);
133 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse IPv6 proxy NDP address, ignoring: %s",
138 r
= in_addr_is_null(AF_INET6
, &buffer
);
140 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
141 "IPv6 proxy NDP address can not be the ANY address, ignoring: %s", rvalue
);
145 ipv6_proxy_ndp_address
->in_addr
= buffer
.in6
;
146 ipv6_proxy_ndp_address
= NULL
;
151 static int set_ipv6_proxy_ndp_address_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, void *userdata
) {
152 Link
*link
= userdata
;
157 r
= sd_netlink_message_get_errno(m
);
158 if (r
< 0 && r
!= -EEXIST
)
159 log_link_error_errno(link
, r
, "Could not add IPv6 proxy ndp address entry: %m");
164 /* send a request to the kernel to add a IPv6 Proxy entry to the neighbour table */
165 int ipv6_proxy_ndp_address_configure(Link
*link
, IPv6ProxyNDPAddress
*ipv6_proxy_ndp_address
) {
166 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
171 assert(link
->network
);
172 assert(link
->manager
);
173 assert(ipv6_proxy_ndp_address
);
175 rtnl
= link
->manager
->rtnl
;
177 /* create new netlink message */
178 r
= sd_rtnl_message_new_neigh(rtnl
, &req
, RTM_NEWNEIGH
, link
->ifindex
, AF_INET6
);
180 return rtnl_log_create_error(r
);
182 r
= sd_rtnl_message_neigh_set_flags(req
, NLM_F_REQUEST
| NTF_PROXY
);
184 return rtnl_log_create_error(r
);
186 r
= sd_netlink_message_append_in6_addr(req
, NDA_DST
, &ipv6_proxy_ndp_address
->in_addr
);
188 return rtnl_log_create_error(r
);
190 r
= sd_netlink_call_async(rtnl
, req
, set_ipv6_proxy_ndp_address_handler
, link
, 0, NULL
);
192 return log_link_error_errno(link
, r
, "Could not send rtnetlink message: %m");
197 /* configure all ipv6 proxy ndp addresses */
198 int ipv6_proxy_ndp_addresses_configure(Link
*link
) {
199 IPv6ProxyNDPAddress
*ipv6_proxy_ndp_address
;
202 /* enable or disable proxy_ndp itself depending on whether ipv6_proxy_ndp_addresses are set or not */
203 r
= ipv6_proxy_ndp_set(link
);
207 LIST_FOREACH(ipv6_proxy_ndp_addresses
, ipv6_proxy_ndp_address
, link
->network
->ipv6_proxy_ndp_addresses
) {
208 r
= ipv6_proxy_ndp_address_configure(link
, ipv6_proxy_ndp_address
);