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 #define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a)
39 int net_get_unique_predictable_data(struct udev_device *device, uint8_t result[8]) {
41 const char *name = NULL, *field = NULL;
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);
56 sz = sizeof(sd_id128_t) + l;
59 /* fetch some persistent data unique to this machine */
60 r = sd_id128_get_machine((sd_id128_t*) v);
63 memcpy(v + sizeof(sd_id128_t), name, l);
65 /* Let's hash the machine ID plus the device name. We
66 * use a fixed, but originally randomly created hash
68 siphash24(result, v, sz, HASH_KEY.bytes);
73 bool net_match_config(const struct ether_addr *match_mac,
74 const char *match_path,
75 const char *match_driver,
76 const char *match_type,
77 const char *match_name,
78 Condition *match_host,
79 Condition *match_virt,
80 Condition *match_kernel,
81 Condition *match_arch,
82 const struct ether_addr *dev_mac,
84 const char *dev_parent_driver,
85 const char *dev_driver,
87 const char *dev_name) {
89 if (match_host && !condition_test_host(match_host))
92 if (match_virt && !condition_test_virtualization(match_virt))
95 if (match_kernel && !condition_test_kernel_command_line(match_kernel))
98 if (match_arch && !condition_test_architecture(match_arch))
101 if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN)))
104 if (match_path && (!dev_path || fnmatch(match_path, dev_path, 0)))
108 if (dev_parent_driver && !streq(match_driver, dev_parent_driver))
110 else if (!streq_ptr(match_driver, dev_driver))
114 if (match_type && !streq_ptr(match_type, dev_type))
117 if (match_name && (!dev_name || fnmatch(match_name, dev_name, 0)))
123 unsigned net_netmask_to_prefixlen(const struct in_addr *addr) {
126 return 32 - u32ctz(be32toh(addr->s_addr));
129 int config_parse_net_condition(const char *unit,
130 const char *filename,
133 unsigned section_line,
140 ConditionType cond = ltype;
141 Condition **ret = data;
144 _cleanup_free_ char *s = NULL;
151 negate = rvalue[0] == '!';
159 c = condition_new(cond, s, false, negate);
164 condition_free(*ret);
170 int config_parse_ifname(const char *unit,
171 const char *filename,
174 unsigned section_line,
193 if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
194 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
195 "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
211 int config_parse_ifalias(const char *unit,
212 const char *filename,
215 unsigned section_line,
234 if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) {
235 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
236 "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
252 int config_parse_hwaddr(const char *unit,
253 const char *filename,
256 unsigned section_line,
262 struct ether_addr **hwaddr = data;
263 struct ether_addr *n;
271 n = new0(struct ether_addr, 1);
275 r = sscanf(rvalue, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
276 &n->ether_addr_octet[0],
277 &n->ether_addr_octet[1],
278 &n->ether_addr_octet[2],
279 &n->ether_addr_octet[3],
280 &n->ether_addr_octet[4],
281 &n->ether_addr_octet[5]);
283 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
284 "Not a valid MAC address, ignoring assignment: %s", rvalue);
295 int net_parse_inaddr(const char *address, unsigned char *family, void *dst) {
303 r = inet_pton(AF_INET, address, dst);
305 /* succsefully parsed IPv4 address */
306 if (*family == AF_UNSPEC)
308 else if (*family != AF_INET)
313 /* not an IPv4 address, so let's try IPv6 */
314 r = inet_pton(AF_INET6, address, dst);
316 /* successfully parsed IPv6 address */
317 if (*family == AF_UNSPEC)
319 else if (*family != AF_INET6)
330 int load_module(struct kmod_ctx *ctx, const char *mod_name) {
331 struct kmod_list *modlist = NULL, *l;
337 r = kmod_module_new_from_lookup(ctx, mod_name, &modlist);
342 log_error("Failed to find module '%s'", mod_name);
346 kmod_list_foreach(l, modlist) {
347 struct kmod_module *mod = kmod_module_get_module(l);
349 r = kmod_module_probe_insert_module(mod, 0, NULL, NULL, NULL, NULL);
351 log_info("Inserted module '%s'", kmod_module_get_name(mod));
353 log_error("Failed to insert '%s': %s", kmod_module_get_name(mod),
357 kmod_module_unref(mod);
360 kmod_module_unref_list(modlist);
365 void serialize_in_addrs(FILE *f, const char *key, struct in_addr *addresses, size_t size) {
373 fprintf(f, "%s=", key);
375 for (i = 0; i < size; i++)
376 fprintf(f, "%s%s", inet_ntoa(addresses[i]),
377 (i < (size - 1)) ? " ": "");
382 int deserialize_in_addrs(struct in_addr **ret, size_t *ret_size, const char *string) {
383 _cleanup_free_ struct in_addr *addresses = NULL;
392 FOREACH_WORD(word, len, string, state) {
393 _cleanup_free_ char *addr_str = NULL;
394 struct in_addr *new_addresses;
397 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in_addr));
401 addresses = new_addresses;
403 addr_str = strndup(word, len);
407 r = inet_pton(AF_INET, addr_str, &(addresses[size]));
421 int deserialize_in6_addrs(struct in6_addr **ret, size_t *ret_size, const char *string) {
422 _cleanup_free_ struct in6_addr *addresses = NULL;
431 FOREACH_WORD(word, len, string, state) {
432 _cleanup_free_ char *addr_str = NULL;
433 struct in6_addr *new_addresses;
436 new_addresses = realloc(addresses, (size + 1) * sizeof(struct in6_addr));
440 addresses = new_addresses;
442 addr_str = strndup(word, len);
446 r = inet_pton(AF_INET6, addr_str, &(addresses[size]));