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>
27 #include "alloc-util.h"
28 #include "condition.h"
29 #include "conf-parser.h"
30 #include "dhcp-lease-internal.h"
31 #include "ether-addr-util.h"
32 #include "hexdecoct.h"
34 #include "network-internal.h"
35 #include "parse-util.h"
36 #include "siphash24.h"
37 #include "socket-util.h"
38 #include "string-util.h"
43 const char *net_get_name(struct udev_device
*device
) {
44 const char *name
, *field
;
48 /* fetch some persistent data unique (on this machine) to this device */
49 FOREACH_STRING(field
, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") {
50 name
= udev_device_get_property_value(device
, field
);
58 #define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a)
60 int net_get_unique_predictable_data(struct udev_device
*device
, uint64_t *result
) {
62 const char *name
= NULL
;
68 name
= net_get_name(device
);
73 sz
= sizeof(sd_id128_t
) + l
;
76 /* fetch some persistent data unique to this machine */
77 r
= sd_id128_get_machine((sd_id128_t
*) v
);
80 memcpy(v
+ sizeof(sd_id128_t
), name
, l
);
82 /* Let's hash the machine ID plus the device name. We
83 * use a fixed, but originally randomly created hash
85 *result
= htole64(siphash24(v
, sz
, HASH_KEY
.bytes
));
90 static bool net_condition_test_strv(char * const *raw_patterns
,
92 if (strv_isempty(raw_patterns
))
95 /* If the patterns begin with "!", edit it out and negate the test. */
96 if (raw_patterns
[0][0] == '!') {
100 length
= strv_length(raw_patterns
) + 1; /* Include the NULL. */
101 patterns
= newa(char*, length
);
102 patterns
[0] = raw_patterns
[0] + 1; /* Skip the "!". */
103 for (i
= 1; i
< length
; i
++)
104 patterns
[i
] = raw_patterns
[i
];
106 return !string
|| !strv_fnmatch(patterns
, string
, 0);
109 return string
&& strv_fnmatch(raw_patterns
, string
, 0);
112 bool net_match_config(const struct ether_addr
*match_mac
,
113 char * const *match_paths
,
114 char * const *match_drivers
,
115 char * const *match_types
,
116 char * const *match_names
,
117 Condition
*match_host
,
118 Condition
*match_virt
,
119 Condition
*match_kernel
,
120 Condition
*match_arch
,
121 const struct ether_addr
*dev_mac
,
122 const char *dev_path
,
123 const char *dev_parent_driver
,
124 const char *dev_driver
,
125 const char *dev_type
,
126 const char *dev_name
) {
128 if (match_host
&& condition_test(match_host
) <= 0)
131 if (match_virt
&& condition_test(match_virt
) <= 0)
134 if (match_kernel
&& condition_test(match_kernel
) <= 0)
137 if (match_arch
&& condition_test(match_arch
) <= 0)
140 if (match_mac
&& (!dev_mac
|| memcmp(match_mac
, dev_mac
, ETH_ALEN
)))
143 if (!net_condition_test_strv(match_paths
, dev_path
))
146 if (!net_condition_test_strv(match_drivers
, dev_driver
))
149 if (!net_condition_test_strv(match_types
, dev_type
))
152 if (!net_condition_test_strv(match_names
, dev_name
))
158 int config_parse_net_condition(const char *unit
,
159 const char *filename
,
162 unsigned section_line
,
169 ConditionType cond
= ltype
;
170 Condition
**ret
= data
;
173 _cleanup_free_
char *s
= NULL
;
180 negate
= rvalue
[0] == '!';
188 c
= condition_new(cond
, s
, false, negate
);
193 condition_free(*ret
);
199 int config_parse_ifnames(
201 const char *filename
,
204 unsigned section_line
,
220 _cleanup_free_
char *word
= NULL
;
222 r
= extract_first_word(&rvalue
, &word
, NULL
, 0);
224 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse interface name list: %s", rvalue
);
230 if (!ifname_valid(word
)) {
231 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue
);
235 r
= strv_push(sv
, word
);
245 int config_parse_ifalias(const char *unit
,
246 const char *filename
,
249 unsigned section_line
,
257 _cleanup_free_
char *n
= NULL
;
268 if (!ascii_is_valid(n
) || strlen(n
) >= IFALIASZ
) {
269 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue
);
283 int config_parse_hwaddr(const char *unit
,
284 const char *filename
,
287 unsigned section_line
,
293 struct ether_addr
**hwaddr
= data
;
294 struct ether_addr
*n
;
304 n
= new0(struct ether_addr
, 1);
308 start
= rvalue
+ strspn(rvalue
, WHITESPACE
);
309 r
= ether_addr_from_string(start
, n
, &offset
);
311 if (r
|| (start
[offset
+ strspn(start
+ offset
, WHITESPACE
)] != '\0')) {
312 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not a valid MAC address, ignoring assignment: %s", rvalue
);
323 int config_parse_iaid(const char *unit
,
324 const char *filename
,
327 unsigned section_line
,
341 r
= safe_atou32(rvalue
, &iaid
);
343 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
344 "Unable to read IAID, ignoring assignment: %s", rvalue
);
348 *((uint32_t *)data
) = iaid
;
353 int config_parse_bridge_port_priority(
355 const char *filename
,
358 unsigned section_line
,
373 r
= safe_atou16(rvalue
, &i
);
375 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
376 "Failed to parse bridge port priority, ignoring: %s", rvalue
);
380 if (i
> LINK_BRIDGE_PORT_PRIORITY_MAX
) {
381 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
382 "Bridge port priority is larger than maximum %u, ignoring: %s", LINK_BRIDGE_PORT_PRIORITY_MAX
, rvalue
);
386 *((uint16_t *)data
) = i
;
392 void serialize_in_addrs(FILE *f
, const struct in_addr
*addresses
, size_t size
) {
399 for (i
= 0; i
< size
; i
++)
400 fprintf(f
, "%s%s", inet_ntoa(addresses
[i
]),
401 (i
< (size
- 1)) ? " ": "");
404 int deserialize_in_addrs(struct in_addr
**ret
, const char *string
) {
405 _cleanup_free_
struct in_addr
*addresses
= NULL
;
412 _cleanup_free_
char *word
= NULL
;
413 struct in_addr
*new_addresses
;
416 r
= extract_first_word(&string
, &word
, NULL
, 0);
422 new_addresses
= realloc(addresses
, (size
+ 1) * sizeof(struct in_addr
));
426 addresses
= new_addresses
;
428 r
= inet_pton(AF_INET
, word
, &(addresses
[size
]));
441 void serialize_in6_addrs(FILE *f
, const struct in6_addr
*addresses
, size_t size
) {
448 for (i
= 0; i
< size
; i
++) {
449 char buffer
[INET6_ADDRSTRLEN
];
451 fputs(inet_ntop(AF_INET6
, addresses
+i
, buffer
, sizeof(buffer
)), f
);
458 int deserialize_in6_addrs(struct in6_addr
**ret
, const char *string
) {
459 _cleanup_free_
struct in6_addr
*addresses
= NULL
;
466 _cleanup_free_
char *word
= NULL
;
467 struct in6_addr
*new_addresses
;
470 r
= extract_first_word(&string
, &word
, NULL
, 0);
476 new_addresses
= realloc(addresses
, (size
+ 1) * sizeof(struct in6_addr
));
480 addresses
= new_addresses
;
482 r
= inet_pton(AF_INET6
, word
, &(addresses
[size
]));
495 void serialize_dhcp_routes(FILE *f
, const char *key
, sd_dhcp_route
**routes
, size_t size
) {
503 fprintf(f
, "%s=", key
);
505 for (i
= 0; i
< size
; i
++) {
506 struct in_addr dest
, gw
;
509 assert_se(sd_dhcp_route_get_destination(routes
[i
], &dest
) >= 0);
510 assert_se(sd_dhcp_route_get_gateway(routes
[i
], &gw
) >= 0);
511 assert_se(sd_dhcp_route_get_destination_prefix_length(routes
[i
], &length
) >= 0);
513 fprintf(f
, "%s/%" PRIu8
, inet_ntoa(dest
), length
);
514 fprintf(f
, ",%s%s", inet_ntoa(gw
), (i
< (size
- 1)) ? " ": "");
520 int deserialize_dhcp_routes(struct sd_dhcp_route
**ret
, size_t *ret_size
, size_t *ret_allocated
, const char *string
) {
521 _cleanup_free_
struct sd_dhcp_route
*routes
= NULL
;
522 size_t size
= 0, allocated
= 0;
526 assert(ret_allocated
);
529 /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
531 _cleanup_free_
char *word
= NULL
;
536 r
= extract_first_word(&string
, &word
, NULL
, 0);
542 if (!GREEDY_REALLOC(routes
, allocated
, size
+ 1))
548 tok_end
= strchr(tok
, '/');
553 r
= inet_aton(tok
, &routes
[size
].dst_addr
);
559 /* get the prefixlen */
560 tok_end
= strchr(tok
, ',');
566 r
= safe_atou(tok
, &n
);
570 routes
[size
].dst_prefixlen
= (uint8_t) n
;
573 /* get the gateway */
574 r
= inet_aton(tok
, &routes
[size
].gw_addr
);
582 *ret_allocated
= allocated
;
589 int serialize_dhcp_option(FILE *f
, const char *key
, const void *data
, size_t size
) {
590 _cleanup_free_
char *hex_buf
= NULL
;
596 hex_buf
= hexmem(data
, size
);
600 fprintf(f
, "%s=%s\n", key
, hex_buf
);
605 int deserialize_dhcp_option(void **data
, size_t *data_len
, const char *string
) {
610 if (strlen(string
) % 2)
613 return unhexmem(string
, strlen(string
), (void **)data
, data_len
);