1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright (C) 2013 Tom Gundersen <teg@jklm.no>
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.
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.
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/>.
21 #include <arpa/inet.h>
23 #include <netinet/ether.h>
28 #include "alloc-util.h"
29 #include "condition.h"
30 #include "conf-parser.h"
31 #include "dhcp-lease-internal.h"
32 #include "ether-addr-util.h"
33 #include "hexdecoct.h"
35 #include "network-internal.h"
36 #include "parse-util.h"
37 #include "siphash24.h"
38 #include "socket-util.h"
39 #include "string-util.h"
44 const char *net_get_name(struct udev_device
*device
) {
45 const char *name
, *field
;
49 /* fetch some persistent data unique (on this machine) to this device */
50 FOREACH_STRING(field
, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") {
51 name
= udev_device_get_property_value(device
, field
);
59 #define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a)
61 int net_get_unique_predictable_data(struct udev_device
*device
, uint64_t *result
) {
63 const char *name
= NULL
;
69 name
= net_get_name(device
);
74 sz
= sizeof(sd_id128_t
) + l
;
77 /* fetch some persistent data unique to this machine */
78 r
= sd_id128_get_machine((sd_id128_t
*) v
);
81 memcpy(v
+ sizeof(sd_id128_t
), name
, l
);
83 /* Let's hash the machine ID plus the device name. We
84 * use a fixed, but originally randomly created hash
86 *result
= htole64(siphash24(v
, sz
, HASH_KEY
.bytes
));
91 static bool net_condition_test_strv(char * const *raw_patterns
,
93 if (strv_isempty(raw_patterns
))
96 /* If the patterns begin with "!", edit it out and negate the test. */
97 if (raw_patterns
[0][0] == '!') {
101 length
= strv_length(raw_patterns
) + 1; /* Include the NULL. */
102 patterns
= newa(char*, length
);
103 patterns
[0] = raw_patterns
[0] + 1; /* Skip the "!". */
104 for (i
= 1; i
< length
; i
++)
105 patterns
[i
] = raw_patterns
[i
];
107 return !string
|| !strv_fnmatch(patterns
, string
, 0);
110 return string
&& strv_fnmatch(raw_patterns
, string
, 0);
113 bool net_match_config(const struct ether_addr
*match_mac
,
114 char * const *match_paths
,
115 char * const *match_drivers
,
116 char * const *match_types
,
117 char * const *match_names
,
118 Condition
*match_host
,
119 Condition
*match_virt
,
120 Condition
*match_kernel_cmdline
,
121 Condition
*match_kernel_version
,
122 Condition
*match_arch
,
123 const struct ether_addr
*dev_mac
,
124 const char *dev_path
,
125 const char *dev_parent_driver
,
126 const char *dev_driver
,
127 const char *dev_type
,
128 const char *dev_name
) {
130 if (match_host
&& condition_test(match_host
) <= 0)
133 if (match_virt
&& condition_test(match_virt
) <= 0)
136 if (match_kernel_cmdline
&& condition_test(match_kernel_cmdline
) <= 0)
139 if (match_kernel_version
&& condition_test(match_kernel_version
) <= 0)
142 if (match_arch
&& condition_test(match_arch
) <= 0)
145 if (match_mac
&& (!dev_mac
|| memcmp(match_mac
, dev_mac
, ETH_ALEN
)))
148 if (!net_condition_test_strv(match_paths
, dev_path
))
151 if (!net_condition_test_strv(match_drivers
, dev_driver
))
154 if (!net_condition_test_strv(match_types
, dev_type
))
157 if (!net_condition_test_strv(match_names
, dev_name
))
163 int config_parse_net_condition(const char *unit
,
164 const char *filename
,
167 unsigned section_line
,
174 ConditionType cond
= ltype
;
175 Condition
**ret
= data
;
178 _cleanup_free_
char *s
= NULL
;
185 negate
= rvalue
[0] == '!';
193 c
= condition_new(cond
, s
, false, negate
);
198 condition_free(*ret
);
204 int config_parse_ifnames(
206 const char *filename
,
209 unsigned section_line
,
225 _cleanup_free_
char *word
= NULL
;
227 r
= extract_first_word(&rvalue
, &word
, NULL
, 0);
229 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse interface name list: %s", rvalue
);
235 if (!ifname_valid(word
)) {
236 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue
);
240 r
= strv_push(sv
, word
);
250 int config_parse_ifalias(const char *unit
,
251 const char *filename
,
254 unsigned section_line
,
262 _cleanup_free_
char *n
= NULL
;
273 if (!ascii_is_valid(n
) || strlen(n
) >= IFALIASZ
) {
274 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue
);
288 int config_parse_hwaddr(const char *unit
,
289 const char *filename
,
292 unsigned section_line
,
298 struct ether_addr
**hwaddr
= data
;
299 struct ether_addr
*n
;
309 n
= new0(struct ether_addr
, 1);
313 start
= rvalue
+ strspn(rvalue
, WHITESPACE
);
314 r
= ether_addr_from_string(start
, n
, &offset
);
316 if (r
|| (start
[offset
+ strspn(start
+ offset
, WHITESPACE
)] != '\0')) {
317 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not a valid MAC address, ignoring assignment: %s", rvalue
);
328 int config_parse_iaid(const char *unit
,
329 const char *filename
,
332 unsigned section_line
,
346 r
= safe_atou32(rvalue
, &iaid
);
348 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
349 "Unable to read IAID, ignoring assignment: %s", rvalue
);
353 *((uint32_t *)data
) = iaid
;
358 int config_parse_bridge_port_priority(
360 const char *filename
,
363 unsigned section_line
,
378 r
= safe_atou16(rvalue
, &i
);
380 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
381 "Failed to parse bridge port priority, ignoring: %s", rvalue
);
385 if (i
> LINK_BRIDGE_PORT_PRIORITY_MAX
) {
386 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
387 "Bridge port priority is larger than maximum %u, ignoring: %s", LINK_BRIDGE_PORT_PRIORITY_MAX
, rvalue
);
391 *((uint16_t *)data
) = i
;
397 void serialize_in_addrs(FILE *f
, const struct in_addr
*addresses
, size_t size
) {
404 for (i
= 0; i
< size
; i
++)
405 fprintf(f
, "%s%s", inet_ntoa(addresses
[i
]),
406 (i
< (size
- 1)) ? " ": "");
409 int deserialize_in_addrs(struct in_addr
**ret
, const char *string
) {
410 _cleanup_free_
struct in_addr
*addresses
= NULL
;
417 _cleanup_free_
char *word
= NULL
;
418 struct in_addr
*new_addresses
;
421 r
= extract_first_word(&string
, &word
, NULL
, 0);
427 new_addresses
= realloc(addresses
, (size
+ 1) * sizeof(struct in_addr
));
431 addresses
= new_addresses
;
433 r
= inet_pton(AF_INET
, word
, &(addresses
[size
]));
446 void serialize_in6_addrs(FILE *f
, const struct in6_addr
*addresses
, size_t size
) {
453 for (i
= 0; i
< size
; i
++) {
454 char buffer
[INET6_ADDRSTRLEN
];
456 fputs(inet_ntop(AF_INET6
, addresses
+i
, buffer
, sizeof(buffer
)), f
);
463 int deserialize_in6_addrs(struct in6_addr
**ret
, const char *string
) {
464 _cleanup_free_
struct in6_addr
*addresses
= NULL
;
471 _cleanup_free_
char *word
= NULL
;
472 struct in6_addr
*new_addresses
;
475 r
= extract_first_word(&string
, &word
, NULL
, 0);
481 new_addresses
= realloc(addresses
, (size
+ 1) * sizeof(struct in6_addr
));
485 addresses
= new_addresses
;
487 r
= inet_pton(AF_INET6
, word
, &(addresses
[size
]));
500 void serialize_dhcp_routes(FILE *f
, const char *key
, sd_dhcp_route
**routes
, size_t size
) {
508 fprintf(f
, "%s=", key
);
510 for (i
= 0; i
< size
; i
++) {
511 struct in_addr dest
, gw
;
514 assert_se(sd_dhcp_route_get_destination(routes
[i
], &dest
) >= 0);
515 assert_se(sd_dhcp_route_get_gateway(routes
[i
], &gw
) >= 0);
516 assert_se(sd_dhcp_route_get_destination_prefix_length(routes
[i
], &length
) >= 0);
518 fprintf(f
, "%s/%" PRIu8
, inet_ntoa(dest
), length
);
519 fprintf(f
, ",%s%s", inet_ntoa(gw
), (i
< (size
- 1)) ? " ": "");
525 int deserialize_dhcp_routes(struct sd_dhcp_route
**ret
, size_t *ret_size
, size_t *ret_allocated
, const char *string
) {
526 _cleanup_free_
struct sd_dhcp_route
*routes
= NULL
;
527 size_t size
= 0, allocated
= 0;
531 assert(ret_allocated
);
534 /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
536 _cleanup_free_
char *word
= NULL
;
541 r
= extract_first_word(&string
, &word
, NULL
, 0);
547 if (!GREEDY_REALLOC(routes
, allocated
, size
+ 1))
553 tok_end
= strchr(tok
, '/');
558 r
= inet_aton(tok
, &routes
[size
].dst_addr
);
564 /* get the prefixlen */
565 tok_end
= strchr(tok
, ',');
571 r
= safe_atou(tok
, &n
);
575 routes
[size
].dst_prefixlen
= (uint8_t) n
;
578 /* get the gateway */
579 r
= inet_aton(tok
, &routes
[size
].gw_addr
);
587 *ret_allocated
= allocated
;
594 int serialize_dhcp_option(FILE *f
, const char *key
, const void *data
, size_t size
) {
595 _cleanup_free_
char *hex_buf
= NULL
;
601 hex_buf
= hexmem(data
, size
);
605 fprintf(f
, "%s=%s\n", key
, hex_buf
);
610 int deserialize_dhcp_option(void **data
, size_t *data_len
, const char *string
) {
615 if (strlen(string
) % 2)
618 return unhexmem(string
, strlen(string
), (void **)data
, data_len
);