chiark / gitweb /
networkd: make IP forwarding for IPv4 and IPv6 individually configurable
authorLennart Poettering <lennart@poettering.net>
Tue, 13 Jan 2015 19:07:13 +0000 (20:07 +0100)
committerLennart Poettering <lennart@poettering.net>
Tue, 13 Jan 2015 19:17:07 +0000 (20:17 +0100)
man/systemd.network.xml
src/network/networkd-link.c
src/network/networkd-manager.c
src/network/networkd-network-gperf.gperf
src/network/networkd-network.c
src/network/networkd.h
src/shared/conf-parser.c
src/shared/util.h

index 484d6f3..c072f08 100644 (file)
                                         packets on the network
                                         interface will be forwarded to
                                         other interfaces according to
-                                        the routing table. Takes a
-                                        boolean
-                                        argument.</para></listitem>
+                                        the routing table. Takes
+                                        either a boolean argument, or
+                                        the values
+                                        <literal>ipv4</literal> or
+                                        <literal>ipv6</literal>, which
+                                        only enables IP forwarding for
+                                        the specified address
+                                        family.</para></listitem>
                                 </varlistentry>
                                 <varlistentry>
                                         <term><varname>IPMasquerade=</varname></term>
index 1e25967..e4800a1 100644 (file)
@@ -88,14 +88,24 @@ static bool link_lldp_enabled(Link *link) {
         return link->network->lldp;
 }
 
