1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2024-12-22 13:33:56 +03:00

Merge pull request #7191 from Mic92/systemd

The change in netdev.c done in the merge is necessary to avoid crashing in
cleanup. This is a follow-up for f3c33b234d.
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2018-01-09 14:01:05 +01:00
commit 2269954112
24 changed files with 1608 additions and 144 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

@ -74,6 +74,7 @@ libsystemd_sources = files('''
sd-id128/id128-util.c
sd-id128/id128-util.h
sd-id128/sd-id128.c
sd-netlink/generic-netlink.c
sd-netlink/local-addresses.c
sd-netlink/local-addresses.h
sd-netlink/netlink-internal.h

View File

@ -0,0 +1,97 @@
#include <linux/genetlink.h>
#include "sd-netlink.h"
#include "netlink-internal.h"
#include "alloc-util.h"
typedef struct {
const char* name;
uint8_t version;
} genl_family;
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) {
return netlink_open_family(ret, NETLINK_GENERIC);
}
static int lookup_id(sd_netlink *nl, sd_genl_family family, uint16_t *id);
static int genl_message_new(sd_netlink *nl, sd_genl_family family, uint16_t nlmsg_type, uint8_t cmd, sd_netlink_message **ret) {
int r;
struct genlmsghdr *genl;
const NLType *genl_cmd_type, *nl_type;
const NLTypeSystem *type_system;
size_t size;
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
assert_return(nl->protocol == NETLINK_GENERIC, -EINVAL);
r = type_system_get_type(&genl_family_type_system_root, &genl_cmd_type, family);
if (r < 0)
return r;
r = message_new_empty(nl, &m);
if (r < 0)
return r;
size = NLMSG_SPACE(sizeof(struct genlmsghdr));
m->hdr = malloc0(size);
if (!m->hdr)
return -ENOMEM;
m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
type_get_type_system(genl_cmd_type, &type_system);
r = type_system_get_type(type_system, &nl_type, cmd);
if (r < 0)
return r;
m->hdr->nlmsg_len = size;
m->hdr->nlmsg_type = nlmsg_type;
type_get_type_system(nl_type, &m->containers[0].type_system);
genl = NLMSG_DATA(m->hdr);
genl->cmd = cmd;
genl->version = genl_families[family].version;
*ret = m;
m = NULL;
return 0;
}
int sd_genl_message_new(sd_netlink *nl, sd_genl_family family, uint8_t cmd, sd_netlink_message **ret) {
int r;
uint16_t id = GENL_ID_CTRL;
if (family != SD_GENL_ID_CTRL) {
r = lookup_id(nl, family, &id);
if (r < 0)
return r;
}
return genl_message_new(nl, family, id, cmd, ret);
}
static int lookup_id(sd_netlink *nl, sd_genl_family family, uint16_t *id) {
int r;
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
r = sd_genl_message_new(nl, SD_GENL_ID_CTRL, CTRL_CMD_GETFAMILY, &req);
if (r < 0)
return r;
r = sd_netlink_message_append_string(req, CTRL_ATTR_FAMILY_NAME, genl_families[family].name);
if (r < 0)
return r;
r = sd_netlink_call(nl, req, 0, &reply);
if (r < 0)
return r;
return sd_netlink_message_read_u16(reply, CTRL_ATTR_FAMILY_ID, id);
}

View File

@ -62,6 +62,8 @@ struct sd_netlink {
struct sockaddr_nl nl;
} sockaddr;
int protocol;
Hashmap *broadcast_group_refs;
bool broadcast_group_dont_leave:1; /* until we can rely on 4.2 */
@ -111,6 +113,8 @@ struct sd_netlink_message {
sd_netlink *rtnl;
int protocol;
struct nlmsghdr *hdr;
struct netlink_container containers[RTNL_CONTAINER_DEPTH];
unsigned n_containers; /* number of containers */
@ -123,6 +127,8 @@ struct sd_netlink_message {
int message_new(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t type);
int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret);
int netlink_open_family(sd_netlink **ret, int family);
int socket_open(int family);
int socket_bind(sd_netlink *nl);
int socket_broadcast_group_ref(sd_netlink *nl, unsigned group);

View File

@ -55,7 +55,7 @@ int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret) {
return -ENOMEM;
m->n_ref = REFCNT_INIT;
m->protocol = rtnl->protocol;
m->sealed = false;
*ret = m;
@ -66,10 +66,15 @@ int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret) {
int message_new(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t type) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
const NLType *nl_type;
const NLTypeSystem *type_system_root;
size_t size;
int r;
r = type_system_get_type(&type_system_root, &nl_type, type);
assert_return(rtnl, -EINVAL);
type_system_root = type_system_get_root(rtnl->protocol);
r = type_system_get_type(type_system_root, &nl_type, type);
if (r < 0)
return r;
@ -186,6 +191,10 @@ static int add_rtattr(sd_netlink_message *m, unsigned short type, const void *da
/* get the new message size (with padding at the end) */
message_length = offset + RTA_ALIGN(rta_length);
/* buffer should be smaller than both one page or 8K to be accepted by the kernel */
if (message_length > MIN(page_size(), 8192UL))
return -ENOBUFS;
/* realloc to fit the new attribute */
new_hdr = realloc(m->hdr, message_length);
if (!new_hdr)
@ -490,7 +499,7 @@ int sd_netlink_message_open_container_union(sd_netlink_message *m, unsigned shor
if (r < 0)
return r;
/* do we evere need non-null size */
/* do we ever need non-null size */
r = add_rtattr(m, type | NLA_F_NESTED, NULL, 0);
if (r < 0)
return r;
@ -500,18 +509,57 @@ int sd_netlink_message_open_container_union(sd_netlink_message *m, unsigned shor
return 0;
}
int sd_netlink_message_close_container(sd_netlink_message *m) {
assert_return(m, -EINVAL);
assert_return(!m->sealed, -EPERM);
assert_return(m->n_containers > 0, -EINVAL);
m->containers[m->n_containers].type_system = NULL;
m->containers[m->n_containers].offset = 0;
m->n_containers--;
return 0;
}
int sd_netlink_message_open_array(sd_netlink_message *m, uint16_t type) {
int r;
assert_return(m, -EINVAL);
assert_return(!m->sealed, -EPERM);
assert_return(m->n_containers > 0, -EINVAL);
r = add_rtattr(m, type | NLA_F_NESTED, NULL, 0);
if (r < 0)
return r;
m->containers[m->n_containers].offset = r;
m->n_containers++;
m->containers[m->n_containers].type_system = m->containers[m->n_containers - 1].type_system;
return 0;
}
int sd_netlink_message_cancel_array(sd_netlink_message *m) {
unsigned i;
uint32_t rta_len;
assert_return(m, -EINVAL);
assert_return(!m->sealed, -EPERM);
assert_return(m->n_containers > 1, -EINVAL);
rta_len = GET_CONTAINER(m, (m->n_containers - 1))->rta_len;
for (i = 0; i < m->n_containers; i++)
GET_CONTAINER(m, i)->rta_len -= rta_len;
m->hdr->nlmsg_len -= rta_len;
m->n_containers--;
m->containers[m->n_containers].type_system = NULL;
return 0;
}
static int netlink_message_read_internal(sd_netlink_message *m, unsigned short type, void **data, bool *net_byteorder) {
struct netlink_attribute *attribute;
struct rtattr *rta;
@ -899,6 +947,7 @@ int sd_netlink_message_get_errno(sd_netlink_message *m) {
int sd_netlink_message_rewind(sd_netlink_message *m) {
const NLType *nl_type;
const NLTypeSystem *type_system_root;
uint16_t type;
size_t size;
unsigned i;
@ -910,6 +959,8 @@ int sd_netlink_message_rewind(sd_netlink_message *m) {
if (!m->sealed)
rtnl_message_seal(m);
type_system_root = type_system_get_root(m->protocol);
for (i = 1; i <= m->n_containers; i++)
m->containers[i].attributes = mfree(m->containers[i].attributes);
@ -921,7 +972,7 @@ int sd_netlink_message_rewind(sd_netlink_message *m) {
assert(m->hdr);
r = type_system_get_type(&type_system_root, &nl_type, m->hdr->nlmsg_type);
r = type_system_get_type(type_system_root, &nl_type, m->hdr->nlmsg_type);
if (r < 0)
return r;

View File

@ -330,11 +330,14 @@ int socket_read_message(sd_netlink *rtnl) {
size_t len;
int r;
unsigned i = 0;
const NLTypeSystem *type_system_root;
assert(rtnl);
assert(rtnl->rbuffer);
assert(rtnl->rbuffer_allocated >= sizeof(struct nlmsghdr));
type_system_root = type_system_get_root(rtnl->protocol);
/* read nothing, just get the pending message size */
r = socket_recv_message(rtnl->fd, &iov, NULL, true);
if (r <= 0)
@ -396,7 +399,8 @@ int socket_read_message(sd_netlink *rtnl) {
}
/* check that we support this message type */
r = type_system_get_type(&type_system_root, &nl_type, new_msg->nlmsg_type);
r = type_system_get_type(type_system_root, &nl_type, new_msg->nlmsg_type);
if (r < 0) {
if (r == -EOPNOTSUPP)
log_debug("sd-netlink: ignored message with unknown type: %i",

View File

@ -36,6 +36,7 @@
#include <linux/if_link.h>
#include <linux/if_tunnel.h>
#include <linux/fib_rules.h>
#include <linux/genetlink.h>
#if HAVE_VXCAN_INFO_PEER
#include <linux/can/vxcan.h>
@ -46,6 +47,8 @@
#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 */
#define BOND_MAX_ARP_TARGETS 16
@ -338,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);
@ -665,11 +668,98 @@ static const NLType rtnl_types[] = {
[RTM_GETRULE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_routing_policy_rule_type_system, .size = sizeof(struct rtmsg) },
};
const NLTypeSystem type_system_root = {
const NLTypeSystem rtnl_type_system_root = {
.count = ELEMENTSOF(rtnl_types),
.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 },
[CTRL_ATTR_FAMILY_ID] = { .type = NETLINK_TYPE_U16 },
};
static const NLTypeSystem genl_get_family_type_system = {
.count = ELEMENTSOF(genl_get_family_types),
.types = genl_get_family_types,
};
static const NLType genl_ctrl_id_ctrl_cmds[] = {
[CTRL_CMD_GETFAMILY] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_get_family_type_system },
};
static const NLTypeSystem genl_ctrl_id_ctrl_type_system = {
.count = ELEMENTSOF(genl_ctrl_id_ctrl_cmds),
.types = genl_ctrl_id_ctrl_cmds,
};
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 = {
.count = ELEMENTSOF(genl_families),
.types = genl_families,
};
static const NLType genl_types[] = {
[GENL_ID_CTRL] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_get_family_type_system, .size = sizeof(struct genlmsghdr) },
};
const NLTypeSystem genl_type_system_root = {
.count = ELEMENTSOF(genl_types),
.types = genl_types,
};
uint16_t type_get_type(const NLType *type) {
assert(type);
return type->type;
@ -703,6 +793,15 @@ uint16_t type_system_get_count(const NLTypeSystem *type_system) {
return type_system->count;
}
const NLTypeSystem *type_system_get_root(int protocol) {
switch (protocol) {
case NETLINK_GENERIC:
return &genl_type_system_root;
default: /* NETLINK_ROUTE: */
return &rtnl_type_system_root;
}
}
int type_system_get_type(const NLTypeSystem *type_system, const NLType **ret, uint16_t type) {
const NLType *nl_type;

View File

@ -54,13 +54,16 @@ struct NLTypeSystemUnion {
const NLTypeSystem *type_systems;
};
extern const NLTypeSystem type_system_root;
extern const NLTypeSystem rtnl_type_system_root;
extern const NLTypeSystem genl_type_system_root;
extern const NLTypeSystem genl_family_type_system_root;
uint16_t type_get_type(const NLType *type);
size_t type_get_size(const NLType *type);
void type_get_type_system(const NLType *type, const NLTypeSystem **ret);
void type_get_type_system_union(const NLType *type, const NLTypeSystemUnion **ret);
const NLTypeSystem* type_system_get_root(int protocol);
uint16_t type_system_get_count(const NLTypeSystem *type_system);
int type_system_get_type(const NLTypeSystem *type_system, const NLType **ret, uint16_t type);
int type_system_get_type_system(const NLTypeSystem *type_system, const NLTypeSystem **ret, uint16_t type);
@ -91,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

@ -98,13 +98,13 @@ int rtnl_set_link_properties(sd_netlink **rtnl, int ifindex, const char *alias,
return 0;
}
int rtnl_message_new_synthetic_error(int error, uint32_t serial, sd_netlink_message **ret) {
int rtnl_message_new_synthetic_error(sd_netlink *rtnl, int error, uint32_t serial, sd_netlink_message **ret) {
struct nlmsgerr *err;
int r;
assert(error <= 0);
r = message_new(NULL, ret, NLMSG_ERROR);
r = message_new(rtnl, ret, NLMSG_ERROR);
if (r < 0)
return r;

View File

@ -24,7 +24,7 @@
#include "util.h"
int rtnl_message_new_synthetic_error(int error, uint32_t serial, sd_netlink_message **ret);
int rtnl_message_new_synthetic_error(sd_netlink *rtnl, int error, uint32_t serial, sd_netlink_message **ret);
uint32_t rtnl_message_get_serial(sd_netlink_message *m);
void rtnl_message_seal(sd_netlink_message *m);

View File

@ -46,6 +46,7 @@ static int sd_netlink_new(sd_netlink **ret) {
rtnl->fd = -1;
rtnl->sockaddr.nl.nl_family = AF_NETLINK;
rtnl->original_pid = getpid_cached();
rtnl->protocol = -1;
LIST_HEAD_INIT(rtnl->match_callbacks);
@ -106,6 +107,8 @@ static bool rtnl_pid_changed(sd_netlink *rtnl) {
int sd_netlink_open_fd(sd_netlink **ret, int fd) {
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
int r;
int protocol;
socklen_t l;
assert_return(ret, -EINVAL);
assert_return(fd >= 0, -EBADF);
@ -114,11 +117,18 @@ int sd_netlink_open_fd(sd_netlink **ret, int fd) {
if (r < 0)
return r;
l = sizeof(protocol);
r = getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &protocol, &l);
if (r < 0)
return r;
rtnl->fd = fd;
rtnl->protocol = protocol;
r = socket_bind(rtnl);
if (r < 0) {
rtnl->fd = -1; /* on failure, the caller remains owner of the fd, hence don't close it here */
rtnl->protocol = -1;
return r;
}
@ -128,11 +138,11 @@ int sd_netlink_open_fd(sd_netlink **ret, int fd) {
return 0;
}
int sd_netlink_open(sd_netlink **ret) {
int netlink_open_family(sd_netlink **ret, int family) {
_cleanup_close_ int fd = -1;
int r;
fd = socket_open(NETLINK_ROUTE);
fd = socket_open(family);
if (fd < 0)
return fd;
@ -145,6 +155,10 @@ int sd_netlink_open(sd_netlink **ret) {
return 0;
}
int sd_netlink_open(sd_netlink **ret) {
return netlink_open_family(ret, NETLINK_ROUTE);
}
int sd_netlink_inc_rcvbuf(sd_netlink *rtnl, size_t size) {
assert_return(rtnl, -EINVAL);
assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
@ -309,7 +323,7 @@ static int process_timeout(sd_netlink *rtnl) {
if (c->timeout > n)
return 0;
r = rtnl_message_new_synthetic_error(-ETIMEDOUT, c->serial, &m);
r = rtnl_message_new_synthetic_error(rtnl, -ETIMEDOUT, c->serial, &m);
if (r < 0)
return r;

View File

@ -143,13 +143,13 @@ static void test_address_get(sd_netlink *rtnl, int ifindex) {
}
static void test_route(void) {
static void test_route(sd_netlink *rtnl) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req;
struct in_addr addr, addr_data;
uint32_t index = 2, u32_data;
int r;
r = sd_rtnl_message_new_route(NULL, &req, RTM_NEWROUTE, AF_INET, RTPROT_STATIC);
r = sd_rtnl_message_new_route(rtnl, &req, RTM_NEWROUTE, AF_INET, RTPROT_STATIC);
if (r < 0) {
log_error_errno(r, "Could not create RTM_NEWROUTE message: %m");
return;
@ -291,13 +291,13 @@ static void test_pipe(int ifindex) {
assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
}
static void test_container(void) {
static void test_container(sd_netlink *rtnl) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
uint16_t u16_data;
uint32_t u32_data;
const char *string_data;
assert_se(sd_rtnl_message_new_link(NULL, &m, RTM_NEWLINK, 0) >= 0);
assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0) >= 0);
assert_se(sd_netlink_message_open_container(m, IFLA_LINKINFO) >= 0);
assert_se(sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "vlan") >= 0);
@ -369,10 +369,10 @@ static void test_get_addresses(sd_netlink *rtnl) {
}
}
static void test_message(void) {
static void test_message(sd_netlink *rtnl) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
assert_se(rtnl_message_new_synthetic_error(-ETIMEDOUT, 1, &m) >= 0);
assert_se(rtnl_message_new_synthetic_error(rtnl, -ETIMEDOUT, 1, &m) >= 0);
assert_se(sd_netlink_message_get_errno(m) == -ETIMEDOUT);
}
@ -384,19 +384,19 @@ int main(void) {
int if_loopback;
uint16_t type;
test_message();
test_match();
test_multiple();
test_route();
test_container();
assert_se(sd_netlink_open(&rtnl) >= 0);
assert_se(rtnl);
test_route(rtnl);
test_message(rtnl);
test_container(rtnl);
if_loopback = (int) if_nametoindex("lo");
assert_se(if_loopback > 0);

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);
@ -111,10 +114,10 @@ static void netdev_cancel_callbacks(NetDev *netdev) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
netdev_join_callback *callback;
if (!netdev)
if (!netdev || !netdev->manager)
return;
rtnl_message_new_synthetic_error(-ENODEV, 0, &m);
rtnl_message_new_synthetic_error(netdev->manager->rtnl, -ENODEV, 0, &m);
while ((callback = netdev->callbacks)) {
if (m) {
@ -330,7 +333,7 @@ int netdev_enslave(NetDev *netdev, Link *link, sd_netlink_message_handler_t call
} else if (IN_SET(netdev->state, NETDEV_STATE_LINGER, NETDEV_STATE_FAILED)) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
r = rtnl_message_new_synthetic_error(-ENODEV, 0, &m);
r = rtnl_message_new_synthetic_error(netdev->manager->rtnl, -ENODEV, 0, &m);
if (r >= 0)
callback(netdev->manager->rtnl, m, link);
} else {

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

@ -907,6 +907,26 @@ static int systemd_netlink_fd(void) {
return rtnl_fd;
}
static int manager_connect_genl(Manager *m) {
int r;
assert(m);
r = sd_genl_socket_open(&m->genl);
if (r < 0)
return r;
r = sd_netlink_inc_rcvbuf(m->genl, RCVBUF_SIZE);
if (r < 0)
return r;
r = sd_netlink_attach_event(m->genl, m->event, 0);
if (r < 0)
return r;
return 0;
}
static int manager_connect_rtnl(Manager *m) {
int fd, r;
@ -1251,6 +1271,10 @@ int manager_new(Manager **ret, sd_event *event) {
if (r < 0)
return r;
r = manager_connect_genl(m);
if (r < 0)
return r;
r = manager_connect_udev(m);
if (r < 0)
return r;
@ -1261,6 +1285,14 @@ int manager_new(Manager **ret, sd_event *event) {
LIST_HEAD_INIT(m->networks);
r = sd_resolve_default(&m->resolve);
if (r < 0)
return r;
r = sd_resolve_attach_event(m->resolve, m->event, 0);
if (r < 0)
return r;
r = setup_default_address_pool(m);
if (r < 0)
return r;
@ -1310,6 +1342,8 @@ void manager_free(Manager *m) {
sd_netlink_unref(m->rtnl);
sd_event_unref(m->event);
sd_resolve_unref(m->resolve);
sd_event_source_unref(m->udev_event_source);
udev_monitor_unref(m->udev_monitor);
udev_unref(m->udev);

View File

@ -25,6 +25,7 @@
#include "sd-bus.h"
#include "sd-event.h"
#include "sd-netlink.h"
#include "sd-resolve.h"
#include "udev.h"
#include "dhcp-identifier.h"
@ -39,7 +40,10 @@ extern const char* const network_dirs[];
struct Manager {
sd_netlink *rtnl;
/* lazy initialized */
sd_netlink *genl;
sd_event *event;
sd_resolve *resolve;
sd_event_source *bus_retry_event_source;
sd_bus *bus;
sd_bus_slot *prepare_for_sleep_slot;

View File

@ -118,6 +118,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

@ -34,7 +34,9 @@
_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_WIREGUARD} sd_genl_family;
/* callback */
@ -94,6 +96,9 @@ int sd_netlink_message_read_in6_addr(sd_netlink_message *m, unsigned short type,
int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short type);
int sd_netlink_message_exit_container(sd_netlink_message *m);
int sd_netlink_message_open_array(sd_netlink_message *m, uint16_t type);
int sd_netlink_message_cancel_array(sd_netlink_message *m);
int sd_netlink_message_rewind(sd_netlink_message *m);
sd_netlink_message *sd_netlink_message_next(sd_netlink_message *m);
@ -177,6 +182,10 @@ int sd_rtnl_message_routing_policy_rule_get_rtm_type(sd_netlink_message *m, unsi
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_netlink, sd_netlink_unref);
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_netlink_message, sd_netlink_message_unref);
/* genl */
int sd_genl_socket_open(sd_netlink **nl);
int sd_genl_message_new(sd_netlink *nl, sd_genl_family family, uint8_t cmd, sd_netlink_message **m);
_SD_END_DECLARATIONS;
#endif