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