diff --git a/meson.build b/meson.build index f406d595e6..ab2404c3c4 100644 --- a/meson.build +++ b/meson.build @@ -3194,7 +3194,6 @@ public_programs += executable( c_args : '-DLOG_REALM=LOG_REALM_UDEV', include_directories : includes, link_with : [libudev_core, - libsystemd_network, libudev_static], dependencies : [versiondep, threads, diff --git a/src/fuzz/meson.build b/src/fuzz/meson.build index a5fac5980e..f8f0c386b3 100644 --- a/src/fuzz/meson.build +++ b/src/fuzz/meson.build @@ -108,7 +108,6 @@ fuzzers += [ [['src/fuzz/fuzz-udev-rules.c'], [libudev_core, libudev_static, - libsystemd_network, libshared], [threads, libacl]], diff --git a/src/libsystemd-network/dhcp-identifier.c b/src/libsystemd-network/dhcp-identifier.c index ea9c77aa9d..953fef19fa 100644 --- a/src/libsystemd-network/dhcp-identifier.c +++ b/src/libsystemd-network/dhcp-identifier.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include +#include #include #include "sd-device.h" @@ -8,7 +9,7 @@ #include "dhcp-identifier.h" #include "dhcp6-protocol.h" -#include "network-internal.h" +#include "network-util.h" #include "siphash24.h" #include "sparse-endian.h" #include "stdio-util.h" diff --git a/src/libsystemd-network/meson.build b/src/libsystemd-network/meson.build index 604cfd999b..8c68d74c82 100644 --- a/src/libsystemd-network/meson.build +++ b/src/libsystemd-network/meson.build @@ -17,6 +17,7 @@ sources = files(''' arp-util.h arp-util.c network-internal.c + network-internal.h sd-ndisc.c ndisc-internal.h ndisc-router.h @@ -42,10 +43,7 @@ sources = files(''' sd-lldp.c '''.split()) -network_internal_h = files('network-internal.h') - libsystemd_network = static_library( 'systemd-network', sources, - network_internal_h, include_directories : includes) diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index e4a07419e4..12b73cd50d 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -4,658 +4,15 @@ #include #include -#include "sd-id128.h" #include "sd-ndisc.h" #include "alloc-util.h" -#include "arphrd-list.h" -#include "condition.h" -#include "conf-parser.h" -#include "device-util.h" #include "dhcp-lease-internal.h" -#include "env-util.h" -#include "ether-addr-util.h" +#include "extract-word.h" #include "hexdecoct.h" #include "log.h" #include "network-internal.h" #include "parse-util.h" -#include "siphash24.h" -#include "socket-util.h" -#include "string-table.h" -#include "string-util.h" -#include "strv.h" -#include "utf8.h" -#include "util.h" - -const char *net_get_name_persistent(sd_device *device) { - const char *name, *field; - - assert(device); - - /* fetch some persistent data unique (on this machine) to this device */ - FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") - if (sd_device_get_property_value(device, field, &name) >= 0) - return name; - - return NULL; -} - -#define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a) - -int net_get_unique_predictable_data(sd_device *device, bool use_sysname, uint64_t *result) { - size_t l, sz = 0; - const char *name; - int r; - uint8_t *v; - - assert(device); - - /* net_get_name_persistent() will return one of the device names based on stable information about - * the device. If this is not available, we fall back to using the actual device name. */ - name = net_get_name_persistent(device); - if (!name && use_sysname) - (void) sd_device_get_sysname(device, &name); - if (!name) - return log_device_debug_errno(device, SYNTHETIC_ERRNO(ENODATA), - "No stable identifying information found"); - - log_device_debug(device, "Using \"%s\" as stable identifying information", name); - l = strlen(name); - sz = sizeof(sd_id128_t) + l; - v = newa(uint8_t, sz); - - /* Fetch some persistent data unique to this machine */ - r = sd_id128_get_machine((sd_id128_t*) v); - if (r < 0) - return r; - memcpy(v + sizeof(sd_id128_t), name, l); - - /* Let's hash the machine ID plus the device name. We use - * a fixed, but originally randomly created hash key here. */ - *result = htole64(siphash24(v, sz, HASH_KEY.bytes)); - return 0; -} - -static bool net_condition_test_strv(char * const *patterns, const char *string) { - char * const *p; - bool match = false, has_positive_rule = false; - - if (strv_isempty(patterns)) - return true; - - STRV_FOREACH(p, patterns) { - const char *q = *p; - bool invert; - - invert = *q == '!'; - q += invert; - - if (!invert) - has_positive_rule = true; - - if (string && fnmatch(q, string, 0) == 0) { - if (invert) - return false; - else - match = true; - } - } - - return has_positive_rule ? match : true; -} - -static bool net_condition_test_ifname(char * const *patterns, const char *ifname, char * const *alternative_names) { - if (net_condition_test_strv(patterns, ifname)) - return true; - - char * const *p; - STRV_FOREACH(p, alternative_names) - if (net_condition_test_strv(patterns, *p)) - return true; - - return false; -} - -static int net_condition_test_property(char * const *match_property, sd_device *device) { - char * const *p; - - if (strv_isempty(match_property)) - return true; - - STRV_FOREACH(p, match_property) { - _cleanup_free_ char *key = NULL; - const char *val, *dev_val; - bool invert, v; - - invert = **p == '!'; - - val = strchr(*p + invert, '='); - if (!val) - return -EINVAL; - - key = strndup(*p + invert, val - *p - invert); - if (!key) - return -ENOMEM; - - val++; - - v = device && - sd_device_get_property_value(device, key, &dev_val) >= 0 && - fnmatch(val, dev_val, 0) == 0; - - if (invert ? v : !v) - return false; - } - - return true; -} - -static const char *const wifi_iftype_table[NL80211_IFTYPE_MAX+1] = { - [NL80211_IFTYPE_ADHOC] = "ad-hoc", - [NL80211_IFTYPE_STATION] = "station", - [NL80211_IFTYPE_AP] = "ap", - [NL80211_IFTYPE_AP_VLAN] = "ap-vlan", - [NL80211_IFTYPE_WDS] = "wds", - [NL80211_IFTYPE_MONITOR] = "monitor", - [NL80211_IFTYPE_MESH_POINT] = "mesh-point", - [NL80211_IFTYPE_P2P_CLIENT] = "p2p-client", - [NL80211_IFTYPE_P2P_GO] = "p2p-go", - [NL80211_IFTYPE_P2P_DEVICE] = "p2p-device", - [NL80211_IFTYPE_OCB] = "ocb", - [NL80211_IFTYPE_NAN] = "nan", -}; - -DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(wifi_iftype, enum nl80211_iftype); - -char *link_get_type_string(unsigned short iftype, sd_device *device) { - const char *t, *devtype; - char *p; - - if (device && - sd_device_get_devtype(device, &devtype) >= 0 && - !isempty(devtype)) - return strdup(devtype); - - t = arphrd_to_name(iftype); - if (!t) - return NULL; - - p = strdup(t); - if (!p) - return NULL; - - ascii_strlower(p); - return p; -} - -bool net_match_config(Set *match_mac, - Set *match_permanent_mac, - char * const *match_paths, - char * const *match_drivers, - char * const *match_iftypes, - char * const *match_names, - char * const *match_property, - char * const *match_wifi_iftype, - char * const *match_ssid, - Set *match_bssid, - sd_device *device, - const struct ether_addr *dev_mac, - const struct ether_addr *dev_permanent_mac, - const char *dev_driver, - unsigned short dev_iftype, - const char *dev_name, - char * const *alternative_names, - enum nl80211_iftype dev_wifi_iftype, - const char *dev_ssid, - const struct ether_addr *dev_bssid) { - - _cleanup_free_ char *dev_iftype_str; - const char *dev_path = NULL; - - dev_iftype_str = link_get_type_string(dev_iftype, device); - - if (device) { - const char *mac_str; - - (void) sd_device_get_property_value(device, "ID_PATH", &dev_path); - if (!dev_driver) - (void) sd_device_get_property_value(device, "ID_NET_DRIVER", &dev_driver); - if (!dev_name) - (void) sd_device_get_sysname(device, &dev_name); - if (!dev_mac && - sd_device_get_sysattr_value(device, "address", &mac_str) >= 0) - dev_mac = ether_aton(mac_str); - } - - if (match_mac && (!dev_mac || !set_contains(match_mac, dev_mac))) - return false; - - if (match_permanent_mac && - (!dev_permanent_mac || - ether_addr_is_null(dev_permanent_mac) || - !set_contains(match_permanent_mac, dev_permanent_mac))) - return false; - - if (!net_condition_test_strv(match_paths, dev_path)) - return false; - - if (!net_condition_test_strv(match_drivers, dev_driver)) - return false; - - if (!net_condition_test_strv(match_iftypes, dev_iftype_str)) - return false; - - if (!net_condition_test_ifname(match_names, dev_name, alternative_names)) - return false; - - if (!net_condition_test_property(match_property, device)) - return false; - - if (!net_condition_test_strv(match_wifi_iftype, wifi_iftype_to_string(dev_wifi_iftype))) - return false; - - if (!net_condition_test_strv(match_ssid, dev_ssid)) - return false; - - if (match_bssid && (!dev_bssid || !set_contains(match_bssid, dev_bssid))) - return false; - - return true; -} - -int config_parse_net_condition(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - ConditionType cond = ltype; - Condition **list = data, *c; - bool negate; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if (isempty(rvalue)) { - *list = condition_free_list_type(*list, cond); - return 0; - } - - negate = rvalue[0] == '!'; - if (negate) - rvalue++; - - c = condition_new(cond, rvalue, false, negate); - if (!c) - return log_oom(); - - /* Drop previous assignment. */ - *list = condition_free_list_type(*list, cond); - - LIST_PREPEND(conditions, *list, c); - return 0; -} - -int config_parse_match_strv( - const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - const char *p = rvalue; - char ***sv = data; - bool invert; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if (isempty(rvalue)) { - *sv = strv_free(*sv); - return 0; - } - - invert = *p == '!'; - p += invert; - - for (;;) { - _cleanup_free_ char *word = NULL, *k = NULL; - - r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE); - if (r == 0) - return 0; - if (r == -ENOMEM) - return log_oom(); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue); - return 0; - } - - if (invert) { - k = strjoin("!", word); - if (!k) - return log_oom(); - } else - k = TAKE_PTR(word); - - r = strv_consume(sv, TAKE_PTR(k)); - if (r < 0) - return log_oom(); - } -} - -int config_parse_match_ifnames( - const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - const char *p = rvalue; - char ***sv = data; - bool invert; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - invert = *p == '!'; - p += invert; - - for (;;) { - _cleanup_free_ char *word = NULL, *k = NULL; - - r = extract_first_word(&p, &word, NULL, 0); - if (r == 0) - return 0; - if (r == -ENOMEM) - return log_oom(); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, 0, - "Failed to parse interface name list: %s", rvalue); - return 0; - } - - if (!ifname_valid_full(word, ltype)) { - log_syntax(unit, LOG_ERR, filename, line, 0, - "Interface name is not valid or too long, ignoring assignment: %s", word); - continue; - } - - if (invert) { - k = strjoin("!", word); - if (!k) - return log_oom(); - } else - k = TAKE_PTR(word); - - r = strv_consume(sv, TAKE_PTR(k)); - if (r < 0) - return log_oom(); - } -} - -int config_parse_match_property( - const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - const char *p = rvalue; - char ***sv = data; - bool invert; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - invert = *p == '!'; - p += invert; - - for (;;) { - _cleanup_free_ char *word = NULL, *k = NULL; - - r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE); - if (r == 0) - return 0; - if (r == -ENOMEM) - return log_oom(); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, 0, - "Invalid syntax, ignoring: %s", rvalue); - return 0; - } - - if (!env_assignment_is_valid(word)) { - log_syntax(unit, LOG_ERR, filename, line, 0, - "Invalid property or value, ignoring assignment: %s", word); - continue; - } - - if (invert) { - k = strjoin("!", word); - if (!k) - return log_oom(); - } else - k = TAKE_PTR(word); - - r = strv_consume(sv, TAKE_PTR(k)); - if (r < 0) - return log_oom(); - } -} - -int config_parse_ifalias(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - char **s = data; - _cleanup_free_ char *n = NULL; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - n = strdup(rvalue); - if (!n) - return log_oom(); - - if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue); - return 0; - } - - if (isempty(n)) - *s = mfree(*s); - else - free_and_replace(*s, n); - - return 0; -} - -int config_parse_hwaddr(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - _cleanup_free_ struct ether_addr *n = NULL; - struct ether_addr **hwaddr = data; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - n = new0(struct ether_addr, 1); - if (!n) - return log_oom(); - - r = ether_addr_from_string(rvalue, n); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Not a valid MAC address, ignoring assignment: %s", rvalue); - return 0; - } - - free_and_replace(*hwaddr, n); - - return 0; -} - -int config_parse_hwaddrs(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - _cleanup_set_free_free_ Set *s = NULL; - const char *p = rvalue; - Set **hwaddrs = data; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if (isempty(rvalue)) { - /* Empty assignment resets the list */ - *hwaddrs = set_free_free(*hwaddrs); - return 0; - } - - s = set_new(ðer_addr_hash_ops); - if (!s) - return log_oom(); - - for (;;) { - _cleanup_free_ char *word = NULL; - _cleanup_free_ struct ether_addr *n = NULL; - - r = extract_first_word(&p, &word, NULL, 0); - if (r == 0) - break; - if (r == -ENOMEM) - return log_oom(); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue); - return 0; - } - - n = new(struct ether_addr, 1); - if (!n) - return log_oom(); - - r = ether_addr_from_string(word, n); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address, ignoring: %s", word); - continue; - } - - r = set_put(s, n); - if (r < 0) - return log_oom(); - if (r > 0) - n = NULL; /* avoid cleanup */ - } - - r = set_ensure_allocated(hwaddrs, ðer_addr_hash_ops); - if (r < 0) - return log_oom(); - - r = set_move(*hwaddrs, s); - if (r < 0) - return log_oom(); - - return 0; -} - -int config_parse_bridge_port_priority( - const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - uint16_t i; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - r = safe_atou16(rvalue, &i); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, - "Failed to parse bridge port priority, ignoring: %s", rvalue); - return 0; - } - - if (i > LINK_BRIDGE_PORT_PRIORITY_MAX) { - log_syntax(unit, LOG_ERR, filename, line, r, - "Bridge port priority is larger than maximum %u, ignoring: %s", LINK_BRIDGE_PORT_PRIORITY_MAX, rvalue); - return 0; - } - - *((uint16_t *)data) = i; - - return 0; -} size_t serialize_in_addrs(FILE *f, const struct in_addr *addresses, diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h index 5dae5ab306..e5b853c0cd 100644 --- a/src/libsystemd-network/network-internal.h +++ b/src/libsystemd-network/network-internal.h @@ -1,53 +1,11 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#include #include +#include -#include "sd-device.h" #include "sd-dhcp-lease.h" -#include "conf-parser.h" -#include "set.h" -#include "strv.h" - -#define LINK_BRIDGE_PORT_PRIORITY_INVALID 128 -#define LINK_BRIDGE_PORT_PRIORITY_MAX 63 - -char *link_get_type_string(unsigned short iftype, sd_device *device); -bool net_match_config(Set *match_mac, - Set *match_permanent_mac, - char * const *match_paths, - char * const *match_drivers, - char * const *match_iftypes, - char * const *match_names, - char * const *match_property, - char * const *match_wifi_iftype, - char * const *match_ssid, - Set *match_bssid, - sd_device *device, - const struct ether_addr *dev_mac, - const struct ether_addr *dev_permanent_mac, - const char *dev_driver, - unsigned short dev_iftype, - const char *dev_name, - char * const *alternative_names, - enum nl80211_iftype dev_wifi_iftype, - const char *dev_ssid, - const struct ether_addr *dev_bssid); - -CONFIG_PARSER_PROTOTYPE(config_parse_net_condition); -CONFIG_PARSER_PROTOTYPE(config_parse_hwaddr); -CONFIG_PARSER_PROTOTYPE(config_parse_hwaddrs); -CONFIG_PARSER_PROTOTYPE(config_parse_match_strv); -CONFIG_PARSER_PROTOTYPE(config_parse_match_ifnames); -CONFIG_PARSER_PROTOTYPE(config_parse_match_property); -CONFIG_PARSER_PROTOTYPE(config_parse_ifalias); -CONFIG_PARSER_PROTOTYPE(config_parse_bridge_port_priority); - -int net_get_unique_predictable_data(sd_device *device, bool use_sysname, uint64_t *result); -const char *net_get_name_persistent(sd_device *device); - size_t serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size, diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index 30ac526fc9..97fd5fd4fb 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -21,10 +21,10 @@ #include "hexdecoct.h" #include "hostname-util.h" #include "in-addr-util.h" -#include "network-internal.h" #include "random-util.h" #include "socket-util.h" #include "string-table.h" +#include "strv.h" #include "util.h" #include "web-util.h" diff --git a/src/libsystemd/sd-network/network-util.c b/src/libsystemd/sd-network/network-util.c index 7753431fc0..acf7500970 100644 --- a/src/libsystemd/sd-network/network-util.c +++ b/src/libsystemd/sd-network/network-util.c @@ -1,8 +1,14 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +#include "sd-id128.h" + #include "alloc-util.h" +#include "arphrd-list.h" +#include "device-util.h" #include "fd-util.h" #include "network-util.h" +#include "siphash24.h" +#include "sparse-endian.h" #include "string-table.h" #include "strv.h" @@ -103,3 +109,72 @@ int parse_operational_state_range(const char *str, LinkOperationalStateRange *ou return 0; } + +char *link_get_type_string(sd_device *device, unsigned short iftype) { + const char *t; + char *p; + + if (device && + sd_device_get_devtype(device, &t) >= 0 && + !isempty(t)) + return strdup(t); + + t = arphrd_to_name(iftype); + if (!t) + return NULL; + + p = strdup(t); + if (!p) + return NULL; + + return ascii_strlower(p); +} + +const char *net_get_name_persistent(sd_device *device) { + const char *name, *field; + + assert(device); + + /* fetch some persistent data unique (on this machine) to this device */ + FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") + if (sd_device_get_property_value(device, field, &name) >= 0) + return name; + + return NULL; +} + +#define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a) + +int net_get_unique_predictable_data(sd_device *device, bool use_sysname, uint64_t *result) { + size_t l, sz = 0; + const char *name; + int r; + uint8_t *v; + + assert(device); + + /* net_get_name_persistent() will return one of the device names based on stable information about + * the device. If this is not available, we fall back to using the actual device name. */ + name = net_get_name_persistent(device); + if (!name && use_sysname) + (void) sd_device_get_sysname(device, &name); + if (!name) + return log_device_debug_errno(device, SYNTHETIC_ERRNO(ENODATA), + "No stable identifying information found"); + + log_device_debug(device, "Using \"%s\" as stable identifying information", name); + l = strlen(name); + sz = sizeof(sd_id128_t) + l; + v = newa(uint8_t, sz); + + /* Fetch some persistent data unique to this machine */ + r = sd_id128_get_machine((sd_id128_t*) v); + if (r < 0) + return r; + memcpy(v + sizeof(sd_id128_t), name, l); + + /* Let's hash the machine ID plus the device name. We use + * a fixed, but originally randomly created hash key here. */ + *result = htole64(siphash24(v, sz, HASH_KEY.bytes)); + return 0; +} diff --git a/src/libsystemd/sd-network/network-util.h b/src/libsystemd/sd-network/network-util.h index 8cfd894b5a..762b15746f 100644 --- a/src/libsystemd/sd-network/network-util.h +++ b/src/libsystemd/sd-network/network-util.h @@ -1,6 +1,10 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include +#include + +#include "sd-device.h" #include "sd-network.h" #include "macro.h" @@ -58,3 +62,7 @@ typedef struct LinkOperationalStateRange { LINK_OPERSTATE_ROUTABLE } int parse_operational_state_range(const char *str, LinkOperationalStateRange *out); + +char *link_get_type_string(sd_device *device, unsigned short iftype); +int net_get_unique_predictable_data(sd_device *device, bool use_sysname, uint64_t *result); +const char *net_get_name_persistent(sd_device *device); diff --git a/src/network/meson.build b/src/network/meson.build index f5ca183088..4123873c60 100644 --- a/src/network/meson.build +++ b/src/network/meson.build @@ -171,7 +171,7 @@ systemd_networkd_wait_online_sources = files(''' wait-online/manager.c wait-online/manager.h wait-online/wait-online.c -'''.split()) + network_internal_h +'''.split()) networkctl_sources = files('networkctl.c') @@ -214,7 +214,6 @@ if conf.get('ENABLE_NETWORKD') == 1 libnetworkd_core = static_library( 'networkd-core', sources, - network_internal_h, networkd_gperf_c, networkd_network_gperf_c, netdev_gperf_c, diff --git a/src/network/netdev/bridge.c b/src/network/netdev/bridge.c index 1f59cd8b42..38432f1578 100644 --- a/src/network/netdev/bridge.c +++ b/src/network/netdev/bridge.c @@ -4,7 +4,6 @@ #include "bridge.h" #include "netlink-util.h" -#include "network-internal.h" #include "networkd-manager.h" #include "string-table.h" #include "vlan-util.h" @@ -342,6 +341,47 @@ int config_parse_bridge_igmp_version( return 0; } +int config_parse_bridge_port_priority( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + uint16_t i; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + /* This is used in networkd-network-gperf.gperf. */ + + r = safe_atou16(rvalue, &i); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to parse bridge port priority, ignoring: %s", rvalue); + return 0; + } + + if (i > LINK_BRIDGE_PORT_PRIORITY_MAX) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Bridge port priority is larger than maximum %u, ignoring: %s", + LINK_BRIDGE_PORT_PRIORITY_MAX, rvalue); + return 0; + } + + *((uint16_t *)data) = i; + + return 0; +} + static void bridge_init(NetDev *n) { Bridge *b; diff --git a/src/network/netdev/bridge.h b/src/network/netdev/bridge.h index d6abda99e8..f3276c5c41 100644 --- a/src/network/netdev/bridge.h +++ b/src/network/netdev/bridge.h @@ -7,6 +7,9 @@ #include "conf-parser.h" #include "netdev.h" +#define LINK_BRIDGE_PORT_PRIORITY_INVALID 128 +#define LINK_BRIDGE_PORT_PRIORITY_MAX 63 + typedef struct Bridge { NetDev meta; @@ -45,3 +48,4 @@ MulticastRouter multicast_router_from_string(const char *s) _pure_; CONFIG_PARSER_PROTOTYPE(config_parse_multicast_router); CONFIG_PARSER_PROTOTYPE(config_parse_bridge_igmp_version); +CONFIG_PARSER_PROTOTYPE(config_parse_bridge_port_priority); diff --git a/src/network/netdev/macsec.c b/src/network/netdev/macsec.c index 82e71c3920..313277ca16 100644 --- a/src/network/netdev/macsec.c +++ b/src/network/netdev/macsec.c @@ -12,7 +12,6 @@ #include "macsec.h" #include "memory-util.h" #include "netlink-util.h" -#include "network-internal.h" #include "networkd-manager.h" #include "path-util.h" #include "socket-util.h" diff --git a/src/network/netdev/netdev-gperf.gperf b/src/network/netdev/netdev-gperf.gperf index 4e89761f2c..35cd01ef0d 100644 --- a/src/network/netdev/netdev-gperf.gperf +++ b/src/network/netdev/netdev-gperf.gperf @@ -7,23 +7,23 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"") #include "bond.h" #include "bridge.h" #include "conf-parser.h" +#include "fou-tunnel.h" #include "geneve.h" #include "ipvlan.h" +#include "l2tp-tunnel.h" #include "macsec.h" #include "macvlan.h" +#include "net-condition.h" +#include "netdev.h" #include "tunnel.h" #include "tuntap.h" #include "veth.h" #include "vlan-util.h" #include "vlan.h" -#include "vxlan.h" #include "vrf.h" -#include "netdev.h" -#include "network-internal.h" #include "vxcan.h" +#include "vxlan.h" #include "wireguard.h" -#include "fou-tunnel.h" -#include "l2tp-tunnel.h" #include "xfrm.h" %} struct ConfigPerfItem; diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c index 9f390b5781..71a4f603be 100644 --- a/src/network/netdev/netdev.c +++ b/src/network/netdev/netdev.c @@ -23,7 +23,6 @@ #include "netdev.h" #include "netdevsim.h" #include "netlink-util.h" -#include "network-internal.h" #include "networkd-manager.h" #include "nlmon.h" #include "path-lookup.h" diff --git a/src/network/networkctl.c b/src/network/networkctl.c index 63a90bc13d..c415fb1a74 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -44,6 +44,7 @@ #include "main-func.h" #include "netlink-util.h" #include "network-internal.h" +#include "network-util.h" #include "pager.h" #include "parse-util.h" #include "pretty-print.h" @@ -704,7 +705,7 @@ static int list_links(int argc, char *argv[], void *userdata) { setup_state = strdup("unmanaged"); setup_state_to_color(setup_state, &on_color_setup, &off_color_setup); - t = link_get_type_string(links[i].iftype, links[i].sd_device); + t = link_get_type_string(links[i].sd_device, links[i].iftype); r = table_add_many(table, TABLE_INT, links[i].ifindex, @@ -1428,7 +1429,7 @@ static int link_status_one( (void) sd_device_get_property_value(info->sd_device, "ID_MODEL", &model); } - t = link_get_type_string(info->iftype, info->sd_device); + t = link_get_type_string(info->sd_device, info->iftype); (void) sd_network_link_get_network_file(info->ifindex, &network); diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 02d33841b6..3983b33527 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -17,7 +17,7 @@ #include "networkd-manager.h" #include "networkd-network.h" #include "string-table.h" -#include "string-util.h" +#include "strv.h" #include "sysctl-util.h" #include "web-util.h" diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index d4d4182ee5..95025acbfd 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -13,7 +13,6 @@ #include "hashmap.h" #include "hostname-util.h" #include "missing_network.h" -#include "network-internal.h" #include "networkd-address.h" #include "networkd-dhcp6.h" #include "networkd-link.h" diff --git a/src/network/networkd-network-bus.c b/src/network/networkd-network-bus.c index 0e5f1488d8..8c52faf185 100644 --- a/src/network/networkd-network-bus.c +++ b/src/network/networkd-network-bus.c @@ -45,11 +45,11 @@ const sd_bus_vtable network_vtable[] = { SD_BUS_PROPERTY("Description", "s", NULL, offsetof(Network, description), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("SourcePath", "s", NULL, offsetof(Network, filename), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("MatchMAC", "as", property_get_ether_addrs, offsetof(Network, match_mac), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("MatchPath", "as", NULL, offsetof(Network, match_path), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("MatchDriver", "as", NULL, offsetof(Network, match_driver), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("MatchType", "as", NULL, offsetof(Network, match_type), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("MatchName", "as", NULL, offsetof(Network, match_name), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("MatchMAC", "as", property_get_ether_addrs, offsetof(Network, match.mac), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("MatchPath", "as", NULL, offsetof(Network, match.path), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("MatchDriver", "as", NULL, offsetof(Network, match.driver), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("MatchType", "as", NULL, offsetof(Network, match.iftype), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("MatchName", "as", NULL, offsetof(Network, match.ifname), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_VTABLE_END }; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 5cc9e3e8f6..619c6a8c59 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -5,7 +5,7 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"") #include #include "conf-parser.h" #include "netem.h" -#include "network-internal.h" +#include "net-condition.h" #include "networkd-address-label.h" #include "networkd-address.h" #include "networkd-can.h" @@ -41,16 +41,16 @@ struct ConfigPerfItem; %struct-type %includes %% -Match.MACAddress, config_parse_hwaddrs, 0, offsetof(Network, match_mac) -Match.PermanentMACAddress, config_parse_hwaddrs, 0, offsetof(Network, match_permanent_mac) -Match.Path, config_parse_match_strv, 0, offsetof(Network, match_path) -Match.Driver, config_parse_match_strv, 0, offsetof(Network, match_driver) -Match.Type, config_parse_match_strv, 0, offsetof(Network, match_type) -Match.WLANInterfaceType, config_parse_match_strv, 0, offsetof(Network, match_wlan_iftype) -Match.SSID, config_parse_match_strv, 0, offsetof(Network, match_ssid) -Match.BSSID, config_parse_hwaddrs, 0, offsetof(Network, match_bssid) -Match.Name, config_parse_match_ifnames, IFNAME_VALID_ALTERNATIVE, offsetof(Network, match_name) -Match.Property, config_parse_match_property, 0, offsetof(Network, match_property) +Match.MACAddress, config_parse_hwaddrs, 0, offsetof(Network, match.mac) +Match.PermanentMACAddress, config_parse_hwaddrs, 0, offsetof(Network, match.permanent_mac) +Match.Path, config_parse_match_strv, 0, offsetof(Network, match.path) +Match.Driver, config_parse_match_strv, 0, offsetof(Network, match.driver) +Match.Type, config_parse_match_strv, 0, offsetof(Network, match.iftype) +Match.WLANInterfaceType, config_parse_match_strv, 0, offsetof(Network, match.wifi_iftype) +Match.SSID, config_parse_match_strv, 0, offsetof(Network, match.ssid) +Match.BSSID, config_parse_hwaddrs, 0, offsetof(Network, match.bssid) +Match.Name, config_parse_match_ifnames, IFNAME_VALID_ALTERNATIVE, offsetof(Network, match.ifname) +Match.Property, config_parse_match_property, 0, offsetof(Network, match.property) Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(Network, conditions) Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(Network, conditions) Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(Network, conditions) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 3254641461..195bf3aaae 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -12,11 +12,11 @@ #include "fd-util.h" #include "hostname-util.h" #include "in-addr-util.h" -#include "networkd-dhcp-server.h" -#include "network-internal.h" +#include "net-condition.h" #include "networkd-address-label.h" #include "networkd-address.h" #include "networkd-dhcp-common.h" +#include "networkd-dhcp-server.h" #include "networkd-fdb.h" #include "networkd-manager.h" #include "networkd-mdb.h" @@ -161,11 +161,7 @@ int network_verify(Network *network) { assert(network); assert(network->filename); - if (set_isempty(network->match_mac) && set_isempty(network->match_permanent_mac) && - strv_isempty(network->match_path) && strv_isempty(network->match_driver) && - strv_isempty(network->match_type) && strv_isempty(network->match_name) && - strv_isempty(network->match_property) && strv_isempty(network->match_wlan_iftype) && - strv_isempty(network->match_ssid) && !network->conditions) + if (net_match_is_empty(&network->match) && !network->conditions) return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "%s: No valid settings found in the [Match] section, ignoring file. " "To match all interfaces, add Name=* in the [Match] section.", @@ -589,16 +585,7 @@ static Network *network_free(Network *network) { free(network->filename); - set_free_free(network->match_mac); - set_free_free(network->match_permanent_mac); - strv_free(network->match_path); - strv_free(network->match_driver); - strv_free(network->match_type); - strv_free(network->match_name); - strv_free(network->match_property); - strv_free(network->match_wlan_iftype); - strv_free(network->match_ssid); - set_free_free(network->match_bssid); + net_match_clear(&network->match); condition_free_list(network->conditions); free(network->description); @@ -705,13 +692,9 @@ int network_get(Manager *manager, unsigned short iftype, sd_device *device, assert(ret); ORDERED_HASHMAP_FOREACH(network, manager->networks) - if (net_match_config(network->match_mac, network->match_permanent_mac, - network->match_path, network->match_driver, - network->match_type, network->match_name, network->match_property, - network->match_wlan_iftype, network->match_ssid, network->match_bssid, - device, mac, permanent_mac, driver, iftype, + if (net_match_config(&network->match, device, mac, permanent_mac, driver, iftype, ifname, alternative_names, wlan_iftype, ssid, bssid)) { - if (network->match_name && device) { + if (network->match.ifname && device) { const char *attr; uint8_t name_assign_type = NET_NAME_UNKNOWN; diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index fd0fe056b2..17e7d432c9 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -10,6 +10,7 @@ #include "condition.h" #include "conf-parser.h" #include "hashmap.h" +#include "net-condition.h" #include "netdev.h" #include "networkd-brvlan.h" #include "networkd-dhcp-common.h" @@ -65,16 +66,7 @@ struct Network { char *description; /* [Match] section */ - Set *match_mac; - Set *match_permanent_mac; - char **match_path; - char **match_driver; - char **match_type; - char **match_name; - char **match_property; - char **match_wlan_iftype; - char **match_ssid; - Set *match_bssid; + NetMatch match; LIST_HEAD(Condition, conditions); /* Master or stacked netdevs */ diff --git a/src/network/test-networkd-conf.c b/src/network/test-networkd-conf.c index 0fe81886bd..d068a4644d 100644 --- a/src/network/test-networkd-conf.c +++ b/src/network/test-networkd-conf.c @@ -1,15 +1,12 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include "ether-addr-util.h" #include "hexdecoct.h" #include "log.h" #include "macro.h" -#include "set.h" -#include "string-util.h" - -#include "network-internal.h" +#include "net-condition.h" #include "networkd-conf.h" #include "networkd-network.h" +#include "strv.h" static void test_config_parse_duid_type_one(const char *rvalue, int ret, DUIDType expected, usec_t expected_time) { DUID actual = {}; @@ -174,7 +171,7 @@ static void test_config_parse_address_one(const char *rvalue, int family, unsign assert_se(network = new0(Network, 1)); network->n_ref = 1; assert_se(network->filename = strdup("hogehoge.network")); - assert_se(config_parse_match_ifnames("network", "filename", 1, "section", 1, "Name", 0, "*", &network->match_name, network) == 0); + assert_se(config_parse_match_ifnames("network", "filename", 1, "section", 1, "Name", 0, "*", &network->match.ifname, network) == 0); assert_se(config_parse_address("network", "filename", 1, "section", 1, "Address", 0, rvalue, network, network) == 0); assert_se(ordered_hashmap_size(network->addresses_by_section) == 1); assert_se(network_verify(network) >= 0); diff --git a/src/network/wait-online/manager.c b/src/network/wait-online/manager.c index 79994bd49c..e3b350f526 100644 --- a/src/network/wait-online/manager.c +++ b/src/network/wait-online/manager.c @@ -8,7 +8,6 @@ #include "link.h" #include "manager.h" #include "netlink-util.h" -#include "network-internal.h" #include "strv.h" #include "time-util.h" #include "util.h" diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 7690eac8cd..0331922124 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -20,7 +20,6 @@ #include "io-util.h" #include "missing_network.h" #include "netlink-util.h" -#include "network-internal.h" #include "ordered-set.h" #include "parse-util.h" #include "random-util.h" diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c index 35d301d9db..e8b3dc78f9 100644 --- a/src/shared/conf-parser.c +++ b/src/shared/conf-parser.c @@ -11,6 +11,7 @@ #include "conf-files.h" #include "conf-parser.h" #include "def.h" +#include "ether-addr-util.h" #include "extract-word.h" #include "fd-util.h" #include "fileio.h" @@ -24,6 +25,7 @@ #include "process-util.h" #include "rlimit-util.h" #include "sd-id128.h" +#include "set.h" #include "signal-util.h" #include "socket-util.h" #include "string-util.h" @@ -251,15 +253,16 @@ static int parse_line( } /* Go through the file and parse each line */ -int config_parse(const char *unit, - const char *filename, - FILE *f, - const char *sections, - ConfigItemLookup lookup, - const void *table, - ConfigParseFlags flags, - void *userdata, - usec_t *ret_mtime) { +int config_parse( + const char *unit, + const char *filename, + FILE *f, + const char *sections, + ConfigItemLookup lookup, + const void *table, + ConfigParseFlags flags, + void *userdata, + usec_t *ret_mtime) { _cleanup_free_ char *section = NULL, *continuation = NULL; _cleanup_fclose_ FILE *ours = NULL; @@ -522,16 +525,17 @@ DEFINE_PARSER(sec, usec_t, parse_sec); DEFINE_PARSER(sec_def_infinity, usec_t, parse_sec_def_infinity); DEFINE_PARSER(mode, mode_t, parse_mode); -int config_parse_iec_size(const char* unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +int config_parse_iec_size( + const char* unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { size_t *sz = data; uint64_t v; @@ -608,16 +612,17 @@ int config_parse_iec_uint64( return 0; } -int config_parse_bool(const char* unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +int config_parse_bool( + const char* unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { int k; bool *b = data; @@ -1181,16 +1186,17 @@ int config_parse_rlimit( return 0; } -int config_parse_permille(const char* unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +int config_parse_permille( + const char* unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { unsigned *permille = data; int r; @@ -1212,17 +1218,20 @@ int config_parse_permille(const char* unit, return 0; } -int config_parse_vlanprotocol(const char* unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +int config_parse_vlanprotocol( + const char* unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + int *vlan_protocol = data; + assert(filename); assert(lvalue); @@ -1244,4 +1253,106 @@ int config_parse_vlanprotocol(const char* unit, return 0; } +int config_parse_hwaddr( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + _cleanup_free_ struct ether_addr *n = NULL; + struct ether_addr **hwaddr = data; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + *hwaddr = mfree(*hwaddr); + return 0; + } + + n = new0(struct ether_addr, 1); + if (!n) + return log_oom(); + + r = ether_addr_from_string(rvalue, n); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Not a valid MAC address, ignoring assignment: %s", rvalue); + return 0; + } + + free_and_replace(*hwaddr, n); + + return 0; +} + +int config_parse_hwaddrs( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + Set **hwaddrs = data; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + /* Empty assignment resets the list */ + *hwaddrs = set_free_free(*hwaddrs); + return 0; + } + + for (const char *p = rvalue;;) { + _cleanup_free_ char *word = NULL; + _cleanup_free_ struct ether_addr *n = NULL; + + r = extract_first_word(&p, &word, NULL, 0); + if (r == 0) + return 0; + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Invalid syntax, ignoring: %s", rvalue); + return 0; + } + + n = new(struct ether_addr, 1); + if (!n) + return log_oom(); + + r = ether_addr_from_string(word, n); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Not a valid MAC address, ignoring: %s", word); + continue; + } + + r = set_ensure_put(hwaddrs, ðer_addr_hash_ops, n); + if (r < 0) + return log_oom(); + if (r > 0) + TAKE_PTR(n); /* avoid cleanup */ + } +} + DEFINE_CONFIG_PARSE(config_parse_percent, parse_percent, "Failed to parse percent value"); diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h index f115cb23af..b194821937 100644 --- a/src/shared/conf-parser.h +++ b/src/shared/conf-parser.h @@ -147,6 +147,8 @@ CONFIG_PARSER_PROTOTYPE(config_parse_ip_port); CONFIG_PARSER_PROTOTYPE(config_parse_mtu); CONFIG_PARSER_PROTOTYPE(config_parse_rlimit); CONFIG_PARSER_PROTOTYPE(config_parse_vlanprotocol); +CONFIG_PARSER_PROTOTYPE(config_parse_hwaddr); +CONFIG_PARSER_PROTOTYPE(config_parse_hwaddrs); CONFIG_PARSER_PROTOTYPE(config_parse_percent); typedef enum Disabled { diff --git a/src/shared/meson.build b/src/shared/meson.build index f30fe44995..53165541ac 100644 --- a/src/shared/meson.build +++ b/src/shared/meson.build @@ -169,6 +169,8 @@ shared_sources = files(''' module-util.h mount-util.c mount-util.h + net-condition.c + net-condition.h netif-naming-scheme.c netif-naming-scheme.h nscd-flush.c diff --git a/src/shared/net-condition.c b/src/shared/net-condition.c new file mode 100644 index 0000000000..bdc8bc3fe4 --- /dev/null +++ b/src/shared/net-condition.c @@ -0,0 +1,428 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include + +#include "condition.h" +#include "env-util.h" +#include "log.h" +#include "net-condition.h" +#include "network-util.h" +#include "socket-util.h" +#include "string-table.h" +#include "strv.h" + +void net_match_clear(NetMatch *match) { + if (!match) + return; + + match->mac = set_free_free(match->mac); + match->permanent_mac = set_free_free(match->permanent_mac); + match->path = strv_free(match->path); + match->driver = strv_free(match->driver); + match->iftype = strv_free(match->iftype); + match->ifname = strv_free(match->ifname); + match->property = strv_free(match->property); + match->wifi_iftype = strv_free(match->wifi_iftype); + match->ssid = strv_free(match->ssid); + match->bssid = set_free_free(match->bssid); +} + +bool net_match_is_empty(const NetMatch *match) { + assert(match); + + return + set_isempty(match->mac) && + set_isempty(match->permanent_mac) && + strv_isempty(match->path) && + strv_isempty(match->driver) && + strv_isempty(match->iftype) && + strv_isempty(match->ifname) && + strv_isempty(match->property) && + strv_isempty(match->wifi_iftype) && + strv_isempty(match->ssid) && + set_isempty(match->bssid); +} + +static bool net_condition_test_strv(char * const *patterns, const char *string) { + char * const *p; + bool match = false, has_positive_rule = false; + + if (strv_isempty(patterns)) + return true; + + STRV_FOREACH(p, patterns) { + const char *q = *p; + bool invert; + + invert = *q == '!'; + q += invert; + + if (!invert) + has_positive_rule = true; + + if (string && fnmatch(q, string, 0) == 0) { + if (invert) + return false; + else + match = true; + } + } + + return has_positive_rule ? match : true; +} + +static bool net_condition_test_ifname(char * const *patterns, const char *ifname, char * const *alternative_names) { + if (net_condition_test_strv(patterns, ifname)) + return true; + + char * const *p; + STRV_FOREACH(p, alternative_names) + if (net_condition_test_strv(patterns, *p)) + return true; + + return false; +} + +static int net_condition_test_property(char * const *match_property, sd_device *device) { + char * const *p; + + if (strv_isempty(match_property)) + return true; + + STRV_FOREACH(p, match_property) { + _cleanup_free_ char *key = NULL; + const char *val, *dev_val; + bool invert, v; + + invert = **p == '!'; + + val = strchr(*p + invert, '='); + if (!val) + return -EINVAL; + + key = strndup(*p + invert, val - *p - invert); + if (!key) + return -ENOMEM; + + val++; + + v = device && + sd_device_get_property_value(device, key, &dev_val) >= 0 && + fnmatch(val, dev_val, 0) == 0; + + if (invert ? v : !v) + return false; + } + + return true; +} + +static const char *const wifi_iftype_table[NL80211_IFTYPE_MAX+1] = { + [NL80211_IFTYPE_ADHOC] = "ad-hoc", + [NL80211_IFTYPE_STATION] = "station", + [NL80211_IFTYPE_AP] = "ap", + [NL80211_IFTYPE_AP_VLAN] = "ap-vlan", + [NL80211_IFTYPE_WDS] = "wds", + [NL80211_IFTYPE_MONITOR] = "monitor", + [NL80211_IFTYPE_MESH_POINT] = "mesh-point", + [NL80211_IFTYPE_P2P_CLIENT] = "p2p-client", + [NL80211_IFTYPE_P2P_GO] = "p2p-go", + [NL80211_IFTYPE_P2P_DEVICE] = "p2p-device", + [NL80211_IFTYPE_OCB] = "ocb", + [NL80211_IFTYPE_NAN] = "nan", +}; + +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(wifi_iftype, enum nl80211_iftype); + +bool net_match_config( + const NetMatch *match, + sd_device *device, + const struct ether_addr *mac, + const struct ether_addr *permanent_mac, + const char *driver, + unsigned short iftype, + const char *ifname, + char * const *alternative_names, + enum nl80211_iftype wifi_iftype, + const char *ssid, + const struct ether_addr *bssid) { + + _cleanup_free_ char *iftype_str; + const char *path = NULL; + + assert(match); + + iftype_str = link_get_type_string(device, iftype); + + if (device) { + const char *mac_str; + + (void) sd_device_get_property_value(device, "ID_PATH", &path); + if (!driver) + (void) sd_device_get_property_value(device, "ID_NET_DRIVER", &driver); + if (!ifname) + (void) sd_device_get_sysname(device, &ifname); + if (!mac && + sd_device_get_sysattr_value(device, "address", &mac_str) >= 0) + mac = ether_aton(mac_str); + } + + if (match->mac && (!mac || !set_contains(match->mac, mac))) + return false; + + if (match->permanent_mac && + (!permanent_mac || + ether_addr_is_null(permanent_mac) || + !set_contains(match->permanent_mac, permanent_mac))) + return false; + + if (!net_condition_test_strv(match->path, path)) + return false; + + if (!net_condition_test_strv(match->driver, driver)) + return false; + + if (!net_condition_test_strv(match->iftype, iftype_str)) + return false; + + if (!net_condition_test_ifname(match->ifname, ifname, alternative_names)) + return false; + + if (!net_condition_test_property(match->property, device)) + return false; + + if (!net_condition_test_strv(match->wifi_iftype, wifi_iftype_to_string(wifi_iftype))) + return false; + + if (!net_condition_test_strv(match->ssid, ssid)) + return false; + + if (match->bssid && (!bssid || !set_contains(match->bssid, bssid))) + return false; + + return true; +} + +int config_parse_net_condition( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + ConditionType cond = ltype; + Condition **list = data, *c; + bool negate; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + *list = condition_free_list_type(*list, cond); + return 0; + } + + negate = rvalue[0] == '!'; + if (negate) + rvalue++; + + c = condition_new(cond, rvalue, false, negate); + if (!c) + return log_oom(); + + /* Drop previous assignment. */ + *list = condition_free_list_type(*list, cond); + + LIST_PREPEND(conditions, *list, c); + return 0; +} + +int config_parse_match_strv( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + const char *p = rvalue; + char ***sv = data; + bool invert; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + *sv = strv_free(*sv); + return 0; + } + + invert = *p == '!'; + p += invert; + + for (;;) { + _cleanup_free_ char *word = NULL, *k = NULL; + + r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE); + if (r == 0) + return 0; + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Invalid syntax, ignoring: %s", rvalue); + return 0; + } + + if (invert) { + k = strjoin("!", word); + if (!k) + return log_oom(); + } else + k = TAKE_PTR(word); + + r = strv_consume(sv, TAKE_PTR(k)); + if (r < 0) + return log_oom(); + } +} + +int config_parse_match_ifnames( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + const char *p = rvalue; + char ***sv = data; + bool invert; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + *sv = strv_free(*sv); + return 0; + } + + invert = *p == '!'; + p += invert; + + for (;;) { + _cleanup_free_ char *word = NULL, *k = NULL; + + r = extract_first_word(&p, &word, NULL, 0); + if (r == 0) + return 0; + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Failed to parse interface name list, ignoring: %s", rvalue); + return 0; + } + + if (!ifname_valid_full(word, ltype)) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Interface name is not valid or too long, ignoring assignment: %s", word); + continue; + } + + if (invert) { + k = strjoin("!", word); + if (!k) + return log_oom(); + } else + k = TAKE_PTR(word); + + r = strv_consume(sv, TAKE_PTR(k)); + if (r < 0) + return log_oom(); + } +} + +int config_parse_match_property( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + const char *p = rvalue; + char ***sv = data; + bool invert; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + *sv = strv_free(*sv); + return 0; + } + + invert = *p == '!'; + p += invert; + + for (;;) { + _cleanup_free_ char *word = NULL, *k = NULL; + + r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE); + if (r == 0) + return 0; + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid syntax, ignoring: %s", rvalue); + return 0; + } + + if (!env_assignment_is_valid(word)) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid property or value, ignoring assignment: %s", word); + continue; + } + + if (invert) { + k = strjoin("!", word); + if (!k) + return log_oom(); + } else + k = TAKE_PTR(word); + + r = strv_consume(sv, TAKE_PTR(k)); + if (r < 0) + return log_oom(); + } +} diff --git a/src/shared/net-condition.h b/src/shared/net-condition.h new file mode 100644 index 0000000000..61058849a9 --- /dev/null +++ b/src/shared/net-condition.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include +#include + +#include "sd-device.h" + +#include "conf-parser.h" +#include "ether-addr-util.h" +#include "set.h" + +typedef struct NetMatch { + Set *mac; + Set *permanent_mac; + char **path; + char **driver; + char **iftype; + char **ifname; + char **property; + char **wifi_iftype; + char **ssid; + Set *bssid; +} NetMatch; + +void net_match_clear(NetMatch *match); +bool net_match_is_empty(const NetMatch *match); + +bool net_match_config( + const NetMatch *match, + sd_device *device, + const struct ether_addr *mac, + const struct ether_addr *permanent_mac, + const char *driver, + unsigned short iftype, + const char *ifname, + char * const *alternative_names, + enum nl80211_iftype wifi_iftype, + const char *ssid, + const struct ether_addr *bssid); + +CONFIG_PARSER_PROTOTYPE(config_parse_net_condition); +CONFIG_PARSER_PROTOTYPE(config_parse_match_strv); +CONFIG_PARSER_PROTOTYPE(config_parse_match_ifnames); +CONFIG_PARSER_PROTOTYPE(config_parse_match_property); diff --git a/src/test/meson.build b/src/test/meson.build index 6234294947..12bcf35708 100644 --- a/src/test/meson.build +++ b/src/test/meson.build @@ -126,8 +126,7 @@ tests += [ [['src/test/test-dns-domain.c'], [libcore, - libshared, - libsystemd_network], + libshared], []], [['src/test/test-boot-timestamps.c'], @@ -530,7 +529,6 @@ tests += [ libjournal_core, libudev_core, libudev_static, - libsystemd_network, libshared], [threads, libseccomp, @@ -766,7 +764,6 @@ tests += [ [['src/test/test-udev.c'], [libudev_core, libudev_static, - libsystemd_network, libshared], [threads, librt, diff --git a/src/udev/meson.build b/src/udev/meson.build index 5eb0f994a5..d67b459388 100644 --- a/src/udev/meson.build +++ b/src/udev/meson.build @@ -206,7 +206,6 @@ fuzzers += [ 'src/fuzz/fuzz.h'], [libudev_core, libudev_static, - libsystemd_network, libshared], [threads, libacl]], diff --git a/src/udev/net/link-config-gperf.gperf b/src/udev/net/link-config-gperf.gperf index 20f5d7e5a4..dc107170cc 100644 --- a/src/udev/net/link-config-gperf.gperf +++ b/src/udev/net/link-config-gperf.gperf @@ -6,7 +6,7 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"") #include "conf-parser.h" #include "ethtool-util.h" #include "link-config.h" -#include "network-internal.h" +#include "net-condition.h" #include "socket-util.h" %} struct ConfigPerfItem; @@ -20,13 +20,13 @@ struct ConfigPerfItem; %struct-type %includes %% -Match.MACAddress, config_parse_hwaddrs, 0, offsetof(link_config, match_mac) -Match.PermanentMACAddress, config_parse_hwaddrs, 0, offsetof(link_config, match_permanent_mac) -Match.OriginalName, config_parse_match_ifnames, 0, offsetof(link_config, match_name) -Match.Path, config_parse_match_strv, 0, offsetof(link_config, match_path) -Match.Driver, config_parse_match_strv, 0, offsetof(link_config, match_driver) -Match.Type, config_parse_match_strv, 0, offsetof(link_config, match_type) -Match.Property, config_parse_match_property, 0, offsetof(link_config, match_property) +Match.MACAddress, config_parse_hwaddrs, 0, offsetof(link_config, match.mac) +Match.PermanentMACAddress, config_parse_hwaddrs, 0, offsetof(link_config, match.permanent_mac) +Match.OriginalName, config_parse_match_ifnames, 0, offsetof(link_config, match.ifname) +Match.Path, config_parse_match_strv, 0, offsetof(link_config, match.path) +Match.Driver, config_parse_match_strv, 0, offsetof(link_config, match.driver) +Match.Type, config_parse_match_strv, 0, offsetof(link_config, match.iftype) +Match.Property, config_parse_match_property, 0, offsetof(link_config, match.property) Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(link_config, conditions) Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(link_config, conditions) Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(link_config, conditions) diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c index d12fd0e299..cbeaad9ccc 100644 --- a/src/udev/net/link-config.c +++ b/src/udev/net/link-config.c @@ -18,9 +18,10 @@ #include "link-config.h" #include "log.h" #include "memory-util.h" +#include "net-condition.h" #include "netif-naming-scheme.h" #include "netlink-util.h" -#include "network-internal.h" +#include "network-util.h" #include "parse-util.h" #include "path-lookup.h" #include "path-util.h" @@ -30,6 +31,7 @@ #include "string-table.h" #include "string-util.h" #include "strv.h" +#include "utf8.h" struct link_config_ctx { LIST_HEAD(link_config, links); @@ -49,13 +51,7 @@ static void link_config_free(link_config *link) { free(link->filename); - set_free_free(link->match_mac); - set_free_free(link->match_permanent_mac); - strv_free(link->match_path); - strv_free(link->match_driver); - strv_free(link->match_type); - strv_free(link->match_name); - strv_free(link->match_property); + net_match_clear(&link->match); condition_free_list(link->conditions); free(link->description); @@ -167,9 +163,7 @@ int link_load_one(link_config_ctx *ctx, const char *filename) { if (r < 0) return r; - if (set_isempty(link->match_mac) && set_isempty(link->match_permanent_mac) && - strv_isempty(link->match_path) && strv_isempty(link->match_driver) && strv_isempty(link->match_type) && - strv_isempty(link->match_name) && strv_isempty(link->match_property) && !link->conditions) { + if (net_match_is_empty(&link->match) && !link->conditions) { log_warning("%s: No valid settings found in the [Match] section, ignoring file. " "To match all interfaces, add OriginalName=* in the [Match] section.", filename); @@ -279,11 +273,8 @@ int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret) (void) link_unsigned_attribute(device, "name_assign_type", &name_assign_type); LIST_FOREACH(links, link, ctx->links) { - if (net_match_config(link->match_mac, link->match_permanent_mac, link->match_path, link->match_driver, - link->match_type, link->match_name, link->match_property, NULL, NULL, NULL, - device, NULL, &permanent_mac, NULL, iftype, NULL, NULL, 0, NULL, NULL)) { - - if (link->match_name && !strv_contains(link->match_name, "*") && name_assign_type == NET_NAME_ENUM) + if (net_match_config(&link->match, device, NULL, &permanent_mac, NULL, iftype, NULL, NULL, 0, NULL, NULL)) { + if (link->match.ifname && !strv_contains(link->match.ifname, "*") && name_assign_type == NET_NAME_ENUM) log_device_warning(device, "Config file %s is applied to device based on potentially unpredictable interface name.", link->filename); else @@ -668,6 +659,48 @@ int link_get_driver(link_config_ctx *ctx, sd_device *device, char **ret) { return 0; } +int config_parse_ifalias( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + char **s = data; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (!isempty(rvalue)) { + *s = mfree(*s); + return 0; + } + + if (!ascii_is_valid(rvalue)) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Interface alias is not ASCII clean, ignoring assignment: %s", rvalue); + return 0; + } + + if (strlen(rvalue) >= IFALIASZ) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Interface alias is too long, ignoring assignment: %s", rvalue); + return 0; + } + + if (free_and_strdup(s, rvalue) < 0) + return log_oom(); + + return 0; +} + static const char* const mac_address_policy_table[_MAC_ADDRESS_POLICY_MAX] = { [MAC_ADDRESS_POLICY_PERSISTENT] = "persistent", [MAC_ADDRESS_POLICY_RANDOM] = "random", diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h index eab1849fcd..1beecb10ea 100644 --- a/src/udev/net/link-config.h +++ b/src/udev/net/link-config.h @@ -7,7 +7,7 @@ #include "conf-parser.h" #include "ethtool-util.h" #include "list.h" -#include "set.h" +#include "net-condition.h" typedef struct link_config_ctx link_config_ctx; typedef struct link_config link_config; @@ -35,13 +35,7 @@ typedef enum NamePolicy { struct link_config { char *filename; - Set *match_mac; - Set *match_permanent_mac; - char **match_path; - char **match_driver; - char **match_type; - char **match_name; - char **match_property; + NetMatch match; LIST_HEAD(Condition, conditions); char *description; @@ -93,6 +87,7 @@ MACAddressPolicy mac_address_policy_from_string(const char *p) _pure_; /* gperf lookup function */ const struct ConfigPerfItem* link_config_gperf_lookup(const char *key, GPERF_LEN_TYPE length); +CONFIG_PARSER_PROTOTYPE(config_parse_ifalias); CONFIG_PARSER_PROTOTYPE(config_parse_mac_address_policy); CONFIG_PARSER_PROTOTYPE(config_parse_name_policy); CONFIG_PARSER_PROTOTYPE(config_parse_alternative_names_policy);