[NetworkManager-openvpn/wip/ernestask/allow-compression] Implement allow-compression support




commit 3d3c0677ed99b451228d9e05a4ef7b34b5ff1cc3
Author: Ernestas Kulik <ernestas@baltic.engineering>
Date:   Fri Jul 29 21:06:03 2022 +0300

    Implement allow-compression support
    
    OpenVPN 2.5 grew a new option for controlling compression:
    allow-compression, which can completely enable or disable it or enable
    it only for incoming traffic. Without supporting the option, some
    configurations are unreadable.

 properties/import-export.c            | 40 ++++++++++++-----
 properties/nm-openvpn-dialog.ui       | 38 +++++++++++++++-
 properties/nm-openvpn-editor.c        | 21 ++++++++-
 properties/tests/conf/compress.ovpn   |  1 +
 properties/tests/test-import-export.c |  1 +
 shared/nm-service-defines.h           |  1 +
 shared/utils.c                        | 32 ++++++++++++++
 shared/utils.h                        | 11 +++++
 src/nm-openvpn-service.c              | 83 +++++++++++++++++++++--------------
 9 files changed, 182 insertions(+), 46 deletions(-)
---
diff --git a/properties/import-export.c b/properties/import-export.c
index 11db39e..db453e9 100644
--- a/properties/import-export.c
+++ b/properties/import-export.c
@@ -999,6 +999,19 @@ do_import (const char *path, const char *contents, gsize contents_len, GError **
                        continue;
                }
 
+               if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_ALLOW_COMPRESSION)) {
+                       if (!args_params_check_nargs_minmax (params, 1, 1, &line_error))
+                               goto handle_line_error;
+
+                       if (!NM_IN_STRSET (params[1], "yes", "no", "asym")) {
+                               line_error = g_strdup_printf (_("allow-compression: invalid argument"));
+                               goto handle_line_error;
+                       }
+
+                       setting_vpn_add_data_item (s_vpn, NM_OPENVPN_KEY_ALLOW_COMPRESSION, params[1]);
+                       continue;
+               }
+
                if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_COMP_LZO)) {
                        const char *v;
 
@@ -2097,18 +2110,23 @@ do_export_create (NMConnection *connection, const char *path, GError **error)
 
        args_write_line_setting_value_int (f, NMV_OVPN_TAG_KEYSIZE, s_vpn, NM_OPENVPN_KEY_KEYSIZE);
 
-       value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_COMP_LZO);
-       if (value) {
-               if (nm_streq (value, "no-by-default"))
-                       value = "no";
-               args_write_line (f, NMV_OVPN_TAG_COMP_LZO, value);
-       }
+       args_write_line_setting_value (f, NMV_OVPN_TAG_ALLOW_COMPRESSION, s_vpn, 
NM_OPENVPN_KEY_ALLOW_COMPRESSION);
 
-       value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_COMPRESS);
-       if (nm_streq0 (value, "yes"))
-               args_write_line (f, NMV_OVPN_TAG_COMPRESS);
-       else if (value)
-               args_write_line_setting_value (f, NMV_OVPN_TAG_COMPRESS, s_vpn, NM_OPENVPN_KEY_COMPRESS);
+       value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_ALLOW_COMPRESSION);
+       if (!nm_streq0 (value, "no")) {
+               value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_COMP_LZO);
+               if (value) {
+                       if (nm_streq (value, "no-by-default"))
+                               value = "no";
+                       args_write_line (f, NMV_OVPN_TAG_COMP_LZO, value);
+               }
+
+               value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_COMPRESS);
+               if (nm_streq0 (value, "yes"))
+                       args_write_line (f, NMV_OVPN_TAG_COMPRESS);
+               else if (value)
+                       args_write_line_setting_value (f, NMV_OVPN_TAG_COMPRESS, s_vpn, 
NM_OPENVPN_KEY_COMPRESS);
+       }
 
        if (nm_streq0 (nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_FLOAT), "yes"))
                args_write_line (f, NMV_OVPN_TAG_FLOAT);
