const char *
dco_version_string(struct gc_arena *gc)
{
- return "v0";
+ OVPN_VERSION version;
+ ZeroMemory(&version, sizeof(OVPN_VERSION));
+
+ /* try to open device by symbolic name */
+ HANDLE h = CreateFile("\\\\.\\ovpn-dco", GENERIC_READ | GENERIC_WRITE,
+ 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, NULL);
+
+ if (h == INVALID_HANDLE_VALUE)
+ {
+ return "N/A";
+ }
+
+ DWORD bytes_returned = 0;
+ if (!DeviceIoControl(h, OVPN_IOCTL_GET_VERSION, NULL, 0,
+ &version, sizeof(version), &bytes_returned, NULL))
+ {
+ CloseHandle(h);
+ return "N/A";
+ }
+
+ CloseHandle(h);
+
+ struct buffer out = alloc_buf_gc(256, gc);
+ buf_printf(&out, "%ld.%ld.%ld", version.Major, version.Minor, version.Patch);
+
+ return BSTR(&out);
}
int
LONG MSS;
} OVPN_SET_PEER, * POVPN_SET_PEER;
+typedef struct _OVPN_VERSION {
+ LONG Major;
+ LONG Minor;
+ LONG Patch;
+} OVPN_VERSION, * POVPN_VERSION;
+
#define OVPN_IOCTL_NEW_PEER CTL_CODE(FILE_DEVICE_UNKNOWN, 1, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define OVPN_IOCTL_GET_STATS CTL_CODE(FILE_DEVICE_UNKNOWN, 2, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define OVPN_IOCTL_NEW_KEY CTL_CODE(FILE_DEVICE_UNKNOWN, 3, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define OVPN_IOCTL_SET_PEER CTL_CODE(FILE_DEVICE_UNKNOWN, 5, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define OVPN_IOCTL_START_VPN CTL_CODE(FILE_DEVICE_UNKNOWN, 6, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define OVPN_IOCTL_DEL_PEER CTL_CODE(FILE_DEVICE_UNKNOWN, 7, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define OVPN_IOCTL_GET_VERSION CTL_CODE(FILE_DEVICE_UNKNOWN, 8, METHOD_BUFFERED, FILE_ANY_ACCESS)