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