diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2018-11-29 03:17:36 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-11-29 03:17:36 +0900 |
commit | fab57f7f1398d746a0d64fd1c9c04ef2ca1eb544 (patch) | |
tree | 39ed01e20ade75dad855477d3d65280a879ebe32 | |
parent | meson: let's bump RLIMIT_NOFILE hard limit to 512K (diff) | |
parent | networkd: add support to configure ip rule port range and protocol. (diff) | |
download | systemd-fab57f7f1398d746a0d64fd1c9c04ef2ca1eb544.tar.gz systemd-fab57f7f1398d746a0d64fd1c9c04ef2ca1eb544.tar.bz2 systemd-fab57f7f1398d746a0d64fd1c9c04ef2ca1eb544.zip |
Merge pull request #10948 from ssahani/iprule-port-proto
networkd: add support to configure ip rule port range and protocol.
-rw-r--r-- | man/systemd.network.xml | 21 | ||||
-rw-r--r-- | meson.build | 3 | ||||
-rw-r--r-- | src/basic/missing.h | 18 | ||||
-rw-r--r-- | src/basic/parse-util.c | 20 | ||||
-rw-r--r-- | src/basic/parse-util.h | 1 | ||||
-rw-r--r-- | src/libsystemd/sd-netlink/netlink-message.c | 19 | ||||
-rw-r--r-- | src/libsystemd/sd-netlink/netlink-types.c | 4 | ||||
-rw-r--r-- | src/network/networkd-link.c | 3 | ||||
-rw-r--r-- | src/network/networkd-manager.c | 25 | ||||
-rw-r--r-- | src/network/networkd-network-gperf.gperf | 3 | ||||
-rw-r--r-- | src/network/networkd-routing-policy-rule.c | 197 | ||||
-rw-r--r-- | src/network/networkd-routing-policy-rule.h | 16 | ||||
-rw-r--r-- | src/systemd/sd-netlink.h | 1 | ||||
-rw-r--r-- | test/fuzz/fuzz-network-parser/25-fibrule-port-range.network | 11 | ||||
-rw-r--r-- | test/fuzz/fuzz-network-parser/directives.network | 3 | ||||
-rw-r--r-- | test/test-network/conf/25-fibrule-port-range.network | 11 | ||||
-rwxr-xr-x | test/test-network/systemd-networkd-tests.py | 20 |
17 files changed, 359 insertions, 17 deletions
diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 1bffedd00..1b6a6d44d 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -992,6 +992,27 @@ <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> + <varlistentry> + <term><varname>SourcePort=</varname></term> + <listitem> + <para>Specifies the source IP port or IP port range match in forwarding information base (FIB) rules. + A port range is specified by the lower and upper port separated by a dash. Defaults to unset.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><varname>DestinationPort=</varname></term> + <listitem> + <para>Specifies the destination IP port or IP port range match in forwarding information base (FIB) rules. + A port range is specified by the lower and upper port separated by a dash. Defaults to unset.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><varname>Protocol=</varname></term> + <listitem> + <para>Specifies the protocol to match in forwarding information base (FIB) rules. Accepted values are tcp, udp and sctp. + Defaults to unset.</para> + </listitem> + </varlistentry> </variablelist> </refsect1> diff --git a/meson.build b/meson.build index a46090ad4..b4093b130 100644 --- a/meson.build +++ b/meson.build @@ -426,6 +426,7 @@ decl_headers = ''' foreach decl : ['char16_t', 'char32_t', 'struct fib_rule_uid_range', + 'struct fib_rule_port_range', 'struct statx', ] @@ -471,7 +472,7 @@ foreach decl : [['IFLA_INET6_ADDR_GEN_MODE', 'linux/if_link.h'], ['IPVLAN_F_PRIVATE', 'linux/if_link.h'], ['NDA_IFINDEX', 'linux/neighbour.h'], ['IFA_FLAGS', 'linux/if_addr.h'], - ['FRA_UID_RANGE', 'linux/fib_rules.h'], + ['FRA_DPORT_RANGE', 'linux/fib_rules.h'], ['LO_FLAGS_PARTSCAN', 'linux/loop.h'], ['VXCAN_INFO_PEER', 'linux/can/vxcan.h'], ['FOU_ATTR_REMCSUM_NOPARTIAL', 'linux/fou.h'], diff --git a/src/basic/missing.h b/src/basic/missing.h index c0c1d4066..99a463b7b 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -9,6 +9,7 @@ #include <linux/audit.h> #include <linux/capability.h> #include <linux/falloc.h> +#include <linux/fib_rules.h> #include <linux/if_link.h> #include <linux/input.h> #include <linux/loop.h> @@ -988,7 +989,7 @@ struct input_mask { #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) #endif -#if !HAVE_FRA_UID_RANGE +#if !HAVE_FRA_DPORT_RANGE #define FRA_UNSPEC 0 #define FRA_DST 1 #define FRA_SRC 2 @@ -1010,7 +1011,11 @@ struct input_mask { #define FRA_PAD 18 #define FRA_L3MDEV 19 #define FRA_UID_RANGE 20 -#define __FRA_MAX 12 +#define FRA_PROTOCOL 21 +#define FRA_IP_PROTO 22 +#define FRA_SPORT_RANGE 23 +#define FRA_DPORT_RANGE 24 +#define __FRA_MAX 25 #define FRA_MAX (__FRA_MAX - 1) #endif @@ -1311,6 +1316,15 @@ struct fib_rule_uid_range { #endif +#if ! HAVE_STRUCT_FIB_RULE_PORT_RANGE + +struct fib_rule_port_range { + __u16 start; + __u16 end; +}; + +#endif + #endif #ifndef SOL_ALG diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c index a9085348b..ce8bb1267 100644 --- a/src/basic/parse-util.c +++ b/src/basic/parse-util.c @@ -710,6 +710,26 @@ int parse_ip_port(const char *s, uint16_t *ret) { return 0; } +int parse_ip_port_range(const char *s, uint16_t *low, uint16_t *high) { + unsigned l, h; + int r; + + r = parse_range(s, &l, &h); + if (r < 0) + return r; + + if (l <= 0 || l > 65535 || h <= 0 || h > 65535) + return -EINVAL; + + if (h < l) + return -EINVAL; + + *low = l; + *high = h; + + return 0; +} + int parse_dev(const char *s, dev_t *ret) { unsigned x, y; dev_t d; diff --git a/src/basic/parse-util.h b/src/basic/parse-util.h index f3267f4cf..e47641b42 100644 --- a/src/basic/parse-util.h +++ b/src/basic/parse-util.h @@ -115,5 +115,6 @@ int parse_permille(const char *p); int parse_nice(const char *p, int *ret); int parse_ip_port(const char *s, uint16_t *ret); +int parse_ip_port_range(const char *s, uint16_t *low, uint16_t *high); int parse_oom_score_adjust(const char *s, int *ret); diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c index 487a58ca7..b0b25639f 100644 --- a/src/libsystemd/sd-netlink/netlink-message.c +++ b/src/libsystemd/sd-netlink/netlink-message.c @@ -562,6 +562,25 @@ static int netlink_message_read_internal(sd_netlink_message *m, unsigned short t return RTA_PAYLOAD(rta); } +int sd_netlink_message_read(sd_netlink_message *m, unsigned short type, size_t size, void *data) { + void *attr_data; + int r; + + assert_return(m, -EINVAL); + + r = netlink_message_read_internal(m, type, &attr_data, NULL); + if (r < 0) + return r; + + if ((size_t) r < size) + return -EIO; + + if (data) + memcpy(data, attr_data, size); + + return 0; +} + int sd_netlink_message_read_string(sd_netlink_message *m, unsigned short type, const char **data) { int r; void *attr_data; diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c index 307b5aa34..823e654d1 100644 --- a/src/libsystemd/sd-netlink/netlink-types.c +++ b/src/libsystemd/sd-netlink/netlink-types.c @@ -641,6 +641,10 @@ static const NLType rtnl_routing_policy_rule_types[] = { [FRA_PAD] = { .type = NETLINK_TYPE_U32 }, [FRA_L3MDEV] = { .type = NETLINK_TYPE_U64 }, [FRA_UID_RANGE] = { .size = sizeof(struct fib_rule_uid_range) }, + [FRA_PROTOCOL] = { .type = NETLINK_TYPE_U8 }, + [FRA_IP_PROTO] = { .type = NETLINK_TYPE_U8 }, + [FRA_SPORT_RANGE] = { .size = sizeof(struct fib_rule_port_range) }, + [FRA_DPORT_RANGE] = { .size = sizeof(struct fib_rule_port_range) }, }; static const NLTypeSystem rtnl_routing_policy_rule_type_system = { diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 1f7b214cd..c6ad712a0 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -794,7 +794,8 @@ 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, rule->iif, rule->oif, &rrule); + rule->to_prefixlen, rule->tos, rule->fwmark, rule->table, rule->iif, rule->oif, + rule->protocol, &rule->sport, &rule->dport, &rrule); if (r == 0) { (void) routing_policy_rule_make_local(link->manager, rrule); continue; diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index fe481f1c0..3b1ae0b41 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -697,7 +697,8 @@ static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *messa } int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) { - uint8_t tos = 0, to_prefixlen = 0, from_prefixlen = 0; + uint8_t tos = 0, to_prefixlen = 0, from_prefixlen = 0, protocol = 0; + struct fib_rule_port_range sport = {}, dport = {}; union in_addr_union to = {}, from = {}; RoutingPolicyRule *rule = NULL; uint32_t fwmark = 0, table = 0; @@ -829,12 +830,30 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, voi return 0; } - (void) routing_policy_rule_get(m, family, &from, from_prefixlen, &to, to_prefixlen, tos, fwmark, table, iif, oif, &rule); + r = sd_netlink_message_read_u8(message, FRA_IP_PROTO, &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(sport), (void *) &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(dport), (void *) &dport); + if (r < 0 && r != -ENODATA) { + log_warning_errno(r, "rtnl: could not get FRA_DPORT_RANGE attribute, ignoring: %m"); + return 0; + } + + (void) routing_policy_rule_get(m, family, &from, from_prefixlen, &to, to_prefixlen, tos, fwmark, table, iif, oif, protocol, &sport, &dport, &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, iif, oif, &rule); + r = routing_policy_rule_add_foreign(m, family, &from, from_prefixlen, &to, to_prefixlen, tos, fwmark, table, iif, oif, protocol, &sport, &dport, &rule); if (r < 0) { log_warning_errno(r, "Could not add rule, ignoring: %m"); return 0; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 8bbdd290a..378b63af8 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -101,6 +101,9 @@ RoutingPolicyRule.From, config_parse_routing_policy_rule_prefix, 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 +RoutingPolicyRule.Protocol, config_parse_routing_policy_rule_protocol, 0, 0 +RoutingPolicyRule.SourcePort, config_parse_routing_policy_rule_port_range, 0, 0 +RoutingPolicyRule.DestinationPort, config_parse_routing_policy_rule_port_range, 0, 0 Route.Gateway, config_parse_gateway, 0, 0 Route.Destination, config_parse_destination, 0, 0 Route.Source, config_parse_destination, 0, 0 diff --git a/src/network/networkd-routing-policy-rule.c b/src/network/networkd-routing-policy-rule.c index 683c16628..1b2222cad 100644 --- a/src/network/networkd-routing-policy-rule.c +++ b/src/network/networkd-routing-policy-rule.c @@ -10,6 +10,7 @@ #include "netlink-util.h" #include "networkd-manager.h" #include "parse-util.h" +#include "socket-protocol-list.h" #include "socket-util.h" #include "string-util.h" #include "strv.h" @@ -76,6 +77,10 @@ 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); + siphash24_compress(&rule->protocol, sizeof(rule->protocol), state); + siphash24_compress(&rule->sport, sizeof(rule->sport), state); + siphash24_compress(&rule->dport, sizeof(rule->dport), state); + if (rule->iif) siphash24_compress(rule->iif, strlen(rule->iif), state); @@ -128,6 +133,18 @@ static int routing_policy_rule_compare_func(const void *_a, const void *_b) { if (!r) return r; + 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; + r = memcmp(&a->from, &b->from, FAMILY_ADDRESS_SIZE(a->family)); if (r != 0) return r; @@ -156,6 +173,9 @@ int routing_policy_rule_get(Manager *m, uint32_t table, const char *iif, const char *oif, + uint8_t protocol, + struct fib_rule_port_range *sport, + struct fib_rule_port_range *dport, RoutingPolicyRule **ret) { RoutingPolicyRule rule, *existing; @@ -172,7 +192,10 @@ int routing_policy_rule_get(Manager *m, .fwmark = fwmark, .table = table, .iif = (char*) iif, - .oif = (char*) oif + .oif = (char*) oif, + .protocol = protocol, + .sport = *sport, + .dport = *dport, }; existing = set_get(m->rules, &rule); @@ -222,6 +245,9 @@ static int routing_policy_rule_add_internal(Manager *m, uint32_t table, const char *_iif, const char *_oif, + uint8_t protocol, + const struct fib_rule_port_range *sport, + const struct fib_rule_port_range *dport, RoutingPolicyRule **ret) { _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL; @@ -257,6 +283,9 @@ static int routing_policy_rule_add_internal(Manager *m, rule->table = table; rule->iif = iif; rule->oif = oif; + rule->protocol = protocol; + rule->sport = *sport; + rule->dport = *dport; r = set_ensure_allocated(rules, &routing_policy_rule_hash_ops); if (r < 0) @@ -286,9 +315,12 @@ int routing_policy_rule_add(Manager *m, uint32_t table, const char *iif, const char *oif, + uint8_t protocol, + const struct fib_rule_port_range *sport, + const struct fib_rule_port_range *dport, RoutingPolicyRule **ret) { - return routing_policy_rule_add_internal(m, &m->rules, family, from, from_prefixlen, to, to_prefixlen, tos, fwmark, table, iif, oif, ret); + return routing_policy_rule_add_internal(m, &m->rules, family, from, from_prefixlen, to, to_prefixlen, tos, fwmark, table, iif, oif, protocol, sport, dport, ret); } int routing_policy_rule_add_foreign(Manager *m, @@ -302,8 +334,11 @@ int routing_policy_rule_add_foreign(Manager *m, uint32_t table, const char *iif, const char *oif, + uint8_t protocol, + const struct fib_rule_port_range *sport, + const struct fib_rule_port_range *dport, RoutingPolicyRule **ret) { - return routing_policy_rule_add_internal(m, &m->rules_foreign, family, from, from_prefixlen, to, to_prefixlen, tos, fwmark, table, iif, oif, ret); + return routing_policy_rule_add_internal(m, &m->rules_foreign, family, from, from_prefixlen, to, to_prefixlen, tos, fwmark, table, iif, oif, protocol, sport, dport, ret); } static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { @@ -544,6 +579,22 @@ int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, sd_netlin return log_error_errno(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_error_errno(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_error_errno(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_error_errno(r, "Could not append FRA_DPORT_RANGE attribute: %m"); + } + rule->link = link; r = sd_netlink_call_async(link->manager->rtnl, NULL, m, callback, @@ -554,7 +605,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, rule->iif, rule->oif, NULL); + rule->to_prefixlen, rule->tos, rule->fwmark, rule->table, rule->iif, rule->oif, rule->protocol, &rule->sport, &rule->dport, NULL); if (r < 0) return log_error_errno(r, "Could not add rule: %m"); @@ -836,6 +887,95 @@ int config_parse_routing_policy_rule_device( return 0; } +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) { + _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL; + 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) + return r; + + r = parse_ip_port_range(rvalue, &low, &high); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse routing policy rule port range '%s'", rvalue); + 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; +} + +int config_parse_routing_policy_rule_protocol( + 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_freep) 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; + + r = socket_protocol_from_name(rvalue); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse routing policy rule protocol, ignoring: %s", rvalue); + return 0; + } + + if (!IN_SET(r, IPPROTO_TCP, IPPROTO_UDP, IPPROTO_SCTP)) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid protocol '%s'. Protocol should be tcp/udp/sctp, ignoring", rvalue); + return 0; + } + + n->protocol = r; + + n = NULL; + + return 0; +} + static int routing_policy_rule_read_full_file(const char *state_file, char **ret) { _cleanup_free_ char *s = NULL; size_t size; @@ -918,6 +1058,27 @@ int routing_policy_serialize_rules(Set *rules, FILE *f) { 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=%hhu-%hhu", + space ? " " : "", + rule->sport.start, rule->sport.end); + space = true; + } + + if (rule->dport.start != 0 || rule->dport.end != 0) { + fprintf(f, "%sdestinationport=%hhu-%hhu", + space ? " " : "", + rule->dport.start, rule->dport.end); + space = true; + } + fprintf(f, "%stable=%"PRIu32 "\n", space ? " " : "", rule->table); @@ -929,6 +1090,7 @@ int routing_policy_serialize_rules(Set *rules, FILE *f) { int routing_policy_load_rules(const char *state_file, Set **rules) { _cleanup_strv_free_ char **l = NULL; _cleanup_free_ char *data = NULL; + uint16_t low = 0, high = 0; const char *p; char **i; int r; @@ -1023,6 +1185,33 @@ int routing_policy_load_rules(const char *state_file, Set **rules) { 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_error_errno(r, "Failed to parse RPDB rule protocol, ignoring: %s", b); + continue; + } + } else if (streq(a, "sourceport")) { + + r = parse_ip_port_range(b, &low, &high); + if (r < 0) { + log_error_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")) { + + r = parse_ip_port_range(b, &low, &high); + if (r < 0) { + log_error_errno(r, "Invalid routing policy rule destination port range, ignoring assignment:'%s'", b); + continue; + } + + rule->dport.start = low; + rule->dport.end = high; } } diff --git a/src/network/networkd-routing-policy-rule.h b/src/network/networkd-routing-policy-rule.h index 2e7474ef5..3bb3b4cd8 100644 --- a/src/network/networkd-routing-policy-rule.h +++ b/src/network/networkd-routing-policy-rule.h @@ -2,6 +2,7 @@ #pragma once #include <inttypes.h> +#include <linux/fib_rules.h> #include <stdbool.h> #include "in-addr-util.h" @@ -24,6 +25,7 @@ struct RoutingPolicyRule { NetworkConfigSection *section; uint8_t tos; + uint8_t protocol; uint32_t table; uint32_t fwmark; @@ -40,6 +42,9 @@ struct RoutingPolicyRule { union in_addr_union to; union in_addr_union from; + struct fib_rule_port_range sport; + struct fib_rule_port_range dport; + LIST_FIELDS(RoutingPolicyRule, rules); }; @@ -54,11 +59,14 @@ 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, const char *iif, const char *oif, RoutingPolicyRule **ret); + uint8_t tos, uint32_t fwmark, uint32_t table, const char *iif, const char *oif, uint8_t protocol, const struct fib_rule_port_range *sport, + const struct fib_rule_port_range *dport, 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, const char *iif, const char *oif, RoutingPolicyRule **ret); + uint8_t tos, uint32_t fwmark, uint32_t table, const char *iif, const char *oif, uint8_t protocol, const struct fib_rule_port_range *sport, + const struct fib_rule_port_range *dport, 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, const char *iif, const char *oif, RoutingPolicyRule **ret); + uint32_t fwmark, uint32_t table, const char *iif, const char *oif, uint8_t protocol, struct fib_rule_port_range *sport, + struct fib_rule_port_range *dport, RoutingPolicyRule **ret); int routing_policy_rule_make_local(Manager *m, RoutingPolicyRule *rule); int routing_policy_serialize_rules(Set *rules, FILE *f); int routing_policy_load_rules(const char *state_file, Set **rules); @@ -70,3 +78,5 @@ CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_fwmark_mask); CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_prefix); CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_priority); CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_device); +CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_port_range); +CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_protocol); diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h index 276953eb8..e1b89559a 100644 --- a/src/systemd/sd-netlink.h +++ b/src/systemd/sd-netlink.h @@ -85,6 +85,7 @@ int sd_netlink_message_open_container(sd_netlink_message *m, unsigned short type int sd_netlink_message_open_container_union(sd_netlink_message *m, unsigned short type, const char *key); int sd_netlink_message_close_container(sd_netlink_message *m); +int sd_netlink_message_read(sd_netlink_message *m, unsigned short type, size_t size, void *data); int sd_netlink_message_read_string(sd_netlink_message *m, unsigned short type, const char **data); int sd_netlink_message_read_u8(sd_netlink_message *m, unsigned short type, uint8_t *data); int sd_netlink_message_read_u16(sd_netlink_message *m, unsigned short type, uint16_t *data); diff --git a/test/fuzz/fuzz-network-parser/25-fibrule-port-range.network b/test/fuzz/fuzz-network-parser/25-fibrule-port-range.network new file mode 100644 index 000000000..b0502175f --- /dev/null +++ b/test/fuzz/fuzz-network-parser/25-fibrule-port-range.network @@ -0,0 +1,11 @@ +[Match] +Name=test1 + +[RoutingPolicyRule] +TypeOfService=0x08 +Table=7 +From= 192.168.100.18 +Priority=111 +SourcePort = 1123-1150 +DestinationPort = 3224-3290 +Protocol = tcp diff --git a/test/fuzz/fuzz-network-parser/directives.network b/test/fuzz/fuzz-network-parser/directives.network index 766c76008..7508f693d 100644 --- a/test/fuzz/fuzz-network-parser/directives.network +++ b/test/fuzz/fuzz-network-parser/directives.network @@ -150,6 +150,9 @@ From= TypeOfService= Priority= FirewallMark= +SourcePort= +DestinationPort= +Protocol= [IPv6PrefixDelegation] RouterPreference= DNSLifetimeSec= diff --git a/test/test-network/conf/25-fibrule-port-range.network b/test/test-network/conf/25-fibrule-port-range.network new file mode 100644 index 000000000..b0502175f --- /dev/null +++ b/test/test-network/conf/25-fibrule-port-range.network @@ -0,0 +1,11 @@ +[Match] +Name=test1 + +[RoutingPolicyRule] +TypeOfService=0x08 +Table=7 +From= 192.168.100.18 +Priority=111 +SourcePort = 1123-1150 +DestinationPort = 3224-3290 +Protocol = tcp diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 74c0e1000..130b20f82 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -427,9 +427,9 @@ class NetworkdNetWorkTests(unittest.TestCase, Utilities): units = ['12-dummy.netdev', 'test-static.network', 'configure-without-carrier.network', '11-dummy.netdev', '23-primary-slave.network', '23-test1-bond199.network', '11-dummy.netdev', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev', '23-active-slave.network', - 'routing-policy-rule.network', '25-address-section.network', '25-address-section-miscellaneous.network', - '25-route-section.network', '25-route-type.network', '25-route-tcp-window-settings.network', - '25-route-gateway.network', '25-route-gateway-on-link.network', + 'routing-policy-rule.network', '25-fibrule-port-range.network', '25-address-section.network', + '25-address-section-miscellaneous.network', '25-route-section.network', '25-route-type.network', + '25-route-tcp-window-settings.network', '25-route-gateway.network', '25-route-gateway-on-link.network', '25-address-link-section.network', '25-ipv6-address-label-section.network', '25-link-section-unmanaged.network', '25-sysctl.network', '25-route-reverse-order.network'] @@ -496,6 +496,20 @@ class NetworkdNetWorkTests(unittest.TestCase, Utilities): self.assertRegex(output, 'oif test1') self.assertRegex(output, 'lookup 7') + def test_routing_policy_rule_port_range(self): + self.copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev') + self.start_networkd() + + self.assertTrue(self.link_exits('test1')) + output = subprocess.check_output(['ip', 'rule']).rstrip().decode('utf-8') + print(output) + self.assertRegex(output, '111') + self.assertRegex(output, 'from 192.168.100.18') + self.assertRegex(output, '1123-1150') + self.assertRegex(output, '3224-3290') + self.assertRegex(output, 'tcp') + self.assertRegex(output, 'lookup 7') + def test_address_preferred_lifetime_zero_ipv6(self): self.copy_unit_to_networkd_unit_path('25-address-section-miscellaneous.network', '12-dummy.netdev') self.start_networkd() |