]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
networkd: add support for wireguard interface type
authorJörg Thalheim <joerg@thalheim.io>
Mon, 18 Dec 2017 14:20:34 +0000 (15:20 +0100)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Tue, 9 Jan 2018 13:00:49 +0000 (14:00 +0100)
More information may be found at wireguard.com.

14 files changed:
man/custom-html.xsl
man/systemd.netdev.xml
src/libsystemd/sd-netlink/generic-netlink.c
src/libsystemd/sd-netlink/netlink-types.c
src/libsystemd/sd-netlink/netlink-types.h
src/network/meson.build
src/network/netdev/netdev-gperf.gperf
src/network/netdev/netdev.c
src/network/netdev/netdev.h
src/network/netdev/wireguard.c [new file with mode: 0644]
src/network/netdev/wireguard.h [new file with mode: 0644]
src/shared/meson.build
src/shared/wireguard-netlink.h [new file with mode: 0644]
src/systemd/sd-netlink.h

index 47ce6abfee0c7749028cbf306960ac9a14149bb0..e8a7404df3eff6436dbb3f6c9a23abe4a486735b 100644 (file)
   </a>
 </xsl:template>
 
+<xsl:template match="citerefentry[@project='wireguard']">
+  <a>
+    <xsl:attribute name="href">
+      <xsl:text>https://git.zx2c4.com/WireGuard/about/src/tools/</xsl:text>
+      <xsl:value-of select="refentrytitle"/>
+      <xsl:text>.</xsl:text>
+      <xsl:value-of select="manvolnum"/>
+    </xsl:attribute>
+    <xsl:call-template name="inline.charseq"/>
+  </a>
+</xsl:template>
+
 <xsl:template match="citerefentry[@project='mankier']">
   <a>
     <xsl:attribute name="href">
index 8f8d54a8eb3e2932ebcf2a45f392fdc10eeec136..eb86db979233991dbb3c487761aed984962711d1 100644 (file)
           <entry>The virtual CAN tunnel driver (vxcan). Similar to the virtual ethernet driver veth, vxcan implements a local CAN traffic tunnel between two virtual CAN network devices. When creating a vxcan, two vxcan devices are created as pair. When one end receives the packet it appears on its pair and vice versa. The vxcan can be used for cross namespace communication.
           </entry></row>
 
+          <row><entry><varname>wireguard</varname></entry>
+          <entry>WireGuard Secure Network Tunnel.</entry></row>
+
         </tbody>
       </tgroup>
     </table>
     as the <literal>[Tun]</literal> section.</para>
   </refsect1>
 
+  <refsect1>
+    <title>[WireGuard] Section Options</title>
+
+    <para>The <literal>[WireGuard]</literal> section accepts the following
+    keys:</para>
+
+    <variablelist class='network-directives'>
+      <varlistentry>
+        <term><varname>PrivateKey=</varname></term>
+        <listitem>
+          <para>The Base64 encoded private key for the interface. It can be
+            generated using the <command>wg genkey</command> command
+            (see <citerefentry project="wireguard"><refentrytitle>wg</refentrytitle><manvolnum>8</manvolnum></citerefentry>).
+            This option is mandatory to use wireguard.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>ListenPort=</varname></term>
+        <listitem>
+          <para>Sets UDP port for listening. Takes either value between 1 and 65535
+            or <literal>auto</literal>. If <literal>auto</literal> is specified,
+            the port is automatically generated based on interface name.
+            Defaults to <literal>auto</literal>.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>FwMark=</varname></term>
+        <listitem>
+          <para>Sets a firewall mark on outgoing wireguard packets from this interface.</para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>[WireGuardPeer] Section Options</title>
+
+    <para>The <literal>[WireGuardPeer]</literal> section accepts the following
+    keys:</para>
+
+    <variablelist class='network-directives'>
+      <varlistentry>
+        <term><varname>PublicKey=</varname></term>
+        <listitem>
+          <para>Sets a Base64 encoded public key calculated by <command>wg pubkey</command>
+            (see <citerefentry project="wireguard"><refentrytitle>wg</refentrytitle><manvolnum>8</manvolnum></citerefentry>)
+            from a private key, and usually transmitted out of band to the
+            author of the configuration file. This option is mandatory for this
+            section.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>PresharedKey=</varname></term>
+        <listitem>
+          <para>Optional preshared key for the interface. It can be generated
+            by the <command>wg genpsk</command> command. This option adds an
+            additional layer of symmetric-key cryptography to be mixed into the
+            already existing public-key cryptography, for post-quantum
+            resistance.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>AllowedIPs=</varname></term>
+        <listitem>
+          <para>Sets a comma-separated list of IP (v4 or v6) addresses with CIDR masks
+            from which this peer is allowed to send incoming traffic and to
+            which outgoing traffic for this peer is directed. The catch-all
+            0.0.0.0/0 may be specified for matching all IPv4 addresses, and
+            ::/0 may be specified for matching all IPv6 addresses. </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>Endpoint=</varname></term>
+        <listitem>
+          <para>Sets an endpoint IP address or hostname, followed by a colon, and then
+            a port number. This endpoint will be updated automatically once to
+            the most recent source IP address and port of correctly
+            authenticated packets from the peer at configuration time.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>PersistentKeepalive=</varname></term>
+        <listitem>
+          <para>Sets a seconds interval, between 1 and 65535 inclusive, of how often
+            to send an authenticated empty packet to the peer for the purpose
+            of keeping a stateful firewall or NAT mapping valid persistently.
+            For example, if the interface very rarely sends traffic, but it
+            might at anytime receive traffic from a peer, and it is behind NAT,
+            the interface might benefit from having a persistent keepalive
+            interval of 25 seconds. If set to 0 or "off", this option is
+            disabled. By default or when unspecified, this option is off.
+            Most users will not need this.</para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
   <refsect1>
     <title>[Bond] Section Options</title>
 
@@ -1391,6 +1491,21 @@ Name=macvtap-test
 Kind=macvtap
       </programlisting>
     </example>
+    <example>
+      <title>/etc/systemd/network/25-wireguard.netdev</title>
+      <programlisting>[NetDev]
+Name=wg0
+Kind=wireguard
+
+[WireGuard]
+PrivateKey=EEGlnEPYJV//kbvvIqxKkQwOiS+UENyPncC4bF46ong=
+ListenPort=51820
+
+[WireGuardPeer]
+PublicKey=RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=
+AllowedIPs=fd31:bf08:57cb::/48,192.168.26.0/24
+Endpoint=wireguard.example.com:51820</programlisting>
+    </example>
   </refsect1>
   <refsect1>
     <title>See Also</title>
