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