diff --git a/properties/nm-openvpn-dialog.ui b/properties/nm-openvpn-dialog.ui
index 24d36f5..9e4fdfe 100644
--- a/properties/nm-openvpn-dialog.ui
+++ b/properties/nm-openvpn-dialog.ui
@@ -64,6 +64,19 @@
     <property name="step_increment">1</property>
     <property name="page_increment">10</property>
   </object>
+  <object class="GtkListStore" id="compression-direction">
+    <columns>
+      <column type="gchararray"/>
+    </columns>
+    <data>
+      <row>
+        <col id="0" translatable="yes">Asymmetric</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Symmetric</col>
+      </row>
+    </data>
+  </object>
   <object class="GtkListStore" id="compression">
     <columns>
       <!-- column-name gchararray -->
@@ -1078,6 +1091,29 @@ config: comp-lzo</property>
                         <property name="position">0</property>
                       </packing>
                     </child>
+                    <child>
+                      <object class="GtkComboBox" id="compression-direction-combo">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="tooltip-text" translatable="yes">Enable or disable outgoing traffic 
compression
+config: allow-compression asym|yes</property>
+                        <property name="model">compression-direction</property>
+                        <property name="active">0</property>
+                        <property name="id_column">0</property>
+                        <property name="sensitive" bind-source="compress_checkbutton" bind-property="active" 
bind-flags="sync-create">false</property>
+                        <child>
+                          <object class="GtkCellRendererText"/>
+                          <attributes>
+                            <attribute name="text">0</attribute>
+                          </attributes>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
                     <child>
                       <object class="GtkComboBox" id="compress_combo">
                         <property name="visible">True</property>
@@ -1095,7 +1131,7 @@ config: comp-lzo</property>
                       <packing>
                         <property name="expand">False</property>
                         <property name="fill">True</property>
-                        <property name="position">1</property>
+                        <property name="position">2</property>
                       </packing>
                     </child>
                   </object>
diff --git a/properties/nm-openvpn-editor.c b/properties/nm-openvpn-editor.c
index 64978f2..3d4c2d9 100644
--- a/properties/nm-openvpn-editor.c
+++ b/properties/nm-openvpn-editor.c
@@ -1565,6 +1565,7 @@ advanced_dialog_new (GHashTable *hash, const char *contype)
        NMSettingSecretFlags pw_flags;
        GError *error = NULL;
        NMOvpnComp comp;
+       NMOvpnAllowCompression allow_compression;
 
        g_return_val_if_fail (hash != NULL, NULL);
 
@@ -1682,11 +1683,18 @@ advanced_dialog_new (GHashTable *hash, const char *contype)
        _builder_init_optional_spinbutton (builder, "fragment_checkbutton", "fragment_spinbutton", !!value,
                                           _nm_utils_ascii_str_to_int64 (value, 10, 0, 65535, 1300));
 
+       allow_compression = nmovpn_allow_compression_from_options (g_hash_table_lookup (hash, 
NM_OPENVPN_KEY_ALLOW_COMPRESSION));
+       combo = GTK_WIDGET (gtk_builder_get_object (builder, "compression-direction-combo"));
+
+       if (allow_compression != NMOVPN_ALLOW_COMPRESSION_NO)
+               gtk_combo_box_set_active (GTK_COMBO_BOX (combo), allow_compression - 1);
+
        comp = nmovpn_compression_from_options (g_hash_table_lookup (hash, NM_OPENVPN_KEY_COMP_LZO),
                                                g_hash_table_lookup (hash, NM_OPENVPN_KEY_COMPRESS));
 
        combo = GTK_WIDGET (gtk_builder_get_object (builder, "compress_combo"));
