]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
091214b6 PF |
2 | /*** |
3 | This file is part of systemd. | |
4 | ||
5 | Copyright (C) 2017 Intel Corporation. All rights reserved. | |
6 | ||
7 | systemd is free software; you can redistribute it and/or modify it | |
8 | under the terms of the GNU Lesser General Public License as published by | |
9 | the Free Software Foundation; either version 2.1 of the License, or | |
10 | (at your option) any later version. | |
11 | ||
12 | systemd is distributed in the hope that it will be useful, but | |
13 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | Lesser General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU Lesser General Public License | |
18 | along with systemd; If not, see <http://www.gnu.org/licenses/>. | |
19 | ***/ | |
20 | ||
21 | #include <netinet/icmp6.h> | |
22 | #include <arpa/inet.h> | |
23 | ||
24 | #include "networkd-address.h" | |
c555a358 | 25 | #include "networkd-manager.h" |
091214b6 PF |
26 | #include "networkd-radv.h" |
27 | #include "sd-radv.h" | |
28 | ||
c555a358 PF |
29 | static int radv_get_ip6dns(Network *network, struct in6_addr **dns, |
30 | size_t *n_dns) { | |
31 | _cleanup_free_ struct in6_addr *addresses = NULL; | |
32 | size_t i, n_addresses = 0, n_allocated = 0; | |
33 | ||
34 | assert(network); | |
35 | assert(dns); | |
36 | assert(n_dns); | |
37 | ||
38 | for (i = 0; i < network->n_dns; i++) { | |
39 | union in_addr_union *addr; | |
40 | ||
41 | if (network->dns[i].family != AF_INET6) | |
42 | continue; | |
43 | ||
44 | addr = &network->dns[i].address; | |
45 | ||
46 | if (in_addr_is_null(AF_INET6, addr) || | |
47 | in_addr_is_link_local(AF_INET6, addr) || | |
48 | in_addr_is_localhost(AF_INET6, addr)) | |
49 | continue; | |
50 | ||
51 | if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + 1)) | |
52 | return -ENOMEM; | |
53 | ||
54 | addresses[n_addresses++] = addr->in6; | |
55 | } | |
56 | ||
57 | if (addresses) { | |
58 | *dns = addresses; | |
59 | addresses = NULL; | |
60 | ||
61 | *n_dns = n_addresses; | |
62 | } | |
63 | ||
64 | return n_addresses; | |
65 | } | |
66 | ||
67 | static int radv_set_dns(Link *link, Link *uplink) { | |
68 | _cleanup_free_ struct in6_addr *dns = NULL; | |
69 | size_t n_dns; | |
70 | usec_t lifetime_usec; | |
71 | int r; | |
72 | ||
73 | if (!link->network->router_emit_dns) | |
74 | return 0; | |
75 | ||
76 | if (link->network->router_dns) { | |
77 | dns = newdup(struct in6_addr, link->network->router_dns, | |
78 | link->network->n_router_dns); | |
79 | if (dns == NULL) | |
80 | return -ENOMEM; | |
81 | ||
82 | n_dns = link->network->n_router_dns; | |
83 | lifetime_usec = link->network->router_dns_lifetime_usec; | |
84 | ||
85 | goto set_dns; | |
86 | } | |
87 | ||
88 | lifetime_usec = SD_RADV_DEFAULT_DNS_LIFETIME_USEC; | |
89 | ||
90 | r = radv_get_ip6dns(link->network, &dns, &n_dns); | |
91 | if (r > 0) | |
92 | goto set_dns; | |
93 | ||
94 | if (uplink) { | |
95 | r = radv_get_ip6dns(uplink->network, &dns, &n_dns); | |
96 | if (r > 0) | |
97 | goto set_dns; | |
98 | } | |
99 | ||
100 | return 0; | |
101 | ||
102 | set_dns: | |
103 | return sd_radv_set_rdnss(link->radv, | |
104 | DIV_ROUND_UP(lifetime_usec, USEC_PER_SEC), | |
105 | dns, n_dns); | |
106 | } | |
107 | ||
108 | static int radv_set_domains(Link *link, Link *uplink) { | |
109 | char **search_domains; | |
110 | usec_t lifetime_usec; | |
111 | ||
112 | if (!link->network->router_emit_domains) | |
113 | return 0; | |
114 | ||
115 | search_domains = link->network->router_search_domains; | |
116 | lifetime_usec = link->network->router_dns_lifetime_usec; | |
117 | ||
118 | if (search_domains) | |
119 | goto set_domains; | |
120 | ||
121 | lifetime_usec = SD_RADV_DEFAULT_DNS_LIFETIME_USEC; | |
122 | ||
123 | search_domains = link->network->search_domains; | |
124 | if (search_domains) | |
125 | goto set_domains; | |
126 | ||
127 | if (uplink) { | |
128 | search_domains = uplink->network->search_domains; | |
129 | if (search_domains) | |
130 | goto set_domains; | |
131 | } | |
132 | ||
133 | return 0; | |
134 | ||
135 | set_domains: | |
136 | return sd_radv_set_dnssl(link->radv, | |
137 | DIV_ROUND_UP(lifetime_usec, USEC_PER_SEC), | |
138 | search_domains); | |
139 | ||
140 | } | |
141 | ||
142 | int radv_emit_dns(Link *link) { | |
143 | Link *uplink; | |
144 | int r; | |
145 | ||
146 | uplink = manager_find_uplink(link->manager, link); | |
147 | ||
148 | r = radv_set_dns(link, uplink); | |
149 | if (r < 0) | |
150 | log_link_warning_errno(link, r, "Could not set RA DNS: %m"); | |
151 | ||
152 | r = radv_set_domains(link, uplink); | |
153 | if (r < 0) | |
154 | log_link_warning_errno(link, r, "Could not set RA Domains: %m"); | |
155 | ||
156 | return 0; | |
157 | } | |
158 | ||
091214b6 PF |
159 | int radv_configure(Link *link) { |
160 | int r; | |
161 | Prefix *p; | |
162 | ||
163 | assert(link); | |
164 | assert(link->network); | |
165 | ||
166 | r = sd_radv_new(&link->radv); | |
167 | if (r < 0) | |
168 | return r; | |
169 | ||
170 | r = sd_radv_attach_event(link->radv, NULL, 0); | |
171 | if (r < 0) | |
172 | return r; | |
173 | ||
174 | r = sd_radv_set_mac(link->radv, &link->mac); | |
175 | if (r < 0) | |
176 | return r; | |
177 | ||
178 | r = sd_radv_set_ifindex(link->radv, link->ifindex); | |
179 | if (r < 0) | |
180 | return r; | |
181 | ||
182 | r = sd_radv_set_managed_information(link->radv, link->network->router_managed); | |
183 | if (r < 0) | |
184 | return r; | |
185 | ||
186 | r = sd_radv_set_other_information(link->radv, link->network->router_other_information); | |
187 | if (r < 0) | |
188 | return r; | |
189 | ||
301a2fb9 PF |
190 | /* a value of 0xffffffff represents infinity, 0x0 means this host is |
191 | not a router */ | |
091214b6 | 192 | r = sd_radv_set_router_lifetime(link->radv, |
945e3225 | 193 | DIV_ROUND_UP(link->network->router_lifetime_usec, USEC_PER_SEC)); |
091214b6 PF |
194 | if (r < 0) |
195 | return r; | |
196 | ||
197 | if (link->network->router_lifetime_usec > 0) { | |
198 | r = sd_radv_set_preference(link->radv, | |
199 | link->network->router_preference); | |
200 | if (r < 0) | |
201 | return r; | |
202 | } | |
203 | ||
204 | LIST_FOREACH(prefixes, p, link->network->static_prefixes) { | |
205 | r = sd_radv_add_prefix(link->radv, p->radv_prefix); | |
206 | if (r != -EEXIST && r < 0) | |
207 | return r; | |
208 | } | |
209 | ||
c555a358 | 210 | return radv_emit_dns(link); |
091214b6 | 211 | } |