Skip to content

Commit

Permalink
networkd: Introduce MACsec
Browse files Browse the repository at this point in the history
This work introduces MACsec to networkd.

Media Access Control Security (MACsec) is an 802.1AE IEEE
industry-standard security technology that provides secure
communication for all traffic on Ethernet links.
MACsec provides point-to-point security on Ethernet links between
directly connected nodes and is capable of identifying and preventing
most security threats, including denial of service, intrusion,
man-in-the-middle, masquerading, passive wiretapping, and playback attacks.

11-macsec.netdev
```
[NetDev]
Name=macsec-test
Kind=macsec

[MACSEC]
Port=11

[MACsecReceiveAssociation]
Port=1234
MACAddress=c6:19:52:8f:e6:a0
PacketNumber=1
KeyId=00
Key=82828282828282828282828282828282

[MACsecReceiveChannel]
Port=1234
MACAddress=c6:19:52:8f:e6:a0

[MACsecTransmitAssociation]
PacketNumber=1024
KeyId=01
Key=81818181818181818181818181818181

```

closes #5754
  • Loading branch information
Susant Sahani committed Apr 2, 2019
1 parent 509276f commit 19196a5
Show file tree
Hide file tree
Showing 17 changed files with 1,422 additions and 155 deletions.
117 changes: 117 additions & 0 deletions man/systemd.netdev.xml
Expand Up @@ -151,6 +151,9 @@
<row><entry><varname>l2tp</varname></entry>
<entry>A Layer 2 Tunneling Protocol (L2TP) is a tunneling protocol used to support virtual private networks (VPNs) or as part of the delivery of services by ISPs. It does not provide any encryption or confidentiality by itself</entry></row>

<row><entry><varname>macsec</varname></entry>
<entry>Media Access Control Security (MACsec) is an 802.1AE IEEE industry-standard security technology that provides secure communication for all traffic on Ethernet links. MACsec provides point-to-point security on Ethernet links between directly connected nodes and is capable of identifying and preventing most security threats.</entry></row>

<row><entry><varname>vrf</varname></entry>
<entry>A Virtual Routing and Forwarding (<ulink url="https://www.kernel.org/doc/Documentation/networking/vrf.txt">VRF</ulink>) interface to create separate routing and forwarding domains.</entry></row>

Expand Down Expand Up @@ -851,6 +854,120 @@
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>[MACSEC] Section Options</title>
<para>The <literal>[MACSEC]</literal> section only applies for
netdevs of kind <literal>macsec</literal>, and accepts the
following keys:</para>

<variablelist class='network-directives'>
<varlistentry>
<term><varname>Port=</varname></term>
<listitem>
<para>Specifies the to be used for the MACsec. Takes either value between 1 and 65535. This option is compulsory.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>Encrypt=</varname></term>
<listitem>
<para>Takes a boolean. When true, enable encryption. Defaults to unset.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>[MACsecReceiveChannel] Section Options</title>
<para>The <literal>[MACsecReceiveChannel]</literal> section only applies for
netdevs of kind <literal>macsec</literal>, and accepts the
following keys:</para>

<variablelist class='network-directives'>
<varlistentry>
<term><varname>Port=</varname></term>
<listitem>
<para>Specifies the port to be used for the MACsec Receive Channel. The port used to make Secure Channel Identifier (SCI).
Takes either value between 1 and 65535. This option is compulsory.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>MACAddress=</varname></term>
<listitem>
<para>Specifies the MAC address to be used for the MACsec Receive Channel. The port used to make Secure Channel Identifier (SCI).
This option is compulsory.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>[MACsecTransmitAssociation] Section Options</title>
<para>The <literal>[MACsecTransmitAssociation]</literal> section only applies for
netdevs of kind <literal>macsec</literal>, and accepts the
following keys:</para>

