1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright (C) 2013 Tom Gundersen <teg@jklm.no>
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <arpa/inet.h>
24 #include <netinet/ether.h>
28 #include "condition.h"
29 #include "conf-parser.h"
30 #include "dhcp-lease-internal.h"
32 #include "network-internal.h"
33 #include "parse-util.h"
34 #include "siphash24.h"
35 #include "string-util.h"
40 const char *net_get_name(struct udev_device
*device
) {
41 const char *name
, *field
;
45 /* fetch some persistent data unique (on this machine) to this device */
46 FOREACH_STRING(field
, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") {
47 name
= udev_device_get_property_value(device
, field
);
55 #define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a)
57 int net_get_unique_predictable_data(struct udev_device
*device
, uint8_t result
[8]) {
59 const char *name
= NULL
;
65 name
= net_get_name(device
);
70 sz
= sizeof(sd_id128_t
) + l
;
73 /* fetch some persistent data unique to this machine */
74 r
= sd_id128_get_machine((sd_id128_t
*) v
);
77 memcpy(v
+ sizeof(sd_id128_t
), name
, l
);
79 /* Let's hash the machine ID plus the device name. We
80 * use a fixed, but originally randomly created hash
82 siphash24(result
, v
, sz
, HASH_KEY
.bytes
);
87 bool net_match_config(const struct ether_addr
*match_mac
,
88 char * const *match_paths
,
89 char * const *match_drivers
,
90 char * const *match_types
,
91 char * const *match_names
,
92 Condition
*match_host
,
93 Condition
*match_virt
,
94 Condition
*match_kernel
,
95 Condition
*match_arch
,
96 const struct ether_addr
*dev_mac
,
98 const char *dev_parent_driver
,
99 const char *dev_driver
,
100 const char *dev_type
,
101 const char *dev_name
) {
103 if (match_host
&& !condition_test(match_host
))
106 if (match_virt
&& !condition_test(match_virt
))
109 if (match_kernel
&& !condition_test(match_kernel
))
112 if (match_arch
&& !condition_test(match_arch
))
115 if (match_mac
&& (!dev_mac
|| memcmp(match_mac
, dev_mac
, ETH_ALEN
)))
118 if (!strv_isempty(match_paths
) &&
119 (!dev_path
|| !strv_fnmatch(match_paths
, dev_path
, 0)))
122 if (!strv_isempty(match_drivers
) &&
123 (!dev_driver
|| !strv_fnmatch(match_drivers
, dev_driver
, 0)))
126 if (!strv_isempty(match_types
) &&
127 (!dev_type
|| !strv_fnmatch_or_empty(match_types
, dev_type
, 0)))
130 if (!strv_isempty(match_names
) &&
131 (!dev_name
|| !strv_fnmatch_or_empty(match_names
, dev_name
, 0)))
137 int config_parse_net_condition(const char *unit
,
138 const char *filename
,
141 unsigned section_line
,
148 ConditionType cond
= ltype
;
149 Condition
**ret
= data
;
152 _cleanup_free_
char *s
= NULL
;
159 negate
= rvalue
[0] == '!';
167 c
= condition_new(cond
, s
, false, negate
);
172 condition_free(*ret
);
178 int config_parse_ifname(const char *unit
,
179 const char *filename
,
182 unsigned section_line
,
190 _cleanup_free_
char *n
= NULL
;
201 if (!ascii_is_valid(n
) || strlen(n
) >= IFNAMSIZ
) {
202 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue
);
216 int config_parse_ifnames(const char *unit
,
217 const char *filename
,
220 unsigned section_line
,
228 const char *word
, *state
;
237 FOREACH_WORD(word
, l
, rvalue
, state
) {
240 n
= strndup(word
, l
);
244 if (!ascii_is_valid(n
) || strlen(n
) >= IFNAMSIZ
) {
245 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue
);
250 r
= strv_consume(sv
, n
);
258 int config_parse_ifalias(const char *unit
,
259 const char *filename
,
262 unsigned section_line
,
270 _cleanup_free_
char *n
= NULL
;
281 if (!ascii_is_valid(n
) || strlen(n
) >= IFALIASZ
) {
282 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue
);
296 int config_parse_hwaddr(const char *unit
,
297 const char *filename
,
300 unsigned section_line
,
306 struct ether_addr
**hwaddr
= data
;
307 struct ether_addr
*n
;
315 n
= new0(struct ether_addr
, 1);
319 r
= sscanf(rvalue
, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
320 &n
->ether_addr_octet
[0],
321 &n
->ether_addr_octet
[1],
322 &n
->ether_addr_octet
[2],
323 &n
->ether_addr_octet
[3],
324 &n
->ether_addr_octet
[4],
325 &n
->ether_addr_octet
[5]);
327 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not a valid MAC address, ignoring assignment: %s", rvalue
);
338 void serialize_in_addrs(FILE *f
, const struct in_addr
*addresses
, size_t size
) {
345 for (i
= 0; i
< size
; i
++)
346 fprintf(f
, "%s%s", inet_ntoa(addresses
[i
]),
347 (i
< (size
- 1)) ? " ": "");
350 int deserialize_in_addrs(struct in_addr
**ret
, const char *string
) {
351 _cleanup_free_
struct in_addr
*addresses
= NULL
;
353 const char *word
, *state
;
359 FOREACH_WORD(word
, len
, string
, state
) {
360 _cleanup_free_
char *addr_str
= NULL
;
361 struct in_addr
*new_addresses
;
364 new_addresses
= realloc(addresses
, (size
+ 1) * sizeof(struct in_addr
));
368 addresses
= new_addresses
;
370 addr_str
= strndup(word
, len
);
374 r
= inet_pton(AF_INET
, addr_str
, &(addresses
[size
]));
387 void serialize_in6_addrs(FILE *f
, const struct in6_addr
*addresses
,
395 for (i
= 0; i
< size
; i
++)
396 fprintf(f
, SD_NDISC_ADDRESS_FORMAT_STR
"%s",
397 SD_NDISC_ADDRESS_FORMAT_VAL(addresses
[i
]),
398 (i
< (size
- 1)) ? " ": "");
401 int deserialize_in6_addrs(struct in6_addr
**ret
, const char *string
) {
402 _cleanup_free_
struct in6_addr
*addresses
= NULL
;
404 const char *word
, *state
;
410 FOREACH_WORD(word
, len
, string
, state
) {
411 _cleanup_free_
char *addr_str
= NULL
;
412 struct in6_addr
*new_addresses
;
415 new_addresses
= realloc(addresses
, (size
+ 1) * sizeof(struct in6_addr
));
419 addresses
= new_addresses
;
421 addr_str
= strndup(word
, len
);
425 r
= inet_pton(AF_INET6
, addr_str
, &(addresses
[size
]));
438 void serialize_dhcp_routes(FILE *f
, const char *key
, struct sd_dhcp_route
*routes
, size_t size
) {
446 fprintf(f
, "%s=", key
);
448 for (i
= 0; i
< size
; i
++) {
449 fprintf(f
, "%s/%" PRIu8
, inet_ntoa(routes
[i
].dst_addr
),
450 routes
[i
].dst_prefixlen
);
451 fprintf(f
, ",%s%s", inet_ntoa(routes
[i
].gw_addr
),
452 (i
< (size
- 1)) ? " ": "");
458 int deserialize_dhcp_routes(struct sd_dhcp_route
**ret
, size_t *ret_size
, size_t *ret_allocated
, const char *string
) {
459 _cleanup_free_
struct sd_dhcp_route
*routes
= NULL
;
460 size_t size
= 0, allocated
= 0;
461 const char *word
, *state
;
466 assert(ret_allocated
);
469 FOREACH_WORD(word
, len
, string
, state
) {
470 /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
471 _cleanup_free_
char* entry
= NULL
;
476 if (!GREEDY_REALLOC(routes
, allocated
, size
+ 1))
479 entry
= strndup(word
, len
);
486 tok_end
= strchr(tok
, '/');
491 r
= inet_aton(tok
, &routes
[size
].dst_addr
);
497 /* get the prefixlen */
498 tok_end
= strchr(tok
, ',');
504 r
= safe_atou(tok
, &n
);
508 routes
[size
].dst_prefixlen
= (uint8_t) n
;
511 /* get the gateway */
512 r
= inet_aton(tok
, &routes
[size
].gw_addr
);
520 *ret_allocated
= allocated
;
527 int serialize_dhcp_option(FILE *f
, const char *key
, const void *data
, size_t size
) {
528 _cleanup_free_
char *hex_buf
= NULL
;
534 hex_buf
= hexmem(data
, size
);
538 fprintf(f
, "%s=%s\n", key
, hex_buf
);
543 int deserialize_dhcp_option(void **data
, size_t *data_len
, const char *string
) {
548 if (strlen(string
) % 2)
551 return unhexmem(string
, strlen(string
), (void **)data
, data_len
);