]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
networkd: allow setting rp_filter for an interface
authorSusant Sahani <ssahani@gmail.com>
Thu, 13 Jul 2023 16:10:48 +0000 (21:40 +0530)
committerSusant Sahani <ssahani@gmail.com>
Fri, 28 Jul 2023 09:08:27 +0000 (14:38 +0530)
man/systemd.network.xml
src/network/networkd-network-gperf.gperf
src/network/networkd-network.c
src/network/networkd-network.h
src/network/networkd-sysctl.c
src/network/networkd-sysctl.h

index 959ce08314f8a4fe1fdb91146b2d2571cdc612ad..56c02e18dbb397a4c5c5c18676fa55467c484e64 100644 (file)
@@ -776,6 +776,22 @@ Table=1234</programlisting></para>
         </listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><varname>IPv4ReversePathFilter=</varname></term>
+        <listitem>
+          <para>Configure IPv4 Reverse Path Filtering. If enabled, when an IPv4 packet is received, the machine will first check
+          whether the <emphasis>source</emphasis> of the packet would be routed through the interface it came in. If there is no
+          route to the source on that interface, the machine will drop the packet. Takes one of
+          <literal>no</literal>, <literal>strict</literal>, or <literal>loose</literal>. When <literal>no</literal>,
+          no source validation will be done. When <literal>strict</literal>, mode each incoming packet is tested against the FIB and
+          if the incoming interface is not the best reverse path, the packet check will fail. By default failed packets are discarded.
+          When <literal>loose</literal>,  mode each incoming packet's source address is tested against the FIB. The packet is dropped
+          only if the source address is not reachable via any interface on that router.
+          See <ulink url="https://tools.ietf.org/html/rfc1027">RFC 3704</ulink>.
+          When unset, the kernel's default will be used.</para>
+        </listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><varname>IPv4AcceptLocal=</varname></term>
         <listitem>
index a5d328e0378fb936115b9fb92a94a10df1c2f88c..4049993beb4b821bffd80e560881f3c129a090c1 100644 (file)
@@ -140,6 +140,7 @@ Network.PrimarySlave,                        config_parse_bool,
 Network.IPv4ProxyARP,                        config_parse_tristate,                                    0,                             offsetof(Network, proxy_arp)
 Network.ProxyARP,                            config_parse_tristate,                                    0,                             offsetof(Network, proxy_arp)
 Network.IPv6ProxyNDPAddress,                 config_parse_ipv6_proxy_ndp_address,                      0,                             0
+Network.IPv4ReversePathFilter,               config_parse_ip_reverse_path_filter,                      0,                             offsetof(Network, ipv4_rp_filter)
 Network.BindCarrier,                         config_parse_strv,                                        0,                             offsetof(Network, bind_carrier)
 Network.ConfigureWithoutCarrier,             config_parse_bool,                                        0,                             offsetof(Network, configure_without_carrier)
 Network.IgnoreCarrierLoss,                   config_parse_ignore_carrier_loss,                         0,                             0
index d4f4a9ed978e3c78eab34c1e399c96fa62f6c174..401484298518ec62567c0dfb60a9b2a524fd3944 100644 (file)
@@ -474,6 +474,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
                 .ipv6_hop_limit = -1,
                 .ipv6_proxy_ndp = -1,
                 .proxy_arp = -1,
+                .ipv4_rp_filter = _IP_REVERSE_PATH_FILTER_INVALID,
 
                 .ipv6_accept_ra = -1,
                 .ipv6_accept_ra_use_dns = true,