<variablelist class='network-directives'>
<varlistentry>
<term><varname>PacketNumber=</varname></term>
<listitem>
<para>Specifies the packet number to be used for replay protection and the construction of
the initialization vector (along with the secure channel identifier [SCI]). Ranges a number between 1 and 4,294,967,295.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>KeyId=</varname></term>
<listitem>
<para>Specifies the identification for they key. Ranges a number between 0 to 255 This option is compulsory.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>Key=</varname></term>
<listitem>
<para>Specifies the identification for the key used in the transmit channel. That same key must be configured on the peer’s matching receive channel.
This option is compulsory. Takes a 128-bits key for example "dffafc8d7b9a43d5b9a3dfbbf6a30c16".</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>[MACsecReceiveAssociation] Section Options</title>
<para>The <literal>[MACsecReceiveAssociation]</literal> section only applies for
netdevs of kind <literal>macsec</literal>, and accepts the
following keys:</para>

<variablelist class='network-directives'>
<varlistentry>
<term><varname>Port=</varname></term>
<listitem>
<para>See [MACsecTransmitAssociation] Section.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>MACAddress=</varname></term>
<listitem>
<para>See [MACsecTransmitAssociation] Section.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>PacketNumber=</varname></term>
<listitem>
<para>See [MACsecTransmitAssociation] Section.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>KeyId=</varname></term>
<listitem>
<para>See [MACsecTransmitAssociation] Section.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>Key=</varname></term>
<listitem>
<para>See [MACsecTransmitAssociation] Section.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>[Tunnel] Section Options</title>

Expand Down
30 changes: 30 additions & 0 deletions src/basic/parse-util.c
Expand Up @@ -566,6 +566,36 @@ int safe_atod(const char *s, double *ret_d) {
return 0;
}

int safe_hexstring_aton(const char *s, uint8_t *b, unsigned int buf_len, unsigned int *len) {
unsigned int c = 0;
char *p;

assert(s);
assert(b);
assert(len);

if (strlen(s) % 2)
return -EINVAL;

for(c = 0; c < buf_len && strlen(s) > 1; s += 2) {
unsigned int i;
char t[3] = {};

strncpy(t, s, 2);

errno = 0;
i = strtoul(t, &p, 16);
if (errno > 0 || i > 0xFF || *p)
return -EINVAL;

b[c++] = i;
}

*len = c;

return 0;
}

