mirror of
https://github.com/systemd/systemd.git
synced 2025-02-22 09:57:34 +03:00
networkd: add support to configure IP Rule (#5725)
Routing Policy rule manipulates rules in the routing policy database control the route selection algorithm. This work supports to configure Rule ``` [RoutingPolicyRule] TypeOfService=0x08 Table=7 From= 192.168.100.18 ``` ``` ip rule show 0: from all lookup local 0: from 192.168.100.18 tos 0x08 lookup 7 ``` V2 changes: 1. Added logic to handle duplicate rules. 2. If rules are changed or deleted and networkd restarted then those are deleted when networkd restarts next time V3: 1. Add parse_fwmark_fwmask
This commit is contained in:
parent
f1e24a259c
commit
bce67bbee3
@ -878,6 +878,55 @@
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>[RoutingPolicyRule] Section Options</title>
|
||||
|
||||
<para>An <literal>[RoutingPolicyRule]</literal> section accepts the
|
||||
following keys. Specify several <literal>[RoutingPolicyRule]</literal>
|
||||
sections to configure several rules.</para>
|
||||
|
||||
<variablelist class='network-directives'>
|
||||
<varlistentry>
|
||||
<term><varname>TypeOfService=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the type of service to match a number between 0 to 255.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>From=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the source address prefix to match. Possibly followed by a slash and the prefix length.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>To=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the destination address prefix to match. Possibly followed by a slash and the prefix length.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>FirewallMark=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the iptables firewall mark value to match (a number between 1 and 4294967295).</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>Table=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the routing table identifier to lookup if the rule
|
||||
selector matches. The table identifier for a route (a number between 1 and 4294967295).</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>Priority=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the priority of this rule. <varname>Priority=</varname> is an unsigned
|
||||
integer. Higher number means lower priority, and rules get processed in order of increasing number.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>[Route] Section Options</title>
|
||||
<para>The <literal>[Route]</literal> section accepts the
|
||||
|
@ -374,6 +374,7 @@ conf.set('SIZEOF_RLIM_T', cc.sizeof('rlim_t', prefix : '#include <sys/resource.h
|
||||
decl_headers = '''
|
||||
#include <uchar.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/fib_rules.h>
|
||||
'''
|
||||
# FIXME: key_serial_t is only defined in keyutils.h, this is bound to fail
|
||||
|
||||
@ -381,6 +382,7 @@ foreach decl : ['char16_t',
|
||||
'char32_t',
|
||||
'key_serial_t',
|
||||
'struct ethtool_link_settings',
|
||||
'struct fib_rule_uid_range',
|
||||
]
|
||||
|
||||
# We get -1 if the size cannot be determined
|
||||
@ -409,6 +411,7 @@ foreach decl : [['IFLA_INET6_ADDR_GEN_MODE', 'linux/if_link.h'],
|
||||
['IFLA_BR_VLAN_DEFAULT_PVID', 'linux/if_link.h'],
|
||||
['NDA_IFINDEX', 'linux/neighbour.h'],
|
||||
['IFA_FLAGS', 'linux/if_addr.h'],
|
||||
['FRA_UID_RANGE', 'linux/fib_rules.h'],
|
||||
['LO_FLAGS_PARTSCAN', 'linux/loop.h'],
|
||||
]
|
||||
prefix = decl.length() > 2 ? decl[2] : ''
|
||||
|
@ -920,6 +920,33 @@ struct input_mask {
|
||||
#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
|
||||
#endif
|
||||
|
||||
#if !HAVE_DECL_FRA_UID_RANGE
|
||||
#define FRA_UNSPEC 0
|
||||
#define FRA_DST 1
|
||||
#define FRA_SRC 2
|
||||
#define FRA_IIFNAME 3
|
||||
#define FRA_GOTO 4
|
||||
#define FRA_UNUSED2 5
|
||||
#define FRA_PRIORITY 6
|
||||
#define FRA_UNUSED3 7
|
||||
#define FRA_UNUSED4 8
|
||||
#define FRA_UNUSED5 9
|
||||
#define FRA_FWMARK 10
|
||||
#define FRA_FLOW 11
|
||||
#define FRA_TUN_ID 12
|
||||
#define FRA_SUPPRESS_IFGROUP 13
|
||||
#define FRA_SUPPRESS_PREFIXLEN 14
|
||||
#define FRA_TABLE 15
|
||||
#define FRA_FWMASK 16
|
||||
#define FRA_OIFNAME 17
|
||||
#define FRA_PAD 18
|
||||
#define FRA_L3MDEV 19
|
||||
#define FRA_UID_RANGE 20
|
||||
#define __FRA_MAX 12
|
||||
|
||||
#define FRA_MAX (__FRA_MAX - 1)
|
||||
#endif
|
||||
|
||||
#if !HAVE_DECL_IFLA_BRPORT_PROXYARP
|
||||
#define IFLA_BRPORT_PROXYARP 10
|
||||
#endif
|
||||
@ -1216,6 +1243,15 @@ struct ethtool_link_settings {
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_FIB_RULE_UID_RANGE
|
||||
|
||||
struct fib_rule_uid_range {
|
||||
__u32 start;
|
||||
__u32 end;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef SOL_ALG
|
||||
|
@ -101,12 +101,8 @@ int message_new(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t type) {
|
||||
int sd_netlink_message_request_dump(sd_netlink_message *m, int dump) {
|
||||
assert_return(m, -EINVAL);
|
||||
assert_return(m->hdr, -EINVAL);
|
||||
assert_return(m->hdr->nlmsg_type == RTM_GETLINK ||
|
||||
m->hdr->nlmsg_type == RTM_GETADDR ||
|
||||
m->hdr->nlmsg_type == RTM_GETROUTE ||
|
||||
m->hdr->nlmsg_type == RTM_GETNEIGH ||
|
||||
m->hdr->nlmsg_type == RTM_GETADDRLABEL ,
|
||||
-EINVAL);
|
||||
|
||||
assert_return(IN_SET(m->hdr->nlmsg_type, RTM_GETLINK, RTM_GETADDR, RTM_GETROUTE, RTM_GETNEIGH, RTM_GETRULE, RTM_GETADDRLABEL), -EINVAL);
|
||||
|
||||
SET_FLAG(m->hdr->nlmsg_flags, NLM_F_DUMP, dump);
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/can/netlink.h>
|
||||
#include <linux/fib_rules.h>
|
||||
#include <linux/in6.h>
|
||||
#include <linux/veth.h>
|
||||
#include <linux/if_bridge.h>
|
||||
@ -29,8 +30,11 @@
|
||||
#include <linux/if_addrlabel.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/if_addr.h>
|
||||
#include <linux/if_bridge.h>
|
||||
#include <linux/if_link.h>
|
||||
#include <linux/if_tunnel.h>
|
||||
#include <linux/fib_rules.h>
|
||||
|
||||
#include "macro.h"
|
||||
#include "missing.h"
|
||||
@ -597,6 +601,31 @@ static const NLTypeSystem rtnl_addrlabel_type_system = {
|
||||
.types = rtnl_addrlabel_types,
|
||||
};
|
||||
|
||||
static const NLType rtnl_routing_policy_rule_types[] = {
|
||||
[FRA_DST] = { .type = NETLINK_TYPE_IN_ADDR },
|
||||
[FRA_SRC] = { .type = NETLINK_TYPE_IN_ADDR },
|
||||
[FRA_IIFNAME] = { .type = NETLINK_TYPE_STRING },
|
||||
[RTA_OIF] = { .type = NETLINK_TYPE_U32 },
|
||||
[RTA_GATEWAY] = { .type = NETLINK_TYPE_IN_ADDR },
|
||||
[FRA_PRIORITY] = { .type = NETLINK_TYPE_U32 },
|
||||
[FRA_FWMARK] = { .type = NETLINK_TYPE_U32 },
|
||||
[FRA_FLOW] = { .type = NETLINK_TYPE_U32 },
|
||||
[FRA_TUN_ID] = { .type = NETLINK_TYPE_U32 },
|
||||
[FRA_SUPPRESS_IFGROUP] = { .type = NETLINK_TYPE_U32 },
|
||||
[FRA_SUPPRESS_PREFIXLEN] = { .type = NETLINK_TYPE_U32 },
|
||||
[FRA_TABLE] = { .type = NETLINK_TYPE_U32 },
|
||||
[FRA_FWMASK] = { .type = NETLINK_TYPE_U32 },
|
||||
[FRA_OIFNAME] = { .type = NETLINK_TYPE_STRING },
|
||||
[FRA_PAD] = { .type = NETLINK_TYPE_U32 },
|
||||
[FRA_L3MDEV] = { .type = NETLINK_TYPE_U64 },
|
||||
[FRA_UID_RANGE] = { .size = sizeof(struct fib_rule_uid_range) },
|
||||
};
|
||||
|
||||
static const NLTypeSystem rtnl_routing_policy_rule_type_system = {
|
||||
.count = ELEMENTSOF(rtnl_routing_policy_rule_types),
|
||||
.types = rtnl_routing_policy_rule_types,
|
||||
};
|
||||
|
||||
static const NLType rtnl_types[] = {
|
||||
[NLMSG_DONE] = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = 0 },
|
||||
[NLMSG_ERROR] = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = sizeof(struct nlmsgerr) },
|
||||
@ -616,6 +645,9 @@ static const NLType rtnl_types[] = {
|
||||
[RTM_NEWADDRLABEL] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_addrlabel_type_system, .size = sizeof(struct ifaddrlblmsg) },
|
||||
[RTM_DELADDRLABEL] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_addrlabel_type_system, .size = sizeof(struct ifaddrlblmsg) },
|
||||
[RTM_GETADDRLABEL] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_addrlabel_type_system, .size = sizeof(struct ifaddrlblmsg) },
|
||||
[RTM_NEWRULE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_routing_policy_rule_type_system, .size = sizeof(struct rtmsg) },
|
||||
[RTM_DELRULE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_routing_policy_rule_type_system, .size = sizeof(struct rtmsg) },
|
||||
[RTM_GETRULE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_routing_policy_rule_type_system, .size = sizeof(struct rtmsg) },
|
||||
};
|
||||
|
||||
const NLTypeSystem type_system_root = {
|
||||
|
@ -47,6 +47,10 @@ static inline bool rtnl_message_type_is_addrlabel(uint16_t type) {
|
||||
return IN_SET(type, RTM_NEWADDRLABEL, RTM_DELADDRLABEL, RTM_GETADDRLABEL);
|
||||
}
|
||||
|
||||
static inline bool rtnl_message_type_is_routing_policy_rule(uint16_t type) {
|
||||
return IN_SET(type, RTM_NEWRULE, RTM_DELRULE, RTM_GETRULE);
|
||||
}
|
||||
|
||||
int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name);
|
||||
int rtnl_set_link_properties(sd_netlink **rtnl, int ifindex, const char *alias, const struct ether_addr *mac, unsigned mtu);
|
||||
|
||||
|
@ -696,6 +696,14 @@ int sd_rtnl_message_get_family(sd_netlink_message *m, int *family) {
|
||||
|
||||
*family = ifa->ifa_family;
|
||||
|
||||
return 0;
|
||||
} else if (rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type)) {
|
||||
struct rtmsg *rtm;
|
||||
|
||||
rtm = NLMSG_DATA(m->hdr);
|
||||
|
||||
*family = rtm->rtm_family;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -754,3 +762,166 @@ int sd_rtnl_message_addrlabel_get_prefixlen(sd_netlink_message *m, unsigned char
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_rtnl_message_new_routing_policy_rule(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int ifal_family) {
|
||||
struct rtmsg *rtm;
|
||||
int r;
|
||||
|
||||
assert_return(rtnl_message_type_is_routing_policy_rule(nlmsg_type), -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
r = message_new(rtnl, ret, nlmsg_type);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (nlmsg_type == RTM_NEWRULE)
|
||||
(*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
|
||||
|
||||
rtm = NLMSG_DATA((*ret)->hdr);
|
||||
rtm->rtm_family = ifal_family;
|
||||
rtm->rtm_protocol = RTPROT_BOOT;
|
||||
rtm->rtm_scope = RT_SCOPE_UNIVERSE;
|
||||
rtm->rtm_type = RTN_UNICAST;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_rtnl_message_routing_policy_rule_set_tos(sd_netlink_message *m, unsigned char tos) {
|
||||
struct rtmsg *routing_policy_rule;
|
||||
|
||||
assert_return(m, -EINVAL);
|
||||
assert_return(m->hdr, -EINVAL);
|
||||
assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
|
||||
|
||||
routing_policy_rule = NLMSG_DATA(m->hdr);
|
||||
|
||||
routing_policy_rule->rtm_tos = tos;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_rtnl_message_routing_policy_rule_get_tos(sd_netlink_message *m, unsigned char *tos) {
|
||||
struct rtmsg *routing_policy_rule;
|
||||
|
||||
assert_return(m, -EINVAL);
|
||||
assert_return(m->hdr, -EINVAL);
|
||||
assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
|
||||
|
||||
routing_policy_rule = NLMSG_DATA(m->hdr);
|
||||
|
||||
*tos = routing_policy_rule->rtm_tos;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_rtnl_message_routing_policy_rule_set_table(sd_netlink_message *m, unsigned char table) {
|
||||
struct rtmsg *routing_policy_rule;
|
||||
|
||||
assert_return(m, -EINVAL);
|
||||
assert_return(m->hdr, -EINVAL);
|
||||
assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
|
||||
|
||||
routing_policy_rule = NLMSG_DATA(m->hdr);
|
||||
|
||||
routing_policy_rule->rtm_table = table;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_rtnl_message_routing_policy_rule_get_table(sd_netlink_message *m, unsigned char *table) {
|
||||
struct rtmsg *routing_policy_rule;
|
||||
|
||||
assert_return(m, -EINVAL);
|
||||
assert_return(m->hdr, -EINVAL);
|
||||
assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
|
||||
|
||||
routing_policy_rule = NLMSG_DATA(m->hdr);
|
||||
|
||||
*table = routing_policy_rule->rtm_table;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_rtnl_message_routing_policy_rule_set_rtm_type(sd_netlink_message *m, unsigned char type) {
|
||||
struct rtmsg *routing_policy_rule;
|
||||
|
||||
assert_return(m, -EINVAL);
|
||||
assert_return(m->hdr, -EINVAL);
|
||||
assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
|
||||
|
||||
routing_policy_rule = NLMSG_DATA(m->hdr);
|
||||
|
||||
routing_policy_rule->rtm_type = type;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_rtnl_message_routing_policy_rule_get_rtm_type(sd_netlink_message *m, unsigned char *type) {
|
||||
struct rtmsg *routing_policy_rule;
|
||||
|
||||
assert_return(m, -EINVAL);
|
||||
assert_return(m->hdr, -EINVAL);
|
||||
assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
|
||||
|
||||
routing_policy_rule = NLMSG_DATA(m->hdr);
|
||||
|
||||
*type = routing_policy_rule->rtm_type;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(sd_netlink_message *m, unsigned char len) {
|
||||
struct rtmsg *routing_policy_rule;
|
||||
|
||||
assert_return(m, -EINVAL);
|
||||
assert_return(m->hdr, -EINVAL);
|
||||
assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
|
||||
|
||||
routing_policy_rule = NLMSG_DATA(m->hdr);
|
||||
|
||||
routing_policy_rule->rtm_dst_len = len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_rtnl_message_routing_policy_rule_get_rtm_dst_prefixlen(sd_netlink_message *m, unsigned char *len) {
|
||||
struct rtmsg *routing_policy_rule;
|
||||
|
||||
assert_return(m, -EINVAL);
|
||||
assert_return(m->hdr, -EINVAL);
|
||||
assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
|
||||
|
||||
routing_policy_rule = NLMSG_DATA(m->hdr);
|
||||
|
||||
*len = routing_policy_rule->rtm_dst_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(sd_netlink_message *m, unsigned char len) {
|
||||
struct rtmsg *routing_policy_rule;
|
||||
|
||||
assert_return(m, -EINVAL);
|
||||
assert_return(m->hdr, -EINVAL);
|
||||
assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
|
||||
|
||||
routing_policy_rule = NLMSG_DATA(m->hdr);
|
||||
|
||||
routing_policy_rule->rtm_src_len = len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_rtnl_message_routing_policy_rule_get_rtm_src_prefixlen(sd_netlink_message *m, unsigned char *len) {
|
||||
struct rtmsg *routing_policy_rule;
|
||||
|
||||
assert_return(m, -EINVAL);
|
||||
assert_return(m->hdr, -EINVAL);
|
||||
assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
|
||||
|
||||
routing_policy_rule = NLMSG_DATA(m->hdr);
|
||||
|
||||
*len = routing_policy_rule->rtm_src_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -894,6 +894,16 @@ int sd_netlink_add_match(sd_netlink *rtnl,
|
||||
if (r < 0)
|
||||
return r;
|
||||
break;
|
||||
case RTM_NEWRULE:
|
||||
case RTM_DELRULE:
|
||||
r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV4_RULE);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV6_RULE);
|
||||
if (r < 0)
|
||||
return r;
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
@ -61,6 +61,8 @@ sources = files('''
|
||||
networkd-network.h
|
||||
networkd-route.c
|
||||
networkd-route.h
|
||||
networkd-routing-policy-rule.c
|
||||
networkd-routing-policy-rule.h
|
||||
networkd-util.c
|
||||
networkd-util.h
|
||||
'''.split())
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "networkd-manager.h"
|
||||
#include "networkd-ndisc.h"
|
||||
#include "networkd-radv.h"
|
||||
#include "networkd-routing-policy-rule.h"
|
||||
#include "set.h"
|
||||
#include "socket-util.h"
|
||||
#include "stdio-util.h"
|
||||
@ -497,8 +498,8 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
|
||||
|
||||
static void link_free(Link *link) {
|
||||
Address *address;
|
||||
Iterator i;
|
||||
Link *carrier;
|
||||
Iterator i;
|
||||
|
||||
if (!link)
|
||||
return;
|
||||
@ -1014,6 +1015,7 @@ static int link_set_bridge_fdb(Link *link) {
|
||||
}
|
||||
|
||||
static int link_enter_set_addresses(Link *link) {
|
||||
RoutingPolicyRule *rule, *rrule = NULL;
|
||||
AddressLabel *label;
|
||||
Address *ad;
|
||||
int r;
|
||||
@ -1050,6 +1052,26 @@ static int link_enter_set_addresses(Link *link) {
|
||||
link->link_messages++;
|
||||
}
|
||||
|
||||
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);
|
||||
if (r == 1) {
|
||||
(void) routing_policy_rule_make_local(link->manager, rrule);
|
||||
continue;
|
||||
}
|
||||
|
||||
r = routing_policy_rule_configure(rule, link, link_routing_policy_rule_handler, false);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "Could not set routing policy rules: %m");
|
||||
link_enter_failed(link);
|
||||
return r;
|
||||
}
|
||||
|
||||
link->link_messages++;
|
||||
}
|
||||
|
||||
routing_policy_rule_purge(link->manager, link);
|
||||
|
||||
/* now that we can figure out a default address for the dhcp server,
|
||||
start it */
|
||||
if (link_dhcp4_server_enabled(link)) {
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/fib_rules.h>
|
||||
|
||||
#include "sd-daemon.h"
|
||||
#include "sd-netlink.h"
|
||||
@ -718,6 +719,113 @@ static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *messa
|
||||
return 1;
|
||||
}
|
||||
|
||||
int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
|
||||
uint8_t tos = 0, to_prefixlen = 0, from_prefixlen = 0;
|
||||
RoutingPolicyRule *rule = NULL;
|
||||
union in_addr_union to, from;
|
||||
uint32_t fwmark = 0, table = 0;
|
||||
Manager *m = userdata;
|
||||
uint16_t type;
|
||||
int family;
|
||||
int r;
|
||||
|
||||
assert(rtnl);
|
||||
assert(message);
|
||||
assert(m);
|
||||
|
||||
if (sd_netlink_message_is_error(message)) {
|
||||
r = sd_netlink_message_get_errno(message);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "rtnl: failed to receive rule: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_get_type(message, &type);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "rtnl: could not get message type: %m");
|
||||
return 0;
|
||||
} else if (!IN_SET(type, RTM_NEWRULE, RTM_DELRULE)) {
|
||||
log_warning("rtnl: received unexpected message type '%u' when processing rule.", type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_rtnl_message_get_family(message, &family);
|
||||
if (r < 0 || !IN_SET(family, AF_INET, AF_INET6)) {
|
||||
log_warning_errno(r, "rtnl: received address with invalid family type %u, ignoring.", type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
r = sd_netlink_message_read_in_addr(message, FRA_SRC, &from.in);
|
||||
if (r >= 0) {
|
||||
r = sd_rtnl_message_routing_policy_rule_get_rtm_src_prefixlen(message, &from_prefixlen);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "rtnl: failed to retrive rule from prefix length: %m");
|
||||
}
|
||||
|
||||
r = sd_netlink_message_read_in_addr(message, FRA_DST, &to.in);
|
||||
if (r >= 0) {
|
||||
r = sd_rtnl_message_routing_policy_rule_get_rtm_dst_prefixlen(message, &to_prefixlen);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "rtnl: failed to retrive rule to prefix length: %m");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
r = sd_netlink_message_read_in6_addr(message, FRA_SRC, &from.in6);
|
||||
if (r >= 0) {
|
||||
r = sd_rtnl_message_routing_policy_rule_get_rtm_src_prefixlen(message, &from_prefixlen);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "rtnl: failed to retrive rule from prefix length: %m");
|
||||
}
|
||||
|
||||
r = sd_netlink_message_read_in6_addr(message, FRA_DST, &to.in6);
|
||||
if (r >= 0) {
|
||||
r = sd_rtnl_message_routing_policy_rule_get_rtm_dst_prefixlen(message, &to_prefixlen);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "rtnl: failed to retrive rule to prefix length: %m");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
log_debug("rtnl: ignoring unsupported rule family: %d", family);
|
||||
}
|
||||
|
||||
if (from_prefixlen == 0 && to_prefixlen == 0)
|
||||
return 0;
|
||||
|
||||
(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) routing_policy_rule_get(m, family, &from, from_prefixlen, &to, to_prefixlen, tos, fwmark, table, &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);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Could not add rule: %m");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case RTM_DELRULE:
|
||||
routing_policy_rule_free(rule);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached("Received invalid RTNL message type");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int systemd_netlink_fd(void) {
|
||||
int n, fd, rtnl_fd = -EINVAL;
|
||||
|
||||
@ -782,6 +890,14 @@ static int manager_connect_rtnl(Manager *m) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_add_match(m->rtnl, RTM_NEWRULE, &manager_rtnl_process_rule, m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_add_match(m->rtnl, RTM_DELRULE, &manager_rtnl_process_rule, m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -875,6 +991,8 @@ static void print_string_set(FILE *f, const char *field, OrderedSet *s) {
|
||||
|
||||
static int manager_save(Manager *m) {
|
||||
_cleanup_ordered_set_free_free_ OrderedSet *dns = NULL, *ntp = NULL, *search_domains = NULL, *route_domains = NULL;
|
||||
RoutingPolicyRule *rule = NULL;
|
||||
bool space = false;
|
||||
Link *link;
|
||||
Iterator i;
|
||||
_cleanup_free_ char *temp_path = NULL;
|
||||
@ -999,6 +1117,28 @@ static int manager_save(Manager *m) {
|
||||
print_string_set(f, "DOMAINS=", search_domains);
|
||||
print_string_set(f, "ROUTE_DOMAINS=", route_domains);
|
||||
|
||||
SET_FOREACH(rule, m->rules, i) {
|
||||
_cleanup_free_ char *from_str = NULL, *to_str = NULL;
|
||||
fputs("RULE=", f);
|
||||
|
||||
if (!in_addr_is_null(rule->family, &rule->from)) {
|
||||
r = in_addr_to_string(rule->family, &rule->from, &from_str);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!in_addr_is_null(rule->family, &rule->to)) {
|
||||
r = in_addr_to_string(rule->family, &rule->to, &to_str);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
fprintf(f, "from=%s%s/%hhu to=%s%s/%hhu tos=%hhu fwmark=%"PRIu32"/%"PRIu32" table=%hhu", space ? " " : "", from_str,
|
||||
rule->from_prefixlen, space ? " " : "", to_str, rule->to_prefixlen, rule->tos, rule->fwmark, rule->fwmask, rule->table);
|
||||
|
||||
fputc('\n', f);
|
||||
}
|
||||
|
||||
r = fflush_and_check(f);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
@ -1084,6 +1224,8 @@ int manager_new(Manager **ret, sd_event *event) {
|
||||
|
||||
m->duid.type = DUID_TYPE_EN;
|
||||
|
||||
(void) routing_policy_rule_load(m);
|
||||
|
||||
*ret = m;
|
||||
m = NULL;
|
||||
|
||||
@ -1091,6 +1233,7 @@ int manager_new(Manager **ret, sd_event *event) {
|
||||
}
|
||||
|
||||
void manager_free(Manager *m) {
|
||||
RoutingPolicyRule *rule;
|
||||
Network *network;
|
||||
NetDev *netdev;
|
||||
Link *link;
|
||||
@ -1101,13 +1244,13 @@ void manager_free(Manager *m) {
|
||||
|
||||
free(m->state_file);
|
||||
|
||||
while ((network = m->networks))
|
||||
network_free(network);
|
||||
|
||||
while ((link = hashmap_first(m->links)))
|
||||
link_unref(link);
|
||||
hashmap_free(m->links);
|
||||
|
||||
while ((network = m->networks))
|
||||
network_free(network);
|
||||
|
||||
hashmap_free(m->networks_by_name);
|
||||
|
||||
while ((netdev = hashmap_first(m->netdevs)))
|
||||
@ -1117,6 +1260,14 @@ void manager_free(Manager *m) {
|
||||
while ((pool = m->address_pools))
|
||||
address_pool_free(pool);
|
||||
|
||||
set_free(m->rules);
|
||||
set_free(m->rules_foreign);
|
||||
|
||||
while ((rule = set_steal_first(m->rules_saved)))
|
||||
free(rule);
|
||||
|
||||
set_free(m->rules_saved);
|
||||
|
||||
sd_netlink_unref(m->rtnl);
|
||||
sd_event_unref(m->event);
|
||||
|
||||
@ -1277,6 +1428,41 @@ int manager_rtnl_enumerate_routes(Manager *m) {
|
||||
return r;
|
||||
}
|
||||
|
||||
int manager_rtnl_enumerate_rules(Manager *m) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
|
||||
sd_netlink_message *rule;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(m->rtnl);
|
||||
|
||||
r = sd_rtnl_message_new_routing_policy_rule(m->rtnl, &req, RTM_GETRULE, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_message_request_dump(req, true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_call(m->rtnl, req, 0, &reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
for (rule = reply; rule; rule = sd_netlink_message_next(rule)) {
|
||||
int k;
|
||||
|
||||
m->enumerating = true;
|
||||
|
||||
k = manager_rtnl_process_rule(m->rtnl, rule, m);
|
||||
if (k < 0)
|
||||
r = k;
|
||||
|
||||
m->enumerating = false;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found) {
|
||||
AddressPool *p;
|
||||
int r;
|
||||
|
@ -65,6 +65,10 @@ struct Manager {
|
||||
DUID duid;
|
||||
char* dynamic_hostname;
|
||||
char* dynamic_timezone;
|
||||
|
||||
Set *rules;
|
||||
Set *rules_foreign;
|
||||
Set *rules_saved;
|
||||
};
|
||||
|
||||
static inline const DUID* link_duid(const Link *link) {
|
||||
@ -88,9 +92,11 @@ bool manager_should_reload(Manager *m);
|
||||
int manager_rtnl_enumerate_links(Manager *m);
|
||||
int manager_rtnl_enumerate_addresses(Manager *m);
|
||||
int manager_rtnl_enumerate_routes(Manager *m);
|
||||
int manager_rtnl_enumerate_rules(Manager *m);
|
||||
|
||||
int manager_rtnl_process_address(sd_netlink *nl, sd_netlink_message *message, void *userdata);
|
||||
int manager_rtnl_process_route(sd_netlink *nl, sd_netlink_message *message, void *userdata);
|
||||
int manager_rtnl_process_rule(sd_netlink *nl, sd_netlink_message *message, void *userdata);
|
||||
|
||||
int manager_send_changed(Manager *m, const char *property, ...) _sentinel_;
|
||||
void manager_dirty(Manager *m);
|
||||
|
@ -84,6 +84,12 @@ Address.AutoJoin, config_parse_address_flags,
|
||||
Address.Scope, config_parse_address_scope, 0, 0
|
||||
IPv6AddressLabel.Prefix, config_parse_address_label_prefix, 0, 0
|
||||
IPv6AddressLabel.Label, config_parse_address_label, 0, 0
|
||||
RoutingPolicyRule.TypeOfService, config_parse_routing_policy_rule_tos, 0, 0
|
||||
RoutingPolicyRule.Priority, config_parse_routing_policy_rule_priority, 0, 0
|
||||
RoutingPolicyRule.Table, config_parse_routing_policy_rule_table, 0, 0
|
||||
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
|
||||
Route.Gateway, config_parse_gateway, 0, 0
|
||||
Route.Destination, config_parse_destination, 0, 0
|
||||
Route.Source, config_parse_destination, 0, 0
|
||||
|
@ -77,7 +77,7 @@ int network_config_section_new(const char *filename, unsigned line, NetworkConfi
|
||||
}
|
||||
|
||||
void network_config_section_free(NetworkConfigSection *cs) {
|
||||
free(cs);
|
||||
free(cs);
|
||||
}
|
||||
|
||||
/* Set defaults following RFC7844 */
|
||||
@ -157,6 +157,7 @@ static int network_load_one(Manager *manager, const char *filename) {
|
||||
LIST_HEAD_INIT(network->ipv6_proxy_ndp_addresses);
|
||||
LIST_HEAD_INIT(network->address_labels);
|
||||
LIST_HEAD_INIT(network->static_prefixes);
|
||||
LIST_HEAD_INIT(network->rules);
|
||||
|
||||
network->stacked_netdevs = hashmap_new(&string_hash_ops);
|
||||
if (!network->stacked_netdevs)
|
||||
@ -182,6 +183,10 @@ static int network_load_one(Manager *manager, const char *filename) {
|
||||
if (!network->prefixes_by_section)
|
||||
return log_oom();
|
||||
|
||||
network->rules_by_section = hashmap_new(&network_config_hash_ops);
|
||||
if (!network->rules_by_section)
|
||||
return log_oom();
|
||||
|
||||
network->filename = strdup(filename);
|
||||
if (!network->filename)
|
||||
return log_oom();
|
||||
@ -258,6 +263,7 @@ static int network_load_one(Manager *manager, const char *filename) {
|
||||
"Network\0"
|
||||
"Address\0"
|
||||
"IPv6AddressLabel\0"
|
||||
"RoutingPolicyRule\0"
|
||||
"Route\0"
|
||||
"DHCP\0"
|
||||
"DHCPv4\0" /* compat */
|
||||
@ -336,13 +342,14 @@ int network_load(Manager *manager) {
|
||||
}
|
||||
|
||||
void network_free(Network *network) {
|
||||
NetDev *netdev;
|
||||
Route *route;
|
||||
Address *address;
|
||||
FdbEntry *fdb_entry;
|
||||
IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
|
||||
RoutingPolicyRule *rule;
|
||||
FdbEntry *fdb_entry;
|
||||
AddressLabel *label;
|
||||
Prefix *prefix;
|
||||
Address *address;
|
||||
NetDev *netdev;
|
||||
Route *route;
|
||||
Iterator i;
|
||||
|
||||
if (!network)
|
||||
@ -396,11 +403,15 @@ void network_free(Network *network) {
|
||||
while ((prefix = network->static_prefixes))
|
||||
prefix_free(prefix);
|
||||
|
||||
while ((rule = network->rules))
|
||||
routing_policy_rule_free(rule);
|
||||
|
||||
hashmap_free(network->addresses_by_section);
|
||||
hashmap_free(network->routes_by_section);
|
||||
hashmap_free(network->fdb_entries_by_section);
|
||||
hashmap_free(network->address_labels_by_section);
|
||||
hashmap_free(network->prefixes_by_section);
|
||||
hashmap_free(network->rules_by_section);
|
||||
|
||||
if (network->manager) {
|
||||
if (network->manager->networks)
|
||||
@ -746,7 +757,7 @@ int config_parse_tunnel(const char *unit,
|
||||
netdev->kind != NETDEV_KIND_VTI &&
|
||||
netdev->kind != NETDEV_KIND_VTI6 &&
|
||||
netdev->kind != NETDEV_KIND_IP6TNL
|
||||
) {
|
||||
) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0,
|
||||
"NetDev is not a tunnel, ignoring assignment: %s", rvalue);
|
||||
return 0;
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "networkd-lldp-tx.h"
|
||||
#include "networkd-ipv6-proxy-ndp.h"
|
||||
#include "networkd-route.h"
|
||||
#include "networkd-routing-policy-rule.h"
|
||||
#include "networkd-util.h"
|
||||
#include "netdev/netdev.h"
|
||||
|
||||
@ -218,6 +219,7 @@ struct Network {
|
||||
LIST_HEAD(IPv6ProxyNDPAddress, ipv6_proxy_ndp_addresses);
|
||||
LIST_HEAD(AddressLabel, address_labels);
|
||||
LIST_HEAD(Prefix, static_prefixes);
|
||||
LIST_HEAD(RoutingPolicyRule, rules);
|
||||
|
||||
unsigned n_static_addresses;
|
||||
unsigned n_static_routes;
|
||||
@ -225,12 +227,14 @@ struct Network {
|
||||
unsigned n_ipv6_proxy_ndp_addresses;
|
||||
unsigned n_address_labels;
|
||||
unsigned n_static_prefixes;
|
||||
unsigned n_rules;
|
||||
|
||||
Hashmap *addresses_by_section;
|
||||
Hashmap *routes_by_section;
|
||||
Hashmap *fdb_entries_by_section;
|
||||
Hashmap *address_labels_by_section;
|
||||
Hashmap *prefixes_by_section;
|
||||
Hashmap *rules_by_section;
|
||||
|
||||
struct in_addr_data *dns;
|
||||
unsigned n_dns;
|
||||
|
900
src/network/networkd-routing-policy-rule.c
Normal file
900
src/network/networkd-routing-policy-rule.c
Normal file
@ -0,0 +1,900 @@
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2017 Susant Sahani
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <net/if.h>
|
||||
#include <linux/fib_rules.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "conf-parser.h"
|
||||
#include "fileio.h"
|
||||
#include "networkd-routing-policy-rule.h"
|
||||
#include "netlink-util.h"
|
||||
#include "networkd-manager.h"
|
||||
#include "parse-util.h"
|
||||
#include "socket-util.h"
|
||||
#include "string-util.h"
|
||||
|
||||
int routing_policy_rule_new(RoutingPolicyRule **ret) {
|
||||
RoutingPolicyRule *rule;
|
||||
|
||||
rule = new0(RoutingPolicyRule, 1);
|
||||
if (!rule)
|
||||
return -ENOMEM;
|
||||
|
||||
rule->family = AF_INET;
|
||||
rule->table = RT_TABLE_MAIN;
|
||||
|
||||
*ret = rule;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void routing_policy_rule_free(RoutingPolicyRule *rule) {
|
||||
|
||||
if (!rule)
|
||||
return;
|
||||
|
||||
if (rule->network) {
|
||||
LIST_REMOVE(rules, rule->network->rules, rule);
|
||||
assert(rule->network->n_rules > 0);
|
||||
rule->network->n_rules--;
|
||||
|
||||
if (rule->section) {
|
||||
hashmap_remove(rule->network->rules_by_section, rule->section);
|
||||
network_config_section_free(rule->section);
|
||||
}
|
||||
|
||||
if (rule->network->manager) {
|
||||
set_remove(rule->network->manager->rules, rule);
|
||||
set_remove(rule->network->manager->rules_foreign, rule);
|
||||
}
|
||||
}
|
||||
|
||||
free(rule);
|
||||
}
|
||||
|
||||
static void routing_policy_rule_hash_func(const void *b, struct siphash *state) {
|
||||
const RoutingPolicyRule *rule = b;
|
||||
|
||||
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);
|
||||
|
||||
siphash24_compress(&rule->tos, sizeof(rule->tos), state);
|
||||
siphash24_compress(&rule->fwmark, sizeof(rule->fwmark), state);
|
||||
siphash24_compress(&rule->table, sizeof(rule->table), state);
|
||||
|
||||
break;
|
||||
default:
|
||||
/* treat any other address family as AF_UNSPEC */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int routing_policy_rule_compare_func(const void *_a, const void *_b) {
|
||||
const RoutingPolicyRule *a = _a, *b = _b;
|
||||
int r;
|
||||
|
||||
if (a->family < b->family)
|
||||
return -1;
|
||||
if (a->family > b->family)
|
||||
return 1;
|
||||
|
||||
switch (a->family) {
|
||||
case AF_INET:
|
||||
case AF_INET6:
|
||||
if (a->from_prefixlen < b->from_prefixlen)
|
||||
return -1;
|
||||
if (a->from_prefixlen > b->from_prefixlen)
|
||||
return 1;
|
||||
|
||||
if (a->to_prefixlen < b->to_prefixlen)
|
||||
return -1;
|
||||
if (a->to_prefixlen > b->to_prefixlen)
|
||||
return 1;
|
||||
|
||||
if (a->tos < b->tos)
|
||||
return -1;
|
||||
if (a->tos > b->tos)
|
||||
return 1;
|
||||
|
||||
if (a->fwmask < b->fwmark)
|
||||
return -1;
|
||||
if (a->fwmask > b->fwmark)
|
||||
return 1;
|
||||
|
||||
if (a->table < b->table)
|
||||
return -1;
|
||||
if (a->table > b->table)
|
||||
return 1;
|
||||
|
||||
r = memcmp(&a->from, &b->from, FAMILY_ADDRESS_SIZE(a->family));
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
return memcmp(&a->to, &b->to, FAMILY_ADDRESS_SIZE(a->family));
|
||||
|
||||
default:
|
||||
/* treat any other address family as AF_UNSPEC */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
const struct hash_ops routing_policy_rule_hash_ops = {
|
||||
.hash = routing_policy_rule_hash_func,
|
||||
.compare = routing_policy_rule_compare_func
|
||||
};
|
||||
|
||||
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) {
|
||||
|
||||
RoutingPolicyRule rule, *existing;
|
||||
|
||||
assert_return(m, -1);
|
||||
|
||||
rule = (RoutingPolicyRule) {
|
||||
.family = family,
|
||||
.from = *from,
|
||||
.from_prefixlen = from_prefixlen,
|
||||
.to = *to,
|
||||
.to_prefixlen = to_prefixlen,
|
||||
.tos = tos,
|
||||
.fwmark = fwmark,
|
||||
.table = table,
|
||||
};
|
||||
|
||||
if (m->rules) {
|
||||
existing = set_get(m->rules, &rule);
|
||||
if (existing) {
|
||||
if (ret)
|
||||
*ret = existing;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (m->rules_foreign) {
|
||||
existing = set_get(m->rules_foreign, &rule);
|
||||
if (existing) {
|
||||
if (ret)
|
||||
*ret = existing;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int routing_policy_rule_make_local(Manager *m, RoutingPolicyRule *rule) {
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
if (set_contains(m->rules_foreign, rule)) {
|
||||
set_remove(m->rules_foreign, rule);
|
||||
|
||||
r = set_ensure_allocated(&m->rules, &routing_policy_rule_hash_ops);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return set_put(m->rules, rule);
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static int routing_policy_rule_add_internal(Set **rules,
|
||||
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) {
|
||||
|
||||
_cleanup_routing_policy_rule_free_ RoutingPolicyRule *rule = NULL;
|
||||
int r;
|
||||
|
||||
assert_return(rules, -EINVAL);
|
||||
|
||||
r = routing_policy_rule_new(&rule);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
rule->family = family;
|
||||
rule->from = *from;
|
||||
rule->from_prefixlen = from_prefixlen;
|
||||
rule->to = *to;
|
||||
rule->to_prefixlen = to_prefixlen;
|
||||
rule->tos = tos;
|
||||
rule->fwmark = fwmark;
|
||||
rule->table = table;
|
||||
|
||||
r = set_ensure_allocated(rules, &routing_policy_rule_hash_ops);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = set_put(*rules, rule);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (ret)
|
||||
*ret = rule;
|
||||
|
||||
rule = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
return routing_policy_rule_add_internal(&m->rules, family, from, from_prefixlen, to, to_prefixlen, tos, fwmark, table, 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) {
|
||||
return routing_policy_rule_add_internal(&m->rules_foreign, family, from, from_prefixlen, to, to_prefixlen, tos, fwmark, table, ret);
|
||||
}
|
||||
|
||||
static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
|
||||
_cleanup_link_unref_ Link *link = userdata;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(link);
|
||||
assert(link->ifname);
|
||||
|
||||
link->link_messages--;
|
||||
|
||||
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
||||
return 1;
|
||||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(link, r, "Could not drop routing policy rule: %m");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int routing_policy_rule_remove(RoutingPolicyRule *routing_policy_rule, Link *link, sd_netlink_message_handler_t callback) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
||||
int r;
|
||||
|
||||
assert(routing_policy_rule);
|
||||
assert(link);
|
||||
assert(link->manager);
|
||||
assert(link->manager->rtnl);
|
||||
assert(link->ifindex > 0);
|
||||
assert(IN_SET(routing_policy_rule->family, AF_INET, AF_INET6));
|
||||
|
||||
r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_DELRULE, routing_policy_rule->family);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not allocate RTM_DELRULE message: %m");
|
||||
|
||||
if (!in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->from)) {
|
||||
if (routing_policy_rule->family == AF_INET)
|
||||
r = sd_netlink_message_append_in_addr(m, FRA_SRC, &routing_policy_rule->from.in);
|
||||
else
|
||||
r = sd_netlink_message_append_in6_addr(m, FRA_SRC, &routing_policy_rule->from.in6);
|
||||
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not append FRA_SRC attribute: %m");
|
||||
|
||||
r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, routing_policy_rule->from_prefixlen);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not set source prefix length: %m");
|
||||
}
|
||||
|
||||
if (!in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->to)) {
|
||||
if (routing_policy_rule->family == AF_INET)
|
||||
r = sd_netlink_message_append_in_addr(m, FRA_DST, &routing_policy_rule->to.in);
|
||||
else
|
||||
r = sd_netlink_message_append_in6_addr(m, FRA_DST, &routing_policy_rule->to.in6);
|
||||
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not append FRA_DST attribute: %m");
|
||||
|
||||
r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, routing_policy_rule->to_prefixlen);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not set destination prefix length: %m");
|
||||
}
|
||||
|
||||
r = sd_netlink_call_async(link->manager->rtnl, m, callback, link, 0, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not send rtnetlink message: %m");
|
||||
|
||||
link_ref(link);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int routing_policy_rule_new_static(Network *network, const char *filename, unsigned section_line, RoutingPolicyRule **ret) {
|
||||
_cleanup_routing_policy_rule_free_ RoutingPolicyRule *rule = NULL;
|
||||
_cleanup_network_config_section_free_ NetworkConfigSection *n = NULL;
|
||||
int r;
|
||||
|
||||
assert(network);
|
||||
assert(ret);
|
||||
assert(!!filename == (section_line > 0));
|
||||
|
||||
r = network_config_section_new(filename, section_line, &n);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
rule = hashmap_get(network->rules_by_section, n);
|
||||
if (rule) {
|
||||
*ret = rule;
|
||||
rule = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = routing_policy_rule_new(&rule);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
rule->section = n;
|
||||
rule->network = network;
|
||||
n = NULL;
|
||||
|
||||
r = hashmap_put(network->rules_by_section, rule->section, rule);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
LIST_APPEND(rules, network->rules, rule);
|
||||
network->n_rules++;
|
||||
|
||||
*ret = rule;
|
||||
rule = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int link_routing_policy_rule_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
|
||||
_cleanup_link_unref_ Link *link = userdata;
|
||||
int r;
|
||||
|
||||
assert(rtnl);
|
||||
assert(m);
|
||||
assert(link);
|
||||
assert(link->ifname);
|
||||
assert(link->link_messages > 0);
|
||||
|
||||
link->link_messages--;
|
||||
|
||||
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
||||
return 1;
|
||||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -EEXIST)
|
||||
log_link_warning_errno(link, r, "Could not add routing policy rule: %m");
|
||||
|
||||
if (link->link_messages == 0)
|
||||
log_link_debug(link, "Routing policy rule configured");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, sd_netlink_message_handler_t callback, bool update) {
|
||||
_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);
|
||||
|
||||
r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_NEWRULE, rule->family);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not allocate RTM_NEWRULE message: %m");
|
||||
|
||||
if (!in_addr_is_null(rule->family, &rule->from)) {
|
||||
if (rule->family == AF_INET)
|
||||
r = sd_netlink_message_append_in_addr(m, FRA_SRC, &rule->from.in);
|
||||
else
|
||||
r = sd_netlink_message_append_in6_addr(m, FRA_SRC, &rule->from.in6);
|
||||
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not append FRA_SRC attribute: %m");
|
||||
|
||||
r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, rule->from_prefixlen);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not set source prefix length: %m");
|
||||
}
|
||||
|
||||
if (!in_addr_is_null(rule->family, &rule->to)) {
|
||||
if (rule->family == AF_INET)
|
||||
r = sd_netlink_message_append_in_addr(m, FRA_DST, &rule->to.in);
|
||||
else
|
||||
r = sd_netlink_message_append_in6_addr(m, FRA_DST, &rule->to.in6);
|
||||
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not append FRA_DST attribute: %m");
|
||||
|
||||
r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, rule->to_prefixlen);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not set destination prefix length: %m");
|
||||
}
|
||||
|
||||
r = sd_netlink_message_append_u32(m, FRA_PRIORITY, rule->priority);
|
||||
if (r < 0)
|
||||
return log_error_errno(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_error_errno(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_error_errno(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_error_errno(r, "Could not set ip rule table: %m");
|
||||
|
||||
r = sd_netlink_message_append_u32(m, FRA_TABLE, rule->table);
|
||||
if (r < 0)
|
||||
return log_error_errno(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_error_errno(r, "Could not append FRA_FWMARK attribute: %m");
|
||||
}
|
||||
|
||||
if (rule->fwmask > 0) {
|
||||
r = sd_netlink_message_append_u32(m, FRA_FWMASK, rule->fwmask);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not append FRA_FWMASK attribute: %m");
|
||||
}
|
||||
|
||||
rule->link = link;
|
||||
|
||||
r = sd_netlink_call_async(link->manager->rtnl, m, callback, link, 0, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not send rtnetlink message: %m");
|
||||
|
||||
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);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not add rule : %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_fwmark_fwmask(const char *s, uint32_t *fwmark, uint32_t *fwmask) {
|
||||
_cleanup_free_ char *f = NULL;
|
||||
char *p;
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
|
||||
f = strdup(s);
|
||||
if (!f)
|
||||
return -ENOMEM;
|
||||
|
||||
p = strchr(f, '/');
|
||||
if (p)
|
||||
*p++ = '\0';
|
||||
|
||||
r = safe_atou32(f, fwmark);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse RPDB rule firewall mark, ignoring: %s", f);
|
||||
|
||||
if (p) {
|
||||
r = safe_atou32(p, fwmask);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse RPDB rule mask, ignoring: %s", f);
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
_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;
|
||||
|
||||
r = safe_atou8(rvalue, &n->tos);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule tos, ignoring: %s", rvalue);
|
||||
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) {
|
||||
|
||||
_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;
|
||||
|
||||
r = safe_atou32(rvalue, &n->priority);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule priority, ignoring: %s", rvalue);
|
||||
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) {
|
||||
|
||||
_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;
|
||||
|
||||
r = safe_atou32(rvalue, &n->table);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule table, ignoring: %s", rvalue);
|
||||
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) {
|
||||
|
||||
_cleanup_routing_policy_rule_free_ RoutingPolicyRule *n = NULL;
|
||||
_cleanup_free_ char *fwmark = 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 = parse_fwmark_fwmask(rvalue, &n->fwmark, &n->fwmask);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", rvalue);
|
||||
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) {
|
||||
|
||||
_cleanup_routing_policy_rule_free_ RoutingPolicyRule *n = NULL;
|
||||
Network *network = userdata;
|
||||
union in_addr_union buffer;
|
||||
uint8_t prefixlen;
|
||||
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 = in_addr_prefix_from_string(rvalue, AF_INET, &buffer, &prefixlen);
|
||||
if (r < 0) {
|
||||
r = in_addr_prefix_from_string(rvalue, AF_INET6, &buffer, &prefixlen);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "RPDB rule prefix is invalid, ignoring assignment: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
n->family = AF_INET6;
|
||||
} else
|
||||
n->family = AF_INET;
|
||||
|
||||
if (streq(lvalue, "To")) {
|
||||
n->to = buffer;
|
||||
n->to_prefixlen = prefixlen;
|
||||
} else {
|
||||
n->from = buffer;
|
||||
n->from_prefixlen = prefixlen;
|
||||
}
|
||||
|
||||
n = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int routing_policy_rule_read_full_file(char *state_file, char **ret) {
|
||||
_cleanup_free_ char *s = NULL, *p = NULL;
|
||||
size_t size;
|
||||
int r;
|
||||
|
||||
assert(state_file);
|
||||
|
||||
r = read_full_file(state_file, &s, &size);
|
||||
if (r == -ENOENT)
|
||||
return -ENODATA;
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (size <= 0)
|
||||
return -ENODATA;
|
||||
|
||||
*ret = s;
|
||||
s = NULL;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
int routing_policy_rule_load(Manager *m) {
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
_cleanup_free_ char *data = NULL;
|
||||
const char *p;
|
||||
char **i;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
r = routing_policy_rule_read_full_file(m->state_file, &data);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
l = strv_split_newlines(data);
|
||||
if (!l)
|
||||
return -ENOMEM;
|
||||
|
||||
r = set_ensure_allocated(&m->rules_saved, &routing_policy_rule_hash_ops);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
STRV_FOREACH(i, l) {
|
||||
_cleanup_routing_policy_rule_free_ RoutingPolicyRule *rule = NULL;
|
||||
|
||||
p = startswith(*i, "RULE=");
|
||||
if (!p)
|
||||
continue;
|
||||
|
||||
p = strchr(*i, '=');
|
||||
p++;
|
||||
|
||||
r = routing_policy_rule_new(&rule);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *word = NULL, *a = NULL, *b = NULL;
|
||||
union in_addr_union buffer;
|
||||
uint8_t prefixlen;
|
||||
|
||||
r = extract_first_word(&p, &word, NULL, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
r = split_pair(word, "=", &a, &b);
|
||||
if (r < 0)
|
||||
continue;
|
||||
|
||||
if (STR_IN_SET(a, "from", "to")) {
|
||||
|
||||
r = in_addr_prefix_from_string(b, AF_INET, &buffer, &prefixlen);
|
||||
if (r < 0) {
|
||||
r = in_addr_prefix_from_string(b, AF_INET6, &buffer, &prefixlen);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "RPDB rule prefix is invalid, ignoring assignment: %s", b);
|
||||
continue;
|
||||
}
|
||||
|
||||
rule->family = AF_INET6;
|
||||
} else
|
||||
rule->family = AF_INET;
|
||||
|
||||
if (streq(a, "to")) {
|
||||
rule->to = buffer;
|
||||
rule->to_prefixlen = prefixlen;
|
||||
} else {
|
||||
rule->from = buffer;
|
||||
rule->from_prefixlen = prefixlen;
|
||||
}
|
||||
} else if (streq(a, "tos")) {
|
||||
r = safe_atou8(b, &rule->tos);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to parse RPDB rule tos, ignoring: %s", b);
|
||||
continue;
|
||||
}
|
||||
} else if (streq(a, "table")) {
|
||||
r = safe_atou32(b, &rule->table);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to parse RPDB rule table, ignoring: %s", b);
|
||||
continue;
|
||||
}
|
||||
} else if (streq(a, "fwmark")) {
|
||||
|
||||
r = parse_fwmark_fwmask(a, &rule->fwmark, &rule->fwmask);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", a);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
r = set_put(m->rules_saved, rule);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Failed to add RPDB rule to saved DB, ignoring: %s", p);
|
||||
continue;
|
||||
}
|
||||
|
||||
rule = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void routing_policy_rule_purge(Manager *m, Link *link) {
|
||||
RoutingPolicyRule *rule, *existing;
|
||||
Iterator i;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(link);
|
||||
|
||||
SET_FOREACH(rule, m->rules_saved, i) {
|
||||
existing = set_get(m->rules_foreign, rule);
|
||||
if (existing) {
|
||||
|
||||
r = routing_policy_rule_remove(rule, link, routing_policy_rule_remove_handler);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Could not remove routing policy rules: %m");
|
||||
continue;
|
||||
}
|
||||
|
||||
link->link_messages++;
|
||||
}
|
||||
}
|
||||
}
|
83
src/network/networkd-routing-policy-rule.h
Normal file
83
src/network/networkd-routing-policy-rule.h
Normal file
@ -0,0 +1,83 @@
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2017 Susant Sahani
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "in-addr-util.h"
|
||||
|
||||
typedef struct RoutingPolicyRule RoutingPolicyRule;
|
||||
|
||||
#include "networkd-link.h"
|
||||
#include "networkd-network.h"
|
||||
|
||||
typedef struct Network Network;
|
||||
typedef struct Link Link;
|
||||
typedef struct NetworkConfigSection NetworkConfigSection;
|
||||
|
||||
struct RoutingPolicyRule {
|
||||
Network *network;
|
||||
Link *link;
|
||||
NetworkConfigSection *section;
|
||||
|
||||
uint8_t tos;
|
||||
|
||||
uint32_t table;
|
||||
uint32_t fwmark;
|
||||
uint32_t fwmask;
|
||||
uint32_t priority;
|
||||
|
||||
int family;
|
||||
unsigned char to_prefixlen;
|
||||
unsigned char from_prefixlen;
|
||||
|
||||
union in_addr_union to;
|
||||
union in_addr_union from;
|
||||
|
||||
LIST_FIELDS(RoutingPolicyRule, rules);
|
||||
};
|
||||
|
||||
int routing_policy_rule_new(RoutingPolicyRule **ret);
|
||||
void routing_policy_rule_free(RoutingPolicyRule *rule);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(RoutingPolicyRule*, routing_policy_rule_free);
|
||||
#define _cleanup_routing_policy_rule_free_ _cleanup_(routing_policy_rule_freep)
|
||||
|
||||
int routing_policy_rule_configure(RoutingPolicyRule *address, Link *link, sd_netlink_message_handler_t callback, bool update);
|
||||
int routing_policy_rule_remove(RoutingPolicyRule *routing_policy_rule, Link *link, sd_netlink_message_handler_t callback);
|
||||
int link_routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
|
||||
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);
|
||||
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);
|
||||
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);
|
@ -132,6 +132,12 @@ int main(int argc, char *argv[]) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = manager_rtnl_enumerate_rules(m);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Could not enumerate rules: %m");
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = manager_start(m);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Could not start manager: %m");
|
||||
|
@ -159,6 +159,18 @@ int sd_rtnl_message_new_addrlabel(sd_netlink *rtnl, sd_netlink_message **ret, ui
|
||||
int sd_rtnl_message_addrlabel_set_prefixlen(sd_netlink_message *m, unsigned char prefixlen);
|
||||
int sd_rtnl_message_addrlabel_get_prefixlen(sd_netlink_message *m, unsigned char *prefixlen);
|
||||
|
||||
int sd_rtnl_message_new_routing_policy_rule(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int ifal_family);
|
||||
int sd_rtnl_message_routing_policy_rule_set_tos(sd_netlink_message *m, unsigned char tos);
|
||||
int sd_rtnl_message_routing_policy_rule_get_tos(sd_netlink_message *m, unsigned char *tos);
|
||||
int sd_rtnl_message_routing_policy_rule_set_table(sd_netlink_message *m, unsigned char table);
|
||||
int sd_rtnl_message_routing_policy_rule_get_table(sd_netlink_message *m, unsigned char *table);
|
||||
int sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(sd_netlink_message *m, unsigned char len);
|
||||
int sd_rtnl_message_routing_policy_rule_get_rtm_src_prefixlen(sd_netlink_message *m, unsigned char *len);
|
||||
int sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(sd_netlink_message *m, unsigned char len);
|
||||
int sd_rtnl_message_routing_policy_rule_get_rtm_dst_prefixlen(sd_netlink_message *m, unsigned char *len);
|
||||
int sd_rtnl_message_routing_policy_rule_set_rtm_type(sd_netlink_message *m, unsigned char type);
|
||||
int sd_rtnl_message_routing_policy_rule_get_rtm_type(sd_netlink_message *m, unsigned char *type);
|
||||
|
||||
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_netlink, sd_netlink_unref);
|
||||
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_netlink_message, sd_netlink_message_unref);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user