networkd: add support for wireguard interface type

More information may be found at wireguard.com.
This commit is contained in:
Jörg Thalheim 2017-12-18 15:20:34 +01:00 committed by Zbigniew Jędrzejewski-Szmek
parent 05d0c2e3cf
commit e5719363f5
14 changed files with 1309 additions and 116 deletions

View File

@ -73,6 +73,18 @@
</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">

View File

@ -184,6 +184,9 @@
<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>
@ -1009,6 +1012,103 @@
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>

View 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) {

View 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 = {

View 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;

View 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

View 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

View 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);

View 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;

View File

@ -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,
};

View File

@ -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);

View 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')

View File

@ -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)

View 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 */