index 886729cd5a1232b16a9991d56ffffe67a5aa537c..0b9775f014812b05f766831ff35b2bfe2e1ef910 100644 (file)
@@ -307,6 +307,7 @@ struct Network {
         int proxy_arp;
         uint32_t ipv6_mtu;
         IPv6PrivacyExtensions ipv6_privacy_extensions;
+        IPReversePathFilter ipv4_rp_filter;
         int ipv6_proxy_ndp;
         Set *ipv6_proxy_ndp_addresses;
 
index 7c9a83ba5799bf8d50722fd3e971cd88dd78e885..0b8169a0176626ae0322bf589dbea7c574391657 100644 (file)
@@ -89,6 +89,21 @@ static int link_set_ipv6_forward(Link *link) {
         return sysctl_write_ip_property(AF_INET6, "all", "forwarding", "1");
 }
 
+static int link_set_ipv4_rp_filter(Link *link) {
+        assert(link);
+
+        if (link->flags & IFF_LOOPBACK)
+                return 0;
+
+        if (!link->network)
+                return 0;
+
+        if (link->network->ipv4_rp_filter < 0)
+                return 0;
+
+        return sysctl_write_ip_property_int(AF_INET, link->ifname, "rp_filter", link->network->ipv4_rp_filter);
+}
+
 static int link_set_ipv6_privacy_extensions(Link *link) {
         IPv6PrivacyExtensions val;
 
@@ -302,6 +317,10 @@ int link_set_sysctl(Link *link) {
         if (r < 0)
                 log_link_warning_errno(link, r, "Cannot set IPv4 route_localnet flag for interface, ignoring: %m");
 
+        r = link_set_ipv4_rp_filter(link);
+        if (r < 0)
+                log_link_warning_errno(link, r, "Cannot set IPv4 reverse path filtering for interface, ignoring: %m");
+
         /* If promote_secondaries is not set, DHCP will work only as long as the IP address does not
          * changes between leases. The kernel will remove all secondary IP addresses of an interface
          * otherwise. The way systemd-networkd works is that the new IP of a lease is added as a
@@ -325,3 +344,13 @@ DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(ipv6_privacy_extensions, IPv6PrivacyExte
                                         IPV6_PRIVACY_EXTENSIONS_YES);
 DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_privacy_extensions, ipv6_privacy_extensions, IPv6PrivacyExtensions,
                          "Failed to parse IPv6 privacy extensions option");
+
+static const char* const ip_reverse_path_filter_table[_IP_REVERSE_PATH_FILTER_MAX] = {
+        [IP_REVERSE_PATH_FILTER_NO]     = "no",
+        [IP_REVERSE_PATH_FILTER_STRICT] = "strict",
+        [IP_REVERSE_PATH_FILTER_LOOSE]  = "loose",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(ip_reverse_path_filter, IPReversePathFilter);
+DEFINE_CONFIG_PARSE_ENUM(config_parse_ip_reverse_path_filter, ip_reverse_path_filter, IPReversePathFilter,
+                         "Failed to parse IP reverse path filter option");
index df5d6e08ffa68b426371e8991f06e55b27004525..ba6915719a157d96159e0d593583ebcd015f7c71 100644 (file)
@@ -17,10 +17,22 @@ typedef enum IPv6PrivacyExtensions {
         _IPV6_PRIVACY_EXTENSIONS_INVALID = -EINVAL,
 } IPv6PrivacyExtensions;
 
+typedef enum IPReversePathFilter {
+        IP_REVERSE_PATH_FILTER_NO,
+        IP_REVERSE_PATH_FILTER_STRICT,
+        IP_REVERSE_PATH_FILTER_LOOSE,
+        _IP_REVERSE_PATH_FILTER_MAX,
+        _IP_REVERSE_PATH_FILTER_INVALID = -EINVAL,
+} IPReversePathFilter;
+
 int link_set_sysctl(Link *link);
 int link_set_ipv6_mtu(Link *link);
 
 const char* ipv6_privacy_extensions_to_string(IPv6PrivacyExtensions i) _const_;
 IPv6PrivacyExtensions ipv6_privacy_extensions_from_string(const char *s) _pure_;
 
+const char* ip_reverse_path_filter_to_string(IPReversePathFilter i) _const_;
+IPReversePathFilter ip_reverse_path_filter_from_string(const char *s) _pure_;
+
 CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_privacy_extensions);
+CONFIG_PARSER_PROTOTYPE(config_parse_ip_reverse_path_filter);