Compare commits
6 Commits
d514454446
...
2be7c6ab3b
Author | SHA1 | Date |
---|---|---|
Yu Watanabe | 2be7c6ab3b | |
Yu Watanabe | a9d240f4bf | |
Yu Watanabe | 0b81225e57 | |
Yu Watanabe | e737dce544 | |
Yu Watanabe | 569eeb0c05 | |
Yu Watanabe | 1e5fd3216a |
|
@ -273,11 +273,6 @@ if conf.get('ENABLE_NETWORKD') == 1
|
|||
[threads],
|
||||
'', '', [], network_include_dir],
|
||||
|
||||
[['src/network/test-routing-policy-rule.c'],
|
||||
[libnetworkd_core,
|
||||
libsystemd_network],
|
||||
[], '', '', [], network_include_dir],
|
||||
|
||||
[['src/network/test-network-tables.c',
|
||||
test_tables_h],
|
||||
[libnetworkd_core,
|
||||
|
|
|
@ -1973,37 +1973,51 @@ static int link_enter_join_netdev(Link *link) {
|
|||
}
|
||||
|
||||
static int link_drop_foreign_config(Link *link) {
|
||||
int r;
|
||||
int k, r;
|
||||
|
||||
assert(link);
|
||||
assert(link->manager);
|
||||
|
||||
r = link_drop_foreign_addresses(link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = link_drop_foreign_neighbors(link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
k = link_drop_foreign_neighbors(link);
|
||||
if (k < 0 && r >= 0)
|
||||
r = k;
|
||||
|
||||
return link_drop_foreign_routes(link);
|
||||
k = link_drop_foreign_routes(link);
|
||||
if (k < 0 && r >= 0)
|
||||
r = k;
|
||||
|
||||
k = manager_drop_foreign_routing_policy_rules(link->manager);
|
||||
if (k < 0 && r >= 0)
|
||||
r = k;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int link_drop_config(Link *link) {
|
||||
int r;
|
||||
int k, r;
|
||||
|
||||
assert(link);
|
||||
assert(link->manager);
|
||||
|
||||
r = link_drop_addresses(link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = link_drop_neighbors(link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
k = link_drop_neighbors(link);
|
||||
if (k < 0 && r >= 0)
|
||||
r = k;
|
||||
|
||||
r = link_drop_routes(link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
k = link_drop_routes(link);
|
||||
if (k < 0 && r >= 0)
|
||||
r = k;
|
||||
|
||||
k = manager_drop_routing_policy_rules(link->manager, link);
|
||||
if (k < 0 && r >= 0)
|
||||
r = k;
|
||||
|
||||
ndisc_flush(link);
|
||||
|
||||
return 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
int link_configure(Link *link) {
|
||||
|
|
|
@ -707,10 +707,6 @@ static int manager_save(Manager *m) {
|
|||
ordered_set_print(f, "DOMAINS=", search_domains);
|
||||
ordered_set_print(f, "ROUTE_DOMAINS=", route_domains);
|
||||
|
||||
r = routing_policy_serialize_rules(m->rules, f);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = fflush_and_check(f);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
@ -851,8 +847,6 @@ int manager_new(Manager **ret) {
|
|||
|
||||
m->duid.type = DUID_TYPE_EN;
|
||||
|
||||
(void) routing_policy_load_rules(m->state_file, &m->rules_saved);
|
||||
|
||||
*ret = TAKE_PTR(m);
|
||||
|
||||
return 0;
|
||||
|
@ -887,7 +881,6 @@ void manager_free(Manager *m) {
|
|||
* So, it is necessary to set NULL after the sets are freed. */
|
||||
m->rules = set_free(m->rules);
|
||||
m->rules_foreign = set_free(m->rules_foreign);
|
||||
set_free(m->rules_saved);
|
||||
|
||||
sd_netlink_unref(m->rtnl);
|
||||
sd_netlink_unref(m->genl);
|
||||
|
|
|
@ -60,7 +60,6 @@ struct Manager {
|
|||
|
||||
Set *rules;
|
||||
Set *rules_foreign;
|
||||
Set *rules_saved;
|
||||
|
||||
/* Manager stores routes without RTA_OIF attribute. */
|
||||
Set *routes;
|
||||
|
|
|
@ -66,6 +66,7 @@ static int routing_policy_rule_new(RoutingPolicyRule **ret) {
|
|||
.uid_range.start = UID_INVALID,
|
||||
.uid_range.end = UID_INVALID,
|
||||
.suppress_prefixlen = -1,
|
||||
.protocol = RTPROT_UNSPEC,
|
||||
.type = FR_ACT_TO_TBL,
|
||||
};
|
||||
|
||||
|
@ -99,6 +100,7 @@ static int routing_policy_rule_new_static(Network *network, const char *filename
|
|||
|
||||
rule->network = network;
|
||||
rule->section = TAKE_PTR(n);
|
||||
rule->protocol = RTPROT_STATIC;
|
||||
|
||||
r = hashmap_ensure_allocated(&network->rules_by_section, &network_config_hash_ops);
|
||||
if (r < 0)
|
||||
|
@ -144,6 +146,7 @@ static int routing_policy_rule_copy(RoutingPolicyRule *dest, RoutingPolicyRule *
|
|||
dest->table = src->table;
|
||||
dest->iif = TAKE_PTR(iif);
|
||||
dest->oif = TAKE_PTR(oif);
|
||||
dest->ipproto = src->ipproto;
|
||||
dest->protocol = src->protocol;
|
||||
dest->sport = src->sport;
|
||||
dest->dport = src->dport;
|
||||
|
@ -177,6 +180,7 @@ static void routing_policy_rule_hash_func(const RoutingPolicyRule *rule, struct
|
|||
siphash24_compress(&rule->table, sizeof(rule->table), state);
|
||||
siphash24_compress(&rule->suppress_prefixlen, sizeof(rule->suppress_prefixlen), state);
|
||||
|
||||
siphash24_compress(&rule->ipproto, sizeof(rule->ipproto), state);
|
||||
siphash24_compress(&rule->protocol, sizeof(rule->protocol), state);
|
||||
siphash24_compress(&rule->sport, sizeof(rule->sport), state);
|
||||
siphash24_compress(&rule->dport, sizeof(rule->dport), state);
|
||||
|
@ -250,6 +254,10 @@ static int routing_policy_rule_compare_func(const RoutingPolicyRule *a, const Ro
|
|||
if (r != 0)
|
||||
return r;
|
||||
|
||||
r = CMP(a->ipproto, b->ipproto);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
r = CMP(a->protocol, b->protocol);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
@ -458,10 +466,14 @@ static int routing_policy_rule_set_netlink_message(RoutingPolicyRule *rule, sd_n
|
|||
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);
|
||||
r = sd_netlink_message_append_u8(m, FRA_IP_PROTO, rule->ipproto);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not append FRA_IP_PROTO attribute: %m");
|
||||
|
||||
r = sd_netlink_message_append_u8(m, FRA_PROTOCOL, rule->protocol);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not append FRA_PROTOCOL 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)
|
||||
|
@ -628,7 +640,7 @@ static int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool manager_links_have_routing_policy_rule(Manager *m, RoutingPolicyRule *rule) {
|
||||
static bool links_have_routing_policy_rule(const Manager *m, const RoutingPolicyRule *rule, const Link *except) {
|
||||
Link *link;
|
||||
|
||||
assert(m);
|
||||
|
@ -637,6 +649,9 @@ static bool manager_links_have_routing_policy_rule(Manager *m, RoutingPolicyRule
|
|||
HASHMAP_FOREACH(link, m->links) {
|
||||
RoutingPolicyRule *link_rule;
|
||||
|
||||
if (link == except)
|
||||
continue;
|
||||
|
||||
if (!link->network)
|
||||
continue;
|
||||
|
||||
|
@ -648,34 +663,29 @@ static bool manager_links_have_routing_policy_rule(Manager *m, RoutingPolicyRule
|
|||
return false;
|
||||
}
|
||||
|
||||
static void routing_policy_rule_purge(Manager *m) {
|
||||
int manager_drop_routing_policy_rules_internal(Manager *m, bool foreign, const Link *except) {
|
||||
RoutingPolicyRule *rule;
|
||||
int r;
|
||||
int k, r = 0;
|
||||
Set *rules;
|
||||
|
||||
assert(m);
|
||||
|
||||
SET_FOREACH(rule, m->rules_saved) {
|
||||
RoutingPolicyRule *existing;
|
||||
|
||||
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. */
|
||||
|
||||
r = routing_policy_rule_remove(existing, m);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Could not remove routing policy rules: %m");
|
||||
rules = foreign ? m->rules_foreign : m->rules;
|
||||
SET_FOREACH(rule, rules) {
|
||||
/* Do not touch rules managed by kernel. */
|
||||
if (rule->protocol == RTPROT_KERNEL)
|
||||
continue;
|
||||
}
|
||||
|
||||
assert_se(set_remove(m->rules_foreign, existing) == existing);
|
||||
routing_policy_rule_free(existing);
|
||||
/* The rule will be configured later, or already configured by a link. */
|
||||
if (links_have_routing_policy_rule(m, rule, except))
|
||||
continue;
|
||||
|
||||
k = routing_policy_rule_remove(rule, m);
|
||||
if (k < 0 && r >= 0)
|
||||
r = k;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int link_set_routing_policy_rules(Link *link) {
|
||||
|
@ -712,7 +722,6 @@ int link_set_routing_policy_rules(Link *link) {
|
|||
return log_link_warning_errno(link, r, "Could not set routing policy rule: %m");
|
||||
}
|
||||
|
||||
routing_policy_rule_purge(link->manager);
|
||||
if (link->routing_policy_rule_messages == 0)
|
||||
link->routing_policy_rules_configured = true;
|
||||
else {
|
||||
|
@ -723,10 +732,34 @@ int link_set_routing_policy_rules(Link *link) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const RoutingPolicyRule kernel_rules[] = {
|
||||
{ .family = AF_INET, .priority = 0, .table = RT_TABLE_LOCAL, .type = FR_ACT_TO_TBL, .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, },
|
||||
{ .family = AF_INET, .priority = 32766, .table = RT_TABLE_MAIN, .type = FR_ACT_TO_TBL, .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, },
|
||||
{ .family = AF_INET, .priority = 32767, .table = RT_TABLE_DEFAULT, .type = FR_ACT_TO_TBL, .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, },
|
||||
{ .family = AF_INET6, .priority = 0, .table = RT_TABLE_LOCAL, .type = FR_ACT_TO_TBL, .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, },
|
||||
{ .family = AF_INET6, .priority = 32766, .table = RT_TABLE_MAIN, .type = FR_ACT_TO_TBL, .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, },
|
||||
};
|
||||
|
||||
static bool routing_policy_rule_is_created_by_kernel(const RoutingPolicyRule *rule) {
|
||||
assert(rule);
|
||||
|
||||
if (rule->l3mdev > 0)
|
||||
/* Currently, [RoutingPolicyRule] does not explicitly set FRA_L3MDEV. So, if the flag
|
||||
* is set, it is safe to treat the rule as created by kernel. */
|
||||
return true;
|
||||
|
||||
for (size_t i = 0; i < ELEMENTSOF(kernel_rules); i++)
|
||||
if (routing_policy_rule_equal(rule, &kernel_rules[i]))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
bool adjust_protocol = false;
|
||||
uint32_t suppress_prefixlen;
|
||||
unsigned flags;
|
||||
uint16_t type;
|
||||
|
@ -852,12 +885,29 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Man
|
|||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = sd_netlink_message_read_u8(message, FRA_IP_PROTO, &tmp->protocol);
|
||||
r = sd_netlink_message_read_u8(message, FRA_IP_PROTO, &tmp->ipproto);
|
||||
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_u8(message, FRA_PROTOCOL, &tmp->protocol);
|
||||
if (r == -ENODATA)
|
||||
/* If FRA_PROTOCOL is supported by kernel, then the attribute is always appended.
|
||||
* When the received message does not have FRA_PROTOCOL, then we need to adjust the
|
||||
* protocol of the rule later. */
|
||||
adjust_protocol = true;
|
||||
else if (r < 0) {
|
||||
log_warning_errno(r, "rtnl: could not get FRA_PROTOCOL attribute, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_read_u8(message, FRA_L3MDEV, &tmp->l3mdev);
|
||||
if (r < 0 && r != -ENODATA) {
|
||||
log_warning_errno(r, "rtnl: could not get FRA_L3MDEV 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");
|
||||
|
@ -884,6 +934,11 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Man
|
|||
if (r >= 0)
|
||||
tmp->suppress_prefixlen = (int) suppress_prefixlen;
|
||||
|
||||
if (adjust_protocol)
|
||||
/* As .network files does not have setting to specify protocol, we can assume the
|
||||
* protocol of the received rule is RTPROT_KERNEL or RTPROT_STATIC. */
|
||||
tmp->protocol = routing_policy_rule_is_created_by_kernel(tmp) ? RTPROT_KERNEL : RTPROT_STATIC;
|
||||
|
||||
(void) routing_policy_rule_get(m, tmp, &rule);
|
||||
|
||||
switch (type) {
|
||||
|
@ -1271,7 +1326,7 @@ int config_parse_routing_policy_rule_ip_protocol(
|
|||
return 0;
|
||||
}
|
||||
|
||||
n->protocol = r;
|
||||
n->ipproto = r;
|
||||
|
||||
n = NULL;
|
||||
|
||||
|
@ -1497,6 +1552,12 @@ static int routing_policy_rule_section_verify(RoutingPolicyRule *rule) {
|
|||
if (rule->family == AF_UNSPEC && rule->address_family == ADDRESS_FAMILY_NO)
|
||||
rule->family = AF_INET;
|
||||
|
||||
/* Currently, [RoutingPolicyRule] does not have a setting to set FRA_L3MDEV flag. Please also
|
||||
* update routing_policy_rule_is_created_by_kernel() when a new setting which sets the flag is
|
||||
* added in the future. */
|
||||
if (rule->l3mdev > 0)
|
||||
assert_not_reached("FRA_L3MDEV flag should not be configured.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1509,342 +1570,3 @@ void network_drop_invalid_routing_policy_rules(Network *network) {
|
|||
if (routing_policy_rule_section_verify(rule) < 0)
|
||||
routing_policy_rule_free(rule);
|
||||
}
|
||||
|
||||
int routing_policy_serialize_rules(Set *rules, FILE *f) {
|
||||
RoutingPolicyRule *rule;
|
||||
int r;
|
||||
|
||||
assert(f);
|
||||
|
||||
SET_FOREACH(rule, rules) {
|
||||
const char *family_str;
|
||||
bool space = false;
|
||||
|
||||
fputs("RULE=", f);
|
||||
|
||||
family_str = af_to_name(rule->family);
|
||||
if (family_str) {
|
||||
fprintf(f, "family=%s",
|
||||
family_str);
|
||||
space = true;
|
||||
}
|
||||
|
||||
if (!in_addr_is_null(rule->family, &rule->from)) {
|
||||
_cleanup_free_ char *str = NULL;
|
||||
|
||||
r = in_addr_to_string(rule->family, &rule->from, &str);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
fprintf(f, "%sfrom=%s/%hhu",
|
||||
space ? " " : "",
|
||||
str, rule->from_prefixlen);
|
||||
space = true;
|
||||
}
|
||||
|
||||
if (!in_addr_is_null(rule->family, &rule->to)) {
|
||||
_cleanup_free_ char *str = NULL;
|
||||
|
||||
r = in_addr_to_string(rule->family, &rule->to, &str);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
fprintf(f, "%sto=%s/%hhu",
|
||||
space ? " " : "",
|
||||
str, rule->to_prefixlen);
|
||||
space = true;
|
||||
}
|
||||
|
||||
if (rule->tos != 0) {
|
||||
fprintf(f, "%stos=%hhu",
|
||||
space ? " " : "",
|
||||
rule->tos);
|
||||
space = true;
|
||||
}
|
||||
|
||||
if (rule->type != 0) {
|
||||
fprintf(f, "%stype=%hhu",
|
||||
space ? " " : "",
|
||||
rule->type);
|
||||
space = true;
|
||||
}
|
||||
|
||||
if (rule->priority != 0) {
|
||||
fprintf(f, "%spriority=%"PRIu32,
|
||||
space ? " " : "",
|
||||
rule->priority);
|
||||
space = true;
|
||||
}
|
||||
|
||||
if (rule->fwmark != 0) {
|
||||
fprintf(f, "%sfwmark=%"PRIu32,
|
||||
space ? " " : "",
|
||||
rule->fwmark);
|
||||
if (rule->fwmask != UINT32_MAX)
|
||||
fprintf(f, "/%"PRIu32, rule->fwmask);
|
||||
space = true;
|
||||
}
|
||||
|
||||
if (rule->iif) {
|
||||
fprintf(f, "%siif=%s",
|
||||
space ? " " : "",
|
||||
rule->iif);
|
||||
space = true;
|
||||
}
|
||||
|
||||
if (rule->oif) {
|
||||
fprintf(f, "%soif=%s",
|
||||
space ? " " : "",
|
||||
rule->oif);
|
||||
space = true;
|
||||
}
|
||||
|
||||
if (rule->protocol != 0) {
|
||||
fprintf(f, "%sprotocol=%hhu",
|
||||
space ? " " : "",
|
||||
rule->protocol);
|
||||
space = true;
|
||||
}
|
||||
|
||||
if (rule->sport.start != 0 || rule->sport.end != 0) {
|
||||
fprintf(f, "%ssourcesport=%"PRIu16"-%"PRIu16,
|
||||
space ? " " : "",
|
||||
rule->sport.start, rule->sport.end);
|
||||
space = true;
|
||||
}
|
||||
|
||||
if (rule->dport.start != 0 || rule->dport.end != 0) {
|
||||
fprintf(f, "%sdestinationport=%"PRIu16"-%"PRIu16,
|
||||
space ? " " : "",
|
||||
rule->dport.start, rule->dport.end);
|
||||
space = true;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (rule->suppress_prefixlen >= 0) {
|
||||
fprintf(f, "%ssuppress_prefixlen=%d",
|
||||
space ? " " : "",
|
||||
rule->suppress_prefixlen);
|
||||
space = true;
|
||||
}
|
||||
|
||||
fprintf(f, "%sinvert_rule=%s table=%"PRIu32"\n",
|
||||
space ? " " : "",
|
||||
yes_no(rule->invert_rule),
|
||||
rule->table);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int routing_policy_rule_read_full_file(const char *state_file, char ***ret) {
|
||||
_cleanup_strv_free_ char **lines = NULL;
|
||||
_cleanup_free_ char *s = NULL;
|
||||
int r;
|
||||
|
||||
assert(state_file);
|
||||
|
||||
r = read_full_file(state_file, &s, NULL);
|
||||
if (r == -ENOENT) {
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
lines = strv_split_newlines(s);
|
||||
if (!lines)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = TAKE_PTR(lines);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int routing_policy_load_rules(const char *state_file, Set **rules) {
|
||||
_cleanup_strv_free_ char **data = NULL;
|
||||
char **i;
|
||||
int r;
|
||||
|
||||
assert(state_file);
|
||||
assert(rules);
|
||||
|
||||
r = routing_policy_rule_read_full_file(state_file, &data);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "Failed to read %s, ignoring: %m", state_file);
|
||||
|
||||
STRV_FOREACH(i, data) {
|
||||
_cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
|
||||
const char *p;
|
||||
|
||||
p = startswith(*i, "RULE=");
|
||||
if (!p)
|
||||
continue;
|
||||
|
||||
r = routing_policy_rule_new(&rule);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *a = NULL;
|
||||
char *b;
|
||||
|
||||
r = extract_first_word(&p, &a, NULL, 0);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
b = strchr(a, '=');
|
||||
if (!b) {
|
||||
log_warning_errno(r, "Failed to parse RPDB rule, ignoring: %s", a);
|
||||
continue;
|
||||
}
|
||||
*b++ = '\0';
|
||||
|
||||
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;
|
||||
} else if (STR_IN_SET(a, "from", "to")) {
|
||||
union in_addr_union *buffer;
|
||||
uint8_t *prefixlen;
|
||||
|
||||
if (streq(a, "to")) {
|
||||
buffer = &rule->to;
|
||||
prefixlen = &rule->to_prefixlen;
|
||||
} else {
|
||||
buffer = &rule->from;
|
||||
prefixlen = &rule->from_prefixlen;
|
||||
}
|
||||
|
||||
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);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "RPDB rule prefix is invalid, ignoring assignment: %s", b);
|
||||
continue;
|
||||
}
|
||||
} else if (streq(a, "tos")) {
|
||||
r = safe_atou8(b, &rule->tos);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Failed to parse RPDB rule TOS, ignoring: %s", b);
|
||||
continue;
|
||||
}
|
||||
} else if (streq(a, "type")) {
|
||||
r = safe_atou8(b, &rule->type);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Failed to parse RPDB rule type, ignoring: %s", b);
|
||||
continue;
|
||||
}
|
||||
} else if (streq(a, "table")) {
|
||||
r = safe_atou32(b, &rule->table);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Failed to parse RPDB rule table, ignoring: %s", b);
|
||||
continue;
|
||||
}
|
||||
} else if (streq(a, "priority")) {
|
||||
r = safe_atou32(b, &rule->priority);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Failed to parse RPDB rule priority, ignoring: %s", b);
|
||||
continue;
|
||||
}
|
||||
} else if (streq(a, "fwmark")) {
|
||||
r = parse_fwmark_fwmask(b, &rule->fwmark, &rule->fwmask);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", a);
|
||||
continue;
|
||||
}
|
||||
} else if (streq(a, "iif")) {
|
||||
if (free_and_strdup(&rule->iif, b) < 0)
|
||||
return log_oom();
|
||||
|
||||
} else if (streq(a, "oif")) {
|
||||
|
||||
if (free_and_strdup(&rule->oif, b) < 0)
|
||||
return log_oom();
|
||||
} else if (streq(a, "protocol")) {
|
||||
r = safe_atou8(b, &rule->protocol);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Failed to parse RPDB rule protocol, ignoring: %s", b);
|
||||
continue;
|
||||
}
|
||||
} else if (streq(a, "sourceport")) {
|
||||
uint16_t low, high;
|
||||
|
||||
r = parse_ip_port_range(b, &low, &high);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Invalid routing policy rule source port range, ignoring assignment: '%s'", b);
|
||||
continue;
|
||||
}
|
||||
|
||||
rule->sport.start = low;
|
||||
rule->sport.end = high;
|
||||
} else if (streq(a, "destinationport")) {
|
||||
uint16_t low, high;
|
||||
|
||||
r = parse_ip_port_range(b, &low, &high);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Invalid routing policy rule destination port range, ignoring assignment: '%s'", b);
|
||||
continue;
|
||||
}
|
||||
|
||||
rule->dport.start = low;
|
||||
rule->dport.end = high;
|
||||
} else if (streq(a, "uidrange")) {
|
||||
uid_t lower, upper;
|
||||
|
||||
r = parse_uid_range(b, &lower, &upper);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Invalid routing policy rule uid range, ignoring assignment: '%s'", b);
|
||||
continue;
|
||||
}
|
||||
|
||||
rule->uid_range.start = lower;
|
||||
rule->uid_range.end = upper;
|
||||
} else if (streq(a, "suppress_prefixlen")) {
|
||||
r = parse_ip_prefix_length(b, &rule->suppress_prefixlen);
|
||||
if (r == -ERANGE) {
|
||||
log_warning_errno(r, "Prefix length outside of valid range 0-128, ignoring: %s", b);
|
||||
continue;
|
||||
}
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Failed to parse RPDB rule suppress_prefixlen, ignoring: %s", b);
|
||||
continue;
|
||||
}
|
||||
} 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;
|
||||
} else
|
||||
log_warning("Unknown RPDB rule, ignoring: %s", a);
|
||||
}
|
||||
|
||||
r = set_ensure_put(rules, &routing_policy_rule_hash_ops, rule);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Failed to add RPDB rule to saved DB, ignoring: %s", *i);
|
||||
continue;
|
||||
}
|
||||
if (r > 0)
|
||||
rule = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -24,9 +24,11 @@ typedef struct RoutingPolicyRule {
|
|||
|
||||
uint8_t tos;
|
||||
uint8_t type;
|
||||
uint8_t protocol;
|
||||
uint8_t ipproto; /* FRA_IP_PROTO */
|
||||
uint8_t protocol; /* FRA_PROTOCOL */
|
||||
uint8_t to_prefixlen;
|
||||
uint8_t from_prefixlen;
|
||||
uint8_t l3mdev; /* FRA_L3MDEV */
|
||||
|
||||
uint32_t table;
|
||||
uint32_t fwmark;
|
||||
|
@ -56,9 +58,13 @@ void network_drop_invalid_routing_policy_rules(Network *network);
|
|||
int link_set_routing_policy_rules(Link *link);
|
||||
|
||||
int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Manager *m);
|
||||
|
||||
int routing_policy_serialize_rules(Set *rules, FILE *f);
|
||||
int routing_policy_load_rules(const char *state_file, Set **rules);
|
||||
int manager_drop_routing_policy_rules_internal(Manager *m, bool foreign, const Link *except);
|
||||
static inline int manager_drop_foreign_routing_policy_rules(Manager *m) {
|
||||
return manager_drop_routing_policy_rules_internal(m, true, NULL);
|
||||
}
|
||||
static inline int manager_drop_routing_policy_rules(Manager *m, const Link *except) {
|
||||
return manager_drop_routing_policy_rules_internal(m, false, except);
|
||||
}
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_tos);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_table);
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "networkd-routing-policy-rule.h"
|
||||
#include "string-util.h"
|
||||
#include "tests.h"
|
||||
#include "tmpfile-util.h"
|
||||
|
||||
static void test_rule_serialization(const char *title, const char *ruleset, const char *expected) {
|
||||
char pattern[] = "/tmp/systemd-test-routing-policy-rule.XXXXXX",
|
||||
pattern2[] = "/tmp/systemd-test-routing-policy-rule.XXXXXX",
|
||||
pattern3[] = "/tmp/systemd-test-routing-policy-rule.XXXXXX";
|
||||
const char *cmd;
|
||||
int fd, fd2, fd3;
|
||||
_cleanup_fclose_ FILE *f = NULL, *f2 = NULL, *f3 = NULL;
|
||||
Set *rules = NULL;
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
size_t buf_size;
|
||||
|
||||
log_info("========== %s ==========", title);
|
||||
log_info("put:\n%s\n", ruleset);
|
||||
|
||||
fd = mkostemp_safe(pattern);
|
||||
assert_se(fd >= 0);
|
||||
assert_se(f = fdopen(fd, "a+"));
|
||||
assert_se(write_string_stream(f, ruleset, 0) == 0);
|
||||
|
||||
assert_se(routing_policy_load_rules(pattern, &rules) == 0);
|
||||
|
||||
fd2 = mkostemp_safe(pattern2);
|
||||
assert_se(fd2 >= 0);
|
||||
assert_se(f2 = fdopen(fd2, "a+"));
|
||||
|
||||
assert_se(routing_policy_serialize_rules(rules, f2) == 0);
|
||||
assert_se(fflush_and_check(f2) == 0);
|
||||
|
||||
assert_se(read_full_file(pattern2, &buf, &buf_size) == 0);
|
||||
|
||||
log_info("got:\n%s", buf);
|
||||
|
||||
fd3 = mkostemp_safe(pattern3);
|
||||
assert_se(fd3 >= 0);
|
||||
assert_se(f3 = fdopen(fd3, "w"));
|
||||
assert_se(write_string_stream(f3, expected ?: ruleset, 0) == 0);
|
||||
|
||||
cmd = strjoina("diff -u ", pattern3, " ", pattern2);
|
||||
log_info("$ %s", cmd);
|
||||
assert_se(system(cmd) == 0);
|
||||
|
||||
set_free(rules);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
|
||||
test_setup_logging(LOG_DEBUG);
|
||||
|
||||
test_rule_serialization("basic parsing",
|
||||
"RULE=family=AF_INET from=1.2.3.4/32 to=2.3.4.5/32 tos=5 type=1 priority=10 fwmark=1/2 invert_rule=yes table=10", NULL);
|
||||
|
||||
test_rule_serialization("ignored values",
|
||||
"RULE=something=to=ignore from=1.2.3.4/32 from=1.2.3.4/32"
|
||||
" \t to=2.3.4.5/24 to=2.3.4.5/32 tos=5 type=1 fwmark=2 fwmark=1 table=10 table=20",
|
||||
"RULE=family=AF_INET from=1.2.3.4/32 to=2.3.4.5/32 tos=5 type=1 fwmark=1 invert_rule=no table=20");
|
||||
|
||||
test_rule_serialization("ipv6",
|
||||
"RULE=family=AF_INET6 from=1::2/64 to=2::3/64 type=1 invert_rule=yes table=6", NULL);
|
||||
|
||||
assert_se(asprintf(&p, "RULE=family=AF_INET6 from=1::2/64 to=2::3/64 type=1 invert_rule=no table=%d", RT_TABLE_MAIN) >= 0);
|
||||
test_rule_serialization("default table",
|
||||
"RULE=from=1::2/64 to=2::3/64", p);
|
||||
|
||||
test_rule_serialization("incoming interface",
|
||||
"RULE=from=1::2/64 to=2::3/64 table=1 iif=lo",
|
||||
"RULE=family=AF_INET6 from=1::2/64 to=2::3/64 type=1 iif=lo invert_rule=no table=1");
|
||||
|
||||
test_rule_serialization("outgoing interface",
|
||||
"RULE=family=AF_INET6 from=1::2/64 to=2::3/64 type=1 oif=eth0 invert_rule=no table=1", NULL);
|
||||
|
||||
test_rule_serialization("freeing interface names",
|
||||
"RULE=from=1::2/64 to=2::3/64 family=AF_INET6 type=1 iif=e0 iif=e1 oif=e0 oif=e1 table=1",
|
||||
"RULE=family=AF_INET6 from=1::2/64 to=2::3/64 type=1 iif=e1 oif=e1 invert_rule=no table=1");
|
||||
|
||||
test_rule_serialization("ignoring invalid family",
|
||||
"RULE=from=1::2/64 to=2::3/64 family=AF_UNSEPC family=AF_INET table=1",
|
||||
"RULE=family=AF_INET6 from=1::2/64 to=2::3/64 type=1 invert_rule=no table=1");
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -3326,7 +3326,7 @@ class NetworkdBridgeTests(unittest.TestCase, Utilities):
|
|||
|
||||
output = check_output('ip rule list table 100')
|
||||
print(output)
|
||||
self.assertEqual(output, '0: from all to 8.8.8.8 lookup 100')
|
||||
self.assertIn('0: from all to 8.8.8.8 lookup 100', output)
|
||||
|
||||
class NetworkdLLDPTests(unittest.TestCase, Utilities):
|
||||
links = ['veth99']
|
||||
|
|
Loading…
Reference in New Issue