-       widget = _builder_init_toggle_button (builder, "compress_checkbutton", comp != NMOVPN_COMP_DISABLED);
+       widget = _builder_init_toggle_button (builder, "compress_checkbutton",
+                                             (allow_compression != NMOVPN_ALLOW_COMPRESSION_NO && comp != 
NMOVPN_COMP_DISABLED));
        g_object_bind_property (widget, "active", combo, "sensitive", G_BINDING_SYNC_CREATE);
        if (comp != NMOVPN_COMP_DISABLED)
                gtk_combo_box_set_active (GTK_COMBO_BOX (combo), comp - 1);
@@ -2094,9 +2102,17 @@ advanced_dialog_new_hash_from_dialog (GtkWidget *dialog)
 
        widget = GTK_WIDGET (gtk_builder_get_object (builder, "compress_checkbutton"));
        if (gtk_check_button_get_active (GTK_CHECK_BUTTON (widget))) {
+               const char *opt_allow_compression;
                const char *opt_compress;
                const char *opt_comp_lzo;
                NMOvpnComp comp;
+               NMOvpnAllowCompression allow_compression;
+
+               combo = GTK_WIDGET (gtk_builder_get_object (builder, "compression-direction-combo"));
+               allow_compression = gtk_combo_box_get_active (GTK_COMBO_BOX (combo)) + 1;
+               nmovpn_allow_compression_to_options (allow_compression, &opt_allow_compression);
+               if (opt_allow_compression)
+                       g_hash_table_insert (hash, NM_OPENVPN_KEY_ALLOW_COMPRESSION, g_strdup 
(opt_allow_compression));
 
                combo = GTK_WIDGET (gtk_builder_get_object (builder, "compress_combo"));
                comp = gtk_combo_box_get_active (GTK_COMBO_BOX (combo)) + 1;
@@ -2105,7 +2121,8 @@ advanced_dialog_new_hash_from_dialog (GtkWidget *dialog)
                        g_hash_table_insert (hash, NM_OPENVPN_KEY_COMPRESS, g_strdup (opt_compress));
                if (opt_comp_lzo)
                        g_hash_table_insert (hash, NM_OPENVPN_KEY_COMP_LZO, g_strdup (opt_comp_lzo));
-       }
+       } else
+               g_hash_table_insert (hash, NM_OPENVPN_KEY_ALLOW_COMPRESSION, g_strdup ("no"));
 
        widget = GTK_WIDGET (gtk_builder_get_object (builder, "mssfix_checkbutton"));
        if (gtk_check_button_get_active (GTK_CHECK_BUTTON (widget)))
diff --git a/properties/tests/conf/compress.ovpn b/properties/tests/conf/compress.ovpn
index 72a06b1..9d89b51 100644
--- a/properties/tests/conf/compress.ovpn
+++ b/properties/tests/conf/compress.ovpn
@@ -3,5 +3,6 @@ dev tun
 client
 ca ca.crt
 
+allow-compression asym
 comp-lzo
 compress lzo
diff --git a/properties/tests/test-import-export.c b/properties/tests/test-import-export.c
index 3fd6412..fdc9e50 100644
--- a/properties/tests/test-import-export.c
+++ b/properties/tests/test-import-export.c
@@ -1045,6 +1045,7 @@ test_compress_import (void)
 
        s_vpn = nm_connection_get_setting_vpn (connection);
 
+       _check_item (s_vpn, NM_OPENVPN_KEY_ALLOW_COMPRESSION, "asym");
        _check_item (s_vpn, NM_OPENVPN_KEY_COMP_LZO, "adaptive");
        _check_item (s_vpn, NM_OPENVPN_KEY_COMPRESS, "lzo");
 }
diff --git a/shared/nm-service-defines.h b/shared/nm-service-defines.h
index bd12ec3..c63c255 100644
--- a/shared/nm-service-defines.h
+++ b/shared/nm-service-defines.h
@@ -29,6 +29,7 @@
 #define NM_DBUS_INTERFACE_OPENVPN  "org.freedesktop.NetworkManager.openvpn"
 #define NM_DBUS_PATH_OPENVPN       "/org/freedesktop/NetworkManager/openvpn"
 
+#define NM_OPENVPN_KEY_ALLOW_COMPRESSION         "allow-compression"
 #define NM_OPENVPN_KEY_ALLOW_PULL_FQDN           "allow-pull-fqdn"
 #define NM_OPENVPN_KEY_AUTH                      "auth"
 #define NM_OPENVPN_KEY_CA                        "ca"
diff --git a/shared/utils.c b/shared/utils.c
index 3ade7d8..133da87 100644
--- a/shared/utils.c
+++ b/shared/utils.c
@@ -113,6 +113,38 @@ _is_inet6_addr (const char *str, gboolean with_square_brackets)
        return inet_pton (AF_INET6, str, &a) == 1;
 }
 
+NMOvpnAllowCompression
+nmovpn_allow_compression_from_options (const char *allow_compression)
+{
+    if (nm_streq0 (allow_compression, "asym"))
+               return NMOVPN_ALLOW_COMPRESSION_ASYM;
+       if (nm_streq0 (allow_compression, "yes"))
+               return NMOVPN_ALLOW_COMPRESSION_YES;
+       if (nm_streq0 (allow_compression, "no"))
+               return NMOVPN_ALLOW_COMPRESSION_NO;
+
+       return NMOVPN_ALLOW_COMPRESSION_ASYM;
+}
+
+void
+nmovpn_allow_compression_to_options (NMOvpnAllowCompression allow_compression,
+                                     const char **opt_allow_compression)
+{
+    NM_SET_OUT (opt_allow_compression, NULL);
+
+    switch (allow_compression) {
+    case NMOVPN_ALLOW_COMPRESSION_ASYM:
+        NM_SET_OUT (opt_allow_compression, "asym");
+        break;
+    case NMOVPN_ALLOW_COMPRESSION_YES:
+        NM_SET_OUT (opt_allow_compression, "yes");
+        break;
+    case NMOVPN_ALLOW_COMPRESSION_NO:
+        NM_SET_OUT (opt_allow_compression, "no");
+        break;
+    }
+}
+
 NMOvpnComp
 nmovpn_compression_from_options (const char *comp_lzo, const char *compress)
 {
diff --git a/shared/utils.h b/shared/utils.h
index 69c4957..064da72 100644
--- a/shared/utils.h
+++ b/shared/utils.h
@@ -23,6 +23,7 @@
 #ifndef UTILS_H
 #define UTILS_H
 
+#define NMV_OVPN_TAG_ALLOW_COMPRESSION      "allow-compression"
 #define NMV_OVPN_TAG_ALLOW_PULL_FQDN        "allow-pull-fqdn"
 #define NMV_OVPN_TAG_AUTH                   "auth"
 #define NMV_OVPN_TAG_AUTH_NOCACHE           "auth-nocache"
@@ -99,6 +100,12 @@ typedef enum {
        NMOVPN_COMP_LEGACY_LZO_ADAPTIVE,  /* "--comp-lzo [adaptive]" */
 } NMOvpnComp;
 
+typedef enum {
+       NMOVPN_ALLOW_COMPRESSION_NO,   /* "--allow-compression no" */
+       NMOVPN_ALLOW_COMPRESSION_ASYM, /* "--allow-compression asym" */
+       NMOVPN_ALLOW_COMPRESSION_YES,  /* "--allow-compression yes" */
+} NMOvpnAllowCompression;
+
 gboolean is_pkcs12 (const char *filepath);
 
 gboolean is_encrypted (const char *filename);
@@ -127,6 +134,10 @@ nmovpn_arg_is_set (const char *value)
        return (value && value[0]) ? value : NULL;
 }
 
