]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-radv.c
Merge pull request #6866 from sourcejedi/set-linger2
[thirdparty/systemd.git] / src / network / networkd-radv.c
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"
24 #include "networkd-manager.h"
25 #include "networkd-radv.h"
26 #include "sd-radv.h"
27
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
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
189 /* a value of 0xffffffff represents infinity, 0x0 means this host is
190 not a router */
191 r = sd_radv_set_router_lifetime(link->radv,
192 DIV_ROUND_UP(link->network->router_lifetime_usec, USEC_PER_SEC));
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
209 return radv_emit_dns(link);
210 }