summaryrefslogtreecommitdiff
path: root/src/shared
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2020-11-27 09:04:19 +0900
committerGitHub <noreply@github.com>2020-11-27 09:04:19 +0900
commit0d5eb02134c6420a7b929915df5a1b18ba841911 (patch)
tree06456aa21b6c98a5d22185e0c9c1cd6c87f0a0a0 /src/shared
parent6d8325f66a40d802b280492416660246db3476a6 (diff)
parent5722fb89bcb4d0fb228c0b99b82b70e00bb6095a (diff)
downloadsystemd-0d5eb02134c6420a7b929915df5a1b18ba841911.tar.gz
Merge pull request #17478 from yuwata/split-network-internal
libsystemd-network: split network-internal.c
Diffstat (limited to 'src/shared')
-rw-r--r--src/shared/conf-parser.c209
-rw-r--r--src/shared/conf-parser.h2
-rw-r--r--src/shared/meson.build2
-rw-r--r--src/shared/net-condition.c428
-rw-r--r--src/shared/net-condition.h45
5 files changed, 637 insertions, 49 deletions
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, &ether_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 <netinet/ether.h>
+
+#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 <linux/nl80211.h>
+#include <stdbool.h>
+
+#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);