networkd: support incoming/outgoing device for rule matching (#7223)

Closes #7210
This commit is contained in:
Susant Sahani 2017-11-21 16:21:50 +05:30 committed by Lennart Poettering
parent 172378e01b
commit 762e2659b9
6 changed files with 126 additions and 9 deletions

View File

@ -926,6 +926,18 @@
integer. Higher number means lower priority, and rules get processed in order of increasing number.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>IncomingInterface=</varname></term>
<listitem>
<para>Specifies incoming device to match. If the interface is loopback, the rule only matches packets originating from this host.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>OutgoingInterface=</varname></term>
<listitem>
<para>Specifies the outgoing device to match. The outgoing interface is only available for packets originating from local sockets that are bound to a device.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>

View File

@ -784,7 +784,7 @@ static int link_set_routing_policy_rule(Link *link) {
LIST_FOREACH(rules, rule, link->network->rules) {
r = routing_policy_rule_get(link->manager, rule->family, &rule->from, rule->from_prefixlen, &rule->to,
rule->to_prefixlen, rule->tos, rule->fwmark, rule->table, &rrule);
rule->to_prefixlen, rule->tos, rule->fwmark, rule->table, rule->iif, rule->oif, &rrule);
if (r == 1) {
(void) routing_policy_rule_make_local(link->manager, rrule);
continue;

View File

@ -732,6 +732,7 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, voi
union in_addr_union to, from;
uint32_t fwmark = 0, table = 0;
Manager *m = userdata;
char *iif, *oif;
uint16_t type;
int family;
int r;
@ -811,13 +812,15 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, voi
(void) sd_netlink_message_read_u32(message, FRA_FWMARK, &fwmark);
(void) sd_netlink_message_read_u32(message, FRA_TABLE, &table);
(void) sd_rtnl_message_routing_policy_rule_get_tos(message, &tos);
(void) sd_netlink_message_read_string(message, FRA_IIFNAME, (const char **) &iif);
(void) sd_netlink_message_read_string(message, FRA_OIFNAME, (const char **) &oif);
(void) routing_policy_rule_get(m, family, &from, from_prefixlen, &to, to_prefixlen, tos, fwmark, table, &rule);
(void) routing_policy_rule_get(m, family, &from, from_prefixlen, &to, to_prefixlen, tos, fwmark, table, iif, oif, &rule);
switch (type) {
case RTM_NEWRULE:
if(!rule) {
r = routing_policy_rule_add_foreign(m, family, &from, from_prefixlen, &to, to_prefixlen, tos, fwmark, table, &rule);
r = routing_policy_rule_add_foreign(m, family, &from, from_prefixlen, &to, to_prefixlen, tos, fwmark, table, iif, oif, &rule);
if (r < 0) {
log_warning_errno(r, "Could not add rule: %m");
return 0;

View File

@ -90,6 +90,8 @@ RoutingPolicyRule.Table, config_parse_routing_policy_rule_table,
RoutingPolicyRule.FirewallMark, config_parse_routing_policy_rule_fwmark_mask, 0, 0
RoutingPolicyRule.From, config_parse_routing_policy_rule_prefix, 0, 0
RoutingPolicyRule.To, config_parse_routing_policy_rule_prefix, 0, 0
RoutingPolicyRule.IncomingInterface, config_parse_routing_policy_rule_device, 0, 0
RoutingPolicyRule.OutgoingInterface, config_parse_routing_policy_rule_device, 0, 0
Route.Gateway, config_parse_gateway, 0, 0
Route.Destination, config_parse_destination, 0, 0
Route.Source, config_parse_destination, 0, 0

View File

@ -66,6 +66,8 @@ void routing_policy_rule_free(RoutingPolicyRule *rule) {
}
}
free(rule->iif);
free(rule->oif);
free(rule);
}
@ -90,6 +92,12 @@ static void routing_policy_rule_hash_func(const void *b, struct siphash *state)
siphash24_compress(&rule->fwmark, sizeof(rule->fwmark), state);
siphash24_compress(&rule->table, sizeof(rule->table), state);
if (rule->iif)
siphash24_compress(&rule->iif, strlen(rule->iif), state);
if (rule->oif)
siphash24_compress(&rule->oif, strlen(rule->oif), state);
break;
default:
/* treat any other address family as AF_UNSPEC */
@ -134,6 +142,14 @@ static int routing_policy_rule_compare_func(const void *_a, const void *_b) {
if (a->table > b->table)
return 1;
r = strcmp_ptr(a->iif, b->iif);
if (!r)
return r;
r = strcmp_ptr(a->oif, b->oif);
if (!r)
return r;
r = memcmp(&a->from, &b->from, FAMILY_ADDRESS_SIZE(a->family));
if (r != 0)
return r;
@ -160,6 +176,8 @@ int routing_policy_rule_get(Manager *m,
uint8_t tos,
uint32_t fwmark,
uint32_t table,
char *iif,
char *oif,
RoutingPolicyRule **ret) {
RoutingPolicyRule rule, *existing;
@ -175,6 +193,8 @@ int routing_policy_rule_get(Manager *m,
.tos = tos,
.fwmark = fwmark,
.table = table,
.iif = iif,
.oif = oif
};
if (m->rules) {
@ -225,6 +245,8 @@ static int routing_policy_rule_add_internal(Set **rules,
uint8_t tos,
uint32_t fwmark,
uint32_t table,
char *iif,
char *oif,
RoutingPolicyRule **ret) {
_cleanup_routing_policy_rule_free_ RoutingPolicyRule *rule = NULL;
@ -244,6 +266,8 @@ static int routing_policy_rule_add_internal(Set **rules,
rule->tos = tos;
rule->fwmark = fwmark;
rule->table = table;
rule->iif = iif;
rule->oif = oif;
r = set_ensure_allocated(rules, &routing_policy_rule_hash_ops);
if (r < 0)
@ -270,9 +294,11 @@ int routing_policy_rule_add(Manager *m,
uint8_t tos,
uint32_t fwmark,
uint32_t table,
char *iif,
char *oif,
RoutingPolicyRule **ret) {
return routing_policy_rule_add_internal(&m->rules, family, from, from_prefixlen, to, to_prefixlen, tos, fwmark, table, ret);
return routing_policy_rule_add_internal(&m->rules, family, from, from_prefixlen, to, to_prefixlen, tos, fwmark, table, iif, oif, ret);
}
int routing_policy_rule_add_foreign(Manager *m,
@ -284,8 +310,10 @@ int routing_policy_rule_add_foreign(Manager *m,
uint8_t tos,
uint32_t fwmark,
uint32_t table,
char *iif,
char *oif,
RoutingPolicyRule **ret) {
return routing_policy_rule_add_internal(&m->rules_foreign, family, from, from_prefixlen, to, to_prefixlen, tos, fwmark, table, ret);
return routing_policy_rule_add_internal(&m->rules_foreign, family, from, from_prefixlen, to, to_prefixlen, tos, fwmark, table, iif, oif, ret);
}
static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
@ -505,6 +533,18 @@ int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, sd_netlin
return log_error_errno(r, "Could not append FRA_FWMASK attribute: %m");
}
if (rule->iif) {
r = sd_netlink_message_append_string(m, FRA_IFNAME, rule->iif);
if (r < 0)
return log_error_errno(r, "Could not append FRA_IFNAME attribute: %m");
}
if (rule->oif) {
r = sd_netlink_message_append_string(m, FRA_OIFNAME, rule->oif);
if (r < 0)
return log_error_errno(r, "Could not append FRA_OIFNAME attribute: %m");
}
rule->link = link;
r = sd_netlink_call_async(link->manager->rtnl, m, callback, link, 0, NULL);
@ -514,7 +554,7 @@ int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, sd_netlin
link_ref(link);
r = routing_policy_rule_add(link->manager, rule->family, &rule->from, rule->from_prefixlen, &rule->to,
rule->to_prefixlen, rule->tos, rule->fwmark, rule->table, NULL);
rule->to_prefixlen, rule->tos, rule->fwmark, rule->table, rule->iif, rule->oif, NULL);
if (r < 0)
return log_error_errno(r, "Could not add rule : %m");
@ -750,6 +790,52 @@ int config_parse_routing_policy_rule_prefix(
return 0;
}
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) {
_cleanup_routing_policy_rule_free_ 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)
return r;
if (!ifname_valid(rvalue)) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse '%s' interface name, ignoring: %s", lvalue, rvalue);
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;
}
static int routing_policy_rule_read_full_file(char *state_file, char **ret) {
_cleanup_free_ char *s = NULL;
size_t size;
@ -861,6 +947,16 @@ int routing_policy_rule_load(Manager *m) {
log_error_errno(r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", a);
continue;
}
} else if (streq(a, "IncomingInterface")) {
rule->iif = strdup(a);
if (!rule->iif)
return log_oom();
} else if (streq(a, "OutgoingInterface")) {
rule->oif = strdup(a);
if (!rule->oif)
return log_oom();
}
}

View File

@ -50,6 +50,9 @@ struct RoutingPolicyRule {
unsigned char to_prefixlen;
unsigned char from_prefixlen;
char *iif;
char *oif;
union in_addr_union to;
union in_addr_union from;
@ -68,11 +71,11 @@ int link_routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_message
int link_routing_policy_rule_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata);
int routing_policy_rule_add(Manager *m, int family, const union in_addr_union *from, uint8_t from_prefixlen, const union in_addr_union *to, uint8_t to_prefixlen,
uint8_t tos, uint32_t fwmark, uint32_t table, RoutingPolicyRule **ret);
uint8_t tos, uint32_t fwmark, uint32_t table, char *iif, char *oif, RoutingPolicyRule **ret);
int routing_policy_rule_add_foreign(Manager *m, int family, const union in_addr_union *from, uint8_t from_prefixlen, const union in_addr_union *to, uint8_t to_prefixlen,
uint8_t tos, uint32_t fwmark, uint32_t table, RoutingPolicyRule **ret);
uint8_t tos, uint32_t fwmark, uint32_t table, char *iif, char *oif, RoutingPolicyRule **ret);
int routing_policy_rule_get(Manager *m, int family, const union in_addr_union *from, uint8_t from_prefixlen, const union in_addr_union *to, uint8_t to_prefixlen, uint8_t tos,
uint32_t fwmark, uint32_t table, RoutingPolicyRule **ret);
uint32_t fwmark, uint32_t table, char *iif, char *oif, RoutingPolicyRule **ret);
int routing_policy_rule_make_local(Manager *m, RoutingPolicyRule *rule);
int routing_policy_rule_load(Manager *m);
void routing_policy_rule_purge(Manager *m, Link *link);
@ -82,3 +85,4 @@ int config_parse_routing_policy_rule_table(const char *unit, const char *filenam
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);
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);
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);
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);