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