-static bool link_ip_forward_enabled(Link *link) {
+static bool link_ipv4_forward_enabled(Link *link) {
         if (link->flags & IFF_LOOPBACK)
                 return false;
 
         if (!link->network)
                 return false;
 
-        return link->network->ip_forward;
+        return IN_SET(link->network->ip_forward, ADDRESS_FAMILY_IPV4, ADDRESS_FAMILY_YES);
+}
+
+static bool link_ipv6_forward_enabled(Link *link) {
+        if (link->flags & IFF_LOOPBACK)
+                return false;
+
+        if (!link->network)
+                return false;
+
+        return IN_SET(link->network->ip_forward, ADDRESS_FAMILY_IPV6, ADDRESS_FAMILY_YES);
 }
 
 #define FLAG_STRING(string, flag, old, new) \
@@ -1225,14 +1235,26 @@ static int link_enter_join_netdev(Link *link) {
         return 0;
 }
 
-static int link_set_ip_forward(Link *link) {
+static int link_set_ipv4_forward(Link *link) {
         const char *p = NULL;
         int r;
 
         p = strappenda("/proc/sys/net/ipv4/conf/", link->ifname, "/forwarding");
-        r = write_string_file_no_create(p, link_ip_forward_enabled(link) ? "1" : "0");
+        r = write_string_file_no_create(p, one_zero(link_ipv4_forward_enabled(link)));
         if (r < 0)
-                log_link_warning_errno(link, r, "Cannot configure IP forwarding for interface: %m");
+                log_link_warning_errno(link, r, "Cannot configure IPv4 forwarding for interface: %m");
+
+        return 0;
+}
+
+static int link_set_ipv6_forward(Link *link) {
+        const char *p = NULL;
+        int r;
+
+        p = strappenda("/proc/sys/net/ipv6/conf/", link->ifname, "/forwarding");
+        r = write_string_file_no_create(p, one_zero(link_ipv6_forward_enabled(link)));
+        if (r < 0)
+                log_link_warning_errno(link, r, "Cannot configure IPv6 forwarding for interface: %m");
 
         return 0;
 }
@@ -1248,7 +1270,11 @@ static int link_configure(Link *link) {
         if (r < 0)
                 return r;
 
-        r = link_set_ip_forward(link);
+        r = link_set_ipv4_forward(link);
+        if (r < 0)
+                return r;
+
+        r = link_set_ipv6_forward(link);
         if (r < 0)
                 return r;
 
index 42b5113..4c90434 100644 (file)
@@ -686,3 +686,5 @@ AddressFamilyBoolean address_family_boolean_from_string(const char *s) {
 
         return _ADDRESS_FAMILY_BOOLEAN_INVALID;
 }
+
+DEFINE_CONFIG_PARSE_ENUM(config_parse_address_family_boolean, address_family_boolean, AddressFamilyBoolean, "Failed to parse option");
index 3eb37b4..5f2f741 100644 (file)
@@ -44,7 +44,7 @@ Network.Domains,             config_parse_domains,               0,
 Network.DNS,                 config_parse_strv,                  0,                             offsetof(Network, dns)
 Network.LLMNR,               config_parse_llmnr,                 0,                             offsetof(Network, llmnr)
 Network.NTP,                 config_parse_strv,                  0,                             offsetof(Network, ntp)
-Network.IPForward,           config_parse_bool,                  0,                             offsetof(Network, ip_forward)
+Network.IPForward,           config_parse_address_family_boolean,0,                             offsetof(Network, ip_forward)
 Network.IPMasquerade,        config_parse_bool,                  0,                             offsetof(Network, ip_masquerade)
 Address.Address,             config_parse_address,               0,                             0
 Address.Peer,                config_parse_address,               0,                             0
index 98f199a..34a06d3 100644 (file)
@@ -111,7 +111,7 @@ static int network_load_one(Manager *manager, const char *filename) {
 
         /* IPMasquerade=yes implies IPForward=yes */
         if (network->ip_masquerade)
-                network->ip_forward = true;
+                network->ip_forward |= ADDRESS_FAMILY_IPV4;
 
         LIST_PREPEND(networks, manager->networks, network);
 
@@ -489,6 +489,10 @@ int config_parse_dhcp(
         assert(rvalue);
         assert(data);
 
+        /* Note that this is mostly like
+         * config_parse_address_family_boolean(), except that it
+         * understands some old names for the enum values */
+
         s = address_family_boolean_from_string(rvalue);
         if (s < 0) {
 
index ea4547b..719a75b 100644 (file)
@@ -55,10 +55,11 @@ typedef struct AddressPool AddressPool;
 typedef struct FdbEntry FdbEntry;
 
 typedef enum AddressFamilyBoolean {
-        ADDRESS_FAMILY_NO,
-        ADDRESS_FAMILY_YES,
-        ADDRESS_FAMILY_IPV4,
-        ADDRESS_FAMILY_IPV6,
+        /* This is a bitmask, though it usually doesn't feel that way! */
+        ADDRESS_FAMILY_NO = 0,
+        ADDRESS_FAMILY_IPV4 = 1,
+        ADDRESS_FAMILY_IPV6 = 2,
+        ADDRESS_FAMILY_YES = 3,
         _ADDRESS_FAMILY_BOOLEAN_MAX,
         _ADDRESS_FAMILY_BOOLEAN_INVALID = -1,
 } AddressFamilyBoolean;
@@ -120,8 +121,8 @@ struct Network {
 
         unsigned cost;
 
+        AddressFamilyBoolean ip_forward;
         bool ip_masquerade;
-        bool ip_forward;
 
         struct ether_addr *mac;
         unsigned mtu;
@@ -391,3 +392,5 @@ int address_pool_acquire(AddressPool *p, unsigned prefixlen, union in_addr_union
 
 const char *address_family_boolean_to_string(AddressFamilyBoolean b) _const_;
 AddressFamilyBoolean address_family_boolean_from_string(const char *s) _const_;
+
+int config_parse_address_family_boolean(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);
index a1a94da..0b1af6c 100644 (file)
@@ -823,8 +823,7 @@ int config_parse_log_facility(
 
         x = log_facility_unshifted_from_string(rvalue);
         if (x < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
-                           "Failed to parse log facility, ignoring: %s", rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse log facility, ignoring: %s", rvalue);
                 return 0;
         }
 
@@ -855,8 +854,7 @@ int config_parse_log_level(
 
         x = log_level_from_string(rvalue);
         if (x < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
-                           "Failed to parse log level, ignoring: %s", rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse log level, ignoring: %s", rvalue);
                 return 0;
         }
 
index b337249..850019a 100644 (file)
@@ -143,6 +143,10 @@ static inline const char* true_false(bool b) {
         return b ? "true" : "false";
 }
 
+static inline const char* one_zero(bool b) {
+        return b ? "1" : "0";
+}
+
 static inline const char* strempty(const char *s) {
         return s ? s : "";
 }