2 This file is part of systemd.
4 Copyright 2017 Florian Klink <flokli@flokli.de>
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 #include <netinet/ether.h>
25 #include "netlink-util.h"
26 #include "networkd-ipv6-proxy-ndp.h"
27 #include "networkd-link.h"
28 #include "networkd-manager.h"
29 #include "networkd-network.h"
30 #include "string-util.h"
32 static bool ipv6_proxy_ndp_is_needed(Link
*link
) {
35 if (link
->flags
& IFF_LOOPBACK
)
41 if (link
->network
->n_ipv6_proxy_ndp_addresses
== 0)
47 static int ipv6_proxy_ndp_set(Link
*link
) {
53 v
= ipv6_proxy_ndp_is_needed(link
);
54 p
= strjoina("/proc/sys/net/ipv6/conf/", link
->ifname
, "/proxy_ndp");
56 r
= write_string_file(p
, one_zero(v
), WRITE_STRING_FILE_VERIFY_ON_FAILURE
);
58 log_link_warning_errno(link
, r
, "Cannot configure proxy NDP for interface: %m");
63 int ipv6_proxy_ndp_address_new_static(Network
*network
, IPv6ProxyNDPAddress
**ret
) {
64 _cleanup_(ipv6_proxy_ndp_address_freep
) IPv6ProxyNDPAddress
*ipv6_proxy_ndp_address
= NULL
;
69 /* allocate space for IPv6ProxyNDPAddress entry */
70 ipv6_proxy_ndp_address
= new0(IPv6ProxyNDPAddress
, 1);
71 if (!ipv6_proxy_ndp_address
)
74 ipv6_proxy_ndp_address
->network
= network
;
76 LIST_PREPEND(ipv6_proxy_ndp_addresses
, network
->ipv6_proxy_ndp_addresses
, ipv6_proxy_ndp_address
);
77 network
->n_ipv6_proxy_ndp_addresses
++;
79 *ret
= ipv6_proxy_ndp_address
;
80 ipv6_proxy_ndp_address
= NULL
;
85 void ipv6_proxy_ndp_address_free(IPv6ProxyNDPAddress
*ipv6_proxy_ndp_address
) {
86 if (!ipv6_proxy_ndp_address
)
89 if (ipv6_proxy_ndp_address
->network
) {
90 LIST_REMOVE(ipv6_proxy_ndp_addresses
, ipv6_proxy_ndp_address
->network
->ipv6_proxy_ndp_addresses
,
91 ipv6_proxy_ndp_address
);
93 assert(ipv6_proxy_ndp_address
->network
->n_ipv6_proxy_ndp_addresses
> 0);
94 ipv6_proxy_ndp_address
->network
->n_ipv6_proxy_ndp_addresses
--;
97 free(ipv6_proxy_ndp_address
);
100 int config_parse_ipv6_proxy_ndp_address(
102 const char *filename
,
105 unsigned section_line
,
112 Network
*network
= userdata
;
113 _cleanup_(ipv6_proxy_ndp_address_freep
) IPv6ProxyNDPAddress
*ipv6_proxy_ndp_address
= NULL
;
115 union in_addr_union buffer
;
123 r
= ipv6_proxy_ndp_address_new_static(network
, &ipv6_proxy_ndp_address
);
127 r
= in_addr_from_string(AF_INET6
, rvalue
, &buffer
);
129 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse IPv6 proxy NDP address, ignoring: %s",
134 r
= in_addr_is_null(AF_INET6
, &buffer
);
136 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
137 "IPv6 proxy NDP address can not be the ANY address, ignoring: %s", rvalue
);
141 ipv6_proxy_ndp_address
->in_addr
= buffer
.in6
;
142 ipv6_proxy_ndp_address
= NULL
;
147 static int set_ipv6_proxy_ndp_address_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, void *userdata
) {
148 Link
*link
= userdata
;
153 r
= sd_netlink_message_get_errno(m
);
154 if (r
< 0 && r
!= -EEXIST
)
155 log_link_error_errno(link
, r
, "Could not add IPv6 proxy ndp address entry: %m");
160 /* send a request to the kernel to add a IPv6 Proxy entry to the neighbour table */
161 int ipv6_proxy_ndp_address_configure(Link
*link
, IPv6ProxyNDPAddress
*ipv6_proxy_ndp_address
) {
162 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
167 assert(link
->network
);
168 assert(link
->manager
);
169 assert(ipv6_proxy_ndp_address
);
171 rtnl
= link
->manager
->rtnl
;
173 /* create new netlink message */
174 r
= sd_rtnl_message_new_neigh(rtnl
, &req
, RTM_NEWNEIGH
, link
->ifindex
, AF_INET6
);
176 return rtnl_log_create_error(r
);
178 r
= sd_rtnl_message_neigh_set_flags(req
, NLM_F_REQUEST
| NTF_PROXY
);
180 return rtnl_log_create_error(r
);
182 r
= sd_netlink_message_append_in6_addr(req
, NDA_DST
, &ipv6_proxy_ndp_address
->in_addr
);
184 return rtnl_log_create_error(r
);
186 r
= sd_netlink_call_async(rtnl
, req
, set_ipv6_proxy_ndp_address_handler
, link
, 0, NULL
);
188 return log_link_error_errno(link
, r
, "Could not send rtnetlink message: %m");
193 /* configure all ipv6 proxy ndp addresses */
194 int ipv6_proxy_ndp_addresses_configure(Link
*link
) {
195 IPv6ProxyNDPAddress
*ipv6_proxy_ndp_address
;
198 /* enable or disable proxy_ndp itself depending on whether ipv6_proxy_ndp_addresses are set or not */
199 r
= ipv6_proxy_ndp_set(link
);
203 LIST_FOREACH(ipv6_proxy_ndp_addresses
, ipv6_proxy_ndp_address
, link
->network
->ipv6_proxy_ndp_addresses
) {
204 r
= ipv6_proxy_ndp_address_configure(link
, ipv6_proxy_ndp_address
);