2020-11-09 05:23:58 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
2017-09-14 21:51:39 +02:00
|
|
|
|
|
|
|
#include <net/if.h>
|
|
|
|
#include <linux/fib_rules.h>
|
|
|
|
|
2019-08-01 22:19:26 +02:00
|
|
|
#include "af-list.h"
|
2017-09-14 21:51:39 +02:00
|
|
|
#include "alloc-util.h"
|
|
|
|
#include "conf-parser.h"
|
|
|
|
#include "fileio.h"
|
2020-01-26 14:22:38 +01:00
|
|
|
#include "format-util.h"
|
2018-11-29 15:58:43 +01:00
|
|
|
#include "ip-protocol-list.h"
|
2017-09-14 21:51:39 +02:00
|
|
|
#include "netlink-util.h"
|
|
|
|
#include "networkd-manager.h"
|
2020-09-29 08:29:56 +02:00
|
|
|
#include "networkd-routing-policy-rule.h"
|
2019-08-01 00:41:36 +02:00
|
|
|
#include "networkd-util.h"
|
2017-09-14 21:51:39 +02:00
|
|
|
#include "parse-util.h"
|
|
|
|
#include "socket-util.h"
|
|
|
|
#include "string-util.h"
|
2018-08-22 07:30:49 +02:00
|
|
|
#include "strv.h"
|
2020-01-26 14:22:38 +01:00
|
|
|
#include "user-util.h"
|
2017-09-14 21:51:39 +02:00
|
|
|
|
2020-09-29 14:43:59 +02:00
|
|
|
RoutingPolicyRule *routing_policy_rule_free(RoutingPolicyRule *rule) {
|
|
|
|
if (!rule)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (rule->network) {
|
|
|
|
assert(rule->section);
|
|
|
|
hashmap_remove(rule->network->rules_by_section, rule->section);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rule->manager) {
|
|
|
|
if (set_get(rule->manager->rules, rule) == rule)
|
|
|
|
set_remove(rule->manager->rules, rule);
|
|
|
|
if (set_get(rule->manager->rules_foreign, rule) == rule)
|
|
|
|
set_remove(rule->manager->rules_foreign, rule);
|
|
|
|
}
|
|
|
|
|
|
|
|
network_config_section_free(rule->section);
|
|
|
|
free(rule->iif);
|
|
|
|
free(rule->oif);
|
|
|
|
|
|
|
|
return mfree(rule);
|
|
|
|
}
|
|
|
|
|
|
|
|
DEFINE_NETWORK_SECTION_FUNCTIONS(RoutingPolicyRule, routing_policy_rule_free);
|
|
|
|
|
|
|
|
static int routing_policy_rule_new(RoutingPolicyRule **ret) {
|
2017-09-14 21:51:39 +02:00
|
|
|
RoutingPolicyRule *rule;
|
|
|
|
|
2018-09-26 18:52:04 +02:00
|
|
|
rule = new(RoutingPolicyRule, 1);
|
2017-09-14 21:51:39 +02:00
|
|
|
if (!rule)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2018-09-26 18:52:04 +02:00
|
|
|
*rule = (RoutingPolicyRule) {
|
|
|
|
.table = RT_TABLE_MAIN,
|
2020-01-26 14:22:38 +01:00
|
|
|
.uid_range.start = UID_INVALID,
|
|
|
|
.uid_range.end = UID_INVALID,
|
2020-02-03 00:25:48 +01:00
|
|
|
.suppress_prefixlen = -1,
|
2018-09-26 18:52:04 +02:00
|
|
|
};
|
2017-09-14 21:51:39 +02:00
|
|
|
|
|
|
|
*ret = rule;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-09-29 07:28:21 +02:00
|
|
|
static int routing_policy_rule_new_static(Network *network, const char *filename, unsigned section_line, RoutingPolicyRule **ret) {
|
|
|
|
_cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
|
|
|
|
_cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(network);
|
|
|
|
assert(ret);
|
2020-09-29 08:29:56 +02:00
|
|
|
assert(filename);
|
|
|
|
assert(section_line > 0);
|
2020-09-29 07:28:21 +02:00
|
|
|
|
2020-09-29 08:29:56 +02:00
|
|
|
r = network_config_section_new(filename, section_line, &n);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2020-09-29 07:28:21 +02:00
|
|
|
|
2020-09-29 08:29:56 +02:00
|
|
|
rule = hashmap_get(network->rules_by_section, n);
|
|
|
|
if (rule) {
|
|
|
|
*ret = TAKE_PTR(rule);
|
|
|
|
return 0;
|
2020-09-29 07:28:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
r = routing_policy_rule_new(&rule);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
rule->network = network;
|
2020-09-29 08:29:56 +02:00
|
|
|
rule->section = TAKE_PTR(n);
|
2020-09-29 07:28:21 +02:00
|
|
|
|
2020-09-29 08:29:56 +02:00
|
|
|
r = hashmap_ensure_allocated(&network->rules_by_section, &network_config_hash_ops);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2020-09-29 07:28:21 +02:00
|
|
|
|
2020-09-29 08:29:56 +02:00
|
|
|
r = hashmap_put(network->rules_by_section, rule->section, rule);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2020-09-29 07:28:21 +02:00
|
|
|
|
|
|
|
*ret = TAKE_PTR(rule);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-08-03 22:16:43 +02:00
|
|
|
static int routing_policy_rule_copy(RoutingPolicyRule *dest, RoutingPolicyRule *src) {
|
|
|
|
_cleanup_free_ char *iif = NULL, *oif = NULL;
|
|
|
|
|
|
|
|
assert(dest);
|
|
|
|
assert(src);
|
|
|
|
|
|
|
|
if (src->iif) {
|
|
|
|
iif = strdup(src->iif);
|
|
|
|
if (!iif)
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (src->oif) {
|
|
|
|
oif = strdup(src->oif);
|
|
|
|
if (!oif)
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
dest->family = src->family;
|
|
|
|
dest->from = src->from;
|
|
|
|
dest->from_prefixlen = src->from_prefixlen;
|
|
|
|
dest->to = src->to;
|
|
|
|
dest->to_prefixlen = src->to_prefixlen;
|
|
|
|
dest->invert_rule = src->invert_rule;
|
|
|
|
dest->tos = src->tos;
|
|
|
|
dest->fwmark = src->fwmark;
|
|
|
|
dest->fwmask = src->fwmask;
|
|
|
|
dest->priority = src->priority;
|
|
|
|
dest->table = src->table;
|
|
|
|
dest->iif = TAKE_PTR(iif);
|
|
|
|
dest->oif = TAKE_PTR(oif);
|
|
|
|
dest->protocol = src->protocol;
|
|
|
|
dest->sport = src->sport;
|
|
|
|
dest->dport = src->dport;
|
2020-01-26 14:22:38 +01:00
|
|
|
dest->uid_range = src->uid_range;
|
2020-02-03 00:25:48 +01:00
|
|
|
dest->suppress_prefixlen = src->suppress_prefixlen;
|
2019-08-03 22:16:43 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-27 14:25:20 +01:00
|
|
|
static void routing_policy_rule_hash_func(const RoutingPolicyRule *rule, struct siphash *state) {
|
2017-09-14 21:51:39 +02:00
|
|
|
assert(rule);
|
|
|
|
|
|
|
|
siphash24_compress(&rule->family, sizeof(rule->family), state);
|
|
|
|
|
|
|
|
switch (rule->family) {
|
|
|
|
case AF_INET:
|
|
|
|
case AF_INET6:
|
|
|
|
siphash24_compress(&rule->from, FAMILY_ADDRESS_SIZE(rule->family), state);
|
|
|
|
siphash24_compress(&rule->from_prefixlen, sizeof(rule->from_prefixlen), state);
|
|
|
|
|
|
|
|
siphash24_compress(&rule->to, FAMILY_ADDRESS_SIZE(rule->family), state);
|
|
|
|
siphash24_compress(&rule->to_prefixlen, sizeof(rule->to_prefixlen), state);
|
|
|
|
|
2019-06-19 06:04:24 +02:00
|
|
|
siphash24_compress_boolean(rule->invert_rule, state);
|
|
|
|
|
2017-09-14 21:51:39 +02:00
|
|
|
siphash24_compress(&rule->tos, sizeof(rule->tos), state);
|
|
|
|
siphash24_compress(&rule->fwmark, sizeof(rule->fwmark), state);
|
2019-06-19 06:04:24 +02:00
|
|
|
siphash24_compress(&rule->fwmask, sizeof(rule->fwmask), state);
|
|
|
|
siphash24_compress(&rule->priority, sizeof(rule->priority), state);
|
2017-09-14 21:51:39 +02:00
|
|
|
siphash24_compress(&rule->table, sizeof(rule->table), state);
|
2020-02-03 00:25:48 +01:00
|
|
|
siphash24_compress(&rule->suppress_prefixlen, sizeof(rule->suppress_prefixlen), state);
|
2017-09-14 21:51:39 +02:00
|
|
|
|
2018-11-27 06:28:54 +01:00
|
|
|
siphash24_compress(&rule->protocol, sizeof(rule->protocol), state);
|
|
|
|
siphash24_compress(&rule->sport, sizeof(rule->sport), state);
|
|
|
|
siphash24_compress(&rule->dport, sizeof(rule->dport), state);
|
2020-01-26 14:22:38 +01:00
|
|
|
siphash24_compress(&rule->uid_range, sizeof(rule->uid_range), state);
|
2018-11-27 06:28:54 +01:00
|
|
|
|
2020-07-20 21:54:37 +02:00
|
|
|
siphash24_compress_string(rule->iif, state);
|
|
|
|
siphash24_compress_string(rule->oif, state);
|
2017-11-21 11:51:50 +01:00
|
|
|
|
2017-09-14 21:51:39 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* treat any other address family as AF_UNSPEC */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-27 14:25:20 +01:00
|
|
|
static int routing_policy_rule_compare_func(const RoutingPolicyRule *a, const RoutingPolicyRule *b) {
|
2017-09-14 21:51:39 +02:00
|
|
|
int r;
|
|
|
|
|
2018-08-03 01:43:37 +02:00
|
|
|
r = CMP(a->family, b->family);
|
|
|
|
if (r != 0)
|
|
|
|
return r;
|
2017-09-14 21:51:39 +02:00
|
|
|
|
|
|
|
switch (a->family) {
|
|
|
|
case AF_INET:
|
|
|
|
case AF_INET6:
|
2018-08-03 01:43:37 +02:00
|
|
|
r = CMP(a->from_prefixlen, b->from_prefixlen);
|
|
|
|
if (r != 0)
|
|
|
|
return r;
|
|
|
|
|
2019-09-17 19:11:31 +02:00
|
|
|
r = memcmp(&a->from, &b->from, FAMILY_ADDRESS_SIZE(a->family));
|
|
|
|
if (r != 0)
|
|
|
|
return r;
|
|
|
|
|
2018-08-03 01:43:37 +02:00
|
|
|
r = CMP(a->to_prefixlen, b->to_prefixlen);
|
|
|
|
if (r != 0)
|
|
|
|
return r;
|
|
|
|
|
2019-09-17 19:11:31 +02:00
|
|
|
r = memcmp(&a->to, &b->to, FAMILY_ADDRESS_SIZE(a->family));
|
|
|
|
if (r != 0)
|
|
|
|
return r;
|
|
|
|
|
2019-06-19 06:04:24 +02:00
|
|
|
r = CMP(a->invert_rule, b->invert_rule);
|
|
|
|
if (r != 0)
|
|
|
|
return r;
|
|
|
|
|
2018-08-03 01:43:37 +02:00
|
|
|
r = CMP(a->tos, b->tos);
|
|
|
|
if (r != 0)
|
|
|
|
return r;
|
|
|
|
|
2019-06-19 06:04:24 +02:00
|
|
|
r = CMP(a->fwmark, b->fwmark);
|
|
|
|
if (r != 0)
|
|
|
|
return r;
|
|
|
|
|
2018-08-03 01:43:37 +02:00
|
|
|
r = CMP(a->fwmask, b->fwmask);
|
|
|
|
if (r != 0)
|
|
|
|
return r;
|
|
|
|
|
2019-06-19 06:04:24 +02:00
|
|
|
r = CMP(a->priority, b->priority);
|
|
|
|
if (r != 0)
|
|
|
|
return r;
|
|
|
|
|
2018-08-03 01:43:37 +02:00
|
|
|
r = CMP(a->table, b->table);
|
|
|
|
if (r != 0)
|
|
|
|
return r;
|
2017-09-14 21:51:39 +02:00
|
|
|
|
2020-02-03 00:25:48 +01:00
|
|
|
r = CMP(a->suppress_prefixlen, b->suppress_prefixlen);
|
|
|
|
if (r != 0)
|
|
|
|
return r;
|
|
|
|
|
2018-11-27 06:28:54 +01:00
|
|
|
r = CMP(a->protocol, b->protocol);
|
|
|
|
if (r != 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = memcmp(&a->sport, &b->sport, sizeof(a->sport));
|
|
|
|
if (r != 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = memcmp(&a->dport, &b->dport, sizeof(a->dport));
|
|
|
|
if (r != 0)
|
|
|
|
return r;
|
|
|
|
|
2020-01-26 14:22:38 +01:00
|
|
|
r = memcmp(&a->uid_range, &b->uid_range, sizeof(a->uid_range));
|
|
|
|
if (r != 0)
|
|
|
|
return r;
|
|
|
|
|
2019-09-17 19:11:31 +02:00
|
|
|
r = strcmp_ptr(a->iif, b->iif);
|
2019-09-17 19:27:58 +02:00
|
|
|
if (r != 0)
|
2017-09-14 21:51:39 +02:00
|
|
|
return r;
|
|
|
|
|
2019-09-17 19:11:31 +02:00
|
|
|
r = strcmp_ptr(a->oif, b->oif);
|
2019-09-17 19:27:58 +02:00
|
|
|
if (r != 0)
|
2019-09-17 19:11:31 +02:00
|
|
|
return r;
|
2017-09-14 21:51:39 +02:00
|
|
|
|
2019-09-17 19:11:31 +02:00
|
|
|
return 0;
|
2017-09-14 21:51:39 +02:00
|
|
|
default:
|
|
|
|
/* treat any other address family as AF_UNSPEC */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-29 03:41:01 +01:00
|
|
|
static bool routing_policy_rule_equal(const RoutingPolicyRule *rule1, const RoutingPolicyRule *rule2) {
|
|
|
|
if (rule1 == rule2)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (!rule1 || !rule2)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return routing_policy_rule_compare_func(rule1, rule2) == 0;
|
|
|
|
}
|
|
|
|
|
2020-07-22 01:22:55 +02:00
|
|
|
DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
|
|
|
|
routing_policy_rule_hash_ops,
|
|
|
|
RoutingPolicyRule,
|
|
|
|
routing_policy_rule_hash_func,
|
|
|
|
routing_policy_rule_compare_func,
|
|
|
|
routing_policy_rule_free);
|
2017-09-14 21:51:39 +02:00
|
|
|
|
2020-09-29 09:23:57 +02:00
|
|
|
static int routing_policy_rule_get(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret) {
|
2017-09-14 21:51:39 +02:00
|
|
|
|
2019-06-19 06:04:24 +02:00
|
|
|
RoutingPolicyRule *existing;
|
2017-09-14 21:51:39 +02:00
|
|
|
|
2019-06-19 06:04:24 +02:00
|
|
|
assert(m);
|
2017-09-14 21:51:39 +02:00
|
|
|
|
2019-06-19 06:04:24 +02:00
|
|
|
existing = set_get(m->rules, rule);
|
2018-09-27 17:50:25 +02:00
|
|
|
if (existing) {
|
|
|
|
if (ret)
|
|
|
|
*ret = existing;
|
|
|
|
return 1;
|
2017-09-14 21:51:39 +02:00
|
|
|
}
|
|
|
|
|
2019-06-19 06:04:24 +02:00
|
|
|
existing = set_get(m->rules_foreign, rule);
|
2018-09-27 17:50:25 +02:00
|
|
|
if (existing) {
|
|
|
|
if (ret)
|
|
|
|
*ret = existing;
|
2018-11-01 15:38:01 +01:00
|
|
|
return 0;
|
2017-09-14 21:51:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
2020-10-04 16:14:08 +02:00
|
|
|
static int routing_policy_rule_add_internal(Manager *m, Set **rules, RoutingPolicyRule *in, int family, RoutingPolicyRule **ret) {
|
tree-wide: drop redundant _cleanup_ macros (#8810)
This drops a good number of type-specific _cleanup_ macros, and patches
all users to just use the generic ones.
In most recent code we abstained from defining type-specific macros, and
this basically removes all those added already, with the exception of
the really low-level ones.
Having explicit macros for this is not too useful, as the expression
without the extra macro is generally just 2ch wider. We should generally
emphesize generic code, unless there are really good reasons for
specific code, hence let's follow this in this case too.
Note that _cleanup_free_ and similar really low-level, libc'ish, Linux
API'ish macros continue to be defined, only the really high-level OO
ones are dropped. From now on this should really be the rule: for really
low-level stuff, such as memory allocation, fd handling and so one, go
ahead and define explicit per-type macros, but for high-level, specific
program code, just use the generic _cleanup_() macro directly, in order
to keep things simple and as readable as possible for the uninitiated.
Note that before this patch some of the APIs (notable libudev ones) were
already used with the high-level macros at some places and with the
generic _cleanup_ macro at others. With this patch we hence unify on the
latter.
2018-04-25 12:31:45 +02:00
|
|
|
_cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
|
2017-09-14 21:51:39 +02:00
|
|
|
int r;
|
|
|
|
|
2019-06-19 06:04:24 +02:00
|
|
|
assert(m);
|
|
|
|
assert(rules);
|
|
|
|
assert(in);
|
2020-10-04 16:14:08 +02:00
|
|
|
assert(IN_SET(family, AF_INET, AF_INET6));
|
|
|
|
assert(in->family == AF_UNSPEC || in->family == family);
|
2017-09-14 21:51:39 +02:00
|
|
|
|
|
|
|
r = routing_policy_rule_new(&rule);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2018-01-24 15:57:53 +01:00
|
|
|
rule->manager = m;
|
2019-08-03 22:16:43 +02:00
|
|
|
|
|
|
|
r = routing_policy_rule_copy(rule, in);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2017-09-14 21:51:39 +02:00
|
|
|
|
2020-10-04 16:14:08 +02:00
|
|
|
rule->family = family;
|
|
|
|
|
2020-06-05 15:12:29 +02:00
|
|
|
r = set_ensure_put(rules, &routing_policy_rule_hash_ops, rule);
|
2017-09-14 21:51:39 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2019-08-11 01:56:37 +02:00
|
|
|
if (r == 0)
|
|
|
|
return -EEXIST;
|
2017-09-14 21:51:39 +02:00
|
|
|
|
|
|
|
if (ret)
|
|
|
|
*ret = rule;
|
|
|
|
|
2019-06-04 07:25:09 +02:00
|
|
|
TAKE_PTR(rule);
|
2017-09-14 21:51:39 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-10-04 16:14:08 +02:00
|
|
|
static int routing_policy_rule_add(Manager *m, RoutingPolicyRule *rule, int family, RoutingPolicyRule **ret) {
|
|
|
|
return routing_policy_rule_add_internal(m, &m->rules, rule, family, ret);
|
2017-09-14 21:51:39 +02:00
|
|
|
}
|
|
|
|
|
2020-09-29 09:23:57 +02:00
|
|
|
static int routing_policy_rule_add_foreign(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret) {
|
2020-10-04 16:14:08 +02:00
|
|
|
return routing_policy_rule_add_internal(m, &m->rules_foreign, rule, rule->family, ret);
|
2017-09-14 21:51:39 +02:00
|
|
|
}
|
|
|
|
|
2020-10-28 09:22:58 +01:00
|
|
|
static void log_routing_policy_rule_debug(const RoutingPolicyRule *rule, int family, const char *str, const Link *link) {
|
|
|
|
assert(rule);
|
|
|
|
assert(IN_SET(family, AF_INET, AF_INET6));
|
|
|
|
assert(str);
|
|
|
|
|
|
|
|
/* link may be NULL. */
|
|
|
|
|
|
|
|
if (DEBUG_LOGGING) {
|
|
|
|
_cleanup_free_ char *from = NULL, *to = NULL;
|
|
|
|
|
|
|
|
(void) in_addr_to_string(family, &rule->from, &from);
|
|
|
|
(void) in_addr_to_string(family, &rule->to, &to);
|
|
|
|
|
|
|
|
log_link_debug(link,
|
|
|
|
"%s routing policy rule: priority: %"PRIu32", %s/%u -> %s/%u, iif: %s, oif: %s, table: %"PRIu32,
|
|
|
|
str, rule->priority, strna(from), rule->from_prefixlen, strna(to), rule->to_prefixlen,
|
|
|
|
strna(rule->iif), strna(rule->oif), rule->table);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-05 23:20:39 +02:00
|
|
|
static int routing_policy_rule_set_netlink_message(RoutingPolicyRule *rule, sd_netlink_message *m, Link *link) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(rule);
|
|
|
|
assert(m);
|
2020-10-28 08:16:58 +01:00
|
|
|
|
|
|
|
/* link may be NULL. */
|
2020-10-05 23:20:39 +02:00
|
|
|
|
|
|
|
if (in_addr_is_null(rule->family, &rule->from) == 0) {
|
|
|
|
r = netlink_message_append_in_addr_union(m, FRA_SRC, rule->family, &rule->from);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not append FRA_SRC attribute: %m");
|
|
|
|
|
2020-12-16 11:58:46 +01:00
|
|
|
r = sd_rtnl_message_routing_policy_rule_set_fib_src_prefixlen(m, rule->from_prefixlen);
|
2020-10-05 23:20:39 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not set source prefix length: %m");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (in_addr_is_null(rule->family, &rule->to) == 0) {
|
|
|
|
r = netlink_message_append_in_addr_union(m, FRA_DST, rule->family, &rule->to);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not append FRA_DST attribute: %m");
|
|
|
|
|
2020-12-16 11:58:46 +01:00
|
|
|
r = sd_rtnl_message_routing_policy_rule_set_fib_dst_prefixlen(m, rule->to_prefixlen);
|
2020-10-05 23:20:39 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not set destination prefix length: %m");
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_append_u32(m, FRA_PRIORITY, rule->priority);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not append FRA_PRIORITY attribute: %m");
|
|
|
|
|
|
|
|
if (rule->tos > 0) {
|
|
|
|
r = sd_rtnl_message_routing_policy_rule_set_tos(m, rule->tos);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not set IP rule TOS: %m");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rule->table < 256) {
|
|
|
|
r = sd_rtnl_message_routing_policy_rule_set_table(m, rule->table);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not set IP rule table: %m");
|
|
|
|
} else {
|
|
|
|
r = sd_rtnl_message_routing_policy_rule_set_table(m, RT_TABLE_UNSPEC);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not set IP rule table: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_message_append_u32(m, FRA_TABLE, rule->table);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not append FRA_TABLE attribute: %m");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rule->fwmark > 0) {
|
|
|
|
r = sd_netlink_message_append_u32(m, FRA_FWMARK, rule->fwmark);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not append FRA_FWMARK attribute: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_message_append_u32(m, FRA_FWMASK, rule->fwmask);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not append FRA_FWMASK attribute: %m");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rule->iif) {
|
|
|
|
r = sd_netlink_message_append_string(m, FRA_IIFNAME, rule->iif);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not append FRA_IIFNAME attribute: %m");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rule->oif) {
|
|
|
|
r = sd_netlink_message_append_string(m, FRA_OIFNAME, rule->oif);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not append FRA_OIFNAME attribute: %m");
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_append_u8(m, FRA_IP_PROTO, rule->protocol);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not append FRA_IP_PROTO attribute: %m");
|
|
|
|
|
|
|
|
if (rule->sport.start != 0 || rule->sport.end != 0) {
|
|
|
|
r = sd_netlink_message_append_data(m, FRA_SPORT_RANGE, &rule->sport, sizeof(rule->sport));
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not append FRA_SPORT_RANGE attribute: %m");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rule->dport.start != 0 || rule->dport.end != 0) {
|
|
|
|
r = sd_netlink_message_append_data(m, FRA_DPORT_RANGE, &rule->dport, sizeof(rule->dport));
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not append FRA_DPORT_RANGE attribute: %m");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rule->uid_range.start != UID_INVALID && rule->uid_range.end != UID_INVALID) {
|
|
|
|
r = sd_netlink_message_append_data(m, FRA_UID_RANGE, &rule->uid_range, sizeof(rule->uid_range));
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not append FRA_UID_RANGE attribute: %m");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rule->invert_rule) {
|
|
|
|
r = sd_rtnl_message_routing_policy_rule_set_flags(m, FIB_RULE_INVERT);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not append FIB_RULE_INVERT attribute: %m");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rule->suppress_prefixlen >= 0) {
|
|
|
|
r = sd_netlink_message_append_u32(m, FRA_SUPPRESS_PREFIXLEN, (uint32_t) rule->suppress_prefixlen);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_error_errno(link, r, "Could not append FRA_SUPPRESS_PREFIXLEN attribute: %m");
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-10-28 08:16:58 +01:00
|
|
|
static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
|
2017-09-14 21:51:39 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
r = sd_netlink_message_get_errno(m);
|
|
|
|
if (r < 0)
|
2020-10-28 08:16:58 +01:00
|
|
|
log_message_warning_errno(m, r, "Could not drop routing policy rule");
|
2017-09-14 21:51:39 +02:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2020-10-28 08:16:58 +01:00
|
|
|
static int routing_policy_rule_remove(RoutingPolicyRule *rule, Manager *manager) {
|
2017-09-14 21:51:39 +02:00
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
|
|
|
int r;
|
|
|
|
|
2020-09-08 20:50:08 +02:00
|
|
|
assert(rule);
|
2020-10-28 08:16:58 +01:00
|
|
|
assert(manager);
|
|
|
|
assert(manager->rtnl);
|
2020-09-08 20:50:08 +02:00
|
|
|
assert(IN_SET(rule->family, AF_INET, AF_INET6));
|
|
|
|
|
2020-10-28 09:22:58 +01:00
|
|
|
log_routing_policy_rule_debug(rule, rule->family, "Removing", NULL);
|
2017-09-14 21:51:39 +02:00
|
|
|
|
2020-10-28 08:16:58 +01:00
|
|
|
r = sd_rtnl_message_new_routing_policy_rule(manager->rtnl, &m, RTM_DELRULE, rule->family);
|
2017-09-14 21:51:39 +02:00
|
|
|
if (r < 0)
|
2020-10-28 08:16:58 +01:00
|
|
|
return log_error_errno(r, "Could not allocate RTM_DELRULE message: %m");
|
2017-09-14 21:51:39 +02:00
|
|
|
|
2020-10-28 08:16:58 +01:00
|
|
|
r = routing_policy_rule_set_netlink_message(rule, m, NULL);
|
2020-10-05 23:20:39 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2017-09-14 21:51:39 +02:00
|
|
|
|
2020-10-28 08:16:58 +01:00
|
|
|
r = sd_netlink_call_async(manager->rtnl, NULL, m,
|
|
|
|
routing_policy_rule_remove_handler,
|
|
|
|
NULL, NULL, 0, __func__);
|
2017-09-14 21:51:39 +02:00
|
|
|
if (r < 0)
|
2020-10-28 08:16:58 +01:00
|
|
|
return log_error_errno(r, "Could not send rtnetlink message: %m");
|
2017-09-14 21:51:39 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-28 21:06:52 +01:00
|
|
|
static int routing_policy_rule_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
2017-09-14 21:51:39 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(rtnl);
|
|
|
|
assert(m);
|
|
|
|
assert(link);
|
|
|
|
assert(link->ifname);
|
2017-12-12 16:25:36 +01:00
|
|
|
assert(link->routing_policy_rule_messages > 0);
|
2017-09-14 21:51:39 +02:00
|
|
|
|
2017-12-12 16:25:36 +01:00
|
|
|
link->routing_policy_rule_messages--;
|
2017-09-14 21:51:39 +02:00
|
|
|
|
|
|
|
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
r = sd_netlink_message_get_errno(m);
|
2019-07-14 17:35:49 +02:00
|
|
|
if (r < 0 && r != -EEXIST) {
|
2019-11-30 07:54:07 +01:00
|
|
|
log_link_message_warning_errno(link, m, r, "Could not add routing policy rule");
|
2019-07-14 17:35:49 +02:00
|
|
|
link_enter_failed(link);
|
|
|
|
return 1;
|
|
|
|
}
|
2017-09-14 21:51:39 +02:00
|
|
|
|
2017-12-12 16:25:36 +01:00
|
|
|
if (link->routing_policy_rule_messages == 0) {
|
2017-09-14 21:51:39 +02:00
|
|
|
log_link_debug(link, "Routing policy rule configured");
|
2017-12-12 16:25:36 +01:00
|
|
|
link->routing_policy_rules_configured = true;
|
|
|
|
link_check_ready(link);
|
|
|
|
}
|
2017-09-14 21:51:39 +02:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2020-10-04 16:14:08 +02:00
|
|
|
static int routing_policy_rule_configure_internal(RoutingPolicyRule *rule, int family, Link *link) {
|
2017-09-14 21:51:39 +02:00
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(rule);
|
|
|
|
assert(link);
|
|
|
|
assert(link->ifindex > 0);
|
|
|
|
assert(link->manager);
|
|
|
|
assert(link->manager->rtnl);
|
|
|
|
|
2020-10-28 09:22:58 +01:00
|
|
|
log_routing_policy_rule_debug(rule, family, "Configuring", link);
|
2019-08-29 21:18:27 +02:00
|
|
|
|
2020-10-04 16:14:08 +02:00
|
|
|
r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_NEWRULE, family);
|
2017-09-14 21:51:39 +02:00
|
|
|
if (r < 0)
|
2020-01-07 04:53:19 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not allocate RTM_NEWRULE message: %m");
|
2017-09-14 21:51:39 +02:00
|
|
|
|
2020-10-05 23:20:39 +02:00
|
|
|
r = routing_policy_rule_set_netlink_message(rule, m, link);
|
2018-11-27 06:28:54 +01:00
|
|
|
if (r < 0)
|
2020-10-05 23:20:39 +02:00
|
|
|
return r;
|
2020-02-03 00:25:48 +01:00
|
|
|
|
2018-11-28 21:06:52 +01:00
|
|
|
r = netlink_call_async(link->manager->rtnl, NULL, m,
|
2020-09-29 07:28:21 +02:00
|
|
|
routing_policy_rule_handler,
|
2018-11-28 21:06:52 +01:00
|
|
|
link_netlink_destroy_callback, link);
|
2017-09-14 21:51:39 +02:00
|
|
|
if (r < 0)
|
2020-01-07 04:53:19 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
|
2017-09-14 21:51:39 +02:00
|
|
|
|
|
|
|
link_ref(link);
|
2020-10-04 16:14:08 +02:00
|
|
|
link->routing_policy_rule_messages++;
|
2017-09-14 21:51:39 +02:00
|
|
|
|
2020-10-04 16:14:08 +02:00
|
|
|
r = routing_policy_rule_add(link->manager, rule, family, NULL);
|
2017-09-14 21:51:39 +02:00
|
|
|
if (r < 0)
|
2020-01-07 04:53:19 +01:00
|
|
|
return log_link_error_errno(link, r, "Could not add rule: %m");
|
2017-09-14 21:51:39 +02:00
|
|
|
|
2019-06-11 16:29:57 +02:00
|
|
|
return 1;
|
2017-09-14 21:51:39 +02:00
|
|
|
}
|
|
|
|
|
2020-10-04 16:14:08 +02:00
|
|
|
static int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if (IN_SET(rule->family, AF_INET, AF_INET6))
|
|
|
|
return routing_policy_rule_configure_internal(rule, rule->family, link);
|
|
|
|
|
|
|
|
if (FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV4)) {
|
|
|
|
r = routing_policy_rule_configure_internal(rule, AF_INET, link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV6)) {
|
|
|
|
r = routing_policy_rule_configure_internal(rule, AF_INET6, link);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-09-29 07:28:21 +02:00
|
|
|
static bool manager_links_have_routing_policy_rule(Manager *m, RoutingPolicyRule *rule) {
|
|
|
|
Link *link;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(rule);
|
|
|
|
|
|
|
|
HASHMAP_FOREACH(link, m->links) {
|
2020-09-29 08:29:56 +02:00
|
|
|
RoutingPolicyRule *link_rule;
|
|
|
|
|
2020-09-29 07:28:21 +02:00
|
|
|
if (!link->network)
|
|
|
|
continue;
|
|
|
|
|
2020-09-29 08:29:56 +02:00
|
|
|
HASHMAP_FOREACH(link_rule, link->network->rules_by_section)
|
2020-10-29 03:41:01 +01:00
|
|
|
if (routing_policy_rule_equal(link_rule, rule))
|
2020-09-29 07:28:21 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-10-28 08:16:58 +01:00
|
|
|
static void routing_policy_rule_purge(Manager *m) {
|
2020-09-29 07:42:56 +02:00
|
|
|
RoutingPolicyRule *rule;
|
2020-09-29 07:28:21 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
SET_FOREACH(rule, m->rules_saved) {
|
2020-09-29 07:42:56 +02:00
|
|
|
RoutingPolicyRule *existing;
|
|
|
|
|
2020-09-29 07:28:21 +02:00
|
|
|
existing = set_get(m->rules_foreign, rule);
|
|
|
|
if (!existing)
|
|
|
|
continue; /* Saved rule does not exist anymore. */
|
|
|
|
|
|
|
|
if (manager_links_have_routing_policy_rule(m, existing))
|
|
|
|
continue; /* Existing links have the saved rule. */
|
|
|
|
|
|
|
|
/* Existing links do not have the saved rule. Let's drop the rule now, and re-configure it
|
|
|
|
* later when it is requested. */
|
|
|
|
|
2020-10-28 08:16:58 +01:00
|
|
|
r = routing_policy_rule_remove(existing, m);
|
2020-09-29 07:28:21 +02:00
|
|
|
if (r < 0) {
|
|
|
|
log_warning_errno(r, "Could not remove routing policy rules: %m");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert_se(set_remove(m->rules_foreign, existing) == existing);
|
|
|
|
routing_policy_rule_free(existing);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-29 07:17:27 +02:00
|
|
|
int link_set_routing_policy_rules(Link *link) {
|
2020-09-29 07:41:01 +02:00
|
|
|
RoutingPolicyRule *rule;
|
2020-09-29 07:17:27 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(link);
|
|
|
|
assert(link->network);
|
|
|
|
|
2020-12-11 06:39:46 +01:00
|
|
|
if (link->routing_policy_rule_messages != 0) {
|
|
|
|
log_link_debug(link, "Routing policy rules are configuring.");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-09-29 07:17:27 +02:00
|
|
|
link->routing_policy_rules_configured = false;
|
|
|
|
|
2020-09-29 08:29:56 +02:00
|
|
|
HASHMAP_FOREACH(rule, link->network->rules_by_section) {
|
2020-09-29 07:41:01 +02:00
|
|
|
RoutingPolicyRule *existing;
|
|
|
|
|
|
|
|
r = routing_policy_rule_get(link->manager, rule, &existing);
|
|
|
|
if (r > 0)
|
|
|
|
continue;
|
|
|
|
if (r == 0) {
|
|
|
|
r = set_ensure_put(&link->manager->rules, &routing_policy_rule_hash_ops, existing);
|
|
|
|
if (r < 0)
|
|
|
|
return log_link_warning_errno(link, r, "Could not store existing routing policy rule: %m");
|
|
|
|
|
|
|
|
set_remove(link->manager->rules_foreign, existing);
|
2020-09-29 07:17:27 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-09-29 07:28:21 +02:00
|
|
|
r = routing_policy_rule_configure(rule, link);
|
2020-09-29 07:17:27 +02:00
|
|
|
if (r < 0)
|
2020-09-29 07:41:01 +02:00
|
|
|
return log_link_warning_errno(link, r, "Could not set routing policy rule: %m");
|
2020-09-29 07:17:27 +02:00
|
|
|
}
|
|
|
|
|
2020-10-28 08:16:58 +01:00
|
|
|
routing_policy_rule_purge(link->manager);
|
2020-09-29 07:17:27 +02:00
|
|
|
if (link->routing_policy_rule_messages == 0)
|
|
|
|
link->routing_policy_rules_configured = true;
|
|
|
|
else {
|
|
|
|
log_link_debug(link, "Setting routing policy rules");
|
|
|
|
link_set_state(link, LINK_STATE_CONFIGURING);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-09-29 09:23:57 +02:00
|
|
|
int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
|
|
|
|
_cleanup_(routing_policy_rule_freep) RoutingPolicyRule *tmp = NULL;
|
|
|
|
RoutingPolicyRule *rule = NULL;
|
|
|
|
const char *iif = NULL, *oif = NULL;
|
|
|
|
uint32_t suppress_prefixlen;
|
|
|
|
unsigned flags;
|
|
|
|
uint16_t type;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(rtnl);
|
|
|
|
assert(message);
|
|
|
|
|
|
|
|
if (sd_netlink_message_is_error(message)) {
|
|
|
|
r = sd_netlink_message_get_errno(message);
|
|
|
|
if (r < 0)
|
|
|
|
log_message_warning_errno(message, r, "rtnl: failed to receive rule message, ignoring");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_get_type(message, &type);
|
|
|
|
if (r < 0) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get message type, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
} else if (!IN_SET(type, RTM_NEWRULE, RTM_DELRULE)) {
|
|
|
|
log_warning("rtnl: received unexpected message type %u when processing rule, ignoring.", type);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = routing_policy_rule_new(&tmp);
|
|
|
|
if (r < 0) {
|
|
|
|
log_oom();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_rtnl_message_get_family(message, &tmp->family);
|
|
|
|
if (r < 0) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get rule family, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
} else if (!IN_SET(tmp->family, AF_INET, AF_INET6)) {
|
|
|
|
log_debug("rtnl: received rule message with invalid family %d, ignoring.", tmp->family);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-10-28 09:28:36 +01:00
|
|
|
r = netlink_message_read_in_addr_union(message, FRA_SRC, tmp->family, &tmp->from);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_SRC attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
} else if (r >= 0) {
|
2020-12-16 11:58:46 +01:00
|
|
|
r = sd_rtnl_message_routing_policy_rule_get_fib_src_prefixlen(message, &tmp->from_prefixlen);
|
2020-10-28 09:28:36 +01:00
|
|
|
if (r < 0) {
|
|
|
|
log_warning_errno(r, "rtnl: received rule message without valid source prefix length, ignoring: %m");
|
2020-09-29 09:23:57 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2020-10-28 09:28:36 +01:00
|
|
|
}
|
2020-09-29 09:23:57 +02:00
|
|
|
|
2020-10-28 09:28:36 +01:00
|
|
|
r = netlink_message_read_in_addr_union(message, FRA_DST, tmp->family, &tmp->to);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_DST attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
} else if (r >= 0) {
|
2020-12-16 11:58:46 +01:00
|
|
|
r = sd_rtnl_message_routing_policy_rule_get_fib_dst_prefixlen(message, &tmp->to_prefixlen);
|
2020-10-28 09:28:36 +01:00
|
|
|
if (r < 0) {
|
|
|
|
log_warning_errno(r, "rtnl: received rule message without valid destination prefix length, ignoring: %m");
|
2020-09-29 09:23:57 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_rtnl_message_routing_policy_rule_get_flags(message, &flags);
|
|
|
|
if (r < 0) {
|
|
|
|
log_warning_errno(r, "rtnl: received rule message without valid flag, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
tmp->invert_rule = flags & FIB_RULE_INVERT;
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_u32(message, FRA_FWMARK, &tmp->fwmark);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_FWMARK attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_u32(message, FRA_FWMASK, &tmp->fwmask);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_FWMASK attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_u32(message, FRA_PRIORITY, &tmp->priority);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_PRIORITY attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_u32(message, FRA_TABLE, &tmp->table);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_TABLE attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_rtnl_message_routing_policy_rule_get_tos(message, &tmp->tos);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get ip rule TOS, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_string(message, FRA_IIFNAME, &iif);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_IIFNAME attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
r = free_and_strdup(&tmp->iif, iif);
|
|
|
|
if (r < 0)
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_string(message, FRA_OIFNAME, &oif);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_OIFNAME attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
r = free_and_strdup(&tmp->oif, oif);
|
|
|
|
if (r < 0)
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_u8(message, FRA_IP_PROTO, &tmp->protocol);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_IP_PROTO attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read(message, FRA_SPORT_RANGE, sizeof(tmp->sport), &tmp->sport);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_SPORT_RANGE attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read(message, FRA_DPORT_RANGE, sizeof(tmp->dport), &tmp->dport);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_DPORT_RANGE attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read(message, FRA_UID_RANGE, sizeof(tmp->uid_range), &tmp->uid_range);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_UID_RANGE attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_u32(message, FRA_SUPPRESS_PREFIXLEN, &suppress_prefixlen);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_warning_errno(r, "rtnl: could not get FRA_SUPPRESS_PREFIXLEN attribute, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (r >= 0)
|
|
|
|
tmp->suppress_prefixlen = (int) suppress_prefixlen;
|
|
|
|
|
|
|
|
(void) routing_policy_rule_get(m, tmp, &rule);
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case RTM_NEWRULE:
|
|
|
|
if (rule)
|
2020-10-28 09:22:58 +01:00
|
|
|
log_routing_policy_rule_debug(tmp, tmp->family, "Received remembered", NULL);
|
2020-09-29 09:23:57 +02:00
|
|
|
else {
|
2020-10-28 09:22:58 +01:00
|
|
|
log_routing_policy_rule_debug(tmp, tmp->family, "Remembering foreign", NULL);
|
2020-09-29 09:23:57 +02:00
|
|
|
r = routing_policy_rule_add_foreign(m, tmp, &rule);
|
|
|
|
if (r < 0) {
|
|
|
|
log_warning_errno(r, "Could not remember foreign rule, ignoring: %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case RTM_DELRULE:
|
|
|
|
if (rule) {
|
2020-10-28 09:22:58 +01:00
|
|
|
log_routing_policy_rule_debug(tmp, tmp->family, "Forgetting", NULL);
|
2020-09-29 09:23:57 +02:00
|
|
|
routing_policy_rule_free(rule);
|
|
|
|
} else
|
2020-10-28 09:22:58 +01:00
|
|
|
log_routing_policy_rule_debug(tmp, tmp->family, "Kernel removed unknown", NULL);
|
2020-09-29 09:23:57 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
assert_not_reached("Received invalid RTNL message type");
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2020-09-08 21:26:49 +02:00
|
|
|
static int parse_fwmark_fwmask(const char *s, uint32_t *ret_fwmark, uint32_t *ret_fwmask) {
|
|
|
|
_cleanup_free_ char *fwmark_str = NULL;
|
|
|
|
uint32_t fwmark, fwmask = 0;
|
|
|
|
const char *slash;
|
2017-09-14 21:51:39 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(s);
|
2020-09-08 21:26:49 +02:00
|
|
|
assert(ret_fwmark);
|
|
|
|
assert(ret_fwmask);
|
2017-09-14 21:51:39 +02:00
|
|
|
|
2020-09-08 21:26:49 +02:00
|
|
|
slash = strchr(s, '/');
|
|
|
|
if (slash) {
|
|
|
|
fwmark_str = strndup(s, slash - s);
|
|
|
|
if (!fwmark_str)
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
2017-09-14 21:51:39 +02:00
|
|
|
|
2020-09-08 21:26:49 +02:00
|
|
|
r = safe_atou32(fwmark_str ?: s, &fwmark);
|
2017-09-14 21:51:39 +02:00
|
|
|
if (r < 0)
|
2020-09-08 21:26:49 +02:00
|
|
|
return r;
|
2017-09-14 21:51:39 +02:00
|
|
|
|
2020-09-08 21:45:54 +02:00
|
|
|
if (fwmark > 0) {
|
|
|
|
if (slash) {
|
|
|
|
r = safe_atou32(slash + 1, &fwmask);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
} else
|
|
|
|
fwmask = UINT32_MAX;
|
2017-09-14 21:51:39 +02:00
|
|
|
}
|
|
|
|
|
2020-09-08 21:26:49 +02:00
|
|
|
*ret_fwmark = fwmark;
|
|
|
|
*ret_fwmask = fwmask;
|
|
|
|
|
2017-09-14 21:51:39 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int config_parse_routing_policy_rule_tos(
|
|
|
|
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) {
|
|
|
|
|
2019-03-01 05:27:47 +01:00
|
|
|
_cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
|
2017-09-14 21:51:39 +02:00
|
|
|
Network *network = userdata;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(section);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
|
|
|
r = routing_policy_rule_new_static(network, filename, section_line, &n);
|
|
|
|
if (r < 0)
|
2020-07-16 07:48:08 +02:00
|
|
|
return log_oom();
|
2017-09-14 21:51:39 +02:00
|
|
|
|
|
|
|
r = safe_atou8(rvalue, &n->tos);
|
|
|
|
if (r < 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse RPDB rule TOS, ignoring: %s", rvalue);
|
2017-09-14 21:51:39 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
n = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int config_parse_routing_policy_rule_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) {
|
|
|
|
|
2019-03-01 05:27:47 +01:00
|
|
|
_cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
|
2017-09-14 21:51:39 +02:00
|
|
|
Network *network = userdata;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(section);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
|
|
|
r = routing_policy_rule_new_static(network, filename, section_line, &n);
|
|
|
|
if (r < 0)
|
2020-07-16 07:48:08 +02:00
|
|
|
return log_oom();
|
2017-09-14 21:51:39 +02:00
|
|
|
|
|
|
|
r = safe_atou32(rvalue, &n->priority);
|
|
|
|
if (r < 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse RPDB rule priority, ignoring: %s", rvalue);
|
2017-09-14 21:51:39 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
n = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int config_parse_routing_policy_rule_table(
|
|
|
|
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) {
|
|
|
|
|
2019-03-01 05:27:47 +01:00
|
|
|
_cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
|
2017-09-14 21:51:39 +02:00
|
|
|
Network *network = userdata;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(section);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
|
|
|
r = routing_policy_rule_new_static(network, filename, section_line, &n);
|
|
|
|
if (r < 0)
|
2020-07-16 07:48:08 +02:00
|
|
|
return log_oom();
|
2017-09-14 21:51:39 +02:00
|
|
|
|
|
|
|
r = safe_atou32(rvalue, &n->table);
|
|
|
|
if (r < 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse RPDB rule table, ignoring: %s", rvalue);
|
2017-09-14 21:51:39 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
n = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int config_parse_routing_policy_rule_fwmark_mask(
|
|
|
|
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) {
|
|
|
|
|
2019-03-01 05:27:47 +01:00
|
|
|
_cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
|
2017-09-14 21:51:39 +02:00
|
|
|
Network *network = userdata;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(section);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
|
|
|
r = routing_policy_rule_new_static(network, filename, section_line, &n);
|
|
|
|
if (r < 0)
|
2020-07-16 07:48:08 +02:00
|
|
|
return log_oom();
|
2017-09-14 21:51:39 +02:00
|
|
|
|
|
|
|
r = parse_fwmark_fwmask(rvalue, &n->fwmark, &n->fwmask);
|
|
|
|
if (r < 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", rvalue);
|
2017-09-14 21:51:39 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
n = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int config_parse_routing_policy_rule_prefix(
|
|
|
|
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) {
|
|
|
|
|
2019-03-01 05:27:47 +01:00
|
|
|
_cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
|
2017-09-14 21:51:39 +02:00
|
|
|
Network *network = userdata;
|
2018-12-03 10:22:05 +01:00
|
|
|
union in_addr_union *buffer;
|
|
|
|
uint8_t *prefixlen;
|
2017-09-14 21:51:39 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(section);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
|
|
|
r = routing_policy_rule_new_static(network, filename, section_line, &n);
|
|
|
|
if (r < 0)
|
2020-07-16 07:48:08 +02:00
|
|
|
return log_oom();
|
2017-09-14 21:51:39 +02:00
|
|
|
|
|
|
|
if (streq(lvalue, "To")) {
|
2018-12-03 10:22:05 +01:00
|
|
|
buffer = &n->to;
|
|
|
|
prefixlen = &n->to_prefixlen;
|
2017-09-14 21:51:39 +02:00
|
|
|
} else {
|
2018-12-03 10:22:05 +01:00
|
|
|
buffer = &n->from;
|
|
|
|
prefixlen = &n->from_prefixlen;
|
|
|
|
}
|
|
|
|
|
2019-08-01 22:07:40 +02:00
|
|
|
if (n->family == AF_UNSPEC)
|
|
|
|
r = in_addr_prefix_from_string_auto(rvalue, &n->family, buffer, prefixlen);
|
|
|
|
else
|
|
|
|
r = in_addr_prefix_from_string(rvalue, n->family, buffer, prefixlen);
|
2018-12-03 10:22:05 +01:00
|
|
|
if (r < 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r, "RPDB rule prefix is invalid, ignoring assignment: %s", rvalue);
|
2018-12-03 10:22:05 +01:00
|
|
|
return 0;
|
2017-09-14 21:51:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
n = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-11-21 11:51:50 +01:00
|
|
|
int config_parse_routing_policy_rule_device(
|
|
|
|
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) {
|
|
|
|
|
2019-03-01 05:27:47 +01:00
|
|
|
_cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
|
2017-11-21 11:51:50 +01:00
|
|
|
Network *network = userdata;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(section);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
|
|
|
r = routing_policy_rule_new_static(network, filename, section_line, &n);
|
|
|
|
if (r < 0)
|
2020-07-16 07:48:08 +02:00
|
|
|
return log_oom();
|
2017-11-21 11:51:50 +01:00
|
|
|
|
|
|
|
if (!ifname_valid(rvalue)) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse '%s' interface name, ignoring: %s", lvalue, rvalue);
|
2017-11-21 11:51:50 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (streq(lvalue, "IncomingInterface")) {
|
|
|
|
r = free_and_strdup(&n->iif, rvalue);
|
|
|
|
if (r < 0)
|
|
|
|
return log_oom();
|
|
|
|
} else {
|
|
|
|
r = free_and_strdup(&n->oif, rvalue);
|
|
|
|
if (r < 0)
|
|
|
|
return log_oom();
|
|
|
|
}
|
|
|
|
|
|
|
|
n = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-27 06:28:54 +01:00
|
|
|
int config_parse_routing_policy_rule_port_range(
|
|
|
|
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) {
|
2019-03-01 05:27:47 +01:00
|
|
|
_cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
|
2018-11-27 06:28:54 +01:00
|
|
|
Network *network = userdata;
|
|
|
|
uint16_t low, high;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(section);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
|
|
|
r = routing_policy_rule_new_static(network, filename, section_line, &n);
|
|
|
|
if (r < 0)
|
2020-07-16 07:48:08 +02:00
|
|
|
return log_oom();
|
2018-11-27 06:28:54 +01:00
|
|
|
|
|
|
|
r = parse_ip_port_range(rvalue, &low, &high);
|
|
|
|
if (r < 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse routing policy rule port range '%s'", rvalue);
|
2018-11-27 06:28:54 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (streq(lvalue, "SourcePort")) {
|
|
|
|
n->sport.start = low;
|
|
|
|
n->sport.end = high;
|
|
|
|
} else {
|
|
|
|
n->dport.start = low;
|
|
|
|
n->dport.end = high;
|
|
|
|
}
|
|
|
|
|
|
|
|
n = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-29 16:42:39 +01:00
|
|
|
int config_parse_routing_policy_rule_ip_protocol(
|
2018-11-27 06:28:54 +01:00
|
|
|
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) {
|
|
|
|
|
2019-03-01 05:27:47 +01:00
|
|
|
_cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
|
2018-11-27 06:28:54 +01:00
|
|
|
Network *network = userdata;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(section);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
|
|
|
r = routing_policy_rule_new_static(network, filename, section_line, &n);
|
|
|
|
if (r < 0)
|
2020-07-16 07:48:08 +02:00
|
|
|
return log_oom();
|
2018-11-27 06:28:54 +01:00
|
|
|
|
2018-11-29 16:43:40 +01:00
|
|
|
r = parse_ip_protocol(rvalue);
|
2018-11-27 06:28:54 +01:00
|
|
|
if (r < 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse IP protocol '%s' for routing policy rule, ignoring: %m", rvalue);
|
2018-11-27 06:28:54 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
n->protocol = r;
|
|
|
|
|
|
|
|
n = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-12-03 13:55:30 +01:00
|
|
|
int config_parse_routing_policy_rule_invert(
|
|
|
|
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) {
|
|
|
|
|
2019-03-01 05:27:47 +01:00
|
|
|
_cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
|
2018-12-03 13:55:30 +01:00
|
|
|
Network *network = userdata;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(section);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
|
|
|
r = routing_policy_rule_new_static(network, filename, section_line, &n);
|
|
|
|
if (r < 0)
|
2020-07-16 07:48:08 +02:00
|
|
|
return log_oom();
|
2018-12-03 13:55:30 +01:00
|
|
|
|
|
|
|
r = parse_boolean(rvalue);
|
|
|
|
if (r < 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse RPDB rule invert, ignoring: %s", rvalue);
|
2018-12-03 13:55:30 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
n->invert_rule = r;
|
|
|
|
|
|
|
|
n = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-08-01 00:41:36 +02:00
|
|
|
int config_parse_routing_policy_rule_family(
|
|
|
|
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_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
|
|
|
|
Network *network = userdata;
|
|
|
|
AddressFamily a;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(section);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
|
|
|
r = routing_policy_rule_new_static(network, filename, section_line, &n);
|
|
|
|
if (r < 0)
|
2020-07-16 07:48:08 +02:00
|
|
|
return log_oom();
|
2019-08-01 00:41:36 +02:00
|
|
|
|
|
|
|
a = routing_policy_rule_address_family_from_string(rvalue);
|
|
|
|
if (a < 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, 0,
|
2019-08-01 00:41:36 +02:00
|
|
|
"Invalid address family '%s', ignoring.", rvalue);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
n->address_family = a;
|
|
|
|
n = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-01-26 14:22:38 +01:00
|
|
|
int config_parse_routing_policy_rule_uid_range(
|
|
|
|
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_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
|
|
|
|
Network *network = userdata;
|
|
|
|
uid_t start, end;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(section);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
|
|
|
r = routing_policy_rule_new_static(network, filename, section_line, &n);
|
|
|
|
if (r < 0)
|
2020-07-16 07:48:08 +02:00
|
|
|
return log_oom();
|
2020-01-26 14:22:38 +01:00
|
|
|
|
|
|
|
r = get_user_creds(&rvalue, &start, NULL, NULL, NULL, 0);
|
|
|
|
if (r >= 0)
|
|
|
|
end = start;
|
|
|
|
else {
|
|
|
|
r = parse_uid_range(rvalue, &start, &end);
|
|
|
|
if (r < 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
2020-01-26 14:22:38 +01:00
|
|
|
"Invalid uid or uid range '%s', ignoring: %m", rvalue);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
n->uid_range.start = start;
|
|
|
|
n->uid_range.end = end;
|
|
|
|
n = NULL;
|
2020-02-03 00:25:48 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int config_parse_routing_policy_rule_suppress_prefixlen(
|
|
|
|
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_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
|
|
|
|
Network *network = userdata;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(section);
|
|
|
|
assert(lvalue);
|
|
|
|
assert(rvalue);
|
|
|
|
assert(data);
|
|
|
|
|
|
|
|
r = routing_policy_rule_new_static(network, filename, section_line, &n);
|
|
|
|
if (r < 0)
|
2020-07-16 07:48:08 +02:00
|
|
|
return log_oom();
|
2020-02-03 00:25:48 +01:00
|
|
|
|
|
|
|
r = parse_ip_prefix_length(rvalue, &n->suppress_prefixlen);
|
|
|
|
if (r == -ERANGE) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r, "Prefix length outside of valid range 0-128, ignoring: %s", rvalue);
|
2020-02-03 00:25:48 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (r < 0) {
|
2020-07-16 07:48:08 +02:00
|
|
|
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse RPDB rule suppress_prefixlen, ignoring: %s", rvalue);
|
2020-02-03 00:25:48 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
n = NULL;
|
|
|
|
|
2020-01-26 14:22:38 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-09-29 17:50:30 +02:00
|
|
|
static int routing_policy_rule_section_verify(RoutingPolicyRule *rule) {
|
2020-09-29 07:28:21 +02:00
|
|
|
if (section_is_invalid(rule->section))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if ((rule->family == AF_INET && FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV6)) ||
|
|
|
|
(rule->family == AF_INET6 && FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV4)))
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
"%s: address family specified by Family= conflicts with the address "
|
|
|
|
"specified by To= or From=. Ignoring [RoutingPolicyRule] section from line %u.",
|
|
|
|
rule->section->filename, rule->section->line);
|
|
|
|
|
2020-10-04 16:14:08 +02:00
|
|
|
if (rule->family == AF_UNSPEC && rule->address_family == ADDRESS_FAMILY_NO)
|
2020-09-29 07:28:21 +02:00
|
|
|
rule->family = AF_INET;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-10-06 20:21:59 +02:00
|
|
|
void network_drop_invalid_routing_policy_rules(Network *network) {
|
2020-09-29 17:50:30 +02:00
|
|
|
RoutingPolicyRule *rule;
|
|
|
|
|
|
|
|
assert(network);
|
|
|
|
|
|
|
|
HASHMAP_FOREACH(rule, network->rules_by_section)
|
|
|
|
if (routing_policy_rule_section_verify(rule) < 0)
|
|
|
|
routing_policy_rule_free(rule);
|
|
|
|
}
|
|
|
|
|
2017-11-27 11:22:51 +01:00
|
|
|
int routing_policy_serialize_rules(Set *rules, FILE *f) {
|
2020-09-29 07:42:56 +02:00
|
|
|
RoutingPolicyRule *rule;
|
2017-11-27 11:22:51 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(f);
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
SET_FOREACH(rule, rules) {
|
2019-08-01 22:19:26 +02:00
|
|
|
const char *family_str;
|
2020-08-28 05:58:49 +02:00
|
|
|
bool space = false;
|
2017-11-27 11:22:51 +01:00
|
|
|
|
|
|
|
fputs("RULE=", f);
|
|
|
|
|
2020-08-28 05:58:49 +02:00
|
|
|
family_str = af_to_name(rule->family);
|
|
|
|
if (family_str) {
|
|
|
|
fprintf(f, "family=%s",
|
|
|
|
family_str);
|
|
|
|
space = true;
|
|
|
|
}
|
|
|
|
|
2017-11-27 11:22:51 +01:00
|
|
|
if (!in_addr_is_null(rule->family, &rule->from)) {
|
2020-09-29 07:42:56 +02:00
|
|
|
_cleanup_free_ char *str = NULL;
|
|
|
|
|
|
|
|
r = in_addr_to_string(rule->family, &rule->from, &str);
|
2017-11-27 11:22:51 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2020-08-28 05:58:49 +02:00
|
|
|
fprintf(f, "%sfrom=%s/%hhu",
|
|
|
|
space ? " " : "",
|
2020-09-29 07:42:56 +02:00
|
|
|
str, rule->from_prefixlen);
|
2017-11-27 11:22:51 +01:00
|
|
|
space = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!in_addr_is_null(rule->family, &rule->to)) {
|
2020-09-29 07:42:56 +02:00
|
|
|
_cleanup_free_ char *str = NULL;
|
|
|
|
|
|
|
|
r = in_addr_to_string(rule->family, &rule->to, &str);
|
2017-11-27 11:22:51 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
fprintf(f, "%sto=%s/%hhu",
|
|
|
|
space ? " " : "",
|
2020-09-29 07:42:56 +02:00
|
|
|
str, rule->to_prefixlen);
|
2017-11-27 11:22:51 +01:00
|
|
|
space = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rule->tos != 0) {
|
|
|
|
fprintf(f, "%stos=%hhu",
|
|
|
|
space ? " " : "",
|
|
|
|
rule->tos);
|
|
|
|
space = true;
|
|
|
|
}
|
|
|
|
|
2020-08-28 05:34:36 +02:00
|
|
|
if (rule->priority != 0) {
|
|
|
|
fprintf(f, "%spriority=%"PRIu32,
|
|
|
|
space ? " " : "",
|
|
|
|
rule->priority);
|
|
|
|
space = true;
|
|
|
|
}
|
2019-08-01 21:22:44 +02:00
|
|
|
|
2017-11-27 11:22:51 +01:00
|
|
|
if (rule->fwmark != 0) {
|
2020-09-08 21:45:54 +02:00
|
|
|
fprintf(f, "%sfwmark=%"PRIu32,
|
2017-11-27 11:22:51 +01:00
|
|
|
space ? " " : "",
|
2020-09-08 21:45:54 +02:00
|
|
|
rule->fwmark);
|
|
|
|
if (rule->fwmask != UINT32_MAX)
|
|
|
|
fprintf(f, "/%"PRIu32, rule->fwmask);
|
2017-11-27 11:22:51 +01:00
|
|
|
space = true;
|
|
|
|
}
|
|
|
|
|
2017-11-27 12:51:08 +01:00
|
|
|
if (rule->iif) {
|
|
|
|
fprintf(f, "%siif=%s",
|
|
|
|
space ? " " : "",
|
|
|
|
rule->iif);
|
|
|
|
space = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rule->oif) {
|
|
|
|
fprintf(f, "%soif=%s",
|
|
|
|
space ? " " : "",
|
|
|
|
rule->oif);
|
|
|
|
space = true;
|
|
|
|
}
|
|
|
|
|
2018-11-27 06:28:54 +01:00
|
|
|
if (rule->protocol != 0) {
|
|
|
|
fprintf(f, "%sprotocol=%hhu",
|
|
|
|
space ? " " : "",
|
|
|
|
rule->protocol);
|
|
|
|
space = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rule->sport.start != 0 || rule->sport.end != 0) {
|
2018-12-01 10:44:35 +01:00
|
|
|
fprintf(f, "%ssourcesport=%"PRIu16"-%"PRIu16,
|
2018-11-27 06:28:54 +01:00
|
|
|
space ? " " : "",
|
|
|
|
rule->sport.start, rule->sport.end);
|
|
|
|
space = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rule->dport.start != 0 || rule->dport.end != 0) {
|
2018-12-01 10:44:35 +01:00
|
|
|
fprintf(f, "%sdestinationport=%"PRIu16"-%"PRIu16,
|
2018-11-27 06:28:54 +01:00
|
|
|
space ? " " : "",
|
|
|
|
rule->dport.start, rule->dport.end);
|
|
|
|
space = true;
|
|
|
|
}
|
|
|
|
|
2020-01-26 14:22:38 +01:00
|
|
|
if (rule->uid_range.start != UID_INVALID && rule->uid_range.end != UID_INVALID) {
|
|
|
|
assert_cc(sizeof(uid_t) == sizeof(uint32_t));
|
|
|
|
fprintf(f, "%suidrange="UID_FMT"-"UID_FMT,
|
|
|
|
space ? " " : "",
|
|
|
|
rule->uid_range.start, rule->uid_range.end);
|
|
|
|
space = true;
|
|
|
|
}
|
|
|
|
|
2020-02-03 00:25:48 +01:00
|
|
|
if (rule->suppress_prefixlen >= 0) {
|
|
|
|
fprintf(f, "%ssuppress_prefixlen=%d",
|
|
|
|
space ? " " : "",
|
|
|
|
rule->suppress_prefixlen);
|
|
|
|
space = true;
|
|
|
|
}
|
|
|
|
|
2020-08-28 05:47:44 +02:00
|
|
|
fprintf(f, "%sinvert_rule=%s table=%"PRIu32"\n",
|
2017-11-27 11:22:51 +01:00
|
|
|
space ? " " : "",
|
2020-08-28 05:47:44 +02:00
|
|
|
yes_no(rule->invert_rule),
|
2017-11-27 11:22:51 +01:00
|
|
|
rule->table);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-09-29 08:04:19 +02:00
|
|
|
static int routing_policy_rule_read_full_file(const char *state_file, char ***ret) {
|
|
|
|
_cleanup_strv_free_ char **lines = NULL;
|
2020-08-28 05:27:32 +02:00
|
|
|
_cleanup_free_ char *s = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(state_file);
|
|
|
|
|
2020-09-29 08:04:19 +02:00
|
|
|
r = read_full_file(state_file, &s, NULL);
|
|
|
|
if (r == -ENOENT) {
|
|
|
|
*ret = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
2020-08-28 05:27:32 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2020-09-29 08:04:19 +02:00
|
|
|
lines = strv_split_newlines(s);
|
|
|
|
if (!lines)
|
|
|
|
return -ENOMEM;
|
2020-08-28 05:27:32 +02:00
|
|
|
|
2020-09-29 08:04:19 +02:00
|
|
|
*ret = TAKE_PTR(lines);
|
|
|
|
return 0;
|
2020-08-28 05:27:32 +02:00
|
|
|
}
|
|
|
|
|
2017-11-27 11:22:51 +01:00
|
|
|
int routing_policy_load_rules(const char *state_file, Set **rules) {
|
2020-09-29 08:04:19 +02:00
|
|
|
_cleanup_strv_free_ char **data = NULL;
|
2017-09-14 21:51:39 +02:00
|
|
|
char **i;
|
|
|
|
int r;
|
|
|
|
|
2017-11-27 11:22:51 +01:00
|
|
|
assert(state_file);
|
|
|
|
assert(rules);
|
2017-09-14 21:51:39 +02:00
|
|
|
|
2017-11-27 11:22:51 +01:00
|
|
|
r = routing_policy_rule_read_full_file(state_file, &data);
|
2020-09-29 08:04:19 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_warning_errno(r, "Failed to read %s, ignoring: %m", state_file);
|
2017-09-14 21:51:39 +02:00
|
|
|
|
2020-09-29 08:04:19 +02:00
|
|
|
STRV_FOREACH(i, data) {
|
tree-wide: drop redundant _cleanup_ macros (#8810)
This drops a good number of type-specific _cleanup_ macros, and patches
all users to just use the generic ones.
In most recent code we abstained from defining type-specific macros, and
this basically removes all those added already, with the exception of
the really low-level ones.
Having explicit macros for this is not too useful, as the expression
without the extra macro is generally just 2ch wider. We should generally
emphesize generic code, unless there are really good reasons for
specific code, hence let's follow this in this case too.
Note that _cleanup_free_ and similar really low-level, libc'ish, Linux
API'ish macros continue to be defined, only the really high-level OO
ones are dropped. From now on this should really be the rule: for really
low-level stuff, such as memory allocation, fd handling and so one, go
ahead and define explicit per-type macros, but for high-level, specific
program code, just use the generic _cleanup_() macro directly, in order
to keep things simple and as readable as possible for the uninitiated.
Note that before this patch some of the APIs (notable libudev ones) were
already used with the high-level macros at some places and with the
generic _cleanup_ macro at others. With this patch we hence unify on the
latter.
2018-04-25 12:31:45 +02:00
|
|
|
_cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
|
2020-09-29 08:04:19 +02:00
|
|
|
const char *p;
|
2017-09-14 21:51:39 +02:00
|
|
|
|
|
|
|
p = startswith(*i, "RULE=");
|
|
|
|
if (!p)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
r = routing_policy_rule_new(&rule);
|
|
|
|
if (r < 0)
|
2020-09-29 08:04:19 +02:00
|
|
|
return log_oom();
|
2017-09-14 21:51:39 +02:00
|
|
|
|
|
|
|
for (;;) {
|
2020-08-28 05:53:08 +02:00
|
|
|
_cleanup_free_ char *a = NULL;
|
|
|
|
char *b;
|
2017-09-14 21:51:39 +02:00
|
|
|
|
2020-08-28 05:53:08 +02:00
|
|
|
r = extract_first_word(&p, &a, NULL, 0);
|
2017-09-14 21:51:39 +02:00
|
|
|
if (r < 0)
|
2020-09-29 08:04:19 +02:00
|
|
|
return log_oom();
|
2017-09-14 21:51:39 +02:00
|
|
|
if (r == 0)
|
|
|
|
break;
|
|
|
|
|
2020-08-28 05:53:08 +02:00
|
|
|
b = strchr(a, '=');
|
|
|
|
if (!b) {
|
|
|
|
log_warning_errno(r, "Failed to parse RPDB rule, ignoring: %s", a);
|
2017-09-14 21:51:39 +02:00
|
|
|
continue;
|
2020-08-28 05:53:08 +02:00
|
|
|
}
|
|
|
|
*b++ = '\0';
|
2017-09-14 21:51:39 +02:00
|
|
|
|
2020-08-28 05:58:49 +02:00
|
|
|
if (streq(a, "family")) {
|
|
|
|
r = af_from_name(b);
|
|
|
|
if (r < 0) {
|
|
|
|
log_warning_errno(r, "Failed to parse RPDB rule family, ignoring: %s", b);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (rule->family != AF_UNSPEC && rule->family != r) {
|
|
|
|
log_warning("RPDB rule family is already specified, ignoring assignment: %s", b);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
rule->family = r;
|
2020-10-05 22:05:33 +02:00
|
|
|
} else if (STR_IN_SET(a, "from", "to")) {
|
2018-12-03 10:22:05 +01:00
|
|
|
union in_addr_union *buffer;
|
|
|
|
uint8_t *prefixlen;
|
2017-09-14 21:51:39 +02:00
|
|
|
|
|
|
|
if (streq(a, "to")) {
|
2018-12-03 10:22:05 +01:00
|
|
|
buffer = &rule->to;
|
|
|
|
prefixlen = &rule->to_prefixlen;
|
2017-09-14 21:51:39 +02:00
|
|
|
} else {
|
2018-12-03 10:22:05 +01:00
|
|
|
buffer = &rule->from;
|
|
|
|
prefixlen = &rule->from_prefixlen;
|
|
|
|
}
|
|
|
|
|
2020-08-28 05:58:49 +02:00
|
|
|
if (rule->family == AF_UNSPEC)
|
|
|
|
r = in_addr_prefix_from_string_auto(b, &rule->family, buffer, prefixlen);
|
|
|
|
else
|
|
|
|
r = in_addr_prefix_from_string(b, rule->family, buffer, prefixlen);
|
2018-12-03 10:22:05 +01:00
|
|
|
if (r < 0) {
|
2020-09-04 01:44:14 +02:00
|
|
|
log_warning_errno(r, "RPDB rule prefix is invalid, ignoring assignment: %s", b);
|
2018-12-03 10:22:05 +01:00
|
|
|
continue;
|
2017-09-14 21:51:39 +02:00
|
|
|
}
|
|
|
|
} else if (streq(a, "tos")) {
|
|
|
|
r = safe_atou8(b, &rule->tos);
|
|
|
|
if (r < 0) {
|
2020-09-04 01:44:14 +02:00
|
|
|
log_warning_errno(r, "Failed to parse RPDB rule TOS, ignoring: %s", b);
|
2017-09-14 21:51:39 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else if (streq(a, "table")) {
|
|
|
|
r = safe_atou32(b, &rule->table);
|
|
|
|
if (r < 0) {
|
2020-09-04 01:44:14 +02:00
|
|
|
log_warning_errno(r, "Failed to parse RPDB rule table, ignoring: %s", b);
|
2017-09-14 21:51:39 +02:00
|
|
|
continue;
|
|
|
|
}
|
2019-08-01 21:22:44 +02:00
|
|
|
} else if (streq(a, "priority")) {
|
|
|
|
r = safe_atou32(b, &rule->priority);
|
|
|
|
if (r < 0) {
|
2020-09-04 01:44:14 +02:00
|
|
|
log_warning_errno(r, "Failed to parse RPDB rule priority, ignoring: %s", b);
|
2019-08-01 21:22:44 +02:00
|
|
|
continue;
|
|
|
|
}
|
2017-09-14 21:51:39 +02:00
|
|
|
} else if (streq(a, "fwmark")) {
|
2017-11-27 12:21:19 +01:00
|
|
|
r = parse_fwmark_fwmask(b, &rule->fwmark, &rule->fwmask);
|
2017-09-14 21:51:39 +02:00
|
|
|
if (r < 0) {
|
2020-09-04 01:44:14 +02:00
|
|
|
log_warning_errno(r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", a);
|
2017-09-14 21:51:39 +02:00
|
|
|
continue;
|
|
|
|
}
|
2017-11-27 12:51:08 +01:00
|
|
|
} else if (streq(a, "iif")) {
|
2017-11-27 13:01:41 +01:00
|
|
|
if (free_and_strdup(&rule->iif, b) < 0)
|
2017-11-21 11:51:50 +01:00
|
|
|
return log_oom();
|
2017-11-27 13:01:41 +01:00
|
|
|
|
2017-11-27 12:51:08 +01:00
|
|
|
} else if (streq(a, "oif")) {
|
2017-11-21 11:51:50 +01:00
|
|
|
|
2017-11-27 13:01:41 +01:00
|
|
|
if (free_and_strdup(&rule->oif, b) < 0)
|
2017-11-21 11:51:50 +01:00
|
|
|
return log_oom();
|
2018-11-27 06:28:54 +01:00
|
|
|
} else if (streq(a, "protocol")) {
|
|
|
|
r = safe_atou8(b, &rule->protocol);
|
|
|
|
if (r < 0) {
|
2020-09-04 01:44:14 +02:00
|
|
|
log_warning_errno(r, "Failed to parse RPDB rule protocol, ignoring: %s", b);
|
2018-11-27 06:28:54 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else if (streq(a, "sourceport")) {
|
2020-09-29 08:04:19 +02:00
|
|
|
uint16_t low, high;
|
|
|
|
|
2018-11-27 06:28:54 +01:00
|
|
|
r = parse_ip_port_range(b, &low, &high);
|
|
|
|
if (r < 0) {
|
2020-09-04 01:44:14 +02:00
|
|
|
log_warning_errno(r, "Invalid routing policy rule source port range, ignoring assignment: '%s'", b);
|
2018-11-27 06:28:54 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
rule->sport.start = low;
|
|
|
|
rule->sport.end = high;
|
|
|
|
} else if (streq(a, "destinationport")) {
|
2020-09-29 08:04:19 +02:00
|
|
|
uint16_t low, high;
|
|
|
|
|
2018-11-27 06:28:54 +01:00
|
|
|
r = parse_ip_port_range(b, &low, &high);
|
|
|
|
if (r < 0) {
|
2020-09-04 01:44:14 +02:00
|
|
|
log_warning_errno(r, "Invalid routing policy rule destination port range, ignoring assignment: '%s'", b);
|
2018-11-27 06:28:54 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
rule->dport.start = low;
|
|
|
|
rule->dport.end = high;
|
2020-01-26 14:22:38 +01:00
|
|
|
} else if (streq(a, "uidrange")) {
|
|
|
|
uid_t lower, upper;
|
|
|
|
|
|
|
|
r = parse_uid_range(b, &lower, &upper);
|
|
|
|
if (r < 0) {
|
2020-09-04 01:44:14 +02:00
|
|
|
log_warning_errno(r, "Invalid routing policy rule uid range, ignoring assignment: '%s'", b);
|
2020-01-26 14:22:38 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
rule->uid_range.start = lower;
|
|
|
|
rule->uid_range.end = upper;
|
2020-02-03 00:25:48 +01:00
|
|
|
} else if (streq(a, "suppress_prefixlen")) {
|
|
|
|
r = parse_ip_prefix_length(b, &rule->suppress_prefixlen);
|
|
|
|
if (r == -ERANGE) {
|
2020-09-04 01:44:14 +02:00
|
|
|
log_warning_errno(r, "Prefix length outside of valid range 0-128, ignoring: %s", b);
|
2020-02-03 00:25:48 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (r < 0) {
|
2020-09-04 01:44:14 +02:00
|
|
|
log_warning_errno(r, "Failed to parse RPDB rule suppress_prefixlen, ignoring: %s", b);
|
2020-02-03 00:25:48 +01:00
|
|
|
continue;
|
|
|
|
}
|
2020-08-28 05:47:44 +02:00
|
|
|
} else if (streq(a, "invert_rule")) {
|
|
|
|
r = parse_boolean(b);
|
|
|
|
if (r < 0) {
|
|
|
|
log_warning_errno(r, "Failed to parse RPDB rule invert_rule, ignoring: %s", b);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
rule->invert_rule = r;
|
2020-08-28 06:00:25 +02:00
|
|
|
} else
|
|
|
|
log_warning("Unknown RPDB rule, ignoring: %s", a);
|
2017-09-14 21:51:39 +02:00
|
|
|
}
|
|
|
|
|
2020-06-05 15:12:29 +02:00
|
|
|
r = set_ensure_put(rules, &routing_policy_rule_hash_ops, rule);
|
2017-09-14 21:51:39 +02:00
|
|
|
if (r < 0) {
|
2020-09-29 08:04:19 +02:00
|
|
|
log_warning_errno(r, "Failed to add RPDB rule to saved DB, ignoring: %s", *i);
|
2017-09-14 21:51:39 +02:00
|
|
|
continue;
|
|
|
|
}
|
2019-08-11 01:56:37 +02:00
|
|
|
if (r > 0)
|
|
|
|
rule = NULL;
|
2017-09-14 21:51:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|