summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Poessinger <christian@poessinger.com>2020-12-29 11:34:40 +0100
committerChristian Poessinger <christian@poessinger.com>2020-12-29 11:51:28 +0100
commitd59354e52a8a7fbdd6bb0a020f50600d64c799a9 (patch)
tree5bc44f1b8ca1dbb38a138ac8fc62645bc308e831
parent5e5e87467dd6b22d1378269f4a62825b7d122a5c (diff)
downloadvyos-1x-d59354e52a8a7fbdd6bb0a020f50600d64c799a9.tar.gz
vyos-1x-d59354e52a8a7fbdd6bb0a020f50600d64c799a9.zip
ethernet: T1466: add EAPoL support
-rw-r--r--data/templates/ethernet/wpa_supplicant.conf.tmpl72
-rw-r--r--interface-definitions/include/interface-eapol.xml.i12
-rw-r--r--interface-definitions/interfaces-ethernet.xml.in3
-rw-r--r--python/vyos/configverify.py9
-rwxr-xr-xsrc/conf_mode/interfaces-ethernet.py24
5 files changed, 118 insertions, 2 deletions
diff --git a/data/templates/ethernet/wpa_supplicant.conf.tmpl b/data/templates/ethernet/wpa_supplicant.conf.tmpl
new file mode 100644
index 000000000..fe518ad45
--- /dev/null
+++ b/data/templates/ethernet/wpa_supplicant.conf.tmpl
@@ -0,0 +1,72 @@
+### Autogenerated by interfaces-ethernet.py ###
+
+# see full documentation:
+# https://w1.fi/cgit/hostap/plain/wpa_supplicant/wpa_supplicant.conf
+
+# For UNIX domain sockets (default on Linux and BSD): This is a directory that
+# will be created for UNIX domain sockets for listening to requests from
+# external programs (CLI/GUI, etc.) for status information and configuration.
+# The socket file will be named based on the interface name, so multiple
+# wpa_supplicant processes can be run at the same time if more than one
+# interface is used.
+# /var/run/wpa_supplicant is the recommended directory for sockets and by
+# default, wpa_cli will use it when trying to connect with wpa_supplicant.
+ctrl_interface=/run/wpa_supplicant
+
+# IEEE 802.1X/EAPOL version
+# wpa_supplicant is implemented based on IEEE Std 802.1X-2004 which defines
+# EAPOL version 2. However, there are many APs that do not handle the new
+# version number correctly (they seem to drop the frames completely). In order
+# to make wpa_supplicant interoperate with these APs, the version number is set
+# to 1 by default. This configuration value can be used to set it to the new
+# version (2).
+# Note: When using MACsec, eapol_version shall be set to 3, which is
+# defined in IEEE Std 802.1X-2010.
+eapol_version=2
+
+# No need to scan for access points in EAPoL mode
+ap_scan=0
+
+# EAP fast re-authentication
+fast_reauth=1
+
+network={
+{% if eapol is defined and eapol is not none %}
+{% if eapol.ca_cert_file is defined and eapol.ca_cert_file is not none %}
+ ca_cert="{{ eapol.ca_cert_file }}"
+{% endif %}
+ client_cert="{{ eapol.cert_file }}"
+ private_key="{{ eapol.key_file }}"
+{% endif %}
+
+ # list of accepted authenticated key management protocols
+ key_mgmt=IEEE8021X
+ eap=TLS
+
+{% if mac is defined and mac is not none %}
+ identity="{{ mac }}"
+{% else %}
+ identity="{{ hw_id }}"
+{% endif %}
+
+ # eapol_flags: IEEE 802.1X/EAPOL options (bit field)
+ # Dynamic WEP key required for non-WPA mode
+ # bit0 (1): require dynamically generated unicast WEP key
+ # bit1 (2): require dynamically generated broadcast WEP key
+ # (3) = require both keys; default)
+ # Note: When using wired authentication (including MACsec drivers),
+ # eapol_flags must be set to 0 for the authentication to be completed
+ # successfully.
+ eapol_flags=0
+
+ # For wired IEEE 802.1X authentication, "allow_canned_success=1" can be
+ # used to configure a mode that allows EAP-Success (and EAP-Failure) without
+ # going through authentication step. Some switches use such sequence when
+ # forcing the port to be authorized/unauthorized or as a fallback option if
+ # the authentication server is unreachable. By default, wpa_supplicant
+ # discards such frames to protect against potential attacks by rogue
+ # devices, but this option can be used to disable that protection for cases
+ # where the server/authenticator does not need to be authenticated.
+ phase1="allow_canned_success=1"
+}
+
diff --git a/interface-definitions/include/interface-eapol.xml.i b/interface-definitions/include/interface-eapol.xml.i
new file mode 100644
index 000000000..94476f0f1
--- /dev/null
+++ b/interface-definitions/include/interface-eapol.xml.i
@@ -0,0 +1,12 @@
+<!-- included start from interface-eapol.xml.i -->
+<node name="eapol">
+ <properties>
+ <help>Extensible Authentication Protocol over Local Area Network</help>
+ </properties>
+ <children>
+ #include <include/certificate.xml.i>
+ #include <include/certificate-ca.xml.i>
+ #include <include/certificate-key.xml.i>
+ </children>
+</node>
+<!-- included end -->
diff --git a/interface-definitions/interfaces-ethernet.xml.in b/interface-definitions/interfaces-ethernet.xml.in
index 5dd685c37..9564f5ab8 100644
--- a/interface-definitions/interfaces-ethernet.xml.in
+++ b/interface-definitions/interfaces-ethernet.xml.in
@@ -28,7 +28,6 @@
</leafNode>
#include <include/interface-disable-link-detect.xml.i>
#include <include/interface-disable.xml.i>
- #include <include/interface-vrf.xml.i>
<leafNode name="duplex">
<properties>
<help>Duplex mode</help>
@@ -54,6 +53,7 @@
</properties>
<defaultValue>auto</defaultValue>
</leafNode>
+ #include <include/interface-eapol.xml.i>
#include <include/interface-hw-id.xml.i>
#include <include/interface-ipv4-options.xml.i>
#include <include/interface-ipv6-options.xml.i>
@@ -187,6 +187,7 @@
</node>
#include <include/vif-s.xml.i>
#include <include/vif.xml.i>
+ #include <include/interface-vrf.xml.i>
#include <include/interface-xdp.xml.i>
</children>
</tagNode>
diff --git a/python/vyos/configverify.py b/python/vyos/configverify.py
index 675dac5b1..96eeb6bb1 100644
--- a/python/vyos/configverify.py
+++ b/python/vyos/configverify.py
@@ -89,6 +89,15 @@ def verify_vrf(config):
'Interface "{ifname}" cannot be both a member of VRF "{vrf}" '
'and bridge "{is_bridge_member}"!'.format(**config))
+def verify_eapol(config):
+ """
+ Common helper function used by interface implementations to perform
+ recurring validation of EAPoL configuration.
+ """
+ if 'eapol' in config:
+ if not {'cert_file', 'key_file'} <= set(config['eapol']):
+ raise ConfigError('Both cert and key-file must be specified '\
+ 'when using EAPoL!')
def verify_address(config):
"""
diff --git a/src/conf_mode/interfaces-ethernet.py b/src/conf_mode/interfaces-ethernet.py
index b358e9725..d8b637dd7 100755
--- a/src/conf_mode/interfaces-ethernet.py
+++ b/src/conf_mode/interfaces-ethernet.py
@@ -28,12 +28,18 @@ from vyos.configverify import verify_mtu
from vyos.configverify import verify_mtu_ipv6
from vyos.configverify import verify_vlan_config
from vyos.configverify import verify_vrf
+from vyos.configverify import verify_eapol
from vyos.ifconfig import EthernetIf
+from vyos.template import render
+from vyos.util import call
from vyos.util import dict_search
from vyos import ConfigError
from vyos import airbag
airbag.enable()
+# XXX: wpa_supplicant works on the source interface
+wpa_suppl_conf = '/run/wpa_supplicant/{ifname}.conf'
+
def get_config(config=None):
"""
Retrive CLI config as dictionary. Dictionary can never be empty, as at least the
@@ -67,6 +73,7 @@ def verify(ethernet):
verify_dhcpv6(ethernet)
verify_address(ethernet)
verify_vrf(ethernet)
+ verify_eapol(ethernet)
# XDP requires multiple TX queues
if 'xdp' in ethernet:
@@ -83,16 +90,31 @@ def verify(ethernet):
return None
def generate(ethernet):
+ if 'eapol' in ethernet:
+ render(wpa_suppl_conf.format(**ethernet),
+ 'ethernet/wpa_supplicant.conf.tmpl', ethernet)
+ else:
+ # delete configuration on interface removal
+ if os.path.isfile(wpa_suppl_conf.format(**ethernet)):
+ os.unlink(wpa_suppl_conf.format(**ethernet))
+
return None
def apply(ethernet):
- e = EthernetIf(ethernet['ifname'])
+ ifname = ethernet['ifname']
+ # take care about EAPoL supplicant daemon
+ eapol_action='stop'
+
+ e = EthernetIf(ifname)
if 'deleted' in ethernet:
# delete interface
e.remove()
else:
e.update(ethernet)
+ if 'eapol' in ethernet:
+ eapol_action='restart'
+ call(f'systemctl {eapol_action} wpa_supplicant-macsec@{ifname}')
if __name__ == '__main__':
try: