Browse code

Implement ovpn version detection

Add detection of the ovpn kernel module type: if a backported
(out-of-tree) version is loaded, the MODULE_VERSION string is read from
sysfs; otherwise, for the in-tree module, the function reports the
kernel release and version.

Change-Id: I7fc033a7ffee73045316763356a95d75ef23f5ad
Signed-off-by: Ralf Lici <ralf@mandelbit.com>
Acked-by: Gert Doering <gert@greenie.muc.de>
Message-Id: <20250515150038.30097-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg31652.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>

Ralf Lici authored on 2025/05/16 00:00:31
Showing 1 changed files
... ...
@@ -1117,10 +1117,77 @@ dco_available(int msglevel)
1117 1117
     return true;
1118 1118
 }
1119 1119
 
1120
+/**
1121
+ * There's no version indicator in the ovpn in-tree module, so we return a
1122
+ * string containing info about the kernel version and release.
1123
+ */
1124
+static const char *
1125
+dco_version_string_in_tree(struct gc_arena *gc)
1126
+{
1127
+    struct buffer buf = alloc_buf_gc(256, gc);
1128
+    struct utsname system;
1129
+
1130
+    if (uname(&system))
1131
+    {
1132
+        return "ERR";
1133
+    }
1134
+
1135
+    buf_puts(&buf, system.release);
1136
+    buf_puts(&buf, " ");
1137
+    buf_puts(&buf, system.version);
1138
+    return BSTR(&buf);
1139
+}
1140
+
1141
+/**
1142
+ * When the module is loaded, the backports version of ovpn has a version file
1143
+ * in sysfs. Read it and return the string.
1144
+ *
1145
+ * The caller is responsible for closing the file pointer.
1146
+ */
1147
+static const char *
1148
+dco_version_string_backports(FILE *fp, struct gc_arena *gc)
1149
+{
1150
+    char *str = gc_malloc(PATH_MAX, false, gc);
1151
+
1152
+    if (!fgets(str, PATH_MAX, fp))
1153
+    {
1154
+        return "ERR";
1155
+    }
1156
+
1157
+    /* remove potential newline at the end of the string */
1158
+    char *nl = strchr(str, '\n');
1159
+    if (nl)
1160
+    {
1161
+        *nl = '\0';
1162
+    }
1163
+
1164
+    return str;
1165
+}
1166
+
1120 1167
 const char *
1121 1168
 dco_version_string(struct gc_arena *gc)
1122 1169
 {
1123
-    return "Unknown";
1170
+    const char *version;
1171
+    struct stat sb;
1172
+    FILE *fp;
1173
+
1174
+    if (stat("/sys/module/ovpn", &sb) != 0 || !S_ISDIR(sb.st_mode))
1175
+    {
1176
+        return "N/A";
1177
+    }
1178
+
1179
+    /* now that we know for sure that the module is loaded, if there's no
1180
+     * version file it means we're dealing with the in-tree version, otherwise
1181
+     * it's backports */
1182
+    fp = fopen("/sys/module/ovpn/version", "r");
1183
+    if (!fp)
1184
+    {
1185
+        return dco_version_string_in_tree(gc);
1186
+    }
1187
+    version = dco_version_string_backports(fp, gc);
1188
+
1189
+    fclose(fp);
1190
+    return version;
1124 1191
 }
1125 1192
 
1126 1193
 void