]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-ipv6-proxy-ndp.c
networkd: don't try to configure IPv6 proxy NDP if IPv6 is not available (#7613)
[thirdparty/systemd.git] / src / network / networkd-ipv6-proxy-ndp.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
a0e5c15d
FK
2/***
3 This file is part of systemd.
4
5 Copyright 2017 Florian Klink <flokli@flokli.de>
6
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.
11
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.
16
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/>.
19***/
20
21#include <netinet/ether.h>
22#include <linux/if.h>
23#include <unistd.h>
24
25#include "fileio.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"
18a121f9 32#include "socket-util.h"
a0e5c15d
FK
33
34static bool ipv6_proxy_ndp_is_needed(Link *link) {
35 assert(link);
36
37 if (link->flags & IFF_LOOPBACK)
38 return false;
39
40 if (!link->network)
41 return false;
42
18a121f9 43 if (link->network->ipv6_proxy_ndp >= 0)
465dfe59
HV
44 return link->network->ipv6_proxy_ndp;
45
a0e5c15d
FK
46 if (link->network->n_ipv6_proxy_ndp_addresses == 0)
47 return false;
48
49 return true;
50}
51
52static int ipv6_proxy_ndp_set(Link *link) {
53 const char *p = NULL;
54 int r, v;
55
56 assert(link);
57
18a121f9
LP
58 if (!socket_ipv6_is_supported())
59 return 0;
60
a0e5c15d
FK
61 v = ipv6_proxy_ndp_is_needed(link);
62 p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/proxy_ndp");
63
64 r = write_string_file(p, one_zero(v), WRITE_STRING_FILE_VERIFY_ON_FAILURE);
65 if (r < 0)
66 log_link_warning_errno(link, r, "Cannot configure proxy NDP for interface: %m");
67
68 return 0;
69}
70
71int ipv6_proxy_ndp_address_new_static(Network *network, IPv6ProxyNDPAddress **ret) {
72 _cleanup_(ipv6_proxy_ndp_address_freep) IPv6ProxyNDPAddress *ipv6_proxy_ndp_address = NULL;
73
74 assert(network);
75 assert(ret);
76
77 /* allocate space for IPv6ProxyNDPAddress entry */
78 ipv6_proxy_ndp_address = new0(IPv6ProxyNDPAddress, 1);
79 if (!ipv6_proxy_ndp_address)
80 return -ENOMEM;
81
82 ipv6_proxy_ndp_address->network = network;
83
84 LIST_PREPEND(ipv6_proxy_ndp_addresses, network->ipv6_proxy_ndp_addresses, ipv6_proxy_ndp_address);
85 network->n_ipv6_proxy_ndp_addresses++;
86
87 *ret = ipv6_proxy_ndp_address;
88 ipv6_proxy_ndp_address = NULL;
89
90 return 0;
91}
92
93void ipv6_proxy_ndp_address_free(IPv6ProxyNDPAddress *ipv6_proxy_ndp_address) {
94 if (!ipv6_proxy_ndp_address)
95 return;
96
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);
100
101 assert(ipv6_proxy_ndp_address->network->n_ipv6_proxy_ndp_addresses > 0);
102 ipv6_proxy_ndp_address->network->n_ipv6_proxy_ndp_addresses--;
103 }
104
105 free(ipv6_proxy_ndp_address);
106}
107
108int config_parse_ipv6_proxy_ndp_address(
109 const char *unit,
110 const char *filename,
111 unsigned line,
112 const char *section,
113 unsigned section_line,
114 const char *lvalue,
115 int ltype,
116 const char *rvalue,
117 void *data,
118 void *userdata) {
119
120 Network *network = userdata;
121 _cleanup_(ipv6_proxy_ndp_address_freep) IPv6ProxyNDPAddress *ipv6_proxy_ndp_address = NULL;
122 int r;
123 union in_addr_union buffer;
124
125 assert(filename);
126 assert(section);
127 assert(lvalue);
128 assert(rvalue);
129 assert(data);
130
131 r = ipv6_proxy_ndp_address_new_static(network, &ipv6_proxy_ndp_address);
132 if (r < 0)
133 return r;
134
135 r = in_addr_from_string(AF_INET6, rvalue, &buffer);
136 if (r < 0) {
137 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IPv6 proxy NDP address, ignoring: %s",
138 rvalue);
139 return 0;
140 }
141
142 r = in_addr_is_null(AF_INET6, &buffer);
143 if (r != 0) {
144 log_syntax(unit, LOG_ERR, filename, line, r,
145 "IPv6 proxy NDP address can not be the ANY address, ignoring: %s", rvalue);
146 return 0;
147 }
148
149 ipv6_proxy_ndp_address->in_addr = buffer.in6;
150 ipv6_proxy_ndp_address = NULL;
151
152 return 0;
153}
154
155static int set_ipv6_proxy_ndp_address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
156 Link *link = userdata;
157 int r;
158
159 assert(link);
160
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");
164
165 return 1;
166}
167
168/* send a request to the kernel to add a IPv6 Proxy entry to the neighbour table */
169int ipv6_proxy_ndp_address_configure(Link *link, IPv6ProxyNDPAddress *ipv6_proxy_ndp_address) {
170 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
171 sd_netlink *rtnl;
172 int r;
173
174 assert(link);
175 assert(link->network);
176 assert(link->manager);
177 assert(ipv6_proxy_ndp_address);
178
179 rtnl = link->manager->rtnl;
180
181 /* create new netlink message */
182 r = sd_rtnl_message_new_neigh(rtnl, &req, RTM_NEWNEIGH, link->ifindex, AF_INET6);
183 if (r < 0)
184 return rtnl_log_create_error(r);
185
186 r = sd_rtnl_message_neigh_set_flags(req, NLM_F_REQUEST | NTF_PROXY);
187 if (r < 0)
188 return rtnl_log_create_error(r);
189
190 r = sd_netlink_message_append_in6_addr(req, NDA_DST, &ipv6_proxy_ndp_address->in_addr);
191 if (r < 0)
192 return rtnl_log_create_error(r);
193
194 r = sd_netlink_call_async(rtnl, req, set_ipv6_proxy_ndp_address_handler, link, 0, NULL);
195 if (r < 0)
196 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
197
198 return 0;
199}
200
201/* configure all ipv6 proxy ndp addresses */
202int ipv6_proxy_ndp_addresses_configure(Link *link) {
203 IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
204 int r;
205
18a121f9
LP
206 assert(link);
207
a0e5c15d
FK
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);
210 if (r != 0)
211 return r;
212
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);
215 if (r != 0)
216 return r;
217 }
218 return 0;
219}