]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
a0e5c15d | 2 | |
9aa5d8ba | 3 | #include <netinet/in.h> |
a0e5c15d | 4 | #include <linux/if.h> |
a0e5c15d | 5 | |
a0e5c15d FK |
6 | #include "netlink-util.h" |
7 | #include "networkd-ipv6-proxy-ndp.h" | |
8 | #include "networkd-link.h" | |
9 | #include "networkd-manager.h" | |
10 | #include "networkd-network.h" | |
18a121f9 | 11 | #include "socket-util.h" |
62e021a9 YW |
12 | #include "string-util.h" |
13 | #include "sysctl-util.h" | |
a0e5c15d | 14 | |
302a796f | 15 | static int set_ipv6_proxy_ndp_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { |
a0e5c15d FK |
16 | int r; |
17 | ||
18 | assert(link); | |
19 | ||
20 | r = sd_netlink_message_get_errno(m); | |
21 | if (r < 0 && r != -EEXIST) | |
5ecb131d | 22 | log_link_message_warning_errno(link, m, r, "Could not add IPv6 proxy ndp address entry, ignoring"); |
a0e5c15d FK |
23 | |
24 | return 1; | |
25 | } | |
26 | ||
27 | /* send a request to the kernel to add a IPv6 Proxy entry to the neighbour table */ | |
d349f502 | 28 | static int ipv6_proxy_ndp_address_configure(Link *link, const struct in6_addr *address) { |
a0e5c15d | 29 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; |
a0e5c15d FK |
30 | int r; |
31 | ||
32 | assert(link); | |
a0e5c15d | 33 | assert(link->manager); |
d349f502 | 34 | assert(address); |
a0e5c15d FK |
35 | |
36 | /* create new netlink message */ | |
d349f502 | 37 | r = sd_rtnl_message_new_neigh(link->manager->rtnl, &req, RTM_NEWNEIGH, link->ifindex, AF_INET6); |
a0e5c15d | 38 | if (r < 0) |
98b02994 | 39 | return log_link_error_errno(link, r, "Could not create RTM_NEWNEIGH message: %m"); |
a0e5c15d FK |
40 | |
41 | r = sd_rtnl_message_neigh_set_flags(req, NLM_F_REQUEST | NTF_PROXY); | |
42 | if (r < 0) | |
98b02994 | 43 | return log_link_error_errno(link, r, "Could not set neighbor flags: %m"); |
a0e5c15d | 44 | |
d349f502 | 45 | r = sd_netlink_message_append_in6_addr(req, NDA_DST, address); |
a0e5c15d | 46 | if (r < 0) |
98b02994 | 47 | return log_link_error_errno(link, r, "Could not append NDA_DST attribute: %m"); |
a0e5c15d | 48 | |
d349f502 | 49 | r = netlink_call_async(link->manager->rtnl, NULL, req, set_ipv6_proxy_ndp_address_handler, |
302a796f | 50 | link_netlink_destroy_callback, link); |
a0e5c15d FK |
51 | if (r < 0) |
52 | return log_link_error_errno(link, r, "Could not send rtnetlink message: %m"); | |
53 | ||
1046bf9b YW |
54 | link_ref(link); |
55 | ||
a0e5c15d FK |
56 | return 0; |
57 | } | |
58 | ||
a8c82f90 YW |
59 | static bool ipv6_proxy_ndp_is_needed(Link *link) { |
60 | assert(link); | |
61 | ||
62 | if (link->flags & IFF_LOOPBACK) | |
63 | return false; | |
64 | ||
65 | if (!link->network) | |
66 | return false; | |
67 | ||
68 | if (link->network->ipv6_proxy_ndp >= 0) | |
69 | return link->network->ipv6_proxy_ndp; | |
70 | ||
d349f502 | 71 | return !set_isempty(link->network->ipv6_proxy_ndp_addresses); |
a8c82f90 YW |
72 | } |
73 | ||
74 | static int ipv6_proxy_ndp_set(Link *link) { | |
75 | bool v; | |
76 | int r; | |
77 | ||
78 | assert(link); | |
79 | ||
80 | if (!socket_ipv6_is_supported()) | |
81 | return 0; | |
82 | ||
83 | v = ipv6_proxy_ndp_is_needed(link); | |
84 | ||
85 | r = sysctl_write_ip_property_boolean(AF_INET6, link->ifname, "proxy_ndp", v); | |
86 | if (r < 0) | |
b1dc5946 | 87 | return log_link_warning_errno(link, r, "Cannot configure proxy NDP for the interface, ignoring: %m"); |
a8c82f90 | 88 | |
fd773a11 | 89 | return v; |
a8c82f90 YW |
90 | } |
91 | ||
a0e5c15d | 92 | /* configure all ipv6 proxy ndp addresses */ |
c16b5821 | 93 | int link_set_ipv6_proxy_ndp_addresses(Link *link) { |
d349f502 | 94 | struct in6_addr *address; |
a0e5c15d FK |
95 | int r; |
96 | ||
18a121f9 | 97 | assert(link); |
d349f502 | 98 | assert(link->network); |
18a121f9 | 99 | |
a0e5c15d FK |
100 | /* enable or disable proxy_ndp itself depending on whether ipv6_proxy_ndp_addresses are set or not */ |
101 | r = ipv6_proxy_ndp_set(link); | |
fd773a11 | 102 | if (r <= 0) |
b1dc5946 | 103 | return 0; |
a0e5c15d | 104 | |
d349f502 YW |
105 | SET_FOREACH(address, link->network->ipv6_proxy_ndp_addresses) { |
106 | r = ipv6_proxy_ndp_address_configure(link, address); | |
107 | if (r < 0) | |
a0e5c15d FK |
108 | return r; |
109 | } | |
d349f502 | 110 | |
a0e5c15d FK |
111 | return 0; |
112 | } | |
a8c82f90 YW |
113 | |
114 | int config_parse_ipv6_proxy_ndp_address( | |
115 | const char *unit, | |
116 | const char *filename, | |
117 | unsigned line, | |
118 | const char *section, | |
119 | unsigned section_line, | |
120 | const char *lvalue, | |
121 | int ltype, | |
122 | const char *rvalue, | |
123 | void *data, | |
124 | void *userdata) { | |
125 | ||
d349f502 | 126 | _cleanup_free_ struct in6_addr *address = NULL; |
a8c82f90 | 127 | Network *network = userdata; |
a8c82f90 | 128 | union in_addr_union buffer; |
d349f502 | 129 | int r; |
a8c82f90 YW |
130 | |
131 | assert(filename); | |
a8c82f90 | 132 | assert(rvalue); |
d349f502 | 133 | assert(network); |
a8c82f90 | 134 | |
d349f502 YW |
135 | if (isempty(rvalue)) { |
136 | network->ipv6_proxy_ndp_addresses = set_free_free(network->ipv6_proxy_ndp_addresses); | |
137 | return 0; | |
138 | } | |
a8c82f90 YW |
139 | |
140 | r = in_addr_from_string(AF_INET6, rvalue, &buffer); | |
141 | if (r < 0) { | |
142 | log_syntax(unit, LOG_WARNING, filename, line, r, | |
d349f502 | 143 | "Failed to parse IPv6 proxy NDP address, ignoring: %s", rvalue); |
a8c82f90 YW |
144 | return 0; |
145 | } | |
146 | ||
147 | if (in_addr_is_null(AF_INET6, &buffer)) { | |
148 | log_syntax(unit, LOG_WARNING, filename, line, 0, | |
149 | "IPv6 proxy NDP address cannot be the ANY address, ignoring: %s", rvalue); | |
150 | return 0; | |
151 | } | |
152 | ||
d349f502 YW |
153 | address = newdup(struct in6_addr, &buffer.in6, 1); |
154 | if (!address) | |
155 | return log_oom(); | |
156 | ||
157 | r = set_ensure_put(&network->ipv6_proxy_ndp_addresses, &in6_addr_hash_ops, address); | |
158 | if (r < 0) | |
159 | return log_oom(); | |
160 | if (r > 0) | |
161 | TAKE_PTR(address); | |
a8c82f90 YW |
162 | |
163 | return 0; | |
164 | } |