chiark / gitweb /
networkd: add minimal IP forwarding and masquerading support to .network files
authorLennart Poettering <lennart@poettering.net>
Tue, 13 Jan 2015 12:47:08 +0000 (13:47 +0100)
committerLennart Poettering <lennart@poettering.net>
Tue, 13 Jan 2015 12:55:15 +0000 (13:55 +0100)
This adds two new settings to networkd's .network files:
IPForwarding=yes and IPMasquerade=yes. The former controls the
"forwarding" sysctl setting of the interface, thus controlling whether
IP forwarding shall be enabled on the specific interface. The latter
controls whether a firewall rule shall be installed that exposes traffic
coming from the interface as coming from the local host to all other
interfaces.

This also enables both options by default for container network
interfaces, thus making "systemd-nspawn --network-veth" have network
connectivity out of the box.

Makefile.am
man/systemd.network.xml
network/80-container-ve.network
src/network/networkd-address.c
src/network/networkd-link.c
src/network/networkd-network-gperf.gperf
src/network/networkd-network.c
src/network/networkd.h
src/shared/in-addr-util.c
src/shared/in-addr-util.h

index 205dafafce125f723077031a67683645188c80fd..9d07a2b6eb2c33faaa5a6c2fef9a6a4eadd6240b 100644 (file)
@@ -5403,6 +5403,11 @@ systemd_networkd_SOURCES = \
 systemd_networkd_LDADD = \
        libsystemd-networkd-core.la
 
 systemd_networkd_LDADD = \
        libsystemd-networkd-core.la
 
+if HAVE_LIBIPTC
+systemd_networkd_LDADD += \
+       libsystemd-fw.la
+endif
+
 noinst_LTLIBRARIES += \
        libsystemd-networkd-core.la
 
 noinst_LTLIBRARIES += \
        libsystemd-networkd-core.la
 
@@ -5493,6 +5498,11 @@ test_network_SOURCES = \
 test_network_LDADD = \
        libsystemd-networkd-core.la
 
 test_network_LDADD = \
        libsystemd-networkd-core.la
 
+if HAVE_LIBIPTC
+test_network_LDADD += \
+       libsystemd-fw.la
+endif
+
 test_network_tables_SOURCES = \
        src/network/test-network-tables.c \
        src/shared/test-tables.h
 test_network_tables_SOURCES = \
        src/network/test-network-tables.c \
        src/shared/test-tables.h
index ea278c70d7c2d13475edee67674fe8155a712647..d54026874e95d92858ee8aa8f804d06f87385371 100644 (file)
                                                 <para>An NTP server address. This option may be specified more than once.</para>
                                         </listitem>
                                 </varlistentry>
                                                 <para>An NTP server address. This option may be specified more than once.</para>
                                         </listitem>
                                 </varlistentry>
+                                <varlistentry>
+                                        <term><varname>IPForward=</varname></term>
+                                        <listitem><para>Configures IP
+                                        forwarding for the network
+                                        interface. If enabled incoming
+                                        packets on the network
+                                        interface will be forwarded to
+                                        other interfaces according to
+                                        the routing table. Takes a
+                                        boolean
+                                        argument.</para></listitem>
+                                </varlistentry>
+                                <varlistentry>
+                                        <term><varname>IPMasquerade=</varname></term>
+                                        <listitem><para>Configures IP
+                                        masquerading for the network
+                                        interface. If enabled packets
+                                        forwarded from the network
+                                        interface will be appear as
+                                        coming from the local
+                                        host. Takes a boolean
+                                        argument. Implies
+                                        <varname>IPForward=yes</varname>.</para></listitem>
+                                </varlistentry>
                                 <varlistentry>
                                         <term><varname>Bridge=</varname></term>
                                         <listitem>
                                 <varlistentry>
                                         <term><varname>Bridge=</varname></term>
                                         <listitem>
index cb04c7cb3dea5a2c85ac3cbdbeb87b82f41da84a..fe24eb45f8b1d4d33a1b590811edceb045e54d40 100644 (file)
@@ -13,3 +13,5 @@ Driver=veth
 Address=0.0.0.0/28
 IPv4LL=yes
 DHCPServer=yes
 Address=0.0.0.0/28
 IPv4LL=yes
 DHCPServer=yes
+IPForward=yes
+IPMasquerade=yes
index b28c2e08f20fda7bcc25e77a87226398f274e7b6..b4eb91ebb60d4c066e4cf653dbd14059ebcbf06b 100644 (file)
 
 #include <net/if.h>
 
 
 #include <net/if.h>
 