int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) {
size_t i;
unsigned val = 0;
Expand Down
2 changes: 2 additions & 0 deletions src/basic/parse-util.h
Expand Up @@ -104,6 +104,8 @@ static inline int safe_atozu(const char *s, size_t *ret_u) {

int safe_atod(const char *s, double *ret_d);

int safe_hexstring_aton(const char *s, uint8_t *b, unsigned int buf_len, unsigned int *len);

int parse_fractional_part_u(const char **s, size_t digits, unsigned *res);

int parse_percent_unbounded(const char *p);
Expand Down
1 change: 1 addition & 0 deletions src/libsystemd/sd-netlink/generic-netlink.c
Expand Up @@ -14,6 +14,7 @@ static const genl_family genl_families[] = {
[SD_GENL_WIREGUARD] = { .name = "wireguard", .version = 1 },
[SD_GENL_FOU] = { .name = "fou", .version = 1 },
[SD_GENL_L2TP] = { .name = "l2tp", .version = 1},
[SD_GENL_MACSEC] = { .name = "macsec", .version = 1},
};

int sd_genl_socket_open(sd_netlink **ret) {
Expand Down
17 changes: 17 additions & 0 deletions src/libsystemd/sd-netlink/netlink-message.c
Expand Up @@ -318,6 +318,23 @@ int sd_netlink_message_append_u32(sd_netlink_message *m, unsigned short type, ui
return 0;
}

int sd_netlink_message_append_u64(sd_netlink_message *m, unsigned short type, uint64_t data) {
int r;

assert_return(m, -EINVAL);
assert_return(!m->sealed, -EPERM);

r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U64);
if (r < 0)
return r;

r = add_rtattr(m, type, &data, sizeof(uint64_t));
if (r < 0)
return r;

return 0;
}

int sd_netlink_message_append_data(sd_netlink_message *m, unsigned short type, const void *data, size_t len) {
int r;

Expand Down
85 changes: 85 additions & 0 deletions src/libsystemd/sd-netlink/netlink-types.c
Expand Up @@ -16,6 +16,7 @@
#include <linux/if_link.h>
#include <linux/if_tunnel.h>
#include <linux/l2tp.h>
#include <linux/if_macsec.h>
#include <linux/veth.h>

#if HAVE_LINUX_FOU_H
Expand Down Expand Up @@ -312,6 +313,22 @@ static const NLType rtnl_link_info_data_can_types[] = {
[IFLA_CAN_CTRLMODE] = { .size = sizeof(struct can_ctrlmode) },
};

static const NLType rtnl_link_info_data_macsec_types[] = {
[IFLA_MACSEC_SCI] = { .type = NETLINK_TYPE_U64 },
[IFLA_MACSEC_PORT] = { .type = NETLINK_TYPE_U16 },
[IFLA_MACSEC_ICV_LEN] = { .type = NETLINK_TYPE_U8 },
[IFLA_MACSEC_CIPHER_SUITE] = { .type = NETLINK_TYPE_U64 },
[IFLA_MACSEC_WINDOW] = { .type = NETLINK_TYPE_U32 },
[IFLA_MACSEC_ENCODING_SA] = { .type = NETLINK_TYPE_U8 },
[IFLA_MACSEC_ENCRYPT] = { .type = NETLINK_TYPE_U8 },
[IFLA_MACSEC_PROTECT] = { .type = NETLINK_TYPE_U8 },
[IFLA_MACSEC_INC_SCI] = { .type = NETLINK_TYPE_U8 },
[IFLA_MACSEC_ES] = { .type = NETLINK_TYPE_U8 },
[IFLA_MACSEC_SCB] = { .type = NETLINK_TYPE_U8 },
[IFLA_MACSEC_REPLAY_PROTECT] = { .type = NETLINK_TYPE_U8 },
[IFLA_MACSEC_VALIDATION] = { .type = NETLINK_TYPE_U8 },
};

/* these strings must match the .kind entries in the kernel */
static const char* const nl_union_link_info_data_table[] = {
[NL_UNION_LINK_INFO_DATA_BOND] = "bond",
Expand Down Expand Up @@ -340,6 +357,7 @@ static const char* const nl_union_link_info_data_table[] = {
[NL_UNION_LINK_INFO_DATA_WIREGUARD] = "wireguard",
[NL_UNION_LINK_INFO_DATA_NETDEVSIM] = "netdevsim",
[NL_UNION_LINK_INFO_DATA_CAN] = "can",
[NL_UNION_LINK_INFO_DATA_MACSEC] = "macsec",
};

DEFINE_STRING_TABLE_LOOKUP(nl_union_link_info_data, NLUnionLinkInfoData);
Expand Down Expand Up @@ -389,6 +407,8 @@ static const NLTypeSystem rtnl_link_info_data_type_systems[] = {
.types = rtnl_link_info_data_vxcan_types },
[NL_UNION_LINK_INFO_DATA_CAN] = { .count = ELEMENTSOF(rtnl_link_info_data_can_types),
.types = rtnl_link_info_data_can_types },
[NL_UNION_LINK_INFO_DATA_MACSEC] = { .count = ELEMENTSOF(rtnl_link_info_data_macsec_types),
.types = rtnl_link_info_data_macsec_types },
};

static const NLTypeSystemUnion rtnl_link_info_data_type_system_union = {
Expand Down Expand Up @@ -849,11 +869,76 @@ static const NLTypeSystem genl_l2tp_tunnel_session_type_system = {
.types = genl_l2tp,
};

static const NLType genl_rxsc_types[] = {
[MACSEC_RXSC_ATTR_SCI] = { .type = NETLINK_TYPE_U64 },
};

static const NLTypeSystem genl_rxsc_config_type_system = {
.count = ELEMENTSOF(genl_rxsc_types),
.types = genl_rxsc_types,
};

static const NLType genl_macsec_rxsc_types[] = {
[MACSEC_ATTR_IFINDEX] = { .type = NETLINK_TYPE_U32 },
[MACSEC_ATTR_RXSC_CONFIG] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_rxsc_config_type_system },
};

static const NLTypeSystem genl_macsec_rxsc_type_system = {
.count = ELEMENTSOF(genl_macsec_rxsc_types),
.types = genl_macsec_rxsc_types,
};

static const NLType genl_macsec_sa_config_types[] = {
[MACSEC_SA_ATTR_AN] = { .type = NETLINK_TYPE_U8 },
[MACSEC_SA_ATTR_ACTIVE] = { .type = NETLINK_TYPE_U8 },
[MACSEC_SA_ATTR_PN] = { .type = NETLINK_TYPE_U32 },
[MACSEC_SA_ATTR_KEYID] = { .size = MACSEC_KEYID_LEN },
[MACSEC_SA_ATTR_KEY] = { .size = MACSEC_MAX_KEY_LEN },
};

static const NLTypeSystem genl_macsec_sa_config_type_system = {
.count = ELEMENTSOF(genl_macsec_sa_config_types),
.types = genl_macsec_sa_config_types,
};

static const NLType genl_macsec_rxsa_types[] = {
[MACSEC_ATTR_IFINDEX] = { .type = NETLINK_TYPE_U32 },
[MACSEC_ATTR_SA_CONFIG] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_macsec_sa_config_type_system },
};

static const NLTypeSystem genl_macsec_rxsa_type_system = {
.count = ELEMENTSOF(genl_macsec_rxsa_types),
.types = genl_macsec_rxsa_types,
};

static const NLType genl_macsec_sa_types[] = {
[MACSEC_ATTR_IFINDEX] = { .type = NETLINK_TYPE_U32 },
[MACSEC_ATTR_RXSC_CONFIG] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_rxsc_config_type_system },
[MACSEC_ATTR_SA_CONFIG] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_macsec_sa_config_type_system },
};

