From 9b396f7cc8a7227183af387be4e4cc17fe72e1e2 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 26 Sep 2022 13:45:35 +0200 Subject: [PATCH] nmtui: add MACsec support --- Makefile.am | 2 + src/nmtui/meson.build | 1 + src/nmtui/nm-editor-utils.c | 8 + src/nmtui/nmt-connect-connection-list.c | 1 + src/nmtui/nmt-editor.c | 3 + src/nmtui/nmt-page-macsec.c | 196 ++++++++++++++++++++++++ src/nmtui/nmt-page-macsec.h | 28 ++++ 7 files changed, 239 insertions(+) create mode 100644 src/nmtui/nmt-page-macsec.c create mode 100644 src/nmtui/nmt-page-macsec.h diff --git a/Makefile.am b/Makefile.am index 73f1bc1cde..58c99be085 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5104,6 +5104,8 @@ src_nmtui_nmtui_SOURCES = \ src/nmtui/nmt-page-ip4.h \ src/nmtui/nmt-page-ip6.c \ src/nmtui/nmt-page-ip6.h \ + src/nmtui/nmt-page-macsec.c \ + src/nmtui/nmt-page-macsec.h \ src/nmtui/nmt-page-ppp.c \ src/nmtui/nmt-page-ppp.h \ src/nmtui/nmt-page-team-port.c \ diff --git a/src/nmtui/meson.build b/src/nmtui/meson.build index dd6484baf6..48f2fbf47e 100644 --- a/src/nmtui/meson.build +++ b/src/nmtui/meson.build @@ -28,6 +28,7 @@ executable( 'nmt-page-ip4.c', 'nmt-page-ip6.c', 'nmt-page-ip-tunnel.c', + 'nmt-page-macsec.c', 'nmt-page-ppp.c', 'nmt-page-team.c', 'nmt-page-team-port.c', diff --git a/src/nmtui/nm-editor-utils.c b/src/nmtui/nm-editor-utils.c index a3ee7a75de..0f69c9627d 100644 --- a/src/nmtui/nm-editor-utils.c +++ b/src/nmtui/nm-editor-utils.c @@ -235,6 +235,14 @@ nm_editor_utils_get_connection_type_list(void) item->id_format = _("IP tunnel connection %d"); g_ptr_array_add(array, item); + item = g_new0(NMEditorConnectionTypeDataReal, 1); + item->data.name = _("MACsec"); + item->data.setting_type = NM_TYPE_SETTING_MACSEC; + item->data.device_type = NM_TYPE_DEVICE_MACSEC; + item->data.virtual = TRUE; + item->id_format = _("MACsec connection %d"); + g_ptr_array_add(array, item); + #if 0 /* Add "VPN" only if there are plugins */ vpn_plugins_hash = nm_vpn_get_plugin_infos (); diff --git a/src/nmtui/nmt-connect-connection-list.c b/src/nmtui/nmt-connect-connection-list.c index f111e6572b..5d771b618e 100644 --- a/src/nmtui/nmt-connect-connection-list.c +++ b/src/nmtui/nmt-connect-connection-list.c @@ -100,6 +100,7 @@ static const char *device_sort_order[] = {"NMDeviceEthernet", NM_SETTING_TEAM_SETTING_NAME, NM_SETTING_BRIDGE_SETTING_NAME, NM_SETTING_IP_TUNNEL_SETTING_NAME, + NM_SETTING_MACSEC_SETTING_NAME, NM_SETTING_WIREGUARD_SETTING_NAME, NM_SETTING_TUN_SETTING_NAME, "NMDeviceModem", diff --git a/src/nmtui/nmt-editor.c b/src/nmtui/nmt-editor.c index 427ac0178b..9a64333afc 100644 --- a/src/nmtui/nmt-editor.c +++ b/src/nmtui/nmt-editor.c @@ -35,6 +35,7 @@ #include "nmt-page-ip-tunnel.h" #include "nmt-page-ip4.h" #include "nmt-page-ip6.h" +#include "nmt-page-macsec.h" #include "nmt-page-ppp.h" #include "nmt-page-team.h" #include "nmt-page-team-port.h" @@ -362,6 +363,8 @@ nmt_editor_constructed(GObject *object) page = nmt_page_bridge_new(priv->edit_connection, deventry); else if (nm_connection_is_type(priv->edit_connection, NM_SETTING_INFINIBAND_SETTING_NAME)) page = nmt_page_infiniband_new(priv->edit_connection, deventry); + else if (nm_connection_is_type(priv->edit_connection, NM_SETTING_MACSEC_SETTING_NAME)) + page = nmt_page_macsec_new(priv->edit_connection, deventry); else if (nm_connection_is_type(priv->edit_connection, NM_SETTING_PPPOE_SETTING_NAME)) page = nmt_page_dsl_new(priv->edit_connection, deventry); else if (nm_connection_is_type(priv->edit_connection, NM_SETTING_TEAM_SETTING_NAME)) diff --git a/src/nmtui/nmt-page-macsec.c b/src/nmtui/nmt-page-macsec.c new file mode 100644 index 0000000000..6a0174868c --- /dev/null +++ b/src/nmtui/nmt-page-macsec.c @@ -0,0 +1,196 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2022 Red Hat, Inc. + */ +/** + * SECTION:nmt-page-macsec + * @short_description: The editor page for MACsec connections + */ + +#include "libnm-client-aux-extern/nm-default-client.h" + +#include "nmt-page-macsec.h" + +#include "libnm-core-aux-intern/nm-libnm-core-utils.h" +#include "nmt-device-entry.h" +#include "nmt-password-fields.h" +#include "nmt-8021x-fields.h" + +typedef struct { + NMSetting8021x *s_8021x; +} NmtPageMacsecPrivate; + +struct _NmtPageMacsec { + NmtEditorPageDevice parent; + NmtPageMacsecPrivate _priv; +}; + +struct _NmtPageMacsecClass { + NmtEditorPageDeviceClass parent; +}; + +G_DEFINE_TYPE(NmtPageMacsec, nmt_page_macsec, NMT_TYPE_EDITOR_PAGE_DEVICE) + +#define NMT_PAGE_MACSEC_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NmtPageMacsec, NMT_IS_PAGE_MACSEC) + +static void +nmt_page_macsec_init(NmtPageMacsec *macsec) +{} + +NmtEditorPage * +nmt_page_macsec_new(NMConnection *conn, NmtDeviceEntry *deventry) +{ + return g_object_new(NMT_TYPE_PAGE_MACSEC, "connection", conn, "device-entry", deventry, NULL); +} + +static void +macsec_mode_changed(NmtNewtWidget *widget, GParamSpec *pspec, gpointer user_data) +{ + NmtPageMacsec *macsec = user_data; + NmtPageMacsecPrivate *priv = NMT_PAGE_MACSEC_GET_PRIVATE(macsec); + NMConnection *conn; + gboolean mode_eap; + gboolean has_setting; + + conn = nmt_editor_page_get_connection(NMT_EDITOR_PAGE(macsec)); + has_setting = !!nm_connection_get_setting(conn, NM_TYPE_SETTING_802_1X); + mode_eap = nmt_newt_popup_get_active(NMT_NEWT_POPUP(widget)) == NM_SETTING_MACSEC_MODE_EAP; + + if (mode_eap != has_setting) { + if (mode_eap) + nm_connection_add_setting(conn, NM_SETTING(priv->s_8021x)); + else + nm_connection_remove_setting(conn, NM_TYPE_SETTING_802_1X); + } +} + +static NmtNewtPopupEntry macsec_mode[] = {{N_("PSK"), "psk"}, {N_("EAP"), "eap"}, {NULL, NULL}}; + +static NmtNewtPopupEntry macsec_validation[] = {{N_("Disabled"), "disabled"}, + {N_("Check"), "check"}, + {N_("Strict"), "strict"}, + {NULL, NULL}}; + +static void +nmt_page_macsec_constructed(GObject *object) +{ + NmtPageMacsec *macsec = NMT_PAGE_MACSEC(object); + NmtPageMacsecPrivate *priv = NMT_PAGE_MACSEC_GET_PRIVATE(macsec); + NMConnection *conn; + NMSettingMacsec *s_macsec; + NMSetting8021x *s_8021x; + NmtNewtStack *stack; + NmtEditorSection *section; + NmtEditorGrid *grid; + NmtNewtWidget *subgrid; + NmtNewtWidget *widget; + NmtNewtWidget *mode; + + conn = nmt_editor_page_get_connection(NMT_EDITOR_PAGE(macsec)); + s_macsec = _nm_connection_ensure_setting(conn, NM_TYPE_SETTING_MACSEC); + + s_8021x = nm_connection_get_setting_802_1x(conn); + if (!s_8021x) { + s_8021x = NM_SETTING_802_1X(nm_setting_802_1x_new()); + nm_setting_802_1x_add_eap_method(s_8021x, "MD5"); + } + priv->s_8021x = g_object_ref(s_8021x); + + section = nmt_editor_section_new(_("MACsec"), NULL, TRUE); + grid = nmt_editor_section_get_body(section); + + widget = nmt_device_entry_new(_("Parent device"), 40, G_TYPE_NONE); + g_object_bind_property(s_macsec, + NM_SETTING_MACSEC_PARENT, + widget, + "interface-name", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + nmt_editor_grid_append(grid, NULL, widget, NULL); + + nmt_editor_grid_append(grid, NULL, nmt_newt_separator_new(), NULL); + + widget = nmt_newt_popup_new((NmtNewtPopupEntry *) &macsec_mode); + nmt_editor_grid_append(grid, _("Mode"), widget, NULL); + mode = widget; + + widget = nmt_newt_stack_new(); + stack = NMT_NEWT_STACK(widget); + + /* PSK stack grid */ + subgrid = nmt_editor_grid_new(); + widget = + nmt_password_fields_new(40, + NMT_PASSWORD_FIELDS_SHOW_PASSWORD | NMT_PASSWORD_FIELDS_NOT_EMPTY); + g_object_bind_property(s_macsec, + NM_SETTING_MACSEC_MKA_CAK, + widget, + "password", + G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); + nmt_editor_grid_append(NMT_EDITOR_GRID(subgrid), _("CAK"), widget, NULL); + + widget = nmt_newt_entry_new(40, 0); + nmt_editor_grid_append(NMT_EDITOR_GRID(subgrid), _("CKN"), widget, NULL); + g_object_bind_property(s_macsec, + NM_SETTING_MACSEC_MKA_CKN, + widget, + "text", + G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); + + nmt_newt_stack_add(stack, "psk", subgrid); + + /* EAP stack grid */ + subgrid = nmt_editor_grid_new(); + widget = NMT_NEWT_WIDGET(nmt_8021x_fields_new(s_8021x, TRUE)); + nmt_editor_grid_append(NMT_EDITOR_GRID(subgrid), NULL, widget, NULL); + nmt_newt_stack_add(stack, "eap", subgrid); + + g_object_bind_property(mode, "active-id", stack, "active-id", G_BINDING_SYNC_CREATE); + nmt_editor_grid_append(grid, NULL, NMT_NEWT_WIDGET(stack), NULL); + + g_object_bind_property(s_macsec, + NM_SETTING_MACSEC_MODE, + mode, + "active", + G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); + g_signal_connect(mode, "notify::active", G_CALLBACK(macsec_mode_changed), macsec); + macsec_mode_changed(mode, NULL, macsec); + + nmt_editor_grid_append(grid, NULL, nmt_newt_separator_new(), NULL); + + /* Other MACsec options */ + widget = nmt_newt_popup_new((NmtNewtPopupEntry *) &macsec_validation); + nmt_editor_grid_append(grid, _("Validation"), widget, NULL); + g_object_bind_property(s_macsec, + NM_SETTING_MACSEC_VALIDATION, + widget, + "active", + G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); + + widget = nmt_newt_entry_new(40, 0); + nmt_editor_grid_append(grid, _("SCI port"), widget, NULL); + g_object_bind_property(s_macsec, + NM_SETTING_MACSEC_PORT, + widget, + "text", + G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); + + widget = nmt_newt_checkbox_new(_("Encrypt traffic")); + nmt_editor_grid_append(grid, NULL, widget, NULL); + g_object_bind_property(s_macsec, + NM_SETTING_MACSEC_ENCRYPT, + widget, + "active", + G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); + + nmt_editor_page_add_section(NMT_EDITOR_PAGE(macsec), section); + + G_OBJECT_CLASS(nmt_page_macsec_parent_class)->constructed(object); +} + +static void +nmt_page_macsec_class_init(NmtPageMacsecClass *macsec_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS(macsec_class); + + object_class->constructed = nmt_page_macsec_constructed; +} diff --git a/src/nmtui/nmt-page-macsec.h b/src/nmtui/nmt-page-macsec.h new file mode 100644 index 0000000000..5427c71571 --- /dev/null +++ b/src/nmtui/nmt-page-macsec.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2022 Red Hat, Inc. + */ + +#ifndef NMT_PAGE_MACSEC_H +#define NMT_PAGE_MACSEC_H + +#include "nmt-editor-page-device.h" + +#define NMT_TYPE_PAGE_MACSEC (nmt_page_macsec_get_type()) +#define NMT_PAGE_MACSEC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), NMT_TYPE_PAGE_MACSEC, NmtPageMacsec)) +#define NMT_PAGE_MACSEC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), NMT_TYPE_PAGE_MACSEC, NmtPageMacsecClass)) +#define NMT_IS_PAGE_MACSEC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NMT_TYPE_PAGE_MACSEC)) +#define NMT_IS_PAGE_MACSEC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NMT_TYPE_PAGE_MACSEC)) +#define NMT_PAGE_MACSEC_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), NMT_TYPE_PAGE_MACSEC, NmtPageMacsecClass)) + +typedef struct _NmtPageMacsec NmtPageMacsec; +typedef struct _NmtPageMacsecClass NmtPageMacsecClass; + +GType nmt_page_macsec_get_type(void); + +NmtEditorPage *nmt_page_macsec_new(NMConnection *conn, NmtDeviceEntry *deventry); + +#endif /* NMT_PAGE_MACSEC_H */