+NMOvpnAllowCompression nmovpn_allow_compression_from_options (const char              *allow_compression);
+void                   nmovpn_allow_compression_to_options   (NMOvpnAllowCompression   allow_compression,
+                                                              const char             
**opt_allow_compression);
+
 NMOvpnComp nmovpn_compression_from_options (const char *comp_lzo,
                                             const char *compress);
 void nmovpn_compression_to_options (NMOvpnComp comp,
diff --git a/src/nm-openvpn-service.c b/src/nm-openvpn-service.c
index 3731e89..e4045b5 100644
--- a/src/nm-openvpn-service.c
+++ b/src/nm-openvpn-service.c
@@ -89,6 +89,7 @@ typedef enum {
        OPENVPN_BINARY_VERSION_INVALID,
        OPENVPN_BINARY_VERSION_UNKNOWN,
        OPENVPN_BINARY_VERSION_2_3_OR_OLDER,
+       OPENVPN_BINARY_VERSION_2_4_OR_OLDER,
        OPENVPN_BINARY_VERSION_2_4_OR_NEWER,
 } OpenvpnBinaryVersion;
 
@@ -138,6 +139,7 @@ typedef struct {
 } ValidProperty;
 
 static const ValidProperty valid_properties[] = {
+       { NM_OPENVPN_KEY_ALLOW_COMPRESSION,         G_TYPE_STRING, 0, 0, FALSE },
        { NM_OPENVPN_KEY_ALLOW_PULL_FQDN,           G_TYPE_BOOLEAN, 0, 0, FALSE },
        { NM_OPENVPN_KEY_AUTH,                      G_TYPE_STRING, 0, 0, FALSE },
        { NM_OPENVPN_KEY_CA,                        G_TYPE_STRING, 0, 0, FALSE },
@@ -576,6 +578,9 @@ openvpn_binary_detect_version (const char *exepath)
 
        if (n <= 3)
                return OPENVPN_BINARY_VERSION_2_3_OR_OLDER;
+       if (n <= 4)
+               return OPENVPN_BINARY_VERSION_2_4_OR_OLDER;
+
        return OPENVPN_BINARY_VERSION_2_4_OR_NEWER;
 }
 
@@ -1339,6 +1344,7 @@ nm_openvpn_start_openvpn_binary (NMOpenvpnPlugin *plugin,
        GPid pid;
        gboolean dev_type_is_tap;
        const char *defport, *proto_tcp;
+       const char *allow_compression = NULL;
        const char *compress;
        const char *tls_remote = NULL;
        const char *nm_openvpn_user, *nm_openvpn_group, *nm_openvpn_chroot;
@@ -1350,6 +1356,7 @@ nm_openvpn_start_openvpn_binary (NMOpenvpnPlugin *plugin,
        guint num_remotes = 0;
        gs_free char *cmd_log = NULL;
        NMOvpnComp comp;
+       NMOvpnAllowCompression allow_comp;
 
        s_vpn = nm_connection_get_setting_vpn (connection);
        if (!s_vpn) {
@@ -1524,6 +1531,9 @@ nm_openvpn_start_openvpn_binary (NMOpenvpnPlugin *plugin,
         * See bgo#769177
         */
 
+       /* New (2.5+) allow-compression option ("yes", "no", "asym") */
+       allow_compression = nm_setting_vpn_get_data_item (s_vpn,
+                                                         NM_OPENVPN_KEY_ALLOW_COMPRESSION);
        /* New (2.4+) compress option ("lz4", "lzo", ...) */
        compress = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_COMPRESS);
        /* Legacy option ("yes", "adaptive", "no", ...) */
@@ -1532,43 +1542,52 @@ nm_openvpn_start_openvpn_binary (NMOpenvpnPlugin *plugin,
        if (compress && tmp)
                _LOGW ("'compress' option overrides 'comp-lzo'");
 
+       allow_comp = nmovpn_allow_compression_from_options (allow_compression);
        comp = nmovpn_compression_from_options (tmp, compress);
        openvpn_binary_detect_version_cached (openvpn_binary, &openvpn_binary_version);
 
-       switch (comp) {
-       case NMOVPN_COMP_DISABLED:
-               break;
-       case NMOVPN_COMP_LZO:
-               if (openvpn_binary_version == OPENVPN_BINARY_VERSION_2_3_OR_OLDER)
-                       args_add_strv (args, "--comp-lzo", "yes");
-               else
-                       args_add_strv (args, "--compress", "lzo");
-               break;
-       case NMOVPN_COMP_LZ4:
-       case NMOVPN_COMP_LZ4_V2:
-       case NMOVPN_COMP_AUTO:
-               if (openvpn_binary_version == OPENVPN_BINARY_VERSION_2_3_OR_OLDER)
-                       _LOGW ("\"compress\" option supported only by OpenVPN >= 2.4");
-
-               if (comp == NMOVPN_COMP_LZ4)
-                       args_add_strv (args, "--compress", "lz4");
-               else if (comp == NMOVPN_COMP_LZ4_V2)
-                       args_add_strv (args, "--compress", "lz4-v2");
-               else
-                       args_add_strv (args, "--compress");
-               break;
-       case NMOVPN_COMP_LEGACY_LZO_DISABLED:
-       case NMOVPN_COMP_LEGACY_LZO_ADAPTIVE:
-               if (openvpn_binary_version != OPENVPN_BINARY_VERSION_2_3_OR_OLDER)
-                       _LOGW ("\"comp-lzo\" is deprecated and will be removed in future OpenVPN releases");
-
-               args_add_strv (args, "--comp-lzo",
-                                 comp == NMOVPN_COMP_LEGACY_LZO_DISABLED
-                              ? "no"
-                              : "adaptive");
-               break;
+       if (nmovpn_arg_is_set (allow_compression)) {
+               if (openvpn_binary_version == OPENVPN_BINARY_VERSION_2_4_OR_OLDER) {
+                       _LOGW ("\"allow-compression\" is only supported in OpenVPN 2.5 and later versions");
+               } else
+                       args_add_strv (args, "--allow-compression", allow_compression);
        }
 
+       if (allow_comp != NMOVPN_ALLOW_COMPRESSION_NO)
+               switch (comp) {
+               case NMOVPN_COMP_DISABLED:
+                       break;
+               case NMOVPN_COMP_LZO:
+                       if (openvpn_binary_version == OPENVPN_BINARY_VERSION_2_3_OR_OLDER)
+                               args_add_strv (args, "--comp-lzo", "yes");
+                       else
+                               args_add_strv (args, "--compress", "lzo");
+                       break;
+               case NMOVPN_COMP_LZ4:
+               case NMOVPN_COMP_LZ4_V2:
+               case NMOVPN_COMP_AUTO:
+                       if (openvpn_binary_version == OPENVPN_BINARY_VERSION_2_3_OR_OLDER)
+                               _LOGW ("\"compress\" option supported only by OpenVPN >= 2.4");
+
+                       if (comp == NMOVPN_COMP_LZ4)
+                               args_add_strv (args, "--compress", "lz4");
+                       else if (comp == NMOVPN_COMP_LZ4_V2)
+                               args_add_strv (args, "--compress", "lz4-v2");
+                       else
+                               args_add_strv (args, "--compress");
+                       break;
+               case NMOVPN_COMP_LEGACY_LZO_DISABLED:
+               case NMOVPN_COMP_LEGACY_LZO_ADAPTIVE:
+                       if (openvpn_binary_version != OPENVPN_BINARY_VERSION_2_3_OR_OLDER)
+                               _LOGW ("\"comp-lzo\" is deprecated and will be removed in future OpenVPN 
releases");
+
+                       args_add_strv (args, "--comp-lzo",
+                                                       comp == NMOVPN_COMP_LEGACY_LZO_DISABLED
+                                               ? "no"
+                                               : "adaptive");
+                       break;
+               }
+
        tmp = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_FLOAT);
        if (nm_streq0 (tmp, "yes"))
                args_add_strv (args, "--float");


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]