From: Lennart Poettering Date: Tue, 13 Jan 2015 19:07:13 +0000 (+0100) Subject: networkd: make IP forwarding for IPv4 and IPv6 individually configurable X-Git-Tag: v219~522 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=769d324c99aab129148bd25f5f663ef441287d86;hp=db9fd84944807ebea04363dada761613360fa6f9 networkd: make IP forwarding for IPv4 and IPv6 individually configurable --- diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 484d6f31c..c072f08f6 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -352,9 +352,14 @@ packets on the network interface will be forwarded to other interfaces according to - the routing table. Takes a - boolean - argument. + the routing table. Takes + either a boolean argument, or + the values + ipv4 or + ipv6, which + only enables IP forwarding for + the specified address + family. IPMasquerade= diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 1e2596749..e4800a10d 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -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; diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 42b51137e..4c9043486 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -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"); diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 3eb37b4d2..5f2f74196 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -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 diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 98f199ad7..34a06d3f3 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -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) { diff --git a/src/network/networkd.h b/src/network/networkd.h index ea4547b94..719a75b8b 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -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); diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c index a1a94da92..0b1af6c57 100644 --- a/src/shared/conf-parser.c +++ b/src/shared/conf-parser.c @@ -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; } diff --git a/src/shared/util.h b/src/shared/util.h index b337249fa..850019ab9 100644 --- a/src/shared/util.h +++ b/src/shared/util.h @@ -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 : ""; }