static const NLTypeSystem genl_macsec_sa_type_system = {
.count = ELEMENTSOF(genl_macsec_sa_types),
.types = genl_macsec_sa_types,
};

static const NLType genl_macsec[] = {
[MACSEC_CMD_ADD_RXSC] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_macsec_rxsc_type_system },
[MACSEC_CMD_ADD_TXSA] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_macsec_rxsa_type_system},
[MACSEC_CMD_ADD_RXSA] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_macsec_sa_type_system },
};

static const NLTypeSystem genl_macsec_device_type_system = {
.count = ELEMENTSOF(genl_macsec),
.types = genl_macsec,
};

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 },
[SD_GENL_FOU] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_fou_cmds_type_system},
[SD_GENL_L2TP] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_l2tp_tunnel_session_type_system },
[SD_GENL_MACSEC] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_macsec_device_type_system },
};

const NLTypeSystem genl_family_type_system_root = {
Expand Down
1 change: 1 addition & 0 deletions src/libsystemd/sd-netlink/netlink-types.h
Expand Up @@ -80,6 +80,7 @@ typedef enum NLUnionLinkInfoData {
NL_UNION_LINK_INFO_DATA_WIREGUARD,
NL_UNION_LINK_INFO_DATA_NETDEVSIM,
NL_UNION_LINK_INFO_DATA_CAN,
NL_UNION_LINK_INFO_DATA_MACSEC,
_NL_UNION_LINK_INFO_DATA_MAX,
_NL_UNION_LINK_INFO_DATA_INVALID = -1
} NLUnionLinkInfoData;
Expand Down
2 changes: 2 additions & 0 deletions src/network/meson.build
Expand Up @@ -39,6 +39,8 @@ sources = files('''
netdev/fou-tunnel.h
netdev/l2tp-tunnel.c
netdev/l2tp-tunnel.h
netdev/macsec.c
netdev/macsec.h
networkd-address-label.c
networkd-address-label.h
networkd-address-pool.c
Expand Down

0 comments on commit 19196a5

Please sign in to comment.