-#include "networkd.h"
-#include "networkd-link.h"
-
 #include "utf8.h"
 #include "util.h"
 #include "conf-parser.h"
 #include "utf8.h"
 #include "util.h"
 #include "conf-parser.h"
+#include "fw-util.h"
 #include "network-internal.h"
 #include "network-internal.h"
+#include "networkd.h"
+#include "networkd-link.h"
 
 static void address_init(Address *address) {
         assert(address);
 
 static void address_init(Address *address) {
         assert(address);
@@ -103,6 +103,54 @@ void address_free(Address *address) {
         free(address);
 }
 
         free(address);
 }
 
+int address_establish(Address *address, Link *link) {
+        bool masq;
+        int r;
+
+        assert(address);
+        assert(link);
+
+        masq = link->network &&
+                link->network->ip_masquerade &&
+                address->family == AF_INET &&
+                address->scope < RT_SCOPE_LINK;
+
+        /* Add firewall entry if this is requested */
+        if (address->ip_forward_done != masq) {
+                union in_addr_union masked = address->in_addr;
+                in_addr_mask(address->family, &masked, address->prefixlen);
+
+                r = fw_add_masquerade(masq, AF_INET, 0, &masked, address->prefixlen, NULL, NULL, 0);
+                if (r < 0)
+                        log_link_warning_errno(link, r, "Could not enable IP masquerading: %m");
+
+                address->ip_forward_done = masq;
+        }
+
+        return 0;
+}
+
+int address_release(Address *address, Link *link) {
+        int r;
+
+        assert(address);
+        assert(link);
+
+        /* Remove masquerading firewall entry if it was added */
+        if (address->ip_forward_done) {
+                union in_addr_union masked = address->in_addr;
+                in_addr_mask(address->family, &masked, address->prefixlen);
+
+                r = fw_add_masquerade(false, AF_INET, 0, &masked, address->prefixlen, NULL, NULL, 0);
+                if (r < 0)
+                        log_link_warning_errno(link, r, "Failed to disable IP masquerading: %m");
+
+                address->ip_forward_done = false;
+        }
+
+        return 0;
+}
+
 int address_drop(Address *address, Link *link,
                  sd_rtnl_message_handler_t callback) {
         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
 int address_drop(Address *address, Link *link,
                  sd_rtnl_message_handler_t callback) {
         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
@@ -115,6 +163,8 @@ int address_drop(Address *address, Link *link,
         assert(link->manager);
         assert(link->manager->rtnl);
 
         assert(link->manager);
         assert(link->manager->rtnl);
 
+        address_release(address, link);
+
         r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR,
                                      link->ifindex, address->family);
         if (r < 0)
         r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR,
                                      link->ifindex, address->family);
         if (r < 0)
@@ -333,6 +383,8 @@ int address_configure(Address *address, Link *link,
 
         link_ref(link);
 
 
         link_ref(link);
 
+        address_establish(address, link);
+
         return 0;
 }
 
         return 0;
 }
 
@@ -549,8 +601,7 @@ bool address_equal(Address *a1, Address *a2) {
                         return (b1 >> (32 - a1->prefixlen)) == (b2 >> (32 - a1->prefixlen));
                 }
 
                         return (b1 >> (32 - a1->prefixlen)) == (b2 >> (32 - a1->prefixlen));
                 }
 
-        case AF_INET6:
-        {
+        case AF_INET6: {
                 uint64_t *b1, *b2;
 
                 b1 = (uint64_t*)&a1->in_addr.in6;
                 uint64_t *b1, *b2;
 
                 b1 = (uint64_t*)&a1->in_addr.in6;
@@ -558,6 +609,7 @@ bool address_equal(Address *a1, Address *a2) {
 
                 return (((b1[0] ^ b2[0]) | (b1[1] ^ b2[1])) == 0UL);
         }
 
                 return (((b1[0] ^ b2[0]) | (b1[1] ^ b2[1])) == 0UL);
         }
+
         default:
                 assert_not_reached("Invalid address family");
         }
         default:
                 assert_not_reached("Invalid address family");
         }
index 63c7a8bf248195f1aad1dd7298a7d6464925a4c7..12944a03a3bca77011e2dfef8998fd3ad6d1342a 100644 (file)
 #include <linux/if.h>
 #include <unistd.h>
 
 #include <linux/if.h>
 #include <unistd.h>
 
