]>
Commit | Line | Data |
---|---|---|
ca5ad760 YW |
1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
2 | ||
0e96961d | 3 | #include "dhcp-internal.h" |
e7d5fe17 | 4 | #include "dhcp6-internal.h" |
0e96961d | 5 | #include "escape.h" |
2805536b | 6 | #include "in-addr-util.h" |
ca5ad760 YW |
7 | #include "networkd-dhcp-common.h" |
8 | #include "networkd-network.h" | |
9 | #include "parse-util.h" | |
10 | #include "string-table.h" | |
426588bc | 11 | #include "strv.h" |
ca5ad760 YW |
12 | |
13 | int config_parse_dhcp( | |
14 | const char* unit, | |
15 | const char *filename, | |
16 | unsigned line, | |
17 | const char *section, | |
18 | unsigned section_line, | |
19 | const char *lvalue, | |
20 | int ltype, | |
21 | const char *rvalue, | |
22 | void *data, | |
23 | void *userdata) { | |
24 | ||
2d792895 | 25 | AddressFamily *dhcp = data, s; |
ca5ad760 YW |
26 | |
27 | assert(filename); | |
28 | assert(lvalue); | |
29 | assert(rvalue); | |
30 | assert(data); | |
31 | ||
32 | /* Note that this is mostly like | |
2d792895 | 33 | * config_parse_address_family(), except that it |
ca5ad760 YW |
34 | * understands some old names for the enum values */ |
35 | ||
2d792895 | 36 | s = address_family_from_string(rvalue); |
ca5ad760 YW |
37 | if (s < 0) { |
38 | ||
39 | /* Previously, we had a slightly different enum here, | |
40 | * support its values for compatibility. */ | |
41 | ||
42 | if (streq(rvalue, "none")) | |
43 | s = ADDRESS_FAMILY_NO; | |
44 | else if (streq(rvalue, "v4")) | |
45 | s = ADDRESS_FAMILY_IPV4; | |
46 | else if (streq(rvalue, "v6")) | |
47 | s = ADDRESS_FAMILY_IPV6; | |
48 | else if (streq(rvalue, "both")) | |
49 | s = ADDRESS_FAMILY_YES; | |
50 | else { | |
51 | log_syntax(unit, LOG_ERR, filename, line, 0, | |
52 | "Failed to parse DHCP option, ignoring: %s", rvalue); | |
53 | return 0; | |
54 | } | |
55 | ||
56 | log_syntax(unit, LOG_WARNING, filename, line, 0, | |
57 | "DHCP=%s is deprecated, please use DHCP=%s instead.", | |
2d792895 | 58 | rvalue, address_family_to_string(s)); |
ca5ad760 YW |
59 | } |
60 | ||
61 | *dhcp = s; | |
62 | return 0; | |
63 | } | |
64 | ||
bdad94d0 YW |
65 | int config_parse_dhcp_route_metric( |
66 | const char* unit, | |
67 | const char *filename, | |
68 | unsigned line, | |
69 | const char *section, | |
70 | unsigned section_line, | |
71 | const char *lvalue, | |
72 | int ltype, | |
73 | const char *rvalue, | |
74 | void *data, | |
75 | void *userdata) { | |
76 | ||
77 | Network *network = data; | |
78 | uint32_t metric; | |
79 | int r; | |
80 | ||
81 | assert(filename); | |
82 | assert(lvalue); | |
83 | assert(rvalue); | |
84 | assert(data); | |
85 | ||
86 | r = safe_atou32(rvalue, &metric); | |
87 | if (r < 0) { | |
88 | log_syntax(unit, LOG_ERR, filename, line, r, | |
89 | "Failed to parse RouteMetric=%s, ignoring assignment: %m", rvalue); | |
90 | return 0; | |
91 | } | |
92 | ||
93 | if (streq_ptr(section, "DHCPv4")) { | |
94 | network->dhcp_route_metric = metric; | |
95 | network->dhcp_route_metric_set = true; | |
96 | } else if (streq_ptr(section, "DHCPv6")) { | |
97 | network->dhcp6_route_metric = metric; | |
98 | network->dhcp6_route_metric_set = true; | |
99 | } else { /* [DHCP] section */ | |
100 | if (!network->dhcp_route_metric_set) | |
101 | network->dhcp_route_metric = metric; | |
102 | if (!network->dhcp6_route_metric_set) | |
103 | network->dhcp6_route_metric = metric; | |
104 | } | |
105 | ||
106 | return 0; | |
107 | } | |
108 | ||
4f7331a8 YW |
109 | int config_parse_dhcp_use_dns( |
110 | const char* unit, | |
111 | const char *filename, | |
112 | unsigned line, | |
113 | const char *section, | |
114 | unsigned section_line, | |
115 | const char *lvalue, | |
116 | int ltype, | |
117 | const char *rvalue, | |
118 | void *data, | |
119 | void *userdata) { | |
120 | ||
121 | Network *network = data; | |
122 | int r; | |
123 | ||
124 | assert(filename); | |
125 | assert(lvalue); | |
126 | assert(rvalue); | |
127 | assert(data); | |
128 | ||
129 | r = parse_boolean(rvalue); | |
130 | if (r < 0) { | |
131 | log_syntax(unit, LOG_ERR, filename, line, r, | |
132 | "Failed to parse UseDNS=%s, ignoring assignment: %m", rvalue); | |
133 | return 0; | |
134 | } | |
135 | ||
bdad94d0 YW |
136 | if (streq_ptr(section, "DHCPv4")) { |
137 | network->dhcp_use_dns = r; | |
138 | network->dhcp_use_dns_set = true; | |
139 | } else if (streq_ptr(section, "DHCPv6")) { | |
140 | network->dhcp6_use_dns = r; | |
141 | network->dhcp6_use_dns_set = true; | |
142 | } else { /* [DHCP] section */ | |
143 | if (!network->dhcp_use_dns_set) | |
144 | network->dhcp_use_dns = r; | |
145 | if (!network->dhcp6_use_dns_set) | |
146 | network->dhcp6_use_dns = r; | |
147 | } | |
4f7331a8 YW |
148 | |
149 | return 0; | |
150 | } | |
151 | ||
152 | int config_parse_dhcp_use_ntp( | |
153 | const char* unit, | |
154 | const char *filename, | |
155 | unsigned line, | |
156 | const char *section, | |
157 | unsigned section_line, | |
158 | const char *lvalue, | |
159 | int ltype, | |
160 | const char *rvalue, | |
161 | void *data, | |
162 | void *userdata) { | |
163 | ||
164 | Network *network = data; | |
165 | int r; | |
166 | ||
167 | assert(filename); | |
168 | assert(lvalue); | |
169 | assert(rvalue); | |
170 | assert(data); | |
171 | ||
172 | r = parse_boolean(rvalue); | |
173 | if (r < 0) { | |
174 | log_syntax(unit, LOG_ERR, filename, line, r, | |
175 | "Failed to parse UseNTP=%s, ignoring assignment: %m", rvalue); | |
176 | return 0; | |
177 | } | |
178 | ||
bdad94d0 YW |
179 | if (streq_ptr(section, "DHCPv4")) { |
180 | network->dhcp_use_ntp = r; | |
181 | network->dhcp_use_ntp_set = true; | |
182 | } else if (streq_ptr(section, "DHCPv6")) { | |
183 | network->dhcp6_use_ntp = r; | |
184 | network->dhcp6_use_ntp_set = true; | |
185 | } else { /* [DHCP] section */ | |
186 | if (!network->dhcp_use_ntp_set) | |
187 | network->dhcp_use_ntp = r; | |
188 | if (!network->dhcp6_use_ntp_set) | |
189 | network->dhcp6_use_ntp = r; | |
190 | } | |
4f7331a8 YW |
191 | |
192 | return 0; | |
193 | } | |
194 | ||
ca5ad760 YW |
195 | int config_parse_section_route_table( |
196 | const char *unit, | |
197 | const char *filename, | |
198 | unsigned line, | |
199 | const char *section, | |
200 | unsigned section_line, | |
201 | const char *lvalue, | |
202 | int ltype, | |
203 | const char *rvalue, | |
204 | void *data, | |
205 | void *userdata) { | |
206 | ||
207 | Network *network = data; | |
208 | uint32_t rt; | |
209 | int r; | |
210 | ||
211 | assert(filename); | |
212 | assert(lvalue); | |
213 | assert(rvalue); | |
214 | assert(data); | |
215 | ||
216 | r = safe_atou32(rvalue, &rt); | |
217 | if (r < 0) { | |
218 | log_syntax(unit, LOG_ERR, filename, line, r, | |
219 | "Failed to parse RouteTable=%s, ignoring assignment: %m", rvalue); | |
220 | return 0; | |
221 | } | |
222 | ||
426588bc | 223 | if (STRPTR_IN_SET(section, "DHCP", "DHCPv4")) { |
ca5ad760 YW |
224 | network->dhcp_route_table = rt; |
225 | network->dhcp_route_table_set = true; | |
226 | } else { /* section is IPv6AcceptRA */ | |
227 | network->ipv6_accept_ra_route_table = rt; | |
228 | network->ipv6_accept_ra_route_table_set = true; | |
229 | } | |
230 | ||
231 | return 0; | |
232 | } | |
233 | ||
234 | int config_parse_iaid(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 | Network *network = data; | |
245 | uint32_t iaid; | |
246 | int r; | |
247 | ||
248 | assert(filename); | |
249 | assert(lvalue); | |
250 | assert(rvalue); | |
251 | assert(network); | |
252 | ||
253 | r = safe_atou32(rvalue, &iaid); | |
254 | if (r < 0) { | |
255 | log_syntax(unit, LOG_ERR, filename, line, r, | |
256 | "Unable to read IAID, ignoring assignment: %s", rvalue); | |
257 | return 0; | |
258 | } | |
259 | ||
260 | network->iaid = iaid; | |
261 | network->iaid_set = true; | |
262 | ||
263 | return 0; | |
264 | } | |
265 | ||
f37f2a6b | 266 | int config_parse_dhcp_user_class( |
3175a8c2 SS |
267 | const char *unit, |
268 | const char *filename, | |
269 | unsigned line, | |
270 | const char *section, | |
271 | unsigned section_line, | |
272 | const char *lvalue, | |
273 | int ltype, | |
274 | const char *rvalue, | |
275 | void *data, | |
276 | void *userdata) { | |
277 | ||
f37f2a6b SS |
278 | char ***l = data; |
279 | int r; | |
280 | ||
281 | assert(l); | |
282 | assert(lvalue); | |
283 | assert(rvalue); | |
284 | ||
285 | if (isempty(rvalue)) { | |
286 | *l = strv_free(*l); | |
287 | return 0; | |
288 | } | |
289 | ||
290 | for (;;) { | |
291 | _cleanup_free_ char *w = NULL; | |
292 | ||
293 | r = extract_first_word(&rvalue, &w, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE); | |
294 | if (r == -ENOMEM) | |
295 | return log_oom(); | |
296 | if (r < 0) { | |
297 | log_syntax(unit, LOG_ERR, filename, line, r, | |
298 | "Failed to split user classes option, ignoring: %s", rvalue); | |
299 | break; | |
300 | } | |
301 | if (r == 0) | |
302 | break; | |
303 | ||
304 | if (ltype == AF_INET) { | |
305 | if (strlen(w) > UINT8_MAX) { | |
306 | log_syntax(unit, LOG_ERR, filename, line, 0, | |
307 | "%s length is not in the range 1-255, ignoring.", w); | |
308 | continue; | |
309 | } | |
310 | } else { | |
311 | if (strlen(w) > UINT16_MAX) { | |
312 | log_syntax(unit, LOG_ERR, filename, line, 0, | |
313 | "%s length is not in the range 1-65535, ignoring.", w); | |
314 | continue; | |
315 | } | |
316 | } | |
317 | ||
318 | r = strv_push(l, w); | |
319 | if (r < 0) | |
320 | return log_oom(); | |
321 | ||
322 | w = NULL; | |
323 | } | |
324 | ||
325 | return 0; | |
326 | } | |
327 | ||
ed0d1b2e SS |
328 | int config_parse_dhcp_vendor_class( |
329 | const char *unit, | |
330 | const char *filename, | |
331 | unsigned line, | |
332 | const char *section, | |
333 | unsigned section_line, | |
334 | const char *lvalue, | |
335 | int ltype, | |
336 | const char *rvalue, | |
337 | void *data, | |
338 | void *userdata) { | |
339 | char ***l = data; | |
340 | int r; | |
341 | ||
342 | assert(l); | |
343 | assert(lvalue); | |
344 | assert(rvalue); | |
345 | ||
346 | if (isempty(rvalue)) { | |
347 | *l = strv_free(*l); | |
348 | return 0; | |
349 | } | |
350 | ||
351 | for (;;) { | |
352 | _cleanup_free_ char *w = NULL; | |
353 | ||
354 | r = extract_first_word(&rvalue, &w, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE); | |
355 | if (r == -ENOMEM) | |
356 | return log_oom(); | |
357 | if (r < 0) { | |
358 | log_syntax(unit, LOG_ERR, filename, line, r, | |
359 | "Failed to split vendor classes option, ignoring: %s", rvalue); | |
360 | break; | |
361 | } | |
362 | if (r == 0) | |
363 | break; | |
364 | ||
365 | if (strlen(w) > UINT8_MAX) { | |
366 | log_syntax(unit, LOG_ERR, filename, line, 0, | |
367 | "%s length is not in the range 1-255, ignoring.", w); | |
368 | continue; | |
369 | } | |
370 | ||
371 | r = strv_push(l, w); | |
372 | if (r < 0) | |
373 | return log_oom(); | |
374 | ||
375 | w = NULL; | |
376 | } | |
377 | ||
378 | return 0; | |
379 | } | |
380 | ||
0e96961d YW |
381 | int config_parse_dhcp_send_option( |
382 | const char *unit, | |
383 | const char *filename, | |
384 | unsigned line, | |
385 | const char *section, | |
386 | unsigned section_line, | |
387 | const char *lvalue, | |
388 | int ltype, | |
389 | const char *rvalue, | |
390 | void *data, | |
391 | void *userdata) { | |
392 | ||
e7d5fe17 AD |
393 | _cleanup_(sd_dhcp_option_unrefp) sd_dhcp_option *opt4 = NULL, *old4 = NULL; |
394 | _cleanup_(sd_dhcp6_option_unrefp) sd_dhcp6_option *opt6 = NULL, *old6 = NULL; | |
b4ccc5de | 395 | uint32_t uint32_data, enterprise_identifier = 0; |
0e96961d | 396 | _cleanup_free_ char *word = NULL, *q = NULL; |
83b56c70 | 397 | OrderedHashmap **options = data; |
b4ccc5de | 398 | uint16_t u16, uint16_data; |
0e96961d YW |
399 | union in_addr_union addr; |
400 | DHCPOptionDataType type; | |
e7d5fe17 | 401 | uint8_t u8, uint8_data; |
0e96961d YW |
402 | const void *udata; |
403 | const char *p; | |
404 | ssize_t sz; | |
405 | int r; | |
406 | ||
407 | assert(filename); | |
408 | assert(lvalue); | |
409 | assert(rvalue); | |
410 | assert(data); | |
411 | ||
412 | if (isempty(rvalue)) { | |
413 | *options = ordered_hashmap_free(*options); | |
414 | return 0; | |
415 | } | |
416 | ||
417 | p = rvalue; | |
b4ccc5de SS |
418 | if (ltype == AF_INET6 && streq(lvalue, "SendVendorOption")) { |
419 | r = extract_first_word(&p, &word, ":", 0); | |
420 | if (r == -ENOMEM) | |
421 | return log_oom(); | |
422 | if (r <= 0 || isempty(p)) { | |
423 | log_syntax(unit, LOG_ERR, filename, line, r, | |
424 | "Invalid DHCP option, ignoring assignment: %s", rvalue); | |
425 | return 0; | |
426 | } | |
427 | ||
428 | r = safe_atou32(word, &enterprise_identifier); | |
429 | if (r < 0) { | |
430 | log_syntax(unit, LOG_ERR, filename, line, r, | |
431 | "Failed to parse DHCPv6 enterprise identifier data, ignoring assignment: %s", p); | |
432 | return 0; | |
433 | } | |
434 | word = mfree(word); | |
435 | } | |
436 | ||
0e96961d YW |
437 | r = extract_first_word(&p, &word, ":", 0); |
438 | if (r == -ENOMEM) | |
439 | return log_oom(); | |
b4ccc5de | 440 | if (r <= 0 || isempty(p)) { |
0e96961d YW |
441 | log_syntax(unit, LOG_ERR, filename, line, r, |
442 | "Invalid DHCP option, ignoring assignment: %s", rvalue); | |
443 | return 0; | |
444 | } | |
445 | ||
e7d5fe17 AD |
446 | if (ltype == AF_INET6) { |
447 | r = safe_atou16(word, &u16); | |
448 | if (r < 0) { | |
449 | log_syntax(unit, LOG_ERR, filename, line, r, | |
450 | "Invalid DHCP option, ignoring assignment: %s", rvalue); | |
451 | return 0; | |
452 | } | |
f37f2a6b | 453 | if (u16 < 1 || u16 >= UINT16_MAX) { |
e7d5fe17 AD |
454 | log_syntax(unit, LOG_ERR, filename, line, 0, |
455 | "Invalid DHCP option, valid range is 1-65535, ignoring assignment: %s", rvalue); | |
456 | return 0; | |
457 | } | |
458 | } else { | |
459 | r = safe_atou8(word, &u8); | |
460 | if (r < 0) { | |
461 | log_syntax(unit, LOG_ERR, filename, line, r, | |
462 | "Invalid DHCP option, ignoring assignment: %s", rvalue); | |
463 | return 0; | |
464 | } | |
ffed0205 | 465 | if (u8 < 1 || u8 >= UINT8_MAX) { |
e7d5fe17 AD |
466 | log_syntax(unit, LOG_ERR, filename, line, 0, |
467 | "Invalid DHCP option, valid range is 1-254, ignoring assignment: %s", rvalue); | |
468 | return 0; | |
469 | } | |
0e96961d YW |
470 | } |
471 | ||
3db7d5d2 | 472 | word = mfree(word); |
0e96961d YW |
473 | r = extract_first_word(&p, &word, ":", 0); |
474 | if (r == -ENOMEM) | |
475 | return log_oom(); | |
1eb73422 | 476 | if (r <= 0 || isempty(p)) { |
0e96961d YW |
477 | log_syntax(unit, LOG_ERR, filename, line, r, |
478 | "Invalid DHCP option, ignoring assignment: %s", rvalue); | |
479 | return 0; | |
480 | } | |
481 | ||
482 | type = dhcp_option_data_type_from_string(word); | |
483 | if (type < 0) { | |
484 | log_syntax(unit, LOG_ERR, filename, line, 0, | |
485 | "Invalid DHCP option data type, ignoring assignment: %s", p); | |
486 | return 0; | |
487 | } | |
488 | ||
489 | switch(type) { | |
490 | case DHCP_OPTION_DATA_UINT8:{ | |
491 | r = safe_atou8(p, &uint8_data); | |
492 | if (r < 0) { | |
493 | log_syntax(unit, LOG_ERR, filename, line, r, | |
e7d5fe17 | 494 | "Failed to parse DHCP uint8 data, ignoring assignment: %s", p); |
0e96961d YW |
495 | return 0; |
496 | } | |
497 | ||
498 | udata = &uint8_data; | |
499 | sz = sizeof(uint8_t); | |
500 | break; | |
501 | } | |
502 | case DHCP_OPTION_DATA_UINT16:{ | |
503 | r = safe_atou16(p, &uint16_data); | |
504 | if (r < 0) { | |
505 | log_syntax(unit, LOG_ERR, filename, line, r, | |
e7d5fe17 | 506 | "Failed to parse DHCP uint16 data, ignoring assignment: %s", p); |
0e96961d YW |
507 | return 0; |
508 | } | |
509 | ||
510 | udata = &uint16_data; | |
511 | sz = sizeof(uint16_t); | |
512 | break; | |
513 | } | |
514 | case DHCP_OPTION_DATA_UINT32: { | |
515 | r = safe_atou32(p, &uint32_data); | |
516 | if (r < 0) { | |
517 | log_syntax(unit, LOG_ERR, filename, line, r, | |
e7d5fe17 | 518 | "Failed to parse DHCP uint32 data, ignoring assignment: %s", p); |
0e96961d YW |
519 | return 0; |
520 | } | |
521 | ||
522 | udata = &uint32_data; | |
523 | sz = sizeof(uint32_t); | |
524 | ||
525 | break; | |
526 | } | |
527 | case DHCP_OPTION_DATA_IPV4ADDRESS: { | |
528 | r = in_addr_from_string(AF_INET, p, &addr); | |
529 | if (r < 0) { | |
530 | log_syntax(unit, LOG_ERR, filename, line, r, | |
e7d5fe17 | 531 | "Failed to parse DHCP ipv4address data, ignoring assignment: %s", p); |
0e96961d YW |
532 | return 0; |
533 | } | |
534 | ||
535 | udata = &addr.in; | |
536 | sz = sizeof(addr.in.s_addr); | |
537 | break; | |
538 | } | |
e7d5fe17 AD |
539 | case DHCP_OPTION_DATA_IPV6ADDRESS: { |
540 | r = in_addr_from_string(AF_INET6, p, &addr); | |
541 | if (r < 0) { | |
542 | log_syntax(unit, LOG_ERR, filename, line, r, | |
543 | "Failed to parse DHCP ipv6address data, ignoring assignment: %s", p); | |
544 | return 0; | |
545 | } | |
546 | ||
547 | udata = &addr.in6; | |
548 | sz = sizeof(addr.in6.s6_addr); | |
549 | break; | |
550 | } | |
0e96961d | 551 | case DHCP_OPTION_DATA_STRING: |
732e3a61 | 552 | sz = cunescape(p, UNESCAPE_ACCEPT_NUL, &q); |
0e96961d YW |
553 | if (sz < 0) { |
554 | log_syntax(unit, LOG_ERR, filename, line, sz, | |
e7d5fe17 | 555 | "Failed to decode DHCP option data, ignoring assignment: %s", p); |
0e96961d YW |
556 | } |
557 | ||
558 | udata = q; | |
559 | break; | |
560 | default: | |
561 | return -EINVAL; | |
562 | } | |
563 | ||
e7d5fe17 | 564 | if (ltype == AF_INET6) { |
b4ccc5de | 565 | r = sd_dhcp6_option_new(u16, udata, sz, enterprise_identifier, &opt6); |
e7d5fe17 AD |
566 | if (r < 0) { |
567 | log_syntax(unit, LOG_ERR, filename, line, r, | |
568 | "Failed to store DHCP option '%s', ignoring assignment: %m", rvalue); | |
569 | return 0; | |
570 | } | |
0e96961d | 571 | |
e7d5fe17 AD |
572 | r = ordered_hashmap_ensure_allocated(options, &dhcp6_option_hash_ops); |
573 | if (r < 0) | |
574 | return log_oom(); | |
0e96961d | 575 | |
e7d5fe17 AD |
576 | /* Overwrite existing option */ |
577 | old6 = ordered_hashmap_get(*options, UINT_TO_PTR(u16)); | |
578 | r = ordered_hashmap_replace(*options, UINT_TO_PTR(u16), opt6); | |
579 | if (r < 0) { | |
580 | log_syntax(unit, LOG_ERR, filename, line, r, | |
581 | "Failed to store DHCP option '%s', ignoring assignment: %m", rvalue); | |
582 | return 0; | |
583 | } | |
584 | TAKE_PTR(opt6); | |
585 | } else { | |
586 | r = sd_dhcp_option_new(u8, udata, sz, &opt4); | |
587 | if (r < 0) { | |
588 | log_syntax(unit, LOG_ERR, filename, line, r, | |
589 | "Failed to store DHCP option '%s', ignoring assignment: %m", rvalue); | |
590 | return 0; | |
591 | } | |
0e96961d | 592 | |
e7d5fe17 AD |
593 | r = ordered_hashmap_ensure_allocated(options, &dhcp_option_hash_ops); |
594 | if (r < 0) | |
595 | return log_oom(); | |
596 | ||
597 | /* Overwrite existing option */ | |
598 | old4 = ordered_hashmap_get(*options, UINT_TO_PTR(u8)); | |
599 | r = ordered_hashmap_replace(*options, UINT_TO_PTR(u8), opt4); | |
600 | if (r < 0) { | |
601 | log_syntax(unit, LOG_ERR, filename, line, r, | |
602 | "Failed to store DHCP option '%s', ignoring assignment: %m", rvalue); | |
603 | return 0; | |
604 | } | |
605 | TAKE_PTR(opt4); | |
606 | } | |
0e96961d YW |
607 | return 0; |
608 | } | |
609 | ||
35f6a5cb SS |
610 | int config_parse_dhcp_request_options( |
611 | const char *unit, | |
612 | const char *filename, | |
613 | unsigned line, | |
614 | const char *section, | |
615 | unsigned section_line, | |
616 | const char *lvalue, | |
617 | int ltype, | |
618 | const char *rvalue, | |
619 | void *data, | |
620 | void *userdata) { | |
621 | ||
622 | Network *network = data; | |
623 | const char *p; | |
624 | int r; | |
625 | ||
626 | assert(filename); | |
627 | assert(lvalue); | |
628 | assert(rvalue); | |
629 | assert(data); | |
630 | ||
631 | if (isempty(rvalue)) { | |
632 | if (ltype == AF_INET) | |
633 | network->dhcp_request_options = set_free(network->dhcp_request_options); | |
634 | else | |
635 | network->dhcp6_request_options = set_free(network->dhcp6_request_options); | |
636 | ||
637 | return 0; | |
638 | } | |
639 | ||
640 | for (p = rvalue;;) { | |
641 | _cleanup_free_ char *n = NULL; | |
642 | uint32_t i; | |
643 | ||
644 | r = extract_first_word(&p, &n, NULL, 0); | |
645 | if (r < 0) { | |
646 | log_syntax(unit, LOG_ERR, filename, line, r, | |
647 | "Failed to parse DHCP request option, ignoring assignment: %s", | |
648 | rvalue); | |
649 | return 0; | |
650 | } | |
651 | if (r == 0) | |
652 | return 0; | |
653 | ||
654 | r = safe_atou32(n, &i); | |
655 | if (r < 0) { | |
656 | log_syntax(unit, LOG_ERR, filename, line, r, | |
657 | "DHCP request option is invalid, ignoring assignment: %s", n); | |
658 | continue; | |
659 | } | |
660 | ||
ffed0205 | 661 | if (i < 1 || i >= UINT8_MAX) { |
35f6a5cb SS |
662 | log_syntax(unit, LOG_ERR, filename, line, r, |
663 | "DHCP request option is invalid, valid range is 1-254, ignoring assignment: %s", n); | |
664 | continue; | |
665 | } | |
666 | ||
de7fef4b ZJS |
667 | r = set_ensure_put(ltype == AF_INET ? &network->dhcp_request_options : &network->dhcp6_request_options, |
668 | NULL, UINT32_TO_PTR(i)); | |
35f6a5cb SS |
669 | if (r < 0) |
670 | log_syntax(unit, LOG_ERR, filename, line, r, | |
671 | "Failed to store DHCP request option '%s', ignoring assignment: %m", n); | |
672 | } | |
673 | ||
674 | return 0; | |
675 | } | |
676 | ||
ca5ad760 YW |
677 | DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains, |
678 | "Failed to parse DHCP use domains setting"); | |
679 | ||
680 | static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = { | |
681 | [DHCP_USE_DOMAINS_NO] = "no", | |
682 | [DHCP_USE_DOMAINS_ROUTE] = "route", | |
683 | [DHCP_USE_DOMAINS_YES] = "yes", | |
684 | }; | |
685 | ||
686 | DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES); | |
2e5580a8 YW |
687 | |
688 | static const char * const dhcp_option_data_type_table[_DHCP_OPTION_DATA_MAX] = { | |
689 | [DHCP_OPTION_DATA_UINT8] = "uint8", | |
690 | [DHCP_OPTION_DATA_UINT16] = "uint16", | |
691 | [DHCP_OPTION_DATA_UINT32] = "uint32", | |
692 | [DHCP_OPTION_DATA_STRING] = "string", | |
693 | [DHCP_OPTION_DATA_IPV4ADDRESS] = "ipv4address", | |
e7d5fe17 | 694 | [DHCP_OPTION_DATA_IPV6ADDRESS] = "ipv6address", |
2e5580a8 YW |
695 | }; |
696 | ||
697 | DEFINE_STRING_TABLE_LOOKUP(dhcp_option_data_type, DHCPOptionDataType); |