]>
Commit | Line | Data |
---|---|---|
ca5ad760 YW |
1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
2 | ||
0e96961d YW |
3 | #include "dhcp-internal.h" |
4 | #include "escape.h" | |
2805536b | 5 | #include "in-addr-util.h" |
ca5ad760 YW |
6 | #include "networkd-dhcp-common.h" |
7 | #include "networkd-network.h" | |
8 | #include "parse-util.h" | |
9 | #include "string-table.h" | |
426588bc | 10 | #include "strv.h" |
ca5ad760 YW |
11 | |
12 | int config_parse_dhcp( | |
13 | const char* unit, | |
14 | const char *filename, | |
15 | unsigned line, | |
16 | const char *section, | |
17 | unsigned section_line, | |
18 | const char *lvalue, | |
19 | int ltype, | |
20 | const char *rvalue, | |
21 | void *data, | |
22 | void *userdata) { | |
23 | ||
2d792895 | 24 | AddressFamily *dhcp = data, s; |
ca5ad760 YW |
25 | |
26 | assert(filename); | |
27 | assert(lvalue); | |
28 | assert(rvalue); | |
29 | assert(data); | |
30 | ||
31 | /* Note that this is mostly like | |
2d792895 | 32 | * config_parse_address_family(), except that it |
ca5ad760 YW |
33 | * understands some old names for the enum values */ |
34 | ||
2d792895 | 35 | s = address_family_from_string(rvalue); |
ca5ad760 YW |
36 | if (s < 0) { |
37 | ||
38 | /* Previously, we had a slightly different enum here, | |
39 | * support its values for compatibility. */ | |
40 | ||
41 | if (streq(rvalue, "none")) | |
42 | s = ADDRESS_FAMILY_NO; | |
43 | else if (streq(rvalue, "v4")) | |
44 | s = ADDRESS_FAMILY_IPV4; | |
45 | else if (streq(rvalue, "v6")) | |
46 | s = ADDRESS_FAMILY_IPV6; | |
47 | else if (streq(rvalue, "both")) | |
48 | s = ADDRESS_FAMILY_YES; | |
49 | else { | |
50 | log_syntax(unit, LOG_ERR, filename, line, 0, | |
51 | "Failed to parse DHCP option, ignoring: %s", rvalue); | |
52 | return 0; | |
53 | } | |
54 | ||
55 | log_syntax(unit, LOG_WARNING, filename, line, 0, | |
56 | "DHCP=%s is deprecated, please use DHCP=%s instead.", | |
2d792895 | 57 | rvalue, address_family_to_string(s)); |
ca5ad760 YW |
58 | } |
59 | ||
60 | *dhcp = s; | |
61 | return 0; | |
62 | } | |
63 | ||
4f7331a8 YW |
64 | int config_parse_dhcp_use_dns( |
65 | const char* unit, | |
66 | const char *filename, | |
67 | unsigned line, | |
68 | const char *section, | |
69 | unsigned section_line, | |
70 | const char *lvalue, | |
71 | int ltype, | |
72 | const char *rvalue, | |
73 | void *data, | |
74 | void *userdata) { | |
75 | ||
76 | Network *network = data; | |
77 | int r; | |
78 | ||
79 | assert(filename); | |
80 | assert(lvalue); | |
81 | assert(rvalue); | |
82 | assert(data); | |
83 | ||
84 | r = parse_boolean(rvalue); | |
85 | if (r < 0) { | |
86 | log_syntax(unit, LOG_ERR, filename, line, r, | |
87 | "Failed to parse UseDNS=%s, ignoring assignment: %m", rvalue); | |
88 | return 0; | |
89 | } | |
90 | ||
91 | network->dhcp_use_dns = r; | |
92 | network->dhcp6_use_dns = r; | |
93 | ||
94 | return 0; | |
95 | } | |
96 | ||
299d578f SS |
97 | int config_parse_dhcp_use_sip( |
98 | const char* unit, | |
99 | const char *filename, | |
100 | unsigned line, | |
101 | const char *section, | |
102 | unsigned section_line, | |
103 | const char *lvalue, | |
104 | int ltype, | |
105 | const char *rvalue, | |
106 | void *data, | |
107 | void *userdata) { | |
108 | ||
109 | Network *network = data; | |
110 | int r; | |
111 | ||
112 | assert(filename); | |
113 | assert(lvalue); | |
114 | assert(rvalue); | |
115 | assert(data); | |
116 | ||
117 | r = parse_boolean(rvalue); | |
118 | if (r < 0) { | |
119 | log_syntax(unit, LOG_ERR, filename, line, r, | |
120 | "Failed to parse UseSIP=%s, ignoring assignment: %m", rvalue); | |
121 | return 0; | |
122 | } | |
123 | ||
124 | network->dhcp_use_sip = r; | |
125 | ||
126 | return 0; | |
127 | } | |
128 | ||
4f7331a8 YW |
129 | int config_parse_dhcp_use_ntp( |
130 | const char* unit, | |
131 | const char *filename, | |
132 | unsigned line, | |
133 | const char *section, | |
134 | unsigned section_line, | |
135 | const char *lvalue, | |
136 | int ltype, | |
137 | const char *rvalue, | |
138 | void *data, | |
139 | void *userdata) { | |
140 | ||
141 | Network *network = data; | |
142 | int r; | |
143 | ||
144 | assert(filename); | |
145 | assert(lvalue); | |
146 | assert(rvalue); | |
147 | assert(data); | |
148 | ||
149 | r = parse_boolean(rvalue); | |
150 | if (r < 0) { | |
151 | log_syntax(unit, LOG_ERR, filename, line, r, | |
152 | "Failed to parse UseNTP=%s, ignoring assignment: %m", rvalue); | |
153 | return 0; | |
154 | } | |
155 | ||
156 | network->dhcp_use_ntp = r; | |
157 | network->dhcp6_use_ntp = r; | |
158 | ||
159 | return 0; | |
160 | } | |
161 | ||
ca5ad760 YW |
162 | int config_parse_section_route_table( |
163 | const char *unit, | |
164 | const char *filename, | |
165 | unsigned line, | |
166 | const char *section, | |
167 | unsigned section_line, | |
168 | const char *lvalue, | |
169 | int ltype, | |
170 | const char *rvalue, | |
171 | void *data, | |
172 | void *userdata) { | |
173 | ||
174 | Network *network = data; | |
175 | uint32_t rt; | |
176 | int r; | |
177 | ||
178 | assert(filename); | |
179 | assert(lvalue); | |
180 | assert(rvalue); | |
181 | assert(data); | |
182 | ||
183 | r = safe_atou32(rvalue, &rt); | |
184 | if (r < 0) { | |
185 | log_syntax(unit, LOG_ERR, filename, line, r, | |
186 | "Failed to parse RouteTable=%s, ignoring assignment: %m", rvalue); | |
187 | return 0; | |
188 | } | |
189 | ||
426588bc | 190 | if (STRPTR_IN_SET(section, "DHCP", "DHCPv4")) { |
ca5ad760 YW |
191 | network->dhcp_route_table = rt; |
192 | network->dhcp_route_table_set = true; | |
193 | } else { /* section is IPv6AcceptRA */ | |
194 | network->ipv6_accept_ra_route_table = rt; | |
195 | network->ipv6_accept_ra_route_table_set = true; | |
196 | } | |
197 | ||
198 | return 0; | |
199 | } | |
200 | ||
201 | int config_parse_iaid(const char *unit, | |
202 | const char *filename, | |
203 | unsigned line, | |
204 | const char *section, | |
205 | unsigned section_line, | |
206 | const char *lvalue, | |
207 | int ltype, | |
208 | const char *rvalue, | |
209 | void *data, | |
210 | void *userdata) { | |
211 | Network *network = data; | |
212 | uint32_t iaid; | |
213 | int r; | |
214 | ||
215 | assert(filename); | |
216 | assert(lvalue); | |
217 | assert(rvalue); | |
218 | assert(network); | |
219 | ||
220 | r = safe_atou32(rvalue, &iaid); | |
221 | if (r < 0) { | |
222 | log_syntax(unit, LOG_ERR, filename, line, r, | |
223 | "Unable to read IAID, ignoring assignment: %s", rvalue); | |
224 | return 0; | |
225 | } | |
226 | ||
227 | network->iaid = iaid; | |
228 | network->iaid_set = true; | |
229 | ||
230 | return 0; | |
231 | } | |
232 | ||
2805536b SS |
233 | int config_parse_dhcp6_pd_hint( |
234 | const char* unit, | |
235 | const char *filename, | |
236 | unsigned line, | |
237 | const char *section, | |
238 | unsigned section_line, | |
239 | const char *lvalue, | |
240 | int ltype, | |
241 | const char *rvalue, | |
242 | void *data, | |
243 | void *userdata) { | |
244 | ||
245 | Network *network = data; | |
246 | int r; | |
247 | ||
248 | assert(filename); | |
249 | assert(lvalue); | |
250 | assert(rvalue); | |
251 | assert(data); | |
252 | ||
253 | r = in_addr_prefix_from_string(rvalue, AF_INET6, (union in_addr_union *) &network->dhcp6_pd_address, &network->dhcp6_pd_length); | |
254 | if (r < 0) { | |
255 | log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse PrefixDelegationHint=%s, ignoring assignment", rvalue); | |
256 | return 0; | |
257 | } | |
258 | ||
259 | if (network->dhcp6_pd_length < 1 || network->dhcp6_pd_length > 128) { | |
260 | log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid prefix length='%d', ignoring assignment", network->dhcp6_pd_length); | |
261 | network->dhcp6_pd_length = 0; | |
262 | return 0; | |
263 | } | |
264 | ||
265 | return 0; | |
266 | } | |
267 | ||
0e96961d YW |
268 | int config_parse_dhcp_send_option( |
269 | const char *unit, | |
270 | const char *filename, | |
271 | unsigned line, | |
272 | const char *section, | |
273 | unsigned section_line, | |
274 | const char *lvalue, | |
275 | int ltype, | |
276 | const char *rvalue, | |
277 | void *data, | |
278 | void *userdata) { | |
279 | ||
280 | _cleanup_(sd_dhcp_option_unrefp) sd_dhcp_option *opt = NULL, *old = NULL; | |
281 | _cleanup_free_ char *word = NULL, *q = NULL; | |
282 | OrderedHashmap **options = userdata; | |
283 | union in_addr_union addr; | |
284 | DHCPOptionDataType type; | |
285 | uint8_t u, uint8_data; | |
286 | uint16_t uint16_data; | |
287 | uint32_t uint32_data; | |
288 | const void *udata; | |
289 | const char *p; | |
290 | ssize_t sz; | |
291 | int r; | |
292 | ||
293 | assert(filename); | |
294 | assert(lvalue); | |
295 | assert(rvalue); | |
296 | assert(data); | |
297 | ||
298 | if (isempty(rvalue)) { | |
299 | *options = ordered_hashmap_free(*options); | |
300 | return 0; | |
301 | } | |
302 | ||
303 | p = rvalue; | |
304 | r = extract_first_word(&p, &word, ":", 0); | |
305 | if (r == -ENOMEM) | |
306 | return log_oom(); | |
307 | if (r <= 0) { | |
308 | log_syntax(unit, LOG_ERR, filename, line, r, | |
309 | "Invalid DHCP option, ignoring assignment: %s", rvalue); | |
310 | return 0; | |
311 | } | |
312 | ||
313 | r = safe_atou8(word, &u); | |
314 | if (r < 0) { | |
315 | log_syntax(unit, LOG_ERR, filename, line, r, | |
316 | "Invalid DHCP option, ignoring assignment: %s", rvalue); | |
317 | return 0; | |
318 | } | |
319 | if (u < 1 || u >= 255) { | |
320 | log_syntax(unit, LOG_ERR, filename, line, 0, | |
321 | "Invalid DHCP option, valid range is 1-254, ignoring assignment: %s", rvalue); | |
322 | return 0; | |
323 | } | |
324 | ||
325 | free(word); | |
326 | r = extract_first_word(&p, &word, ":", 0); | |
327 | if (r == -ENOMEM) | |
328 | return log_oom(); | |
329 | if (r <= 0) { | |
330 | log_syntax(unit, LOG_ERR, filename, line, r, | |
331 | "Invalid DHCP option, ignoring assignment: %s", rvalue); | |
332 | return 0; | |
333 | } | |
334 | ||
335 | type = dhcp_option_data_type_from_string(word); | |
336 | if (type < 0) { | |
337 | log_syntax(unit, LOG_ERR, filename, line, 0, | |
338 | "Invalid DHCP option data type, ignoring assignment: %s", p); | |
339 | return 0; | |
340 | } | |
341 | ||
342 | switch(type) { | |
343 | case DHCP_OPTION_DATA_UINT8:{ | |
344 | r = safe_atou8(p, &uint8_data); | |
345 | if (r < 0) { | |
346 | log_syntax(unit, LOG_ERR, filename, line, r, | |
347 | "Failed to parse DHCPv4 uint8 data, ignoring assignment: %s", p); | |
348 | return 0; | |
349 | } | |
350 | ||
351 | udata = &uint8_data; | |
352 | sz = sizeof(uint8_t); | |
353 | break; | |
354 | } | |
355 | case DHCP_OPTION_DATA_UINT16:{ | |
356 | r = safe_atou16(p, &uint16_data); | |
357 | if (r < 0) { | |
358 | log_syntax(unit, LOG_ERR, filename, line, r, | |
359 | "Failed to parse DHCPv4 uint16 data, ignoring assignment: %s", p); | |
360 | return 0; | |
361 | } | |
362 | ||
363 | udata = &uint16_data; | |
364 | sz = sizeof(uint16_t); | |
365 | break; | |
366 | } | |
367 | case DHCP_OPTION_DATA_UINT32: { | |
368 | r = safe_atou32(p, &uint32_data); | |
369 | if (r < 0) { | |
370 | log_syntax(unit, LOG_ERR, filename, line, r, | |
371 | "Failed to parse DHCPv4 uint32 data, ignoring assignment: %s", p); | |
372 | return 0; | |
373 | } | |
374 | ||
375 | udata = &uint32_data; | |
376 | sz = sizeof(uint32_t); | |
377 | ||
378 | break; | |
379 | } | |
380 | case DHCP_OPTION_DATA_IPV4ADDRESS: { | |
381 | r = in_addr_from_string(AF_INET, p, &addr); | |
382 | if (r < 0) { | |
383 | log_syntax(unit, LOG_ERR, filename, line, r, | |
384 | "Failed to parse DHCPv4 ipv4address data, ignoring assignment: %s", p); | |
385 | return 0; | |
386 | } | |
387 | ||
388 | udata = &addr.in; | |
389 | sz = sizeof(addr.in.s_addr); | |
390 | break; | |
391 | } | |
392 | case DHCP_OPTION_DATA_STRING: | |
393 | sz = cunescape(p, 0, &q); | |
394 | if (sz < 0) { | |
395 | log_syntax(unit, LOG_ERR, filename, line, sz, | |
396 | "Failed to decode DHCPv4 option data, ignoring assignment: %s", p); | |
397 | } | |
398 | ||
399 | udata = q; | |
400 | break; | |
401 | default: | |
402 | return -EINVAL; | |
403 | } | |
404 | ||
405 | r = sd_dhcp_option_new(u, udata, sz, &opt); | |
406 | if (r < 0) { | |
407 | log_syntax(unit, LOG_ERR, filename, line, r, | |
408 | "Failed to store DHCPv4 option '%s', ignoring assignment: %m", rvalue); | |
409 | return 0; | |
410 | } | |
411 | ||
412 | r = ordered_hashmap_ensure_allocated(options, &dhcp_option_hash_ops); | |
413 | if (r < 0) | |
414 | return log_oom(); | |
415 | ||
416 | /* Overwrite existing option */ | |
417 | old = ordered_hashmap_remove(*options, UINT_TO_PTR(u)); | |
418 | r = ordered_hashmap_put(*options, UINT_TO_PTR(u), opt); | |
419 | if (r < 0) { | |
420 | log_syntax(unit, LOG_ERR, filename, line, r, | |
421 | "Failed to store DHCPv4 option '%s', ignoring assignment: %m", rvalue); | |
422 | return 0; | |
423 | } | |
424 | ||
425 | TAKE_PTR(opt); | |
426 | return 0; | |
427 | } | |
428 | ||
ca5ad760 YW |
429 | DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains, |
430 | "Failed to parse DHCP use domains setting"); | |
431 | ||
432 | static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = { | |
433 | [DHCP_USE_DOMAINS_NO] = "no", | |
434 | [DHCP_USE_DOMAINS_ROUTE] = "route", | |
435 | [DHCP_USE_DOMAINS_YES] = "yes", | |
436 | }; | |
437 | ||
438 | DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES); | |
2e5580a8 YW |
439 | |
440 | static const char * const dhcp_option_data_type_table[_DHCP_OPTION_DATA_MAX] = { | |
441 | [DHCP_OPTION_DATA_UINT8] = "uint8", | |
442 | [DHCP_OPTION_DATA_UINT16] = "uint16", | |
443 | [DHCP_OPTION_DATA_UINT32] = "uint32", | |
444 | [DHCP_OPTION_DATA_STRING] = "string", | |
445 | [DHCP_OPTION_DATA_IPV4ADDRESS] = "ipv4address", | |
446 | }; | |
447 | ||
448 | DEFINE_STRING_TABLE_LOOKUP(dhcp_option_data_type, DHCPOptionDataType); |