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