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 <netinet/ether.h>
24 #include <arpa/inet.h>
28 #include "siphash24.h"
29 #include "libudev-private.h"
30 #include "network-internal.h"
34 #include "conf-parser.h"
35 #include "condition.h"
37 const char *net_get_name(struct udev_device *device) {
38 const char *name = NULL, *field = NULL;
42 /* fetch some persistent data unique (on this machine) to this device */
43 FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT",
44 "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") {
45 name = udev_device_get_property_value(device, field);
53 #define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a)
55 int net_get_unique_predictable_data(struct udev_device *device, uint8_t result[8]) {
57 const char *name = NULL;
63 name = net_get_name(device);
68 sz = sizeof(sd_id128_t) + l;
71 /* fetch some persistent data unique to this machine */
72 r = sd_id128_get_machine((sd_id128_t*) v);
75 memcpy(v + sizeof(sd_id128_t), name, l);
77 /* Let's hash the machine ID plus the device name. We
78 * use a fixed, but originally randomly created hash
80 siphash24(result, v, sz, HASH_KEY.bytes);
85 bool net_match_config(const struct ether_addr *match_mac,
86 const char *match_path,
87 const char *match_driver,
88 const char *match_type,
89 const char *match_name,
90 Condition *match_host,
91 Condition *match_virt,
92 Condition *match_kernel,
93 Condition *match_arch,
94 const struct ether_addr *dev_mac,
96 const char *dev_parent_driver,
97 const char *dev_driver,
99 const char *dev_name) {
101 if (match_host && !condition_test_host(match_host))
104 if (match_virt && !condition_test_virtualization(match_virt))
107 if (match_kernel && !condition_test_kernel_command_line(match_kernel))
110 if (match_arch && !condition_test_architecture(match_arch))
113 if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN)))
116 if (match_path && (!dev_path || fnmatch(match_path, dev_path, 0)))
120 if (dev_parent_driver && !streq(match_driver, dev_parent_driver))
122 else if (!streq_ptr(match_driver, dev_driver))
126 if (match_type && !streq_ptr(match_type, dev_type))
129 if (match_name && (!dev_name || fnmatch(match_name, dev_name, 0)))
135 unsigned net_netmask_to_prefixlen(const struct in_addr *addr) {
138 return 32 - u32ctz(be32toh(addr->s_addr));
141 int config_parse_net_condition(const char *unit,
142 const char *filename,
145 unsigned section_line,
152 ConditionType cond = ltype;
153 Condition **ret = data;
156 _cleanup_free_ char *s = NULL;
163 negate = rvalue[0] == '!';
171 c = condition_new(cond, s, false, negate);
176 condition_free(*ret);
182 int config_parse_ifname(const char *unit,
183 const char *filename,
186 unsigned section_line,
194 _cleanup_free_ char *n = NULL;
205 if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
206 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
207 "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
222 int config_parse_ifalias(const char *unit,
223 const char *filename,
226 unsigned section_line,
245 if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) {
246 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
247 "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
263 int config_parse_hwaddr(const char *unit,
264 const char *filename,
267 unsigned section_line,
273 struct ether_addr **hwaddr = data;
274 struct ether_addr *n;
282 n = new0(struct ether_addr, 1);
286 r = sscanf(rvalue, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
287 &n->ether_addr_octet[0],
288 &n->ether_addr_octet[1],
289 &n->ether_addr_octet[2],
290 &n->ether_addr_octet[3],
291 &n->ether_addr_octet[4],
292 &n->ether_addr_octet[5]);
294 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
295 "Not a valid MAC address, ignoring assignment: %s", rvalue);
306 int net_parse_inaddr(const char *address, unsigned char *family, void *dst) {
314 r = inet_pton(AF_INET, address, dst);
316 /* succsefully parsed IPv4 address */
317 if (*family == AF_UNSPEC)
319 else if (*family != AF_INET)
324 /* not an IPv4 address, so let's try IPv6 */
325 r = inet_pton(AF_INET6, address, dst);
327 /* successfully parsed IPv6 address */
328 if (*family == AF_UNSPEC)
330 else if (*family != AF_INET6)
341 void serialize_in_addrs(FILE *f, const char *key, struct in_addr *addresses, size_t size) {
349 fprintf(f, "%s=", key);
351 for (i = 0; i < size; i++)
352 fprintf(f, "%s%s", inet_ntoa(addresses[i]),
353 (i < (size - 1)) ? " ": "");
358 int deserialize_in_addrs(struct in_addr **ret, size_t *ret_size, const char *string) {
359 _cleanup_free_ struct in_addr *addresses = NULL;
368 FOREACH_WORD(word, len, string, state) {
369 _cleanup_free_ char *addr_str = NULL;
370 struct in_addr *new_addresses;
373 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in_addr));
377 addresses = new_addresses;
379 addr_str = strndup(word, len);
383 r = inet_pton(AF_INET, addr_str, &(addresses[size]));
397 int deserialize_in6_addrs(struct in6_addr **ret, size_t *ret_size, const char *string) {
398 _cleanup_free_ struct in6_addr *addresses = NULL;
407 FOREACH_WORD(word, len, string, state) {
408 _cleanup_free_ char *addr_str = NULL;
409 struct in6_addr *new_addresses;
412 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in6_addr));
416 addresses = new_addresses;
418 addr_str = strndup(word, len);
422 r = inet_pton(AF_INET6, addr_str, &(addresses[size]));