-#include "networkd-link.h"
-#include "networkd-netdev.h"
-#include "libudev-private.h"
-#include "udev-util.h"
 #include "util.h"
 #include "virt.h"
 #include "util.h"
 #include "virt.h"
+#include "fileio.h"
 #include "bus-util.h"
 #include "bus-util.h"
+#include "udev-util.h"
+#include "libudev-private.h"
 #include "network-internal.h"
 #include "network-internal.h"
+#include "networkd-link.h"
+#include "networkd-netdev.h"
 #include "conf-parser.h"
 #include "conf-parser.h"
-
 #include "dhcp-lease-internal.h"
 
 static bool link_dhcp6_enabled(Link *link) {
 #include "dhcp-lease-internal.h"
 
 static bool link_dhcp6_enabled(Link *link) {
@@ -82,12 +82,22 @@ static bool link_lldp_enabled(Link *link) {
         if (!link->network)
                 return false;
 
         if (!link->network)
                 return false;
 
-        if(link->network->bridge)
+        if (link->network->bridge)
                 return false;
 
         return link->network->lldp;
 }
 
                 return false;
 
         return link->network->lldp;
 }
 
+static bool link_ip_forward_enabled(Link *link) {
+        if (link->flags & IFF_LOOPBACK)
+                return false;
+
+        if (!link->network)
+                return false;
+
+        return link->network->ip_forward;
+}
+
 #define FLAG_STRING(string, flag, old, new) \
         (((old ^ new) & flag) \
                 ? ((old & flag) ? (" -" string) : (" +" string)) \
 #define FLAG_STRING(string, flag, old, new) \
         (((old ^ new) & flag) \
                 ? ((old & flag) ? (" -" string) : (" +" string)) \
@@ -653,9 +663,7 @@ static int link_enter_set_addresses(Link *link) {
         LIST_FOREACH(addresses, ad, link->network->static_addresses) {
                 r = address_configure(ad, link, &address_handler);
                 if (r < 0) {
         LIST_FOREACH(addresses, ad, link->network->static_addresses) {
                 r = address_configure(ad, link, &address_handler);
                 if (r < 0) {
-                        log_link_warning(link,
-                                         "could not set addresses: %s",
-                                         strerror(-r));
+                        log_link_warning_errno(link, r, "Could not set addresses: %m");
                         link_enter_failed(link);
                         return r;
                 }
                         link_enter_failed(link);
                         return r;
                 }
@@ -1217,6 +1225,18 @@ static int link_enter_join_netdev(Link *link) {
         return 0;
 }
 
         return 0;
 }
 
+static int link_set_ip_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");
+        if (r < 0)
+                log_link_warning_errno(link, r, "Cannot configure IP forwarding for interface: %m");
+
+        return 0;
+}
+
 static int link_configure(Link *link) {
         int r;
 
 static int link_configure(Link *link) {
         int r;
 
@@ -1228,6 +1248,10 @@ static int link_configure(Link *link) {
         if (r < 0)
                 return r;
 
         if (r < 0)
                 return r;
 
+        r = link_set_ip_forward(link);
+        if (r < 0)
+                return r;
+
         if (link_ipv4ll_enabled(link)) {
                 r = ipv4ll_configure(link);
                 if (r < 0)
         if (link_ipv4ll_enabled(link)) {
                 r = ipv4ll_configure(link);
                 if (r < 0)
@@ -1364,16 +1388,27 @@ int link_initialized(Link *link, struct udev_device *device) {
         return 0;
 }
 
         return 0;
 }
 
+static Address* link_get_equal_address(Link *link, Address *needle) {
+        Address *i;
+
+        assert(link);
+        assert(needle);
+
+        LIST_FOREACH(addresses, i, link->addresses)
+                if (address_equal(i, needle))
+                        return i;
+
+        return NULL;
+}
+
 int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
         Manager *m = userdata;
         Link *link = NULL;
         uint16_t type;
         _cleanup_address_free_ Address *address = NULL;
 int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
         Manager *m = userdata;
         Link *link = NULL;
         uint16_t type;
         _cleanup_address_free_ Address *address = NULL;
-        Address *ad;
-        char buf[INET6_ADDRSTRLEN];
-        char valid_buf[FORMAT_TIMESPAN_MAX];
+        Address *existing;
+        char buf[INET6_ADDRSTRLEN], valid_buf[FORMAT_TIMESPAN_MAX];
         const char *valid_str = NULL;
         const char *valid_str = NULL;
-        bool address_dropped = false;
         int r, ifindex;
 
         assert(rtnl);
         int r, ifindex;
 
         assert(rtnl);
@@ -1415,50 +1450,42 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, void *use
 
         r = sd_rtnl_message_addr_get_family(message, &address->family);
         if (r < 0 || !IN_SET(address->family, AF_INET, AF_INET6)) {
 
         r = sd_rtnl_message_addr_get_family(message, &address->family);
         if (r < 0 || !IN_SET(address->family, AF_INET, AF_INET6)) {
-                log_link_warning(link,
-                                 "rtnl: received address with invalid family, ignoring");
+                log_link_warning(link, "rtnl: received address with invalid family, ignoring");
                 return 0;
         }
 
         r = sd_rtnl_message_addr_get_prefixlen(message, &address->prefixlen);
         if (r < 0) {
                 return 0;
         }
 
         r = sd_rtnl_message_addr_get_prefixlen(message, &address->prefixlen);
         if (r < 0) {
-                log_link_warning(link,
-                                 "rtnl: received address with invalid prefixlen, ignoring");
+                log_link_warning(link, "rtnl: received address with invalid prefixlen, ignoring");
                 return 0;
         }
 
         r = sd_rtnl_message_addr_get_scope(message, &address->scope);
         if (r < 0) {
                 return 0;
         }
 
         r = sd_rtnl_message_addr_get_scope(message, &address->scope);
         if (r < 0) {
-                log_link_warning(link,
-                                 "rtnl: received address with invalid scope, ignoring");
+                log_link_warning(link, "rtnl: received address with invalid scope, ignoring");
                 return 0;
         }
 
         r = sd_rtnl_message_addr_get_flags(message, &address->flags);
         if (r < 0) {
                 return 0;
         }
 
         r = sd_rtnl_message_addr_get_flags(message, &address->flags);
         if (r < 0) {
-                log_link_warning(link,
-                                 "rtnl: received address with invalid flags, ignoring");
+                log_link_warning(link, "rtnl: received address with invalid flags, ignoring");
                 return 0;
         }
 
         switch (address->family) {
         case AF_INET:
                 return 0;
         }
 
         switch (address->family) {
         case AF_INET:
-                r = sd_rtnl_message_read_in_addr(message, IFA_LOCAL,
-                                                 &address->in_addr.in);
+                r = sd_rtnl_message_read_in_addr(message, IFA_LOCAL, &address->in_addr.in);
                 if (r < 0) {
                 if (r < 0) {
-                        log_link_warning(link,
-                                         "rtnl: received address without valid address, ignoring");
+                        log_link_warning(link, "rtnl: received address without valid address, ignoring");
                         return 0;
                 }
 
                 break;
 
         case AF_INET6:
                         return 0;
                 }
 
                 break;
 
         case AF_INET6:
-                r = sd_rtnl_message_read_in6_addr(message, IFA_ADDRESS,
-                                                  &address->in_addr.in6);
+                r = sd_rtnl_message_read_in6_addr(message, IFA_ADDRESS, &address->in_addr.in6);
                 if (r < 0) {
                 if (r < 0) {
-                        log_link_warning(link,
-                                         "rtnl: received address without valid address, ignoring");
+                        log_link_warning(link, "rtnl: received address without valid address, ignoring");
                         return 0;
                 }
 
                         return 0;
                 }
 
@@ -1468,14 +1495,12 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, void *use
                 assert_not_reached("invalid address family");
         }
 
                 assert_not_reached("invalid address family");
         }
 
-        if (!inet_ntop(address->family, &address->in_addr, buf,
-                       INET6_ADDRSTRLEN)) {
+        if (!inet_ntop(address->family, &address->in_addr, buf, INET6_ADDRSTRLEN)) {
                 log_link_warning(link, "could not print address");
                 return 0;
         }
 
                 log_link_warning(link, "could not print address");
                 return 0;
         }
 
-        r = sd_rtnl_message_read_cache_info(message, IFA_CACHEINFO,
-                                            &address->cinfo);
+        r = sd_rtnl_message_read_cache_info(message, IFA_CACHEINFO, &address->cinfo);
         if (r >= 0) {
                 if (address->cinfo.ifa_valid == CACHE_INFO_INFINITY_LIFE_TIME)
                         valid_str = "ever";
         if (r >= 0) {
                 if (address->cinfo.ifa_valid == CACHE_INFO_INFINITY_LIFE_TIME)
                         valid_str = "ever";
@@ -1485,43 +1510,40 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, void *use
                                                     USEC_PER_SEC);
         }
 
                                                     USEC_PER_SEC);
         }
 
-        LIST_FOREACH(addresses, ad, link->addresses) {
-                if (address_equal(ad, address)) {
-                        LIST_REMOVE(addresses, link->addresses, ad);
+        existing = link_get_equal_address(link, address);
+
+        switch (type) {
+        case RTM_NEWADDR:
+                if (existing) {
+                        log_link_debug(link, "Updating address: %s/%u (valid for %s)", buf, address->prefixlen, valid_str);
 
 
-                        address_free(ad);
 
 
-                        address_dropped = true;
+                        existing->scope = address->scope;
+                        existing->flags = address->flags;
+                        existing->cinfo = address->cinfo;
 
 
-                        break;
-                }
-        }
+                } else {
+                        log_link_debug(link, "Adding address: %s/%u (valid for %s)", buf, address->prefixlen, valid_str);
 
 
-        switch (type) {
-        case RTM_NEWADDR:
-                if (!address_dropped)
-                        log_link_debug(link, "added address: %s/%u (valid for %s)",
-                                       buf, address->prefixlen, valid_str);
-                else
-                        log_link_debug(link, "updated address: %s/%u (valid for %s)",
-                                       buf, address->prefixlen, valid_str);
+                        LIST_PREPEND(addresses, link->addresses, address);
+                        address_establish(address, link);
 
 
-                LIST_PREPEND(addresses, link->addresses, address);
-                address = NULL;
+                        address = NULL;
 
 
-                link_save(link);
+                        link_save(link);
+                }
 
                 break;
 
                 break;
+
         case RTM_DELADDR:
         case RTM_DELADDR:
-                if (address_dropped) {
-                        log_link_debug(link, "removed address: %s/%u (valid for %s)",
-                                       buf, address->prefixlen, valid_str);
 
 
-                        link_save(link);
+                if (existing) {
+                        log_link_debug(link, "Removing address: %s/%u (valid for %s)", buf, address->prefixlen, valid_str);
+                        address_release(existing, link);
+                        LIST_REMOVE(addresses, link->addresses, existing);
+                        address_free(existing);
                 } else
                 } else
-                        log_link_warning(link,
-                                         "removing non-existent address: %s/%u (valid for %s)",
-                                         buf, address->prefixlen, valid_str);
+                        log_link_warning(link, "Removing non-existent address: %s/%u (valid for %s)", buf, address->prefixlen, valid_str);
 
                 break;
         default:
 
                 break;
         default:
index 5094b488f3971d2c1f1c3c29153fefdf1d5c019b..3eb37b4d24fdce10c17c67bdcac02362205b1a34 100644 (file)
@@ -44,6 +44,8 @@ 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.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.IPMasquerade,        config_parse_bool,                  0,                             offsetof(Network, ip_masquerade)
 Address.Address,             config_parse_address,               0,                             0
 Address.Peer,                config_parse_address,               0,                             0
 Address.Broadcast,           config_parse_broadcast,             0,                             0
 Address.Address,             config_parse_address,               0,                             0
 Address.Peer,                config_parse_address,               0,                             0
 Address.Broadcast,           config_parse_broadcast,             0,                             0
index 966b59b878d8f658b0cf906ff6d59e90e7d9affc..d6504cc1787cfebe17307eae97d98b07cb656361 100644 (file)
 #include <ctype.h>
 #include <net/if.h>
 
 #include <ctype.h>
 #include <net/if.h>
 
-#include "networkd.h"
-#include "networkd-netdev.h"
-#include "networkd-link.h"
-#include "network-internal.h"
 #include "path-util.h"
 #include "conf-files.h"
 #include "conf-parser.h"
 #include "util.h"
 #include "path-util.h"
 #include "conf-files.h"
 #include "conf-parser.h"
 #include "util.h"
+#include "networkd.h"
+#include "networkd-netdev.h"
+#include "networkd-link.h"
+#include "network-internal.h"
 
 static int network_load_one(Manager *manager, const char *filename) {
         _cleanup_network_free_ Network *network = NULL;
 
 static int network_load_one(Manager *manager, const char *filename) {
         _cleanup_network_free_ Network *network = NULL;
@@ -109,6 +109,10 @@ static int network_load_one(Manager *manager, const char *filename) {
         if (r < 0)
                 return r;
 
         if (r < 0)
                 return r;
 
+        /* IPMasquerade=yes implies IPForward=yes */
+        if (network->ip_masquerade)
+                network->ip_forward = true;
+
         LIST_PREPEND(networks, manager->networks, network);
 
         LIST_FOREACH(routes, route, network->static_routes) {
         LIST_PREPEND(networks, manager->networks, network);
 
         LIST_FOREACH(routes, route, network->static_routes) {
index 7107c5f9321dd47b5a897ff6268b43c9bfc5e97c..39b2d2bec9c6b50485068d2816e18b6c52617480 100644 (file)
@@ -120,6 +120,9 @@ struct Network {
 
         unsigned cost;
 
 
         unsigned cost;
 
+        bool ip_masquerade;
+        bool ip_forward;
+
         struct ether_addr *mac;
         unsigned mtu;
 
         struct ether_addr *mac;
         unsigned mtu;
 
@@ -157,6 +160,8 @@ struct Address {
         union in_addr_union in_addr;
         union in_addr_union in_addr_peer;
 
         union in_addr_union in_addr;
         union in_addr_union in_addr_peer;
 
+        bool ip_forward_done;
+
         LIST_FIELDS(Address, addresses);
 };
 
         LIST_FIELDS(Address, addresses);
 };
 
@@ -326,6 +331,8 @@ void address_free(Address *address);
 int address_configure(Address *address, Link *link, sd_rtnl_message_handler_t callback);
 int address_update(Address *address, Link *link, sd_rtnl_message_handler_t callback);
 int address_drop(Address *address, Link *link, sd_rtnl_message_handler_t callback);
 int address_configure(Address *address, Link *link, sd_rtnl_message_handler_t callback);
 int address_update(Address *address, Link *link, sd_rtnl_message_handler_t callback);
 int address_drop(Address *address, Link *link, sd_rtnl_message_handler_t callback);
+int address_establish(Address *address, Link *link);
+int address_release(Address *address, Link *link);
 bool address_equal(Address *a1, Address *a2);
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(Address*, address_free);
 bool address_equal(Address *a1, Address *a2);
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(Address*, address_free);
index b02e7516ca4d69400dc7d5dd95d3776e7eba0614..d88864b5987f7387ebd99e2ea9a689d05038c478 100644 (file)
@@ -300,3 +300,39 @@ int in_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask
         in_addr_prefixlen_to_netmask(mask, prefixlen);
         return 0;
 }
         in_addr_prefixlen_to_netmask(mask, prefixlen);
         return 0;
 }
+
+int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen) {
+        assert(addr);
+
+        if (family == AF_INET) {
+                struct in_addr mask;
+
+                if (!in_addr_prefixlen_to_netmask(&mask, prefixlen))
+                        return -EINVAL;
+
+                addr->in.s_addr &= mask.s_addr;
+                return 0;
+        }
+
+        if (family == AF_INET6) {
+                unsigned i;
+
+                for (i = 0; i < 16; i++) {
+                        uint8_t mask;
+
+                        if (prefixlen >= 8) {
+                                mask = 0xFF;
+                                prefixlen -= 8;
+                        } else {
+                                mask = 0xFF << (8 - prefixlen);
+                                prefixlen = 0;
+                        }
+
+                        addr->in6.s6_addr[i] &= mask;
+                }
+
+                return 0;
+        }
+
+        return -EAFNOSUPPORT;
+}
index 4cf4418b4be7b72d5b1839cace93d66639dd28ed..51af08868cda48af0db4681613a5be4b853234ac 100644 (file)
@@ -43,8 +43,11 @@ unsigned char in_addr_netmask_to_prefixlen(const struct in_addr *addr);
 struct in_addr* in_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen);
 int in_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen);
 int in_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask);
 struct in_addr* in_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen);
 int in_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen);
 int in_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask);
+int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen);
 
 static inline size_t FAMILY_ADDRESS_SIZE(int family) {
         assert(family == AF_INET || family == AF_INET6);
         return family == AF_INET6 ? 16 : 4;
 }
 
 static inline size_t FAMILY_ADDRESS_SIZE(int family) {
         assert(family == AF_INET || family == AF_INET6);
         return family == AF_INET6 ? 16 : 4;
 }
+
+#define IN_ADDR_NULL ((union in_addr_union) {})