index e6e0f958babda5b545efd712b3d7bbe416569290..771658d9aef01e9b00cb19931b3ebb658489142d 100644 (file)
@@ -11,6 +11,7 @@ typedef struct {
 
 static const genl_family genl_families[] = {
         [SD_GENL_ID_CTRL] = { .name = "", .version = 1 },
+        [SD_GENL_WIREGUARD] = { .name = "wireguard", .version = 1 },
 };
 
 int sd_genl_socket_open(sd_netlink **ret) {
index 6dea62e313d673199979eed79b89fdb1cfc88aab..718aa74f15822bbf319998bff1b97cb701c53c31 100644 (file)
@@ -47,6 +47,7 @@
 #include "netlink-types.h"
 #include "string-table.h"
 #include "util.h"
+#include "wireguard-netlink.h"
 #include "sd-netlink.h"
 
 /* Maximum ARP IP target defined in kernel */
@@ -340,7 +341,7 @@ static const char* const nl_union_link_info_data_table[] = {
         [NL_UNION_LINK_INFO_DATA_VCAN] = "vcan",
         [NL_UNION_LINK_INFO_DATA_GENEVE] = "geneve",
         [NL_UNION_LINK_INFO_DATA_VXCAN] = "vxcan",
-
+        [NL_UNION_LINK_INFO_DATA_WIREGUARD] = "wireguard",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(nl_union_link_info_data, NLUnionLinkInfoData);
@@ -672,6 +673,54 @@ const NLTypeSystem rtnl_type_system_root = {
         .types = rtnl_types,
 };
 
+static const NLType genl_wireguard_allowedip_types[] = {
+        [WGALLOWEDIP_A_FAMILY] = { .type = NETLINK_TYPE_U16 },
+        [WGALLOWEDIP_A_IPADDR] = { .type = NETLINK_TYPE_IN_ADDR },
+        [WGALLOWEDIP_A_CIDR_MASK] = { .type = NETLINK_TYPE_U8 },
+};
+
+static const NLTypeSystem genl_wireguard_allowedip_type_system = {
+        .count = ELEMENTSOF(genl_wireguard_allowedip_types),
+        .types = genl_wireguard_allowedip_types,
+};
+
+static const NLType genl_wireguard_peer_types[] = {
+        [WGPEER_A_PUBLIC_KEY] = { .size = WG_KEY_LEN  },
+        [WGPEER_A_FLAGS] = { .type = NETLINK_TYPE_U32 },
+        [WGPEER_A_PRESHARED_KEY] = { .size = WG_KEY_LEN },
+        [WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL] = { .type = NETLINK_TYPE_U32 },
+        [WGPEER_A_ENDPOINT] = { /* either size of sockaddr_in or sockaddr_in6 depending on address family */ },
+        [WGPEER_A_ALLOWEDIPS] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_wireguard_allowedip_type_system },
+};
+
+static const NLTypeSystem genl_wireguard_peer_type_system = {
+        .count = ELEMENTSOF(genl_wireguard_peer_types),
+        .types = genl_wireguard_peer_types,
+};
+
+static const NLType genl_wireguard_set_device_types[] = {
+        [WGDEVICE_A_IFINDEX] = { .type = NETLINK_TYPE_U32 },
+        [WGDEVICE_A_IFNAME] = { .type = NETLINK_TYPE_STRING },
+        [WGDEVICE_A_FLAGS] = { .type = NETLINK_TYPE_U32 },
+        [WGDEVICE_A_PRIVATE_KEY] = { .size = WG_KEY_LEN },
+        [WGDEVICE_A_LISTEN_PORT] = { .type = NETLINK_TYPE_U16 },
+        [WGDEVICE_A_FWMARK] = { .type = NETLINK_TYPE_U32 },
+        [WGDEVICE_A_PEERS] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_wireguard_peer_type_system },
+};
+
+static const NLTypeSystem genl_wireguard_set_device_type_system = {
+        .count = ELEMENTSOF(genl_wireguard_set_device_types),
+        .types = genl_wireguard_set_device_types,
+};
+
+static const NLType genl_wireguard_cmds[] = {
+        [WG_CMD_SET_DEVICE] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_wireguard_set_device_type_system },
+};
+
+static const NLTypeSystem genl_wireguard_type_system = {
+        .count = ELEMENTSOF(genl_wireguard_cmds),
+        .types = genl_wireguard_cmds,
+};
 
 static const NLType genl_get_family_types[] = {
         [CTRL_ATTR_FAMILY_NAME] = { .type = NETLINK_TYPE_STRING },
@@ -694,6 +743,7 @@ static const NLTypeSystem genl_ctrl_id_ctrl_type_system = {
 
 static const NLType genl_families[] = {
         [SD_GENL_ID_CTRL]  = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_ctrl_id_ctrl_type_system },
+        [SD_GENL_WIREGUARD] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_wireguard_type_system },
 };
 
 const NLTypeSystem genl_family_type_system_root = {
index 2012319e8a1971053b9f82e145b8a38e502e318b..ea7f8d5e6c64c0909974245f092478bffcfbd0b0 100644 (file)
@@ -94,6 +94,7 @@ typedef enum NLUnionLinkInfoData {
         NL_UNION_LINK_INFO_DATA_VCAN,
         NL_UNION_LINK_INFO_DATA_GENEVE,
         NL_UNION_LINK_INFO_DATA_VXCAN,
+        NL_UNION_LINK_INFO_DATA_WIREGUARD,
         _NL_UNION_LINK_INFO_DATA_MAX,
         _NL_UNION_LINK_INFO_DATA_INVALID = -1
 } NLUnionLinkInfoData;
index f97484eb265fe429406ef09e915f9871616313c3..d777b5f8c2eb2314ed007ecf65356b861e110b1d 100644 (file)
@@ -46,6 +46,8 @@ sources = files('''
         netdev/geneve.h
         netdev/vxcan.c
         netdev/vxcan.h
+        netdev/wireguard.c
+        netdev/wireguard.h
         networkd-address-label.c
         networkd-address-label.h
         networkd-address-pool.c
index 1b4cb5a60c239b980a51dd5e4dab164a4959ebbd..ba6268fa66e82d26d9c870ae2c96984e6cb86419 100644 (file)
@@ -18,6 +18,7 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
 #include "netdev/vrf.h"
 #include "netdev/netdev.h"
 #include "netdev/vxcan.h"
+#include "netdev/wireguard.h"
 #include "vlan-util.h"
 %}
 struct ConfigPerfItem;
@@ -31,117 +32,125 @@ struct ConfigPerfItem;
 %struct-type
 %includes
 %%
-Match.Host,                  config_parse_net_condition,           CONDITION_HOST,                offsetof(NetDev, match_host)
-Match.Virtualization,        config_parse_net_condition,           CONDITION_VIRTUALIZATION,      offsetof(NetDev, match_virt)
-Match.KernelCommandLine,     config_parse_net_condition,           CONDITION_KERNEL_COMMAND_LINE, offsetof(NetDev, match_kernel_cmdline)
-Match.KernelVersion,         config_parse_net_condition,           CONDITION_KERNEL_VERSION,      offsetof(NetDev, match_kernel_version)
-Match.Architecture,          config_parse_net_condition,           CONDITION_ARCHITECTURE,        offsetof(NetDev, match_arch)
-NetDev.Description,          config_parse_string,                  0,                             offsetof(NetDev, description)
-NetDev.Name,                 config_parse_ifname,                  0,                             offsetof(NetDev, ifname)
-NetDev.Kind,                 config_parse_netdev_kind,             0,                             offsetof(NetDev, kind)
-NetDev.MTUBytes,             config_parse_iec_size,                0,                             offsetof(NetDev, mtu)
-NetDev.MACAddress,           config_parse_hwaddr,                  0,                             offsetof(NetDev, mac)
-VLAN.Id,                     config_parse_vlanid,                  0,                             offsetof(VLan, id)
-VLAN.GVRP,                   config_parse_tristate,                0,                             offsetof(VLan, gvrp)
-VLAN.MVRP,                   config_parse_tristate,                0,                             offsetof(VLan, mvrp)
-VLAN.LooseBinding,           config_parse_tristate,                0,                             offsetof(VLan, loose_binding)
-VLAN.ReorderHeader,          config_parse_tristate,                0,                             offsetof(VLan, reorder_hdr)
-MACVLAN.Mode,                config_parse_macvlan_mode,            0,                             offsetof(MacVlan, mode)
-MACVTAP.Mode,                config_parse_macvlan_mode,            0,                             offsetof(MacVlan, mode)
-IPVLAN.Mode,                 config_parse_ipvlan_mode,             0,                             offsetof(IPVlan, mode)
-IPVLAN.Flags,                config_parse_ipvlan_flags,             0,                            offsetof(IPVlan, flags)
-Tunnel.Local,                config_parse_tunnel_address,          0,                             offsetof(Tunnel, local)
-Tunnel.Remote,               config_parse_tunnel_address,          0,                             offsetof(Tunnel, remote)
-Tunnel.TOS,                  config_parse_unsigned,                0,                             offsetof(Tunnel, tos)
-Tunnel.TTL,                  config_parse_unsigned,                0,                             offsetof(Tunnel, ttl)
-Tunnel.Key,                  config_parse_tunnel_key,              0,                             offsetof(Tunnel, key)
-Tunnel.InputKey,             config_parse_tunnel_key,              0,                             offsetof(Tunnel, ikey)
-Tunnel.OutputKey,            config_parse_tunnel_key,              0,                             offsetof(Tunnel, okey)
-Tunnel.DiscoverPathMTU,      config_parse_bool,                    0,                             offsetof(Tunnel, pmtudisc)
-Tunnel.Mode,                 config_parse_ip6tnl_mode,             0,                             offsetof(Tunnel, ip6tnl_mode)
-Tunnel.IPv6FlowLabel,        config_parse_ipv6_flowlabel,          0,                             offsetof(Tunnel, ipv6_flowlabel)
-Tunnel.CopyDSCP,             config_parse_bool,                    0,                             offsetof(Tunnel, copy_dscp)
-Tunnel.EncapsulationLimit,   config_parse_encap_limit,             0,                             offsetof(Tunnel, encap_limit)
-Tunnel.Independent,          config_parse_bool,                    0,                             offsetof(Tunnel, independent)
-Tunnel.AllowLocalRemote,     config_parse_tristate,                0,                             offsetof(Tunnel, allow_localremote)
-Peer.Name,                   config_parse_ifname,                  0,                             offsetof(Veth, ifname_peer)
-Peer.MACAddress,             config_parse_hwaddr,                  0,                             offsetof(Veth, mac_peer)
-VXCAN.Peer,                  config_parse_ifname,                  0,                             offsetof(VxCan, ifname_peer)
-VXLAN.Id,                    config_parse_uint64,                  0,                             offsetof(VxLan, id)
-VXLAN.Group,                 config_parse_vxlan_address,           0,                             offsetof(VxLan, remote)
-VXLAN.Local,                 config_parse_vxlan_address,           0,                             offsetof(VxLan, local)
-VXLAN.Remote,                config_parse_vxlan_address,           0,                             offsetof(VxLan, remote)
-VXLAN.TOS,                   config_parse_unsigned,                0,                             offsetof(VxLan, tos)
-VXLAN.TTL,                   config_parse_unsigned,                0,                             offsetof(VxLan, ttl)
-VXLAN.MacLearning,           config_parse_bool,                    0,                             offsetof(VxLan, learning)
-VXLAN.ARPProxy,              config_parse_bool,                    0,                             offsetof(VxLan, arp_proxy)
-VXLAN.ReduceARPProxy,        config_parse_bool,                    0,                             offsetof(VxLan, arp_proxy)
-VXLAN.L2MissNotification,    config_parse_bool,                    0,                             offsetof(VxLan, l2miss)
-VXLAN.L3MissNotification,    config_parse_bool,                    0,                             offsetof(VxLan, l3miss)
-VXLAN.RouteShortCircuit,     config_parse_bool,                    0,                             offsetof(VxLan, route_short_circuit)
-VXLAN.UDPCheckSum,           config_parse_bool,                    0,                             offsetof(VxLan, udpcsum)
-VXLAN.UDPChecksum,           config_parse_bool,                    0,                             offsetof(VxLan, udpcsum)
-VXLAN.UDP6ZeroCheckSumRx,    config_parse_bool,                    0,                             offsetof(VxLan, udp6zerocsumrx)
-VXLAN.UDP6ZeroChecksumRx,    config_parse_bool,                    0,                             offsetof(VxLan, udp6zerocsumrx)
-VXLAN.UDP6ZeroCheckSumTx,    config_parse_bool,                    0,                             offsetof(VxLan, udp6zerocsumtx)
-VXLAN.UDP6ZeroChecksumTx,    config_parse_bool,                    0,                             offsetof(VxLan, udp6zerocsumtx)
-VXLAN.RemoteChecksumTx,      config_parse_bool,                    0,                             offsetof(VxLan, remote_csum_tx)
-VXLAN.RemoteChecksumRx,      config_parse_bool,                    0,                             offsetof(VxLan, remote_csum_rx)
-VXLAN.FDBAgeingSec,          config_parse_sec,                     0,                             offsetof(VxLan, fdb_ageing)
-VXLAN.GroupPolicyExtension,  config_parse_bool,                    0,                             offsetof(VxLan, group_policy)
-VXLAN.MaximumFDBEntries,     config_parse_unsigned,                0,                             offsetof(VxLan, max_fdb)
-VXLAN.PortRange,             config_parse_port_range,              0,                             0
-VXLAN.DestinationPort,       config_parse_ip_port,                 0,                             offsetof(VxLan, dest_port)
-VXLAN.FlowLabel,             config_parse_flow_label,              0,                             0
-GENEVE.Id,                   config_parse_geneve_vni,              0,                             offsetof(Geneve, id)
-GENEVE.Remote,               config_parse_geneve_address,          0,                             offsetof(Geneve, remote)
-GENEVE.TOS,                  config_parse_uint8,                   0,                             offsetof(Geneve, tos)
-GENEVE.TTL,                  config_parse_uint8,                   0,                             offsetof(Geneve, ttl)
-GENEVE.UDPChecksum,          config_parse_bool,                    0,                             offsetof(Geneve, udpcsum)
-GENEVE.UDP6ZeroCheckSumRx,   config_parse_bool,                    0,                             offsetof(Geneve, udp6zerocsumrx)
-GENEVE.UDP6ZeroCheckSumTx,   config_parse_bool,                    0,                             offsetof(Geneve, udp6zerocsumtx)
-GENEVE.DestinationPort,      config_parse_ip_port,                 0,                             offsetof(Geneve, dest_port)
-GENEVE.FlowLabel,            config_parse_geneve_flow_label,       0,                             0
-Tun.OneQueue,                config_parse_bool,                    0,                             offsetof(TunTap, one_queue)
-Tun.MultiQueue,              config_parse_bool,                    0,                             offsetof(TunTap, multi_queue)
-Tun.PacketInfo,              config_parse_bool,                    0,                             offsetof(TunTap, packet_info)
-Tun.User,                    config_parse_string,                  0,                             offsetof(TunTap, user_name)
-Tun.Group,                   config_parse_string,                  0,                             offsetof(TunTap, group_name)
-Tap.OneQueue,                config_parse_bool,                    0,                             offsetof(TunTap, one_queue)
-Tap.MultiQueue,              config_parse_bool,                    0,                             offsetof(TunTap, multi_queue)
-Tap.PacketInfo,              config_parse_bool,                    0,                             offsetof(TunTap, packet_info)
-Tap.VNetHeader,              config_parse_bool,                    0,                             offsetof(TunTap, vnet_hdr)
-Tap.User,                    config_parse_string,                  0,                             offsetof(TunTap, user_name)
-Tap.Group,                   config_parse_string,                  0,                             offsetof(TunTap, group_name)
-Bond.Mode,                   config_parse_bond_mode,               0,                             offsetof(Bond, mode)
-Bond.TransmitHashPolicy,     config_parse_bond_xmit_hash_policy,   0,                             offsetof(Bond, xmit_hash_policy)
-Bond.LACPTransmitRate,       config_parse_bond_lacp_rate,          0,                             offsetof(Bond, lacp_rate)
-Bond.AdSelect,               config_parse_bond_ad_select,          0,                             offsetof(Bond, ad_select)
-Bond.FailOverMACPolicy,      config_parse_bond_fail_over_mac,      0,                             offsetof(Bond, fail_over_mac)
-Bond.ARPIPTargets,           config_parse_arp_ip_target_address,   0,                             0
-Bond.ARPValidate,            config_parse_bond_arp_validate,       0,                             offsetof(Bond, arp_validate)
-Bond.ARPAllTargets,          config_parse_bond_arp_all_targets,    0,                             offsetof(Bond, arp_all_targets)
-Bond.PrimaryReselectPolicy,  config_parse_bond_primary_reselect,   0,                             offsetof(Bond, primary_reselect)
-Bond.ResendIGMP,             config_parse_unsigned,                0,                             offsetof(Bond, resend_igmp)
-Bond.PacketsPerSlave,        config_parse_unsigned,                0,                             offsetof(Bond, packets_per_slave)
-Bond.GratuitousARP,          config_parse_unsigned,                0,                             offsetof(Bond, num_grat_arp)
-Bond.AllSlavesActive,        config_parse_unsigned,                0,                             offsetof(Bond, all_slaves_active)
-Bond.MinLinks,               config_parse_unsigned,                0,                             offsetof(Bond, min_links)
-Bond.MIIMonitorSec,          config_parse_sec,                     0,                             offsetof(Bond, miimon)
-Bond.UpDelaySec,             config_parse_sec,                     0,                             offsetof(Bond, updelay)
-Bond.DownDelaySec,           config_parse_sec,                     0,                             offsetof(Bond, downdelay)
-Bond.ARPIntervalSec,         config_parse_sec,                     0,                             offsetof(Bond, arp_interval)
-Bond.LearnPacketIntervalSec, config_parse_sec,                     0,                             offsetof(Bond, lp_interval)
-Bridge.HelloTimeSec,         config_parse_sec,                     0,                             offsetof(Bridge, hello_time)
-Bridge.MaxAgeSec,            config_parse_sec,                     0,                             offsetof(Bridge, max_age)
-Bridge.AgeingTimeSec,        config_parse_sec,                     0,                             offsetof(Bridge, ageing_time)
-Bridge.ForwardDelaySec,      config_parse_sec,                     0,                             offsetof(Bridge, forward_delay)
-Bridge.Priority,             config_parse_uint16,                  0,                             offsetof(Bridge, priority)
-Bridge.GroupForwardMask,     config_parse_uint16,                  0,                             offsetof(Bridge, group_fwd_mask)
-Bridge.DefaultPVID,          config_parse_default_port_vlanid,     0,                             offsetof(Bridge, default_pvid)
-Bridge.MulticastQuerier,     config_parse_tristate,                0,                             offsetof(Bridge, mcast_querier)
-Bridge.MulticastSnooping,    config_parse_tristate,                0,                             offsetof(Bridge, mcast_snooping)
-Bridge.VLANFiltering,        config_parse_tristate,                0,                             offsetof(Bridge, vlan_filtering)
-Bridge.STP,                  config_parse_tristate,                0,                             offsetof(Bridge, stp)
-VRF.TableId,                 config_parse_uint32,                  0,                             offsetof(Vrf, table) /* deprecated */
-VRF.Table,                   config_parse_route_table,             0,                             offsetof(Vrf, table)
+Match.Host,                        config_parse_net_condition,           CONDITION_HOST,                offsetof(NetDev, match_host)
+Match.Virtualization,              config_parse_net_condition,           CONDITION_VIRTUALIZATION,      offsetof(NetDev, match_virt)
+Match.KernelCommandLine,           config_parse_net_condition,           CONDITION_KERNEL_COMMAND_LINE, offsetof(NetDev, match_kernel_cmdline)
+Match.KernelVersion,               config_parse_net_condition,           CONDITION_KERNEL_VERSION,      offsetof(NetDev, match_kernel_version)
+Match.Architecture,                config_parse_net_condition,           CONDITION_ARCHITECTURE,        offsetof(NetDev, match_arch)
+NetDev.Description,                config_parse_string,                  0,                             offsetof(NetDev, description)
+NetDev.Name,                       config_parse_ifname,                  0,                             offsetof(NetDev, ifname)
+NetDev.Kind,                       config_parse_netdev_kind,             0,                             offsetof(NetDev, kind)
+NetDev.MTUBytes,                   config_parse_iec_size,                0,                             offsetof(NetDev, mtu)
+NetDev.MACAddress,                 config_parse_hwaddr,                  0,                             offsetof(NetDev, mac)
+VLAN.Id,                           config_parse_vlanid,                  0,                             offsetof(VLan, id)
+VLAN.GVRP,                         config_parse_tristate,                0,                             offsetof(VLan, gvrp)
+VLAN.MVRP,                         config_parse_tristate,                0,                             offsetof(VLan, mvrp)
+VLAN.LooseBinding,                 config_parse_tristate,                0,                             offsetof(VLan, loose_binding)
+VLAN.ReorderHeader,                config_parse_tristate,                0,                             offsetof(VLan, reorder_hdr)
+MACVLAN.Mode,                      config_parse_macvlan_mode,            0,                             offsetof(MacVlan, mode)
+MACVTAP.Mode,                      config_parse_macvlan_mode,            0,                             offsetof(MacVlan, mode)
+IPVLAN.Mode,                       config_parse_ipvlan_mode,             0,                             offsetof(IPVlan, mode)
+IPVLAN.Flags,                      config_parse_ipvlan_flags,             0,                            offsetof(IPVlan, flags)
+Tunnel.Local,                      config_parse_tunnel_address,          0,                             offsetof(Tunnel, local)
+Tunnel.Remote,                     config_parse_tunnel_address,          0,                             offsetof(Tunnel, remote)
+Tunnel.TOS,                        config_parse_unsigned,                0,                             offsetof(Tunnel, tos)
+Tunnel.TTL,                        config_parse_unsigned,                0,                             offsetof(Tunnel, ttl)
+Tunnel.Key,                        config_parse_tunnel_key,              0,                             offsetof(Tunnel, key)
+Tunnel.InputKey,                   config_parse_tunnel_key,              0,                             offsetof(Tunnel, ikey)
+Tunnel.OutputKey,                  config_parse_tunnel_key,              0,                             offsetof(Tunnel, okey)
+Tunnel.DiscoverPathMTU,            config_parse_bool,                    0,                             offsetof(Tunnel, pmtudisc)
+Tunnel.Mode,                       config_parse_ip6tnl_mode,             0,                             offsetof(Tunnel, ip6tnl_mode)
+Tunnel.IPv6FlowLabel,              config_parse_ipv6_flowlabel,          0,                             offsetof(Tunnel, ipv6_flowlabel)
+Tunnel.CopyDSCP,                   config_parse_bool,                    0,                             offsetof(Tunnel, copy_dscp)
+Tunnel.EncapsulationLimit,         config_parse_encap_limit,             0,                             offsetof(Tunnel, encap_limit)
+Tunnel.Independent,                config_parse_bool,                    0,                             offsetof(Tunnel, independent)
+Tunnel.AllowLocalRemote,           config_parse_tristate,                0,                             offsetof(Tunnel, allow_localremote)
+Peer.Name,                         config_parse_ifname,                  0,                             offsetof(Veth, ifname_peer)
+Peer.MACAddress,                   config_parse_hwaddr,                  0,                             offsetof(Veth, mac_peer)
+VXCAN.Peer,                        config_parse_ifname,                  0,                             offsetof(VxCan, ifname_peer)
+VXLAN.Id,                          config_parse_uint64,                  0,                             offsetof(VxLan, id)
+VXLAN.Group,                       config_parse_vxlan_address,           0,                             offsetof(VxLan, remote)
+VXLAN.Local,                       config_parse_vxlan_address,           0,                             offsetof(VxLan, local)
+VXLAN.Remote,                      config_parse_vxlan_address,           0,                             offsetof(VxLan, remote)
+VXLAN.TOS,                         config_parse_unsigned,                0,                             offsetof(VxLan, tos)
+VXLAN.TTL,                         config_parse_unsigned,                0,                             offsetof(VxLan, ttl)
+VXLAN.MacLearning,                 config_parse_bool,                    0,                             offsetof(VxLan, learning)
+VXLAN.ARPProxy,                    config_parse_bool,                    0,                             offsetof(VxLan, arp_proxy)
+VXLAN.ReduceARPProxy,              config_parse_bool,                    0,                             offsetof(VxLan, arp_proxy)
+VXLAN.L2MissNotification,          config_parse_bool,                    0,                             offsetof(VxLan, l2miss)
+VXLAN.L3MissNotification,          config_parse_bool,                    0,                             offsetof(VxLan, l3miss)
+VXLAN.RouteShortCircuit,           config_parse_bool,                    0,                             offsetof(VxLan, route_short_circuit)
+VXLAN.UDPCheckSum,                 config_parse_bool,                    0,                             offsetof(VxLan, udpcsum)
+VXLAN.UDPChecksum,                 config_parse_bool,                    0,                             offsetof(VxLan, udpcsum)
+VXLAN.UDP6ZeroCheckSumRx,          config_parse_bool,                    0,                             offsetof(VxLan, udp6zerocsumrx)
+VXLAN.UDP6ZeroChecksumRx,          config_parse_bool,                    0,                             offsetof(VxLan, udp6zerocsumrx)
+VXLAN.UDP6ZeroCheckSumTx,          config_parse_bool,                    0,                             offsetof(VxLan, udp6zerocsumtx)
+VXLAN.UDP6ZeroChecksumTx,          config_parse_bool,                    0,                             offsetof(VxLan, udp6zerocsumtx)
+VXLAN.RemoteChecksumTx,            config_parse_bool,                    0,                             offsetof(VxLan, remote_csum_tx)
+VXLAN.RemoteChecksumRx,            config_parse_bool,                    0,                             offsetof(VxLan, remote_csum_rx)
+VXLAN.FDBAgeingSec,                config_parse_sec,                     0,                             offsetof(VxLan, fdb_ageing)
+VXLAN.GroupPolicyExtension,        config_parse_bool,                    0,                             offsetof(VxLan, group_policy)
+VXLAN.MaximumFDBEntries,           config_parse_unsigned,                0,                             offsetof(VxLan, max_fdb)
+VXLAN.PortRange,                   config_parse_port_range,              0,                             0
+VXLAN.DestinationPort,             config_parse_ip_port,                 0,                             offsetof(VxLan, dest_port)
+VXLAN.FlowLabel,                   config_parse_flow_label,              0,                             0
+GENEVE.Id,                         config_parse_geneve_vni,              0,                             offsetof(Geneve, id)
+GENEVE.Remote,                     config_parse_geneve_address,          0,                             offsetof(Geneve, remote)
+GENEVE.TOS,                        config_parse_uint8,                   0,                             offsetof(Geneve, tos)
+GENEVE.TTL,                        config_parse_uint8,                   0,                             offsetof(Geneve, ttl)
+GENEVE.UDPChecksum,                config_parse_bool,                    0,                             offsetof(Geneve, udpcsum)
+GENEVE.UDP6ZeroCheckSumRx,         config_parse_bool,                    0,                             offsetof(Geneve, udp6zerocsumrx)
+GENEVE.UDP6ZeroCheckSumTx,         config_parse_bool,                    0,                             offsetof(Geneve, udp6zerocsumtx)
+GENEVE.DestinationPort,            config_parse_ip_port,                 0,                             offsetof(Geneve, dest_port)
+GENEVE.FlowLabel,                  config_parse_geneve_flow_label,       0,                             0
+Tun.OneQueue,                      config_parse_bool,                    0,                             offsetof(TunTap, one_queue)
+Tun.MultiQueue,                    config_parse_bool,                    0,                             offsetof(TunTap, multi_queue)
+Tun.PacketInfo,                    config_parse_bool,                    0,                             offsetof(TunTap, packet_info)
+Tun.User,                          config_parse_string,                  0,                             offsetof(TunTap, user_name)
+Tun.Group,                         config_parse_string,                  0,                             offsetof(TunTap, group_name)
+Tap.OneQueue,                      config_parse_bool,                    0,                             offsetof(TunTap, one_queue)
+Tap.MultiQueue,                    config_parse_bool,                    0,                             offsetof(TunTap, multi_queue)
+Tap.PacketInfo,                    config_parse_bool,                    0,                             offsetof(TunTap, packet_info)
+Tap.VNetHeader,                    config_parse_bool,                    0,                             offsetof(TunTap, vnet_hdr)
+Tap.User,                          config_parse_string,                  0,                             offsetof(TunTap, user_name)
+Tap.Group,                         config_parse_string,                  0,                             offsetof(TunTap, group_name)
+Bond.Mode,                         config_parse_bond_mode,               0,                             offsetof(Bond, mode)
+Bond.TransmitHashPolicy,           config_parse_bond_xmit_hash_policy,   0,                             offsetof(Bond, xmit_hash_policy)
+Bond.LACPTransmitRate,             config_parse_bond_lacp_rate,          0,                             offsetof(Bond, lacp_rate)
+Bond.AdSelect,                     config_parse_bond_ad_select,          0,                             offsetof(Bond, ad_select)
+Bond.FailOverMACPolicy,            config_parse_bond_fail_over_mac,      0,                             offsetof(Bond, fail_over_mac)
+Bond.ARPIPTargets,                 config_parse_arp_ip_target_address,   0,                             0
+Bond.ARPValidate,                  config_parse_bond_arp_validate,       0,                             offsetof(Bond, arp_validate)
+Bond.ARPAllTargets,                config_parse_bond_arp_all_targets,    0,                             offsetof(Bond, arp_all_targets)
+Bond.PrimaryReselectPolicy,        config_parse_bond_primary_reselect,   0,                             offsetof(Bond, primary_reselect)
+Bond.ResendIGMP,                   config_parse_unsigned,                0,                             offsetof(Bond, resend_igmp)
+Bond.PacketsPerSlave,              config_parse_unsigned,                0,                             offsetof(Bond, packets_per_slave)
+Bond.GratuitousARP,                config_parse_unsigned,                0,                             offsetof(Bond, num_grat_arp)
+Bond.AllSlavesActive,              config_parse_unsigned,                0,                             offsetof(Bond, all_slaves_active)
+Bond.MinLinks,                     config_parse_unsigned,                0,                             offsetof(Bond, min_links)
+Bond.MIIMonitorSec,                config_parse_sec,                     0,                             offsetof(Bond, miimon)
+Bond.UpDelaySec,                   config_parse_sec,                     0,                             offsetof(Bond, updelay)
+Bond.DownDelaySec,                 config_parse_sec,                     0,                             offsetof(Bond, downdelay)
+Bond.ARPIntervalSec,               config_parse_sec,                     0,                             offsetof(Bond, arp_interval)
+Bond.LearnPacketIntervalSec,       config_parse_sec,                     0,                             offsetof(Bond, lp_interval)
+Bridge.HelloTimeSec,               config_parse_sec,                     0,                             offsetof(Bridge, hello_time)
+Bridge.MaxAgeSec,                  config_parse_sec,                     0,                             offsetof(Bridge, max_age)
+Bridge.AgeingTimeSec,              config_parse_sec,                     0,                             offsetof(Bridge, ageing_time)
+Bridge.ForwardDelaySec,            config_parse_sec,                     0,                             offsetof(Bridge, forward_delay)
+Bridge.Priority,                   config_parse_uint16,                  0,                             offsetof(Bridge, priority)
+Bridge.GroupForwardMask,           config_parse_uint16,                  0,                             offsetof(Bridge, group_fwd_mask)
+Bridge.DefaultPVID,                config_parse_default_port_vlanid,     0,                             offsetof(Bridge, default_pvid)
+Bridge.MulticastQuerier,           config_parse_tristate,                0,                             offsetof(Bridge, mcast_querier)
+Bridge.MulticastSnooping,          config_parse_tristate,                0,                             offsetof(Bridge, mcast_snooping)
+Bridge.VLANFiltering,              config_parse_tristate,                0,                             offsetof(Bridge, vlan_filtering)
+Bridge.STP,                        config_parse_tristate,                0,                             offsetof(Bridge, stp)
+VRF.TableId,                       config_parse_uint32,                  0,                             offsetof(Vrf, table) /* deprecated */
+VRF.Table,                         config_parse_route_table,             0,                             offsetof(Vrf, table)
+WireGuard.FwMark,                  config_parse_unsigned,                0,                             offsetof(Wireguard, fwmark)
+WireGuard.ListenPort,              config_parse_wireguard_listen_port,   0,                             offsetof(Wireguard, port)
+WireGuard.PrivateKey,              config_parse_wireguard_private_key,   0,                             0
+WireGuardPeer.AllowedIPs,          config_parse_wireguard_allowed_ips,   0,                             0
+WireGuardPeer.Endpoint,            config_parse_wireguard_endpoint,      0,                             0
+WireGuardPeer.PublicKey,           config_parse_wireguard_public_key,    0,                             0
+WireGuardPeer.PresharedKey,        config_parse_wireguard_preshared_key, 0,                             0
+WireGuardPeer.PersistentKeepalive, config_parse_wireguard_keepalive,     0,                             0
index 4adaac26b8f3bba7a8cfc867ab8dd4103df19cf3..d609b0fb725ee8eae7dc43e00ca6651061b485aa 100644 (file)
@@ -49,6 +49,7 @@
 #include "netdev/vrf.h"
 #include "netdev/vcan.h"
 #include "netdev/vxcan.h"
+#include "netdev/wireguard.h"
 
 const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
         [NETDEV_KIND_BRIDGE] = &bridge_vtable,
@@ -75,6 +76,7 @@ const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
         [NETDEV_KIND_VCAN] = &vcan_vtable,
         [NETDEV_KIND_GENEVE] = &geneve_vtable,
         [NETDEV_KIND_VXCAN] = &vxcan_vtable,
+        [NETDEV_KIND_WIREGUARD] = &wireguard_vtable,
 };
 
 static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
@@ -102,6 +104,7 @@ static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
         [NETDEV_KIND_VCAN] = "vcan",
         [NETDEV_KIND_GENEVE] = "geneve",
         [NETDEV_KIND_VXCAN] = "vxcan",
+        [NETDEV_KIND_WIREGUARD] = "wireguard",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
index 507b86a078f96c99a40856bef218c00eae48f855..bd1a94c9be90829393165c02115e83cff49e70e3 100644 (file)
@@ -60,6 +60,7 @@ typedef enum NetDevKind {
         NETDEV_KIND_VCAN,
         NETDEV_KIND_GENEVE,
         NETDEV_KIND_VXCAN,
+        NETDEV_KIND_WIREGUARD,
         _NETDEV_KIND_MAX,
         _NETDEV_KIND_INVALID = -1
 } NetDevKind;
diff --git a/src/network/netdev/wireguard.c b/src/network/netdev/wireguard.c
new file mode 100644 (file)
index 0000000..f1f4bab
--- /dev/null
@@ -0,0 +1,721 @@
+/***
+    This file is part of systemd.
+
+    Copyright 2016-2017 Jörg Thalheim <joerg@thalheim.io>
+    Copyright 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
+
+    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 <sys/ioctl.h>
+#include <net/if.h>
+
+#include "alloc-util.h"
+#include "parse-util.h"
+#include "fd-util.h"
+#include "strv.h"
+#include "hexdecoct.h"
+#include "string-util.h"
+#include "wireguard.h"
+#include "networkd-link.h"
+#include "networkd-util.h"
+#include "networkd-manager.h"
+#include "wireguard-netlink.h"
+
+static void resolve_endpoints(NetDev *netdev);
+
+static WireguardPeer *wireguard_peer_new(Wireguard *w, unsigned section) {
+        WireguardPeer *peer;
+
+        assert(w);
+
+        if (w->last_peer_section == section && w->peers)
+                return w->peers;
+
+        peer = new0(WireguardPeer, 1);
+        if (!peer)
+                return NULL;
+        peer->flags = WGPEER_F_REPLACE_ALLOWEDIPS;
+
+        LIST_PREPEND(peers, w->peers, peer);
+        w->last_peer_section = section;
+
+        return peer;
+}
+
+static int set_wireguard_interface(NetDev *netdev) {
+        int r;
+        unsigned int i, j;
+        WireguardPeer *peer, *peer_start;
+        WireguardIPmask *mask, *mask_start = NULL;
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL;
+        Wireguard *w;
+        uint32_t serial;
+
+        assert(netdev);
+        w = WIREGUARD(netdev);
+        assert(w);
+
+        peer_start = w->peers;
+
+        do {
+                message = sd_netlink_message_unref(message);
+
+                r = sd_genl_message_new(netdev->manager->genl, SD_GENL_WIREGUARD, WG_CMD_SET_DEVICE, &message);
+                if (r < 0)
+                        return log_netdev_error_errno(netdev, r, "Failed to allocate generic netlink message: %m");
+
+                r = sd_netlink_message_append_string(message, WGDEVICE_A_IFNAME, netdev->ifname);
+                if (r < 0)
+                        return log_netdev_error_errno(netdev, r, "Could not append wireguard interface name: %m");
+
+                if (peer_start == w->peers) {
+                        r = sd_netlink_message_append_data(message, WGDEVICE_A_PRIVATE_KEY, &w->private_key, WG_KEY_LEN);
+                        if (r < 0)
+                                return log_netdev_error_errno(netdev, r, "Could not append wireguard private key: %m");
+
+                        r = sd_netlink_message_append_u16(message, WGDEVICE_A_LISTEN_PORT, w->port);
+                        if (r < 0)
+                                return log_netdev_error_errno(netdev, r, "Could not append wireguard port: %m");
+
+                        r = sd_netlink_message_append_u32(message, WGDEVICE_A_FWMARK, w->fwmark);
+                        if (r < 0)
+                                return log_netdev_error_errno(netdev, r, "Could not append wireguard fwmark: %m");
+
+                        r = sd_netlink_message_append_u32(message, WGDEVICE_A_FLAGS, w->flags);
+                        if (r < 0)
+                                return log_netdev_error_errno(netdev, r, "Could not append wireguard flags: %m");
+                }
+
+                r = sd_netlink_message_open_container(message, WGDEVICE_A_PEERS);
+                if (r < 0)
+                        return log_netdev_error_errno(netdev, r, "Could not append wireguard peer attributes: %m");
+
+                i = 0;
+
+                LIST_FOREACH(peers, peer, peer_start) {
+                        r = sd_netlink_message_open_array(message, ++i);
+                        if (r < 0)
+                                break;
+
+                        r = sd_netlink_message_append_data(message, WGPEER_A_PUBLIC_KEY, &peer->public_key, sizeof(peer->public_key));
+                        if (r < 0)
+                                break;
+
+                        if (!mask_start) {
+                                r = sd_netlink_message_append_data(message, WGPEER_A_PRESHARED_KEY, &peer->preshared_key, WG_KEY_LEN);
+                                if (r < 0)
+                                        break;
+
+                                r = sd_netlink_message_append_u32(message, WGPEER_A_FLAGS, peer->flags);
+                                if (r < 0)
+                                        break;
+
+                                r = sd_netlink_message_append_u32(message, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, peer->persistent_keepalive_interval);
+                                if (r < 0)
+                                        break;
+
+                                if (peer->endpoint.sa.sa_family == AF_INET) {
+                                        r = sd_netlink_message_append_data(message, WGPEER_A_ENDPOINT, &peer->endpoint.in, sizeof(peer->endpoint.in));
+                                        if (r < 0)
+                                                break;
+                                } else if (peer->endpoint.sa.sa_family == AF_INET6) {
+                                        r = sd_netlink_message_append_data(message, WGPEER_A_ENDPOINT, &peer->endpoint.in6, sizeof(peer->endpoint.in6));
+                                        if (r < 0)
+                                                break;
+                                }
+
+                                mask_start = peer->ipmasks;
+                        }
+
+                        r = sd_netlink_message_open_container(message, WGPEER_A_ALLOWEDIPS);
+                        if (r < 0) {
+                                mask_start = NULL;
+                                break;
+                        }
+                        j = 0;
+                        LIST_FOREACH(ipmasks, mask, mask_start) {
+                                r = sd_netlink_message_open_array(message, ++j);
+                                if (r < 0)
+                                        break;
+
+                                r = sd_netlink_message_append_u16(message, WGALLOWEDIP_A_FAMILY, mask->family);
+                                if (r < 0)
+                                        break;
+
+                                if (mask->family == AF_INET) {
+                                        r = sd_netlink_message_append_in_addr(message, WGALLOWEDIP_A_IPADDR, &mask->ip.in);
+                                        if (r < 0)
+                                                break;
+                                } else if (mask->family == AF_INET6) {
+                                        r = sd_netlink_message_append_in6_addr(message, WGALLOWEDIP_A_IPADDR, &mask->ip.in6);
+                                        if (r < 0)
+                                                break;
+                                }
+
+                                r = sd_netlink_message_append_u8(message, WGALLOWEDIP_A_CIDR_MASK, mask->cidr);
+                                if (r < 0)
+                                        break;
+
+                                r = sd_netlink_message_close_container(message);
+                                if (r < 0)
+                                        return log_netdev_error_errno(netdev, r, "Could not add wireguard allowed ip: %m");
+                        }
+                        mask_start = mask;
+                        if (mask_start) {
+                                r = sd_netlink_message_cancel_array(message);
+                                if (r < 0)
+                                        return log_netdev_error_errno(netdev, r, "Could not cancel wireguard allowed ip message attribute: %m");
+                        }
+                        r = sd_netlink_message_close_container(message);
+                        if (r < 0)
+                                return log_netdev_error_errno(netdev, r, "Could not add wireguard allowed ip: %m");
+
+                        r = sd_netlink_message_close_container(message);
+                        if (r < 0)
+                                return log_netdev_error_errno(netdev, r, "Could not add wireguard peer: %m");
+                }
+
+                peer_start = peer;
+                if (peer_start && !mask_start) {
+                        r = sd_netlink_message_cancel_array(message);
+                        if (r < 0)
+                                return log_netdev_error_errno(netdev, r, "Could not cancel wireguard peers: %m");
+                }
+
+                r = sd_netlink_message_close_container(message);
+                if (r < 0)
+                        return log_netdev_error_errno(netdev, r, "Could not close wireguard container: %m");
+
+                r = sd_netlink_send(netdev->manager->genl, message, &serial);
+                if (r < 0)
+                        return log_netdev_error_errno(netdev, r, "Could not set wireguard device: %m");
+
+        } while (peer || mask_start);
+
+        return 0;
+}
+
+static WireguardEndpoint* wireguard_endpoint_free(WireguardEndpoint *e) {
+        if (!e)
+                return NULL;
+        netdev_unref(e->netdev);
+        e->host = mfree(e->host);
+        e->port = mfree(e->port);
+        return mfree(e);
+}
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(WireguardEndpoint*, wireguard_endpoint_free);
+
+static int on_resolve_retry(sd_event_source *s, usec_t usec, void *userdata) {
+        NetDev *netdev = userdata;
+        Wireguard *w;
+
+        assert(netdev);
+        w = WIREGUARD(netdev);
+        assert(w);
+
+        w->resolve_retry_event_source = sd_event_source_unref(w->resolve_retry_event_source);
+
+        w->unresolved_endpoints = w->failed_endpoints;
+        w->failed_endpoints = NULL;
+
+        resolve_endpoints(netdev);
+
+        return 0;
+}
+
+/*
+ * Given the number of retries this function will return will an exponential
+ * increasing time in milliseconds to wait starting at 200ms and capped at 25 seconds.
+ */
+static int exponential_backoff_milliseconds(unsigned n_retries) {
+        return (2 << MAX(n_retries, 7U)) * 100 * USEC_PER_MSEC;
+}
+
+static int wireguard_resolve_handler(sd_resolve_query *q,
+                                     int ret,
+                                     const struct addrinfo *ai,
+                                     void *userdata) {
+        NetDev *netdev;
+        Wireguard *w;
+        _cleanup_(wireguard_endpoint_freep) WireguardEndpoint *e;
+        int r;
+
+        assert(userdata);
+        e = userdata;
+        netdev = e->netdev;
+
+        assert(netdev);
+        w = WIREGUARD(netdev);
+        assert(w);
+
+        w->resolve_query = sd_resolve_query_unref(w->resolve_query);
+
+        if (ret != 0) {
+                log_netdev_error(netdev, "Failed to resolve host '%s:%s': %s", e->host, e->port, gai_strerror(ret));
+                LIST_PREPEND(endpoints, w->failed_endpoints, e);
+                e = NULL;
+        } else if ((ai->ai_family == AF_INET && ai->ai_addrlen == sizeof(struct sockaddr_in)) ||
+                        (ai->ai_family == AF_INET6 && ai->ai_addrlen == sizeof(struct sockaddr_in6)))
+                memcpy(&e->peer->endpoint, ai->ai_addr, ai->ai_addrlen);
+        else
+                log_netdev_error(netdev, "Neither IPv4 nor IPv6 address found for peer endpoint: %s:%s", e->host, e->port);
+
+        if (w->unresolved_endpoints) {
+                resolve_endpoints(netdev);
+                return 0;
+        }
+
+        set_wireguard_interface(netdev);
+        if (w->failed_endpoints) {
+                w->n_retries++;
+                r = sd_event_add_time(netdev->manager->event,
+                                      &w->resolve_retry_event_source,
+                                      CLOCK_MONOTONIC,
+                                      now(CLOCK_MONOTONIC) + exponential_backoff_milliseconds(w->n_retries),
+                                      0,
+                                      on_resolve_retry,
+                                      netdev);
+                if (r < 0)
+                        log_netdev_warning_errno(netdev, r, "Could not arm resolve retry handler: %m");
+        }
+
+        return 0;
+}
+
+static void resolve_endpoints(NetDev *netdev) {
+        int r = 0;
+        Wireguard *w;
+        WireguardEndpoint *endpoint;
+        static const struct addrinfo hints = {
+                .ai_family = AF_UNSPEC,
+                .ai_socktype = SOCK_DGRAM,
+                .ai_protocol = IPPROTO_UDP
+        };
+
+        assert(netdev);
+        w = WIREGUARD(netdev);
+        assert(w);
+
+        LIST_FOREACH(endpoints, endpoint, w->unresolved_endpoints) {
+                r = sd_resolve_getaddrinfo(netdev->manager->resolve,
+                                           &w->resolve_query,
+                                           endpoint->host,
+                                           endpoint->port,
+                                           &hints,
+                                           wireguard_resolve_handler,
+                                           endpoint);
+
+                if (r == -ENOBUFS)
+                        break;
+
+                LIST_REMOVE(endpoints, w->unresolved_endpoints, endpoint);
+
+                if (r < 0)
+                        log_netdev_error_errno(netdev, r, "Failed create resolver: %m");
+        }
+}
+
+
+static int netdev_wireguard_post_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
+        Wireguard *w;
+
+        assert(netdev);
+        w = WIREGUARD(netdev);
+        assert(w);
+
+        set_wireguard_interface(netdev);
+        resolve_endpoints(netdev);
+        return 0;
+}
+
+int config_parse_wireguard_listen_port(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) {
+        uint16_t *s = data;
+        uint16_t port = 0;
+        int r;
+
+        assert(rvalue);
+        assert(data);
+
+        if (!streq(rvalue, "auto")) {
+                r = parse_ip_port(rvalue, &port);
+                if (r < 0)
+                        log_syntax(unit, LOG_ERR, filename, line, r, "Invalid port specification, ignoring assignment: %s", rvalue);
+        }
+
+        *s = port;
+
+        return 0;
+}
+
+static int parse_wireguard_key(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_free_ void *key = NULL;
+        size_t len;
+        int r;
+
+        assert(filename);
+        assert(rvalue);
+        assert(userdata);
+
+        r = unbase64mem(rvalue, strlen(rvalue), &key, &len);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r, "Could not parse wireguard key \"%s\", ignoring assignment: %m", rvalue);
+                return 0;
+        }
+        if (len != WG_KEY_LEN) {
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Wireguard key is too short, ignoring assignment: %s", rvalue);
+                return 0;
+        }
+
+        memcpy(userdata, key, WG_KEY_LEN);
+        return true;
+}
+
+int config_parse_wireguard_private_key(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) {
+        Wireguard *w;
+
+        assert(data);
+
+        w = WIREGUARD(data);
+
+        assert(w);
+
+        return parse_wireguard_key(unit,
+                                   filename,
+                                   line,
+                                   section,
+                                   section_line,
+                                   lvalue,
+                                   ltype,
+                                   rvalue,
+                                   data,
+                                   &w->private_key);
+
+}
+
+int config_parse_wireguard_preshared_key(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) {
+        Wireguard *w;
+        WireguardPeer *peer;
+
+        assert(data);
+
+        w = WIREGUARD(data);
+
+        assert(w);
+
+        peer = wireguard_peer_new(w, section_line);
+        if (!peer)
+                return log_oom();
+
+        return parse_wireguard_key(unit,
+                                   filename,
+                                   line,
+                                   section,
+                                   section_line,
+                                   lvalue,
+                                   ltype,
+                                   rvalue,
+                                   data,
+                                   peer->preshared_key);
+}
+
+
+int config_parse_wireguard_public_key(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) {
+        Wireguard *w;
+        WireguardPeer *peer;
+
+        assert(data);
+
+        w = WIREGUARD(data);
+
+        assert(w);
+
+        peer = wireguard_peer_new(w, section_line);
+        if (!peer)
+                return log_oom();
+
+        return parse_wireguard_key(unit,
+                                   filename,
+                                   line,
+                                   section,
+                                   section_line,
+                                   lvalue,
+                                   ltype,
+                                   rvalue,
+                                   data,
+                                   peer->public_key);
+}
+
+int config_parse_wireguard_allowed_ips(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) {
+        union in_addr_union addr;
+        unsigned char prefixlen;
+        int r, family;
+        Wireguard *w;
+        WireguardPeer *peer;
+        WireguardIPmask *ipmask;
+
+        assert(rvalue);
+        assert(data);
+
+        w = WIREGUARD(data);
+
+        peer = wireguard_peer_new(w, section_line);
+        if (!peer)
+                return log_oom();
+
+        for (;;) {
+                _cleanup_free_ char *word = NULL;
+
+                r = extract_first_word(&rvalue, &word, "," WHITESPACE, 0);
+                if (r == 0)
+                        break;
+                if (r == -ENOMEM)
+                        return log_oom();
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r, "Failed to split allowed ips \"%s\" option: %m", rvalue);
+                        break;
+                }
+
+                r = in_addr_prefix_from_string_auto(word, &family, &addr, &prefixlen);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r, "Network address is invalid, ignoring assignment: %s", word);
+                        return 0;
+                }
+
+                ipmask = new0(WireguardIPmask, 1);
+                if (!ipmask)
+                        return log_oom();
+                ipmask->family = family;
+                ipmask->ip.in6 = addr.in6;
+                ipmask->cidr = prefixlen;
+
+                LIST_PREPEND(ipmasks, peer->ipmasks, ipmask);
+        }
+
+        return 0;
+}
+
+int config_parse_wireguard_endpoint(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) {
+        Wireguard *w;
+        WireguardPeer *peer;
+        size_t len;
+        const char *begin, *end = NULL;
+        _cleanup_free_ char *host = NULL, *port = NULL;
+        _cleanup_(wireguard_endpoint_freep) WireguardEndpoint *endpoint = NULL;
+
+        assert(data);
+        assert(rvalue);
+
+        w = WIREGUARD(data);
+
+        assert(w);
+
+        peer = wireguard_peer_new(w, section_line);
+        if (!peer)
+                return log_oom();
+
+        endpoint = new0(WireguardEndpoint, 1);
+        if (!endpoint)
+                return log_oom();
+
+        if (rvalue[0] == '[') {
+                begin = &rvalue[1];
+                end = strchr(rvalue, ']');
+                if (!end) {
+                        log_syntax(unit, LOG_ERR, filename, line, 0, "Unable to find matching brace of endpoint, ignoring assignment: %s", rvalue);
+                        return 0;
+                }
+                len = end - begin;
+                ++end;
+                if (*end != ':' || !*(end + 1)) {
+                        log_syntax(unit, LOG_ERR, filename, line, 0, "Unable to find port of endpoint: %s", rvalue);
+                        return 0;
+                }
+                ++end;
+        } else {
+                begin = rvalue;
+                end = strrchr(rvalue, ':');
+                if (!end || !*(end + 1)) {
+                        log_syntax(unit, LOG_ERR, filename, line, 0, "Unable to find port of endpoint: %s", rvalue);
+                        return 0;
+                }
+                len = end - begin;
+                ++end;
+        }
+
+        host = strndup(begin, len);
+        if (!host)
+                return log_oom();
+
+        port = strdup(end);
+        if (!port)
+                return log_oom();
+
+        endpoint->peer = peer;
+        endpoint->host = host;
+        endpoint->port = port;
+        endpoint->netdev = netdev_ref(data);
+        LIST_PREPEND(endpoints, w->unresolved_endpoints, endpoint);
+
+        peer = NULL;
+        host = NULL;
+        port = NULL;
+        endpoint = NULL;
+
+        return 0;
+}
+
+int config_parse_wireguard_keepalive(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 r;
+        uint16_t keepalive = 0;
+        Wireguard *w;
+        WireguardPeer *peer;
+
+        assert(rvalue);
+        assert(data);
+
+        w = WIREGUARD(data);
+
+        assert(w);
+
+        peer = wireguard_peer_new(w, section_line);
+        if (!peer)
+                return log_oom();
+
+        if (streq(rvalue, "off"))
+                keepalive = 0;
+        else {
+                r = safe_atou16(rvalue, &keepalive);
+                if (r < 0)
+                        log_syntax(unit, LOG_ERR, filename, line, r, "The persistent keepalive interval must be 0-65535. Ignore assignment: %s", rvalue);
+        }
+
+        peer->persistent_keepalive_interval = keepalive;
+        return 0;
+}
+
+static void wireguard_init(NetDev *netdev) {
+        Wireguard *w;
+
+        assert(netdev);
+
+        w = WIREGUARD(netdev);
+
+        assert(w);
+
+        w->flags = WGDEVICE_F_REPLACE_PEERS;
+}
+
+static void wireguard_done(NetDev *netdev) {
+        Wireguard *w;
+        WireguardPeer *peer;
+        WireguardIPmask *mask;
+
+        assert(netdev);
+        w = WIREGUARD(netdev);
+        assert(!w->unresolved_endpoints);
+        w->resolve_retry_event_source = sd_event_source_unref(w->resolve_retry_event_source);
+
+        while ((peer = w->peers)) {
+                LIST_REMOVE(peers, w->peers, peer);
+                while ((mask = peer->ipmasks)) {
+                        LIST_REMOVE(ipmasks, peer->ipmasks, mask);
+                        free(mask);
+                }
+                free(peer);
+        }
+}
+
+const NetDevVTable wireguard_vtable = {
+        .object_size = sizeof(Wireguard),
+        .sections = "Match\0NetDev\0WireGuard\0WireGuardPeer\0",
+        .post_create = netdev_wireguard_post_create,
+        .init = wireguard_init,
+        .done = wireguard_done,
+        .create_type = NETDEV_CREATE_INDEPENDENT,
+};
diff --git a/src/network/netdev/wireguard.h b/src/network/netdev/wireguard.h
new file mode 100644 (file)
index 0000000..f788fa4
--- /dev/null
@@ -0,0 +1,98 @@
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2016 Jörg Thalheim <joerg@thalheim.io>
+
+  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/>.
+***/
+
+typedef struct Wireguard Wireguard;
+
+#include "netdev.h"
+#include "sd-resolve.h"
+#include "wireguard-netlink.h"
+#include "socket-util.h"
+#include "in-addr-util.h"
+
+#ifndef IFNAMSIZ
+#define IFNAMSIZ 16
+#endif
+
+typedef struct WireguardIPmask {
+        uint16_t family;
+        union in_addr_union ip;
+        uint8_t cidr;
+
+        LIST_FIELDS(struct WireguardIPmask, ipmasks);
+} WireguardIPmask;
+
+typedef struct WireguardPeer {
+        uint8_t public_key[WG_KEY_LEN];
+        uint8_t preshared_key[WG_KEY_LEN];
+        uint32_t flags;
+
+        union sockaddr_union endpoint;
+
+        uint16_t persistent_keepalive_interval;
+
+        LIST_HEAD(WireguardIPmask, ipmasks);
+        LIST_FIELDS(struct WireguardPeer, peers);
+} WireguardPeer;
+
+typedef struct WireguardEndpoint {
+        char *host;
+        char *port;
+
+        NetDev *netdev;
+        WireguardPeer *peer;
+
+        LIST_FIELDS(struct WireguardEndpoint, endpoints);
+} WireguardEndpoint;
+
+struct Wireguard {
+        NetDev meta;
+        unsigned last_peer_section;
+
+        char interface[IFNAMSIZ];
+        uint32_t flags;
+
+        uint8_t public_key[WG_KEY_LEN];
+        uint8_t private_key[WG_KEY_LEN];
+        uint32_t fwmark;
+
+        uint16_t port;
+
+        LIST_HEAD(WireguardPeer, peers);
+        size_t allocation_size;
+        sd_event_source *resolve_retry_event_source;
+
+        LIST_HEAD(WireguardEndpoint, unresolved_endpoints);
+        LIST_HEAD(WireguardEndpoint, failed_endpoints);
+        unsigned n_retries;
+        sd_resolve_query *resolve_query;
+};
+
+DEFINE_NETDEV_CAST(WIREGUARD, Wireguard);
+extern const NetDevVTable wireguard_vtable;
+
+int config_parse_wireguard_allowed_ips(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_wireguard_endpoint(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_wireguard_listen_port(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_wireguard_public_key(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_wireguard_private_key(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_wireguard_preshared_key(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_wireguard_keepalive(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 06a944c49df1c7587cb4998ab045fd2e5e929e14..dbf6cca3218935a7cf01f49e1a0027476146434a 100644 (file)
@@ -120,6 +120,7 @@ shared_sources = '''
         volatile-util.h
         watchdog.c
         watchdog.h
+        wireguard-netlink.h
 '''.split()
 
 test_tables_h = files('test-tables.h')
diff --git a/src/shared/wireguard-netlink.h b/src/shared/wireguard-netlink.h
new file mode 100644 (file)
index 0000000..eb17091
--- /dev/null
@@ -0,0 +1,179 @@
+#pragma once
+
+/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR MIT)
+ *
+ * Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
+ *
+ * Documentation
+ * =============
+ *
+ * The below enums and macros are for interfacing with WireGuard, using generic
+ * netlink, with family WG_GENL_NAME and version WG_GENL_VERSION. It defines two
+ * methods: get and set. Note that while they share many common attributes, these
+ * two functions actually accept a slightly different set of inputs and outputs.
+ *
+ * WG_CMD_GET_DEVICE
+ * -----------------
+ *
+ * May only be called via NLM_F_REQUEST | NLM_F_DUMP. The command should contain
+ * one but not both of:
+ *
+ *     WGDEVICE_A_IFINDEX: NLA_U32
+ *     WGDEVICE_A_IFNAME: NLA_NUL_STRING, maxlen IFNAMESIZ - 1
+ *
+ * The kernel will then return several messages (NLM_F_MULTI) containing the following
+ * tree of nested items:
+ *
+ *     WGDEVICE_A_IFINDEX: NLA_U32
+ *     WGDEVICE_A_IFNAME: NLA_NUL_STRING, maxlen IFNAMESIZ - 1
+ *     WGDEVICE_A_PRIVATE_KEY: len WG_KEY_LEN
+ *     WGDEVICE_A_PUBLIC_KEY: len WG_KEY_LEN
+ *     WGDEVICE_A_LISTEN_PORT: NLA_U16
+ *     WGDEVICE_A_FWMARK: NLA_U32
+ *     WGDEVICE_A_PEERS: NLA_NESTED
+ *             0: NLA_NESTED
+ *                     WGPEER_A_PUBLIC_KEY: len WG_KEY_LEN
+ *                     WGPEER_A_PRESHARED_KEY: len WG_KEY_LEN
+ *                     WGPEER_A_ENDPOINT: struct sockaddr_in or struct sockaddr_in6
+ *                     WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL: NLA_U16
+ *                     WGPEER_A_LAST_HANDSHAKE_TIME: struct timespec
+ *                     WGPEER_A_RX_BYTES: NLA_U64
+ *                     WGPEER_A_TX_BYTES: NLA_U64
+ *                     WGPEER_A_ALLOWEDIPS: NLA_NESTED
+ *                             0: NLA_NESTED
+ *                                     WGALLOWEDIP_A_FAMILY: NLA_U16
+ *                                     WGALLOWEDIP_A_IPADDR: struct in_addr or struct in6_addr
+ *                                     WGALLOWEDIP_A_CIDR_MASK: NLA_U8
+ *                             1: NLA_NESTED
+ *                                     ...
+ *                             2: NLA_NESTED
+ *                                     ...
+ *                             ...
+ *             1: NLA_NESTED
+ *                     ...
+ *             ...
+ *
+ * It is possible that all of the allowed IPs of a single peer will not
+ * fit within a single netlink message. In that case, the same peer will
+ * be written in the following message, except it will only contain
+ * WGPEER_A_PUBLIC_KEY and WGPEER_A_ALLOWEDIPS. This may occur several
+ * times in a row for the same peer. It is then up to the receiver to
+ * coalesce adjacent peers. Likewise, it is possible that all peers will
+ * not fit within a single message. So, subsequent peers will be sent
+ * in following messages, except those will only contain WGDEVICE_A_IFNAME
+ * and WGDEVICE_A_PEERS. It is then up to the receiver to coalesce these
+ * messages to form the complete list of peers.
+ *
+ * Since this is an NLA_F_DUMP command, the final message will always be
+ * NLMSG_DONE, even if an error occurs. However, this NLMSG_DONE message
+ * contains an integer error code. It is either zero or a negative error
+ * code corresponding to the errno.
+ *
+ * WG_CMD_SET_DEVICE
+ * -----------------
+ *
+ * May only be called via NLM_F_REQUEST. The command should contain the following
+ * tree of nested items, containing one but not both of WGDEVICE_A_IFINDEX
+ * and WGDEVICE_A_IFNAME:
+ *
+ *     WGDEVICE_A_IFINDEX: NLA_U32
+ *     WGDEVICE_A_IFNAME: NLA_NUL_STRING, maxlen IFNAMESIZ - 1
+ *     WGDEVICE_A_FLAGS: NLA_U32, 0 or WGDEVICE_F_REPLACE_PEERS if all current
+ *                       peers should be removed prior to adding the list below.
+ *     WGDEVICE_A_PRIVATE_KEY: len WG_KEY_LEN, all zeros to remove
+ *     WGDEVICE_A_LISTEN_PORT: NLA_U16, 0 to choose randomly
+ *     WGDEVICE_A_FWMARK: NLA_U32, 0 to disable
+ *     WGDEVICE_A_PEERS: NLA_NESTED
+ *             0: NLA_NESTED
+ *                     WGPEER_A_PUBLIC_KEY: len WG_KEY_LEN
+ *                     WGPEER_A_FLAGS: NLA_U32, 0 and/or WGPEER_F_REMOVE_ME if the specified peer
+ *                                     should be removed rather than added/updated and/or
+ *                                     WGPEER_F_REPLACE_ALLOWEDIPS if all current allowed IPs of
+ *                                     this peer should be removed prior to adding the list below.
+ *                     WGPEER_A_PRESHARED_KEY: len WG_KEY_LEN, all zeros to remove
+ *                     WGPEER_A_ENDPOINT: struct sockaddr_in or struct sockaddr_in6
+ *                     WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL: NLA_U16, 0 to disable
+ *                     WGPEER_A_ALLOWEDIPS: NLA_NESTED
+ *                             0: NLA_NESTED
+ *                                     WGALLOWEDIP_A_FAMILY: NLA_U16
+ *                                     WGALLOWEDIP_A_IPADDR: struct in_addr or struct in6_addr
+ *                                     WGALLOWEDIP_A_CIDR_MASK: NLA_U8
+ *                             1: NLA_NESTED
+ *                                     ...
+ *                             2: NLA_NESTED
+ *                                     ...
+ *                             ...
+ *             1: NLA_NESTED
+ *                     ...
+ *             ...
+ *
+ * It is possible that the amount of configuration data exceeds that of
+ * the maximum message length accepted by the kernel. In that case,
+ * several messages should be sent one after another, with each
+ * successive one filling in information not contained in the prior. Note
+ * that if WGDEVICE_F_REPLACE_PEERS is specified in the first message, it
+ * probably should not be specified in fragments that come after, so that
+ * the list of peers is only cleared the first time but appened after.
+ * Likewise for peers, if WGPEER_F_REPLACE_ALLOWEDIPS is specified in the
+ * first message of a peer, it likely should not be specified in subsequent
+ * fragments.
+ *
+ * If an error occurs, NLMSG_ERROR will reply containing an errno.
+ */
+
+#define WG_GENL_NAME "wireguard"
+#define WG_GENL_VERSION 1
+
+#define WG_KEY_LEN 32
+
+enum wg_cmd {
+        WG_CMD_GET_DEVICE,
+        WG_CMD_SET_DEVICE,
+        __WG_CMD_MAX
+};
+#define WG_CMD_MAX (__WG_CMD_MAX - 1)
+
+enum wgdevice_flag {
+ WGDEVICE_F_REPLACE_PEERS = 1U << 0
+};
+enum wgdevice_attribute {
+        WGDEVICE_A_UNSPEC,
+        WGDEVICE_A_IFINDEX,
+        WGDEVICE_A_IFNAME,
+        WGDEVICE_A_PRIVATE_KEY,
+        WGDEVICE_A_PUBLIC_KEY,
+        WGDEVICE_A_FLAGS,
+        WGDEVICE_A_LISTEN_PORT,
+        WGDEVICE_A_FWMARK,
+        WGDEVICE_A_PEERS,
+        __WGDEVICE_A_LAST
+};
+#define WGDEVICE_A_MAX (__WGDEVICE_A_LAST - 1)
+
+enum wgpeer_flag {
+        WGPEER_F_REMOVE_ME = 1U << 0,
+        WGPEER_F_REPLACE_ALLOWEDIPS = 1U << 1
+};
+enum wgpeer_attribute {
+        WGPEER_A_UNSPEC,
+        WGPEER_A_PUBLIC_KEY,
+        WGPEER_A_PRESHARED_KEY,
+        WGPEER_A_FLAGS,
+        WGPEER_A_ENDPOINT,
+        WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+        WGPEER_A_LAST_HANDSHAKE_TIME,
+        WGPEER_A_RX_BYTES,
+        WGPEER_A_TX_BYTES,
+        WGPEER_A_ALLOWEDIPS,
+        __WGPEER_A_LAST
+};
+#define WGPEER_A_MAX (__WGPEER_A_LAST - 1)
+
+enum wgallowedip_attribute {
+        WGALLOWEDIP_A_UNSPEC,
+        WGALLOWEDIP_A_FAMILY,
+        WGALLOWEDIP_A_IPADDR,
+        WGALLOWEDIP_A_CIDR_MASK,
+        __WGALLOWEDIP_A_LAST
+};
+#define WGALLOWEDIP_A_MAX (__WGALLOWEDIP_A_LAST - 1)
index 7c4d51ea798457080300fd381c35f238fd22b317..e742807e92cfce3a9a2d39477b5c059e165affa5 100644 (file)
@@ -36,7 +36,7 @@ _SD_BEGIN_DECLARATIONS;
 typedef struct sd_netlink sd_netlink;
 typedef struct sd_genl_socket sd_genl_socket;
 typedef struct sd_netlink_message sd_netlink_message;
-typedef enum {SD_GENL_ID_CTRL} sd_genl_family;
+typedef enum {SD_GENL_ID_CTRL, SD_GENL_WIREGUARD} sd_genl_family;
 
 /* callback */