2017-10-19 05:48:23 +03:00
|
|
|
// SoftEther VPN Source Code - Developer Edition Master Branch
|
2014-01-04 17:00:08 +04:00
|
|
|
// Cedar Communication Module
|
|
|
|
|
|
|
|
|
2018-09-10 01:46:29 +03:00
|
|
|
// Proto_OpenVPN.c
|
2014-01-04 17:00:08 +04:00
|
|
|
// OpenVPN protocol stack
|
|
|
|
|
2021-04-05 05:48:25 +03:00
|
|
|
#include "Proto_OpenVPN.h"
|
|
|
|
|
|
|
|
#include "Cedar.h"
|
|
|
|
#include "Connection.h"
|
|
|
|
#include "IPC.h"
|
|
|
|
#include "Logging.h"
|
|
|
|
#include "Proto_EtherIP.h"
|
|
|
|
#include "Proto_PPP.h"
|
|
|
|
#include "Server.h"
|
|
|
|
|
|
|
|
#include "Mayaqua/Internat.h"
|
|
|
|
#include "Mayaqua/Memory.h"
|
|
|
|
#include "Mayaqua/Object.h"
|
|
|
|
#include "Mayaqua/Str.h"
|
|
|
|
#include "Mayaqua/Table.h"
|
|
|
|
#include "Mayaqua/Tick64.h"
|
2014-01-04 17:00:08 +04:00
|
|
|
|
|
|
|
// Ping signature of the OpenVPN protocol
|
|
|
|
static UCHAR ping_signature[] =
|
|
|
|
{
|
|
|
|
0x2a, 0x18, 0x7b, 0xf3, 0x64, 0x1e, 0xb4, 0xcb,
|
|
|
|
0x07, 0xed, 0x2d, 0x0a, 0x98, 0x1f, 0xc7, 0x48
|
|
|
|
};
|
|
|
|
|
2020-07-17 03:55:47 +03:00
|
|
|
const PROTO_IMPL *OvsGetProtoImpl()
|
2019-07-26 08:58:22 +03:00
|
|
|
{
|
2020-07-17 03:55:47 +03:00
|
|
|
static const PROTO_IMPL impl =
|
2019-07-26 08:58:22 +03:00
|
|
|
{
|
2020-07-17 03:55:47 +03:00
|
|
|
OvsName,
|
2020-07-20 03:03:44 +03:00
|
|
|
OvsOptions,
|
2020-08-12 01:49:31 +03:00
|
|
|
NULL,
|
2019-07-26 08:58:22 +03:00
|
|
|
OvsInit,
|
|
|
|
OvsFree,
|
|
|
|
OvsIsPacketForMe,
|
|
|
|
OvsProcessData,
|
2020-07-12 04:09:12 +03:00
|
|
|
OvsProcessDatagrams
|
2019-07-26 08:58:22 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
return &impl;
|
|
|
|
}
|
|
|
|
|
2020-07-17 03:55:47 +03:00
|
|
|
const char *OvsName()
|
|
|
|
{
|
|
|
|
return "OpenVPN";
|
|
|
|
}
|
|
|
|
|
2020-07-20 03:03:44 +03:00
|
|
|
const PROTO_OPTION *OvsOptions()
|
2019-07-26 08:58:22 +03:00
|
|
|
{
|
2020-07-20 03:03:44 +03:00
|
|
|
static const PROTO_OPTION options[] =
|
|
|
|
{
|
|
|
|
{ .Name = "DefaultClientOption", .Type = PROTO_OPTION_STRING, .String = "dev-type tun,link-mtu 1500,tun-mtu 1500,cipher AES-128-CBC,auth SHA1,keysize 128,key-method 2,tls-client" },
|
|
|
|
{ .Name = "Obfuscation", .Type = PROTO_OPTION_BOOL, .Bool = false },
|
2021-04-21 09:29:30 +03:00
|
|
|
{ .Name = "ObfuscationMask", .Type = PROTO_OPTION_STRING, .String = "" },
|
|
|
|
{ .Name = "PingSendInterval", .Type = PROTO_OPTION_UINT32, .UInt32 = 3000 },
|
2020-07-20 03:03:44 +03:00
|
|
|
{ .Name = "PushDummyIPv4AddressOnL2Mode", .Type = PROTO_OPTION_BOOL, .Bool = true },
|
2021-04-21 09:29:30 +03:00
|
|
|
{ .Name = "Timeout", .Type = PROTO_OPTION_UINT32, .UInt32 = 30000 },
|
2020-07-20 03:03:44 +03:00
|
|
|
{ .Name = NULL, .Type = PROTO_OPTION_UNKNOWN }
|
|
|
|
};
|
|
|
|
|
|
|
|
return options;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool OvsInit(void **param, const LIST *options, CEDAR *cedar, INTERRUPT_MANAGER *im, SOCK_EVENT *se, const char *cipher, const char *hostname)
|
|
|
|
{
|
|
|
|
if (param == NULL || options == NULL || cedar == NULL || im == NULL || se == NULL)
|
2019-07-26 08:58:22 +03:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-07-17 02:59:22 +03:00
|
|
|
Debug("OvsInit(): cipher: %s, hostname: %s\n", cipher, hostname);
|
|
|
|
|
2020-07-20 00:45:12 +03:00
|
|
|
*param = NewOpenVpnServer(options, cedar, im, se);
|
2019-07-26 08:58:22 +03:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OvsFree(void *param)
|
|
|
|
{
|
|
|
|
FreeOpenVpnServer(param);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check whether it's an OpenVPN packet
|
2020-07-29 21:00:46 +03:00
|
|
|
bool OvsIsPacketForMe(const PROTO_MODE mode, const void *data, const UINT size)
|
2019-07-26 08:58:22 +03:00
|
|
|
{
|
2020-07-29 21:00:46 +03:00
|
|
|
if (data == NULL || size < 2)
|
2019-07-26 08:58:22 +03:00
|
|
|
{
|
2020-07-29 21:00:46 +03:00
|
|
|
return false;
|
|
|
|
}
|
2019-07-26 08:58:22 +03:00
|
|
|
|
2020-07-29 21:00:46 +03:00
|
|
|
if (mode == PROTO_MODE_TCP)
|
|
|
|
{
|
|
|
|
const UCHAR *raw = data;
|
|
|
|
if (raw[0] == 0x00 && raw[1] == 0x0E)
|
2020-05-11 08:07:04 +03:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (mode == PROTO_MODE_UDP)
|
2019-07-26 08:58:22 +03:00
|
|
|
{
|
2020-05-11 08:07:04 +03:00
|
|
|
OPENVPN_PACKET *packet = OvsParsePacket(data, size);
|
|
|
|
if (packet == NULL)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
OvsFreePacket(packet);
|
2019-07-26 08:58:22 +03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-05-11 09:23:29 +03:00
|
|
|
bool OvsProcessData(void *param, TCP_RAW_DATA *in, FIFO *out)
|
2019-07-26 08:58:22 +03:00
|
|
|
{
|
|
|
|
bool ret = true;
|
|
|
|
UINT i;
|
2020-05-11 08:07:04 +03:00
|
|
|
OPENVPN_SERVER *server = param;
|
2019-07-26 08:58:22 +03:00
|
|
|
UCHAR buf[OPENVPN_TCP_MAX_PACKET_SIZE];
|
|
|
|
|
2020-05-11 09:23:29 +03:00
|
|
|
if (server == NULL || in == NULL || out == NULL)
|
2019-07-26 08:58:22 +03:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Separate to a list of datagrams by interpreting the data received from the TCP socket
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
UDPPACKET *packet;
|
2019-10-27 11:01:56 +03:00
|
|
|
USHORT payload_size, packet_size;
|
2020-05-11 09:23:29 +03:00
|
|
|
FIFO *fifo = in->Data;
|
2019-10-27 11:01:56 +03:00
|
|
|
const UINT fifo_size = FifoSize(fifo);
|
2019-07-26 08:58:22 +03:00
|
|
|
|
2019-10-27 11:01:56 +03:00
|
|
|
if (fifo_size < sizeof(USHORT))
|
2019-07-26 08:58:22 +03:00
|
|
|
{
|
2019-10-27 11:01:56 +03:00
|
|
|
// Non-arrival
|
2019-07-26 08:58:22 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-10-27 11:01:56 +03:00
|
|
|
// The beginning of a packet contains the data size
|
|
|
|
payload_size = READ_USHORT(FifoPtr(fifo));
|
|
|
|
packet_size = payload_size + sizeof(USHORT);
|
2019-07-26 08:58:22 +03:00
|
|
|
|
2019-10-27 11:01:56 +03:00
|
|
|
if (payload_size == 0 || packet_size > sizeof(buf))
|
2019-07-26 08:58:22 +03:00
|
|
|
{
|
|
|
|
ret = false;
|
2019-10-27 11:01:56 +03:00
|
|
|
Debug("OvsProcessData(): Invalid payload size: %u bytes\n", payload_size);
|
2019-07-26 08:58:22 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-10-27 11:01:56 +03:00
|
|
|
if (fifo_size < packet_size)
|
2019-07-26 08:58:22 +03:00
|
|
|
{
|
2019-10-27 11:01:56 +03:00
|
|
|
// Non-arrival
|
2019-07-26 08:58:22 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-10-27 11:01:56 +03:00
|
|
|
if (ReadFifo(fifo, buf, packet_size) != packet_size)
|
2019-07-26 08:58:22 +03:00
|
|
|
{
|
|
|
|
ret = false;
|
2019-10-27 11:01:56 +03:00
|
|
|
Debug("OvsProcessData(): ReadFifo() failed to read the packet\n");
|
2019-07-26 08:58:22 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-10-27 11:01:56 +03:00
|
|
|
// Insert packet into the list
|
2020-05-11 09:23:29 +03:00
|
|
|
packet = NewUdpPacket(&in->SrcIP, in->SrcPort, &in->DstIP, in->DstPort, Clone(buf + sizeof(USHORT), payload_size), payload_size);
|
2019-07-26 08:58:22 +03:00
|
|
|
Add(server->RecvPacketList, packet);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Process the list of received datagrams
|
2020-05-11 09:23:29 +03:00
|
|
|
OvsRecvPacket(server, server->RecvPacketList, OPENVPN_PROTOCOL_TCP);
|
2019-07-26 08:58:22 +03:00
|
|
|
|
|
|
|
// Release the received packet list
|
|
|
|
for (i = 0; i < LIST_NUM(server->RecvPacketList); ++i)
|
|
|
|
{
|
|
|
|
UDPPACKET *p = LIST_DATA(server->RecvPacketList, i);
|
|
|
|
FreeUdpPacket(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
DeleteAll(server->RecvPacketList);
|
|
|
|
|
|
|
|
// Store in the queue by getting a list of the datagrams to be transmitted from the OpenVPN server
|
|
|
|
for (i = 0; i < LIST_NUM(server->SendPacketList); ++i)
|
|
|
|
{
|
|
|
|
UDPPACKET *p = LIST_DATA(server->SendPacketList, i);
|
|
|
|
|
|
|
|
// Store the size in the TCP send queue first
|
|
|
|
USHORT us = Endian16((USHORT)p->Size);
|
|
|
|
|
2020-05-11 09:23:29 +03:00
|
|
|
WriteFifo(out, &us, sizeof(USHORT));
|
2019-07-26 08:58:22 +03:00
|
|
|
|
|
|
|
// Write the data body
|
2020-05-11 09:23:29 +03:00
|
|
|
WriteFifo(out, p->Data, p->Size);
|
2019-07-26 08:58:22 +03:00
|
|
|
|
|
|
|
// Packet release
|
|
|
|
FreeUdpPacket(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
DeleteAll(server->SendPacketList);
|
|
|
|
|
2020-05-11 08:07:04 +03:00
|
|
|
if (server->Giveup <= server->Now)
|
2019-07-26 08:58:22 +03:00
|
|
|
{
|
2020-05-11 09:23:29 +03:00
|
|
|
UINT i;
|
|
|
|
for (i = 0; i < LIST_NUM(server->SessionList); ++i)
|
2020-05-11 08:07:04 +03:00
|
|
|
{
|
|
|
|
OPENVPN_SESSION *se = LIST_DATA(server->SessionList, i);
|
2014-01-04 17:00:08 +04:00
|
|
|
|
2020-05-11 08:07:04 +03:00
|
|
|
if (se->Established)
|
|
|
|
{
|
|
|
|
return ret && server->DisconnectCount < 1;
|
|
|
|
}
|
|
|
|
}
|
2019-07-26 08:58:22 +03:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-07-12 04:09:12 +03:00
|
|
|
server->SupressSendPacket = FifoSize(out) > MAX_BUFFERING_PACKET_SIZE;
|
|
|
|
|
2020-05-11 08:07:04 +03:00
|
|
|
return ret;
|
2014-01-04 17:00:08 +04:00
|
|
|
}
|
|
|
|
|
2020-05-11 09:23:29 +03:00
|
|
|
bool OvsProcessDatagrams(void *param, LIST *in, LIST *out)
|
|
|
|
{
|
|
|
|
UINT i;
|
|
|
|
LIST *to_send;
|
|
|
|
OPENVPN_SERVER *server = param;
|
|
|
|
|
|
|
|
if (server == NULL || in == NULL || out == NULL)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
OvsRecvPacket(server, in, OPENVPN_PROTOCOL_UDP);
|
|
|
|
|
|
|
|
to_send = server->SendPacketList;
|
|
|
|
|
|
|
|
for (i = 0; i < LIST_NUM(to_send); ++i)
|
|
|
|
{
|
|
|
|
Add(out, LIST_DATA(to_send, i));
|
|
|
|
}
|
|
|
|
|
|
|
|
DeleteAll(server->SendPacketList);
|
|
|
|
|
|
|
|
if (server->Giveup <= server->Now)
|
|
|
|
{
|
|
|
|
UINT i;
|
|
|
|
for (i = 0; i < LIST_NUM(server->SessionList); ++i)
|
|
|
|
{
|
|
|
|
OPENVPN_SESSION *se = LIST_DATA(server->SessionList, i);
|
|
|
|
|
|
|
|
if (se->Established)
|
|
|
|
{
|
|
|
|
return server->DisconnectCount < 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-01-04 17:00:08 +04:00
|
|
|
// Write the OpenVPN log
|
|
|
|
void OvsLog(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_CHANNEL *c, char *name, ...)
|
|
|
|
{
|
|
|
|
wchar_t prefix[MAX_SIZE * 2];
|
|
|
|
wchar_t buf2[MAX_SIZE * 2];
|
|
|
|
va_list args;
|
|
|
|
// Validate arguments
|
|
|
|
if (s == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (se == NULL)
|
|
|
|
{
|
|
|
|
UniStrCpy(prefix, sizeof(prefix), _UU("LO_PREFIX_RAW"));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (c == NULL)
|
|
|
|
{
|
|
|
|
UniFormat(prefix, sizeof(prefix), _UU("LO_PREFIX_SESSION"),
|
2020-05-12 01:06:59 +03:00
|
|
|
se->Id, &se->ClientIp, se->ClientPort, &se->ServerIp, se->ServerPort);
|
2014-01-04 17:00:08 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
UniFormat(prefix, sizeof(prefix), _UU("LO_PREFIX_CHANNEL"),
|
2020-05-12 01:06:59 +03:00
|
|
|
se->Id, &se->ClientIp, se->ClientPort, &se->ServerIp, se->ServerPort,
|
|
|
|
c->KeyId);
|
2014-01-04 17:00:08 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
va_start(args, name);
|
|
|
|
UniFormatArgs(buf2, sizeof(buf2), _UU(name), args);
|
|
|
|
va_end(args);
|
|
|
|
|
|
|
|
UniStrCat(prefix, sizeof(prefix), buf2);
|
|
|
|
|
|
|
|
WriteServerLog(s->Cedar, prefix);
|
|
|
|
}
|
|
|
|
|
2018-10-31 20:14:38 +03:00
|
|
|
// Encrypt the data
|
2018-11-03 18:14:56 +03:00
|
|
|
UINT OvsEncrypt(CIPHER *cipher, MD *md, UCHAR *iv, UCHAR *tag, UCHAR *dest, UCHAR *src, UINT src_size, UCHAR *aad, UINT aad_size)
|
2018-10-31 20:14:38 +03:00
|
|
|
{
|
|
|
|
// Validate arguments
|
2018-11-03 18:14:56 +03:00
|
|
|
if (cipher == NULL || (cipher->IsAeadCipher == false && md == NULL))
|
2018-10-31 20:14:38 +03:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-03 18:14:56 +03:00
|
|
|
if (cipher->IsAeadCipher)
|
2018-10-31 20:14:38 +03:00
|
|
|
{
|
2018-11-03 18:14:56 +03:00
|
|
|
// Encrypt in AEAD mode (no HMAC)
|
|
|
|
UINT dest_size = CipherProcessAead(cipher, iv, tag, 16, dest, src, src_size, aad, aad_size);
|
|
|
|
if (dest_size == 0)
|
|
|
|
{
|
|
|
|
Debug("OvsEncrypt(): CipherProcessAead() failed!\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return dest_size;
|
2018-10-31 20:14:38 +03:00
|
|
|
}
|
2018-11-03 18:14:56 +03:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// Encrypt in non-AEAD mode (with HMAC)
|
|
|
|
UINT ret;
|
|
|
|
UINT dest_size = CipherProcess(cipher, iv, dest + md->Size + cipher->IvSize, src, src_size);
|
|
|
|
if (dest_size == 0)
|
|
|
|
{
|
|
|
|
Debug("OvsEncrypt(): CipherProcess() failed!\n");
|
|
|
|
return 0;
|
|
|
|
}
|
2018-10-31 20:14:38 +03:00
|
|
|
|
2018-11-03 18:14:56 +03:00
|
|
|
// Copy the IV
|
|
|
|
Copy(dest + md->Size, iv, cipher->IvSize);
|
|
|
|
dest_size += cipher->IvSize;
|
2018-10-31 20:14:38 +03:00
|
|
|
|
2018-11-03 18:14:56 +03:00
|
|
|
// Calculate the HMAC
|
|
|
|
ret = MdProcess(md, dest, dest + md->Size, dest_size);
|
|
|
|
if (ret == 0)
|
|
|
|
{
|
|
|
|
Debug("OvsEncrypt(): MdProcess() failed!\n");
|
|
|
|
return 0;
|
|
|
|
}
|
2018-10-31 20:14:38 +03:00
|
|
|
|
2018-11-03 18:14:56 +03:00
|
|
|
return dest_size + ret;
|
|
|
|
}
|
2018-10-31 20:14:38 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Decrypt the data
|
2018-11-03 18:14:56 +03:00
|
|
|
UINT OvsDecrypt(CIPHER *cipher, MD *md, UCHAR *iv, UCHAR *dest, UCHAR *src, UINT size)
|
2018-10-31 20:14:38 +03:00
|
|
|
{
|
|
|
|
// Validate arguments
|
2018-11-03 18:14:56 +03:00
|
|
|
if (cipher == NULL)
|
2018-10-31 20:14:38 +03:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-03 18:14:56 +03:00
|
|
|
if (cipher->IsAeadCipher)
|
2018-10-31 20:14:38 +03:00
|
|
|
{
|
2018-11-03 18:14:56 +03:00
|
|
|
UCHAR *tag = src;
|
2018-10-31 20:14:38 +03:00
|
|
|
|
2018-11-03 18:14:56 +03:00
|
|
|
if (iv == NULL || size <= OPENVPN_TAG_SIZE)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2018-10-31 20:14:38 +03:00
|
|
|
|
2018-11-03 18:14:56 +03:00
|
|
|
src += OPENVPN_TAG_SIZE;
|
|
|
|
size -= OPENVPN_TAG_SIZE;
|
2018-10-31 20:14:38 +03:00
|
|
|
|
2018-11-03 18:14:56 +03:00
|
|
|
// Payload
|
|
|
|
if (size >= 1 && (cipher->BlockSize == 0 || (size % cipher->BlockSize) == 0))
|
|
|
|
{
|
|
|
|
// Decryption
|
|
|
|
UINT ret = CipherProcessAead(cipher, iv, tag, OPENVPN_TAG_SIZE, dest, src, size, iv, sizeof(UINT));
|
|
|
|
if (ret == 0)
|
|
|
|
{
|
|
|
|
Debug("OvsDecrypt(): CipherProcessAead() failed!\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2018-10-31 20:14:38 +03:00
|
|
|
}
|
2018-11-03 18:14:56 +03:00
|
|
|
else
|
|
|
|
{
|
|
|
|
UCHAR *hmac;
|
|
|
|
UCHAR hmac_test[128];
|
2018-10-31 20:14:38 +03:00
|
|
|
|
2018-11-03 18:14:56 +03:00
|
|
|
if (md == NULL || iv == NULL || size < (md->Size + cipher->IvSize + sizeof(UINT)))
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2018-10-31 20:14:38 +03:00
|
|
|
|
2018-11-03 18:14:56 +03:00
|
|
|
// HMAC
|
|
|
|
hmac = src;
|
|
|
|
src += md->Size;
|
|
|
|
size -= md->Size;
|
|
|
|
|
|
|
|
if (MdProcess(md, hmac_test, src, size) == 0)
|
|
|
|
{
|
|
|
|
Debug("OvsDecrypt(): MdProcess() failed!\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Cmp(hmac_test, hmac, md->Size) != 0)
|
2018-10-31 20:14:38 +03:00
|
|
|
{
|
2018-11-03 18:14:56 +03:00
|
|
|
Debug("OvsDecrypt(): HMAC verification failed!\n");
|
|
|
|
return 0;
|
2018-10-31 20:14:38 +03:00
|
|
|
}
|
|
|
|
|
2018-11-03 18:14:56 +03:00
|
|
|
// IV
|
|
|
|
Copy(iv, src, cipher->IvSize);
|
|
|
|
src += cipher->IvSize;
|
|
|
|
size -= cipher->IvSize;
|
|
|
|
|
|
|
|
// Payload
|
|
|
|
if (size >= 1 && (cipher->BlockSize == 0 || (size % cipher->BlockSize) == 0))
|
|
|
|
{
|
|
|
|
// Decryption
|
|
|
|
UINT ret = CipherProcess(cipher, iv, dest, src, size);
|
|
|
|
if (ret == 0)
|
|
|
|
{
|
|
|
|
Debug("OvsDecrypt(): CipherProcess() failed!\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2018-10-31 20:14:38 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-13 00:32:37 +03:00
|
|
|
// XOR the bytes with the specified string
|
|
|
|
void OvsDataXorMask(void *data, const UINT data_size, const char *mask, const UINT mask_size)
|
|
|
|
{
|
|
|
|
UINT i;
|
|
|
|
UCHAR *buf;
|
|
|
|
// Validate arguments
|
|
|
|
if (data == NULL || data_size == 0 || mask == NULL || mask_size == 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0, buf = data; i < data_size; i++, buf++)
|
|
|
|
{
|
|
|
|
*buf = *buf ^ mask[i % mask_size];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// XOR each byte with its position within the buffer
|
|
|
|
void OvsDataXorPtrPos(void *data, const UINT size)
|
|
|
|
{
|
|
|
|
UINT i;
|
|
|
|
UCHAR *buf;
|
|
|
|
// Validate arguments
|
|
|
|
if (data == NULL || size == 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0, buf = data; i < size; i++, buf++)
|
|
|
|
{
|
|
|
|
*buf = *buf ^ i + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reverse bytes order if they're more than 2, keeping the first byte unchanged
|
|
|
|
void OvsDataReverse(void *data, const UINT size)
|
|
|
|
{
|
|
|
|
UINT i;
|
|
|
|
UCHAR tmp;
|
|
|
|
UCHAR *buf_start, *buf_end;
|
|
|
|
// Validate arguments
|
|
|
|
if (data == NULL || size < 3)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0, buf_start = (UCHAR *)data + 1, buf_end = (UCHAR *)data + (size - 1); i < (size - 1 ) / 2; i++, buf_start++, buf_end--)
|
|
|
|
{
|
|
|
|
tmp = *buf_start;
|
|
|
|
*buf_start = *buf_end;
|
|
|
|
*buf_end = tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Detects the method used to obfuscate the packet
|
|
|
|
UINT OvsDetectObfuscation(void *data, UINT size, char *xormask)
|
|
|
|
{
|
|
|
|
UINT ret;
|
|
|
|
void *tmp;
|
|
|
|
OPENVPN_PACKET *parsed_packet;
|
|
|
|
// Validate arguments
|
|
|
|
if (data == NULL || size == 0)
|
|
|
|
{
|
|
|
|
return INFINITE;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = INFINITE;
|
|
|
|
tmp = NULL;
|
|
|
|
|
|
|
|
// OPENVPN_SCRAMBLE_MODE_DISABLED
|
|
|
|
parsed_packet = OvsParsePacket(data, size);
|
|
|
|
if (parsed_packet != NULL)
|
|
|
|
{
|
|
|
|
ret = OPENVPN_SCRAMBLE_MODE_DISABLED;
|
|
|
|
goto final;
|
|
|
|
}
|
|
|
|
|
|
|
|
// OPENVPN_SCRAMBLE_MODE_XORMASK
|
|
|
|
tmp = Clone(data, size);
|
|
|
|
|
|
|
|
OvsDataXorMask(tmp, size, xormask, StrLen(xormask));
|
|
|
|
|
|
|
|
parsed_packet = OvsParsePacket(tmp, size);
|
|
|
|
if (parsed_packet != NULL)
|
|
|
|
{
|
|
|
|
ret = OPENVPN_SCRAMBLE_MODE_XORMASK;
|
|
|
|
goto final;
|
|
|
|
}
|
|
|
|
|
|
|
|
Free(tmp);
|
|
|
|
|
|
|
|
// OPENVPN_SCRAMBLE_MODE_XORPTRPOS
|
|
|
|
tmp = Clone(data, size);
|
|
|
|
|
|
|
|
OvsDataXorPtrPos(tmp, size);
|
|
|
|
|
|
|
|
parsed_packet = OvsParsePacket(tmp, size);
|
|
|
|
if (parsed_packet != NULL)
|
|
|
|
{
|
|
|
|
ret = OPENVPN_SCRAMBLE_MODE_XORPTRPOS;
|
|
|
|
goto final;
|
|
|
|
}
|
|
|
|
|
|
|
|
Free(tmp);
|
|
|
|
|
|
|
|
// OPENVPN_SCRAMBLE_MODE_REVERSE
|
|
|
|
tmp = Clone(data, size);
|
|
|
|
|
|
|
|
OvsDataReverse(tmp, size);
|
|
|
|
|
|
|
|
parsed_packet = OvsParsePacket(tmp, size);
|
|
|
|
if (parsed_packet != NULL)
|
|
|
|
{
|
|
|
|
ret = OPENVPN_SCRAMBLE_MODE_REVERSE;
|
|
|
|
goto final;
|
|
|
|
}
|
|
|
|
|
|
|
|
Free(tmp);
|
|
|
|
|
|
|
|
// OPENVPN_SCRAMBLE_MODE_OBFUSCATE
|
|
|
|
tmp = Clone(data, size);
|
|
|
|
|
|
|
|
OvsDataXorMask(tmp, size, xormask, StrLen(xormask));
|
|
|
|
OvsDataXorPtrPos(tmp, size);
|
|
|
|
OvsDataReverse(tmp, size);
|
|
|
|
OvsDataXorPtrPos(tmp, size);
|
|
|
|
|
|
|
|
parsed_packet = OvsParsePacket(tmp, size);
|
|
|
|
if (parsed_packet != NULL)
|
|
|
|
{
|
|
|
|
ret = OPENVPN_SCRAMBLE_MODE_OBFUSCATE;
|
|
|
|
goto final;
|
|
|
|
}
|
|
|
|
|
|
|
|
final:
|
|
|
|
OvsFreePacket(parsed_packet);
|
|
|
|
Free(tmp);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-01-04 17:00:08 +04:00
|
|
|
// Process the received packet
|
2020-05-11 09:23:29 +03:00
|
|
|
void OvsProceccRecvPacket(OPENVPN_SERVER *s, UDPPACKET *p, UINT protocol)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
2018-11-13 00:32:37 +03:00
|
|
|
OPENVPN_CHANNEL *c;
|
2014-01-04 17:00:08 +04:00
|
|
|
OPENVPN_SESSION *se;
|
|
|
|
OPENVPN_PACKET *recv_packet;
|
|
|
|
// Validate arguments
|
|
|
|
if (s == NULL || p == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Search for the session
|
2020-05-11 09:23:29 +03:00
|
|
|
se = OvsFindOrCreateSession(s, &p->DstIP, p->DestPort, &p->SrcIP, p->SrcPort, protocol);
|
2014-01-04 17:00:08 +04:00
|
|
|
if (se == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-11-13 00:32:37 +03:00
|
|
|
// Detect obfuscation mode and save it for the next packets in the same session
|
|
|
|
if (se->ObfuscationMode == INFINITE)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
2020-07-20 00:45:12 +03:00
|
|
|
se->ObfuscationMode = OvsDetectObfuscation(p->Data, p->Size, s->ObfuscationMask);
|
2018-11-13 00:32:37 +03:00
|
|
|
if (se->ObfuscationMode != INFINITE)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
2018-11-13 00:32:37 +03:00
|
|
|
Debug("OvsProceccRecvPacket(): detected packet obfuscation/scrambling mode: %u\n", se->ObfuscationMode);
|
2014-01-04 17:00:08 +04:00
|
|
|
}
|
2018-11-13 00:32:37 +03:00
|
|
|
else
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
2018-11-13 00:32:37 +03:00
|
|
|
Debug("OvsProceccRecvPacket(): failed to detect packet obfuscation/scrambling mode!\n");
|
|
|
|
return;
|
2014-01-04 17:00:08 +04:00
|
|
|
}
|
2018-11-13 00:32:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Handle scrambled packet
|
|
|
|
switch (se->ObfuscationMode)
|
|
|
|
{
|
|
|
|
case OPENVPN_SCRAMBLE_MODE_DISABLED:
|
|
|
|
break;
|
|
|
|
case OPENVPN_SCRAMBLE_MODE_XORMASK:
|
2020-07-20 00:45:12 +03:00
|
|
|
OvsDataXorMask(p->Data, p->Size, s->ObfuscationMask, StrLen(s->ObfuscationMask));
|
2018-11-13 00:32:37 +03:00
|
|
|
break;
|
|
|
|
case OPENVPN_SCRAMBLE_MODE_XORPTRPOS:
|
|
|
|
OvsDataXorPtrPos(p->Data, p->Size);
|
|
|
|
break;
|
|
|
|
case OPENVPN_SCRAMBLE_MODE_REVERSE:
|
|
|
|
OvsDataReverse(p->Data, p->Size);
|
|
|
|
break;
|
|
|
|
case OPENVPN_SCRAMBLE_MODE_OBFUSCATE:
|
2020-07-20 00:45:12 +03:00
|
|
|
OvsDataXorMask(p->Data, p->Size, s->ObfuscationMask, StrLen(s->ObfuscationMask));
|
2018-11-13 00:32:37 +03:00
|
|
|
OvsDataXorPtrPos(p->Data, p->Size);
|
|
|
|
OvsDataReverse(p->Data, p->Size);
|
|
|
|
OvsDataXorPtrPos(p->Data, p->Size);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse the packet
|
|
|
|
recv_packet = OvsParsePacket(p->Data, p->Size);
|
|
|
|
if (recv_packet == NULL)
|
|
|
|
{
|
|
|
|
Debug("OvsProceccRecvPacket(): OvsParsePacket() returned NULL!\n");
|
|
|
|
return;
|
|
|
|
}
|
2014-01-04 17:00:08 +04:00
|
|
|
|
2018-11-19 23:30:42 +03:00
|
|
|
c = se->Channels[recv_packet->KeyId];
|
2018-11-13 00:32:37 +03:00
|
|
|
|
|
|
|
if (recv_packet->OpCode != OPENVPN_P_DATA_V1)
|
|
|
|
{
|
|
|
|
// Control packet
|
2018-11-19 23:30:42 +03:00
|
|
|
Debug("OvsProceccRecvPacket(): Received control packet. PacketId: %u, OpCode: %u, KeyId: %u, MySessionId: %I64u\n",
|
2020-05-12 01:06:59 +03:00
|
|
|
recv_packet->PacketId, recv_packet->OpCode, recv_packet->KeyId, recv_packet->MySessionId);
|
2018-11-19 23:30:42 +03:00
|
|
|
|
2018-11-13 00:32:37 +03:00
|
|
|
if (recv_packet->OpCode == OPENVPN_P_CONTROL_HARD_RESET_CLIENT_V2 ||
|
2020-05-12 01:06:59 +03:00
|
|
|
recv_packet->OpCode == OPENVPN_P_CONTROL_SOFT_RESET_V1)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
2018-11-13 00:32:37 +03:00
|
|
|
// Connection request packet
|
2018-11-19 23:30:42 +03:00
|
|
|
if (c != NULL && c->Status == OPENVPN_CHANNEL_STATUS_ESTABLISHED)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
2018-11-19 23:30:42 +03:00
|
|
|
// If there's already an established data channel, release it
|
2018-11-13 00:32:37 +03:00
|
|
|
OvsFreeChannel(se->Channels[recv_packet->KeyId]);
|
2018-11-19 23:30:42 +03:00
|
|
|
c = se->Channels[recv_packet->KeyId] = NULL;
|
|
|
|
Debug("OvsProceccRecvPacket(): Released established data channel: %u\n", recv_packet->KeyId);
|
2014-01-04 17:00:08 +04:00
|
|
|
}
|
2018-11-13 00:32:37 +03:00
|
|
|
|
2018-11-19 23:30:42 +03:00
|
|
|
if (c == NULL)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
2018-11-19 23:30:42 +03:00
|
|
|
// Create a new channel
|
|
|
|
c = OvsNewChannel(se, recv_packet->KeyId);
|
|
|
|
if (se->ClientSessionId == 0)
|
|
|
|
{
|
|
|
|
se->ClientSessionId = recv_packet->MySessionId;
|
|
|
|
}
|
|
|
|
se->Channels[recv_packet->KeyId] = c;
|
|
|
|
Debug("OvsProceccRecvPacket(): Created a new channel: %u\n", recv_packet->KeyId);
|
|
|
|
OvsLog(s, se, c, "LO_NEW_CHANNEL");
|
2018-11-13 00:32:37 +03:00
|
|
|
}
|
|
|
|
}
|
2020-05-12 01:06:59 +03:00
|
|
|
/* else if (recv_packet->OpCode == OPENVPN_P_CONTROL_SOFT_RESET_V1)
|
|
|
|
{
|
|
|
|
// Response to soft reset request packet
|
|
|
|
OPENVPN_PACKET *p;
|
2014-01-04 17:00:08 +04:00
|
|
|
|
2020-05-12 01:06:59 +03:00
|
|
|
p = OvsNewControlPacket(OPENVPN_P_CONTROL_SOFT_RESET_V1, recv_packet->KeyId, se->ServerSessionId,
|
|
|
|
0, NULL, 0, 0, 0, NULL);
|
2014-01-04 17:00:08 +04:00
|
|
|
|
2020-05-12 01:06:59 +03:00
|
|
|
OvsSendPacketNow(s, se, p);
|
2014-01-04 17:00:08 +04:00
|
|
|
|
2020-05-12 01:06:59 +03:00
|
|
|
OvsFreePacket(p);
|
|
|
|
}
|
|
|
|
*/
|
2018-11-13 00:32:37 +03:00
|
|
|
if (c != NULL)
|
|
|
|
{
|
|
|
|
// Delete the send packet list by looking the packet ID in the ACK list of arrived packet
|
|
|
|
OvsDeleteFromSendingControlPacketList(c, recv_packet->NumAck, recv_packet->AckPacketId);
|
|
|
|
|
|
|
|
if (recv_packet->OpCode != OPENVPN_P_ACK_V1)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
2018-11-13 00:32:37 +03:00
|
|
|
// Add the Packet ID of arrived packet to the list
|
|
|
|
InsertIntDistinct(c->AckReplyList, recv_packet->PacketId);
|
2014-01-04 17:00:08 +04:00
|
|
|
|
2018-11-13 00:32:37 +03:00
|
|
|
if ((recv_packet->PacketId > c->MaxRecvPacketId)
|
2020-05-12 01:06:59 +03:00
|
|
|
|| (recv_packet->OpCode == OPENVPN_P_CONTROL_HARD_RESET_CLIENT_V2)
|
|
|
|
|| (recv_packet->OpCode == OPENVPN_P_CONTROL_SOFT_RESET_V1))
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
2018-11-13 00:32:37 +03:00
|
|
|
c->MaxRecvPacketId = recv_packet->PacketId;
|
2014-01-04 17:00:08 +04:00
|
|
|
|
2018-11-13 00:32:37 +03:00
|
|
|
// Process the received control packet
|
|
|
|
OvsProcessRecvControlPacket(s, se, c, recv_packet);
|
2014-01-04 17:00:08 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-11-13 00:32:37 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Data packet
|
2018-11-19 23:30:42 +03:00
|
|
|
if (c != NULL && c->Status == OPENVPN_CHANNEL_STATUS_ESTABLISHED)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
2018-11-19 23:30:42 +03:00
|
|
|
UINT size;
|
|
|
|
UCHAR *data = s->TmpBuf;
|
|
|
|
if (c->CipherDecrypt->IsAeadCipher)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
2018-11-19 23:30:42 +03:00
|
|
|
// Update variable part (packet ID) of IV
|
|
|
|
Copy(c->IvRecv, recv_packet->Data, sizeof(recv_packet->PacketId));
|
2014-01-04 17:00:08 +04:00
|
|
|
|
2018-11-19 23:30:42 +03:00
|
|
|
// Decrypt
|
|
|
|
size = OvsDecrypt(c->CipherDecrypt, NULL, c->IvRecv, data, recv_packet->Data + sizeof(UINT), recv_packet->DataSize - sizeof(UINT));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Decrypt
|
|
|
|
size = OvsDecrypt(c->CipherDecrypt, c->MdRecv, c->IvRecv, data, recv_packet->Data, recv_packet->DataSize);
|
2019-10-26 01:36:07 +03:00
|
|
|
if (size > sizeof(UINT))
|
|
|
|
{
|
|
|
|
// Seek buffer after the packet ID
|
|
|
|
data += sizeof(UINT);
|
|
|
|
size -= sizeof(UINT);
|
|
|
|
}
|
2018-11-19 23:30:42 +03:00
|
|
|
}
|
2014-01-04 17:00:08 +04:00
|
|
|
|
2018-11-19 23:30:42 +03:00
|
|
|
// Update of last communication time
|
|
|
|
se->LastCommTick = s->Now;
|
2018-11-03 18:14:56 +03:00
|
|
|
|
2018-11-19 23:30:42 +03:00
|
|
|
if (size < sizeof(ping_signature) || Cmp(data, ping_signature, sizeof(ping_signature)) != 0)
|
|
|
|
{
|
|
|
|
// Receive a packet!
|
|
|
|
if (se->Ipc != NULL)
|
2018-11-13 00:32:37 +03:00
|
|
|
{
|
2018-11-19 23:30:42 +03:00
|
|
|
switch (se->Mode)
|
2018-11-03 18:14:56 +03:00
|
|
|
{
|
2018-11-19 23:30:42 +03:00
|
|
|
case OPENVPN_MODE_L2: // Send an Ethernet packet to a session
|
|
|
|
IPCSendL2(se->Ipc, data, size);
|
|
|
|
break;
|
|
|
|
case OPENVPN_MODE_L3: // Send an IPv4 packet to a session
|
|
|
|
IPCSendIPv4(se->Ipc, data, size);
|
|
|
|
break;
|
2014-01-04 17:00:08 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-11-13 00:32:37 +03:00
|
|
|
|
|
|
|
OvsFreePacket(recv_packet);
|
2014-01-04 17:00:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Remove a packet which the opponent has received from the transmission list
|
|
|
|
void OvsDeleteFromSendingControlPacketList(OPENVPN_CHANNEL *c, UINT num_acks, UINT *acks)
|
|
|
|
{
|
|
|
|
LIST *o;
|
|
|
|
UINT i;
|
|
|
|
// Validate arguments
|
|
|
|
if (c == NULL || num_acks == 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
o = NewListFast(NULL);
|
2020-05-12 01:06:59 +03:00
|
|
|
for (i = 0; i < num_acks; i++)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
|
|
|
UINT ack = acks[i];
|
|
|
|
UINT j;
|
|
|
|
|
2020-05-12 01:06:59 +03:00
|
|
|
for (j = 0; j < LIST_NUM(c->SendControlPacketList); j++)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
|
|
|
OPENVPN_CONTROL_PACKET *p = LIST_DATA(c->SendControlPacketList, j);
|
|
|
|
|
|
|
|
if (p->PacketId == ack)
|
|
|
|
{
|
|
|
|
AddDistinct(o, p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-12 01:06:59 +03:00
|
|
|
for (i = 0; i < LIST_NUM(o); i++)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
|
|
|
OPENVPN_CONTROL_PACKET *p = LIST_DATA(o, i);
|
|
|
|
|
|
|
|
Delete(c->SendControlPacketList, p);
|
|
|
|
|
|
|
|
OvsFreeControlPacket(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
ReleaseList(o);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Process the received control packet
|
|
|
|
void OvsProcessRecvControlPacket(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_CHANNEL *c, OPENVPN_PACKET *p)
|
|
|
|
{
|
|
|
|
FIFO *recv_fifo = NULL;
|
|
|
|
FIFO *send_fifo = NULL;
|
|
|
|
// Validate arguments
|
|
|
|
if (s == NULL || se == NULL || c == NULL || p == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (p->OpCode == OPENVPN_P_CONTROL_V1)
|
|
|
|
{
|
|
|
|
Debug("SSL (c=%u): %u\n", c->KeyId, p->DataSize);
|
|
|
|
|
|
|
|
if (c->SslPipe == NULL)
|
|
|
|
{
|
|
|
|
// Create an SSL pipe
|
|
|
|
Lock(s->Cedar->lock);
|
|
|
|
{
|
2020-05-11 09:23:29 +03:00
|
|
|
if (s->Dh->Size != s->Cedar->DhParamBits)
|
|
|
|
{
|
|
|
|
DhFree(s->Dh);
|
|
|
|
s->Dh = DhNewFromBits(s->Cedar->DhParamBits);
|
|
|
|
}
|
|
|
|
|
|
|
|
c->SslPipe = NewSslPipeEx(true, s->Cedar->ServerX, s->Cedar->ServerK, s->Dh, true, &c->ClientCert);
|
2014-01-04 17:00:08 +04:00
|
|
|
}
|
|
|
|
Unlock(s->Cedar->lock);
|
|
|
|
|
|
|
|
Debug("SSL Pipe Created (c=%u).\n", c->KeyId);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c->SslPipe->IsDisconnected == false)
|
|
|
|
{
|
|
|
|
// Pour the physically received data into SSL pipe
|
|
|
|
if (FifoSize(c->SslPipe->RawIn->SendFifo) < OPENVPN_MAX_SSL_RECV_BUF_SIZE)
|
|
|
|
{
|
|
|
|
Debug("SSL_Write: %u\n", p->DataSize);
|
|
|
|
WriteFifo(c->SslPipe->RawIn->SendFifo, p->Data, p->DataSize);
|
|
|
|
}
|
|
|
|
SyncSslPipe(c->SslPipe);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c->SslPipe != NULL && c->SslPipe->IsDisconnected == false)
|
|
|
|
{
|
|
|
|
recv_fifo = c->SslPipe->SslInOut->RecvFifo;
|
|
|
|
send_fifo = c->SslPipe->SslInOut->SendFifo;
|
|
|
|
}
|
|
|
|
|
|
|
|
Debug("SIZE: recv_fifo = %u, send_fifo = %u\n", FifoSize(recv_fifo), FifoSize(send_fifo));
|
|
|
|
|
|
|
|
switch (c->Status)
|
|
|
|
{
|
|
|
|
case OPENVPN_CHANNEL_STATUS_INIT:
|
|
|
|
switch (p->OpCode)
|
|
|
|
{
|
|
|
|
case OPENVPN_P_CONTROL_SOFT_RESET_V1:
|
|
|
|
// Key update (soft reset)
|
|
|
|
if (se->Established)
|
|
|
|
{
|
|
|
|
if (c->IsInitiatorServer == false)
|
|
|
|
{
|
|
|
|
OvsSendControlPacket(c, OPENVPN_P_CONTROL_SOFT_RESET_V1, NULL, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
c->Status = OPENVPN_CHANNEL_STATUS_TLS_WAIT_CLIENT_KEY;
|
|
|
|
c->IsRekeyChannel = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OPENVPN_P_CONTROL_HARD_RESET_CLIENT_V2:
|
|
|
|
// New connection (hard reset)
|
2019-10-22 05:14:05 +03:00
|
|
|
OvsSendControlPacketEx(c, OPENVPN_P_CONTROL_HARD_RESET_SERVER_V2, NULL, 0, true);
|
2014-01-04 17:00:08 +04:00
|
|
|
|
|
|
|
c->Status = OPENVPN_CHANNEL_STATUS_TLS_WAIT_CLIENT_KEY;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OPENVPN_CHANNEL_STATUS_TLS_WAIT_CLIENT_KEY:
|
|
|
|
if (FifoSize(recv_fifo) >= 1)
|
|
|
|
{
|
|
|
|
OPENVPN_KEY_METHOD_2 data;
|
|
|
|
UCHAR *ptr = FifoPtr(recv_fifo);
|
|
|
|
|
|
|
|
// Parse OPENVPN_KEY_METHOD_2
|
|
|
|
UINT read_size = OvsParseKeyMethod2(&data, ptr, FifoSize(recv_fifo), true);
|
|
|
|
if (read_size != 0)
|
|
|
|
{
|
|
|
|
BUF *b;
|
|
|
|
|
|
|
|
// Success in parsing key information
|
|
|
|
ReadFifo(recv_fifo, NULL, read_size);
|
|
|
|
|
|
|
|
// Set session parameters
|
|
|
|
OvsSetupSessionParameters(s, se, c, &data);
|
|
|
|
|
|
|
|
// Build OPENVPN_KEY_METHOD_2 to respond
|
|
|
|
b = OvsBuildKeyMethod2(&c->ServerKey);
|
|
|
|
|
|
|
|
// Transmission of the response data
|
|
|
|
if (b != NULL)
|
|
|
|
{
|
|
|
|
WriteFifo(send_fifo, b->Buf, b->Size);
|
|
|
|
|
|
|
|
FreeBuf(b);
|
|
|
|
}
|
|
|
|
|
|
|
|
// State transition
|
|
|
|
c->Status = OPENVPN_CHANNEL_STATUS_TLS_WAIT_CLIENT_PUSH_REQUEST;
|
|
|
|
if (c->IsRekeyChannel)
|
|
|
|
{
|
|
|
|
c->Status = OPENVPN_CHANNEL_STATUS_ESTABLISHED;
|
|
|
|
c->EstablishedTick = s->Now;
|
|
|
|
Debug("OpenVPN Channel %u Established (re-key).\n", c->KeyId);
|
|
|
|
OvsLog(s, se, c, "LO_CHANNEL_ESTABLISHED_NEWKEY");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OPENVPN_CHANNEL_STATUS_TLS_WAIT_CLIENT_PUSH_REQUEST:
|
|
|
|
if (FifoSize(recv_fifo) >= 1)
|
|
|
|
{
|
|
|
|
char tmp[MAX_SIZE];
|
|
|
|
UINT read_size = OvsPeekStringFromFifo(recv_fifo, tmp, sizeof(tmp));
|
|
|
|
|
|
|
|
if (read_size >= 1)
|
|
|
|
{
|
|
|
|
Debug("Client->Server (c=%u): %s\n", c->KeyId, tmp);
|
|
|
|
|
|
|
|
ReadFifo(recv_fifo, NULL, read_size);
|
|
|
|
|
|
|
|
if (StartWith(tmp, "PUSH_REQUEST"))
|
|
|
|
{
|
|
|
|
// Since connection requested, start VPN connection
|
|
|
|
// When the IPC VPN connection has not been started yet, start it
|
|
|
|
OvsBeginIPCAsyncConnectionIfEmpty(s, se, c);
|
|
|
|
|
|
|
|
// State transition
|
|
|
|
c->Status = OPENVPN_CHANNEL_STATUS_TLS_VPN_CONNECTING;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OPENVPN_CHANNEL_STATUS_TLS_VPN_CONNECTING:
|
|
|
|
case OPENVPN_CHANNEL_STATUS_ESTABLISHED:
|
|
|
|
if (FifoSize(recv_fifo) >= 1)
|
|
|
|
{
|
|
|
|
char tmp[MAX_SIZE];
|
|
|
|
UINT read_size = OvsPeekStringFromFifo(recv_fifo, tmp, sizeof(tmp));
|
|
|
|
|
|
|
|
if (read_size >= 1)
|
|
|
|
{
|
|
|
|
Debug("Client->Server (c=%u): %s\n", c->KeyId, tmp);
|
|
|
|
|
|
|
|
ReadFifo(recv_fifo, NULL, read_size);
|
|
|
|
|
|
|
|
if (StartWith(tmp, "PUSH_REQUEST"))
|
|
|
|
{
|
|
|
|
WriteFifo(send_fifo, se->PushReplyStr, StrLen(se->PushReplyStr));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Calculate the proper MSS
|
|
|
|
UINT OvsCalcTcpMss(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_CHANNEL *c)
|
|
|
|
{
|
|
|
|
UINT ret = MTU_FOR_PPPOE;
|
|
|
|
// Validate arguments
|
|
|
|
if (s == NULL || se == NULL || c == NULL)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c->MdSend == NULL || c->CipherEncrypt == NULL)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (se->Protocol == OPENVPN_PROTOCOL_TCP)
|
|
|
|
{
|
|
|
|
// Calculation is not required for TCP mode
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// IPv4 / IPv6
|
|
|
|
if (IsIP4(&se->ClientIp))
|
|
|
|
{
|
|
|
|
ret -= 20;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ret -= 40;
|
|
|
|
}
|
|
|
|
|
|
|
|
// UDP
|
|
|
|
ret -= 8;
|
|
|
|
|
|
|
|
// opcode
|
|
|
|
ret -= 1;
|
|
|
|
|
|
|
|
// HMAC
|
|
|
|
ret -= c->MdSend->Size;
|
|
|
|
|
|
|
|
// IV
|
|
|
|
ret -= c->CipherEncrypt->IvSize;
|
|
|
|
|
|
|
|
// Packet ID
|
|
|
|
ret -= 4;
|
|
|
|
|
|
|
|
if (c->CipherEncrypt->IsNullCipher == false)
|
|
|
|
{
|
|
|
|
// block
|
|
|
|
ret -= c->CipherEncrypt->BlockSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (se->Mode == OPENVPN_MODE_L2)
|
|
|
|
{
|
|
|
|
// Inner Ethernet Header
|
|
|
|
ret -= 14;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Inner IPv4
|
|
|
|
ret -= 20;
|
|
|
|
|
|
|
|
// Inner TCP
|
|
|
|
ret -= 20;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// When the IPC VPN connection has not been started yet, start it
|
|
|
|
void OvsBeginIPCAsyncConnectionIfEmpty(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_CHANNEL *c)
|
|
|
|
{
|
|
|
|
// Validate arguments
|
|
|
|
if (s == NULL || se == NULL || c == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IsIPCConnected(se->Ipc) == false)
|
|
|
|
{
|
|
|
|
FreeIPC(se->Ipc);
|
|
|
|
|
|
|
|
se->Ipc = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (se->IpcAsync == NULL)
|
|
|
|
{
|
2018-04-20 18:33:07 +03:00
|
|
|
LIST *pi;
|
2014-01-04 17:00:08 +04:00
|
|
|
IPC_PARAM p;
|
|
|
|
ETHERIP_ID id;
|
|
|
|
|
|
|
|
Zero(&p, sizeof(p));
|
|
|
|
Zero(&id, sizeof(id));
|
|
|
|
|
|
|
|
// Parse the user name
|
|
|
|
PPPParseUsername(s->Cedar, c->ClientKey.Username, &id);
|
|
|
|
|
|
|
|
|
|
|
|
// Build IPC connection parameters
|
|
|
|
StrCpy(p.ClientName, sizeof(p.ClientName), OPENVPN_IPC_CLIENT_NAME);
|
|
|
|
StrCpy(p.Postfix, sizeof(p.Postfix), (se->Mode == OPENVPN_MODE_L3 ? OPENVPN_IPC_POSTFIX_L3 : OPENVPN_IPC_POSTFIX_L2));
|
|
|
|
|
|
|
|
StrCpy(p.UserName, sizeof(p.UserName), id.UserName);
|
|
|
|
StrCpy(p.HubName, sizeof(p.HubName), id.HubName);
|
|
|
|
StrCpy(p.Password, sizeof(p.Password), c->ClientKey.Password);
|
|
|
|
|
|
|
|
Copy(&p.ClientIp, &se->ClientIp, sizeof(IP));
|
|
|
|
p.ClientPort = se->ClientPort;
|
|
|
|
|
|
|
|
Copy(&p.ServerIp, &se->ServerIp, sizeof(IP));
|
|
|
|
p.ServerPort = se->ServerPort;
|
|
|
|
|
|
|
|
if (c->CipherEncrypt->IsNullCipher == false)
|
|
|
|
{
|
|
|
|
StrCpy(p.CryptName, sizeof(p.CryptName), c->CipherEncrypt->Name);
|
|
|
|
}
|
|
|
|
|
2018-04-20 18:33:07 +03:00
|
|
|
// OpenVPN sends the default gateway's MAC address,
|
|
|
|
// if the option --push-peer-info is enabled.
|
|
|
|
// It also sends all of the client's environment
|
|
|
|
// variables whose names start with "UV_".
|
2018-10-06 23:41:35 +03:00
|
|
|
pi = NewEntryList(c->ClientKey.PeerInfo, "\n", "=\t");
|
2018-04-20 18:33:07 +03:00
|
|
|
|
|
|
|
// Check presence of custom hostname
|
2018-10-06 23:41:35 +03:00
|
|
|
if (EntryListHasKey(pi, "UV_HOSTNAME"))
|
2018-04-20 18:33:07 +03:00
|
|
|
{
|
2018-10-06 23:41:35 +03:00
|
|
|
StrCpy(p.ClientHostname, sizeof(p.ClientHostname), EntryListStrValue(pi, "UV_HOSTNAME"));
|
2018-04-20 18:33:07 +03:00
|
|
|
}
|
|
|
|
else // Use the default gateway's MAC address
|
|
|
|
{
|
2018-10-06 23:41:35 +03:00
|
|
|
StrCpy(p.ClientHostname, sizeof(p.ClientHostname), EntryListStrValue(pi, "IV_HWADDR"));
|
2018-04-20 18:33:07 +03:00
|
|
|
}
|
|
|
|
|
2018-10-06 23:41:35 +03:00
|
|
|
FreeEntryList(pi);
|
2018-04-20 18:33:07 +03:00
|
|
|
|
2014-01-04 17:00:08 +04:00
|
|
|
if (se->Mode == OPENVPN_MODE_L3)
|
|
|
|
{
|
|
|
|
// L3 Mode
|
|
|
|
p.IsL3Mode = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// L2 Mode
|
|
|
|
p.BridgeMode = true;
|
|
|
|
}
|
|
|
|
|
2019-06-29 15:30:58 +03:00
|
|
|
if (IsEmptyStr(c->ClientKey.Username) || IsEmptyStr(c->ClientKey.Password))
|
2018-04-06 00:04:58 +03:00
|
|
|
{
|
2019-06-29 15:30:58 +03:00
|
|
|
// OpenVPN X.509 certificate authentication will be used only when no username / password is specified
|
|
|
|
if (c->ClientCert.X != NULL)
|
|
|
|
{
|
|
|
|
p.ClientCertificate = c->ClientCert.X;
|
|
|
|
}
|
2018-04-06 00:04:58 +03:00
|
|
|
}
|
|
|
|
|
2019-10-19 11:34:12 +03:00
|
|
|
p.Layer = (se->Mode == OPENVPN_MODE_L2) ? IPC_LAYER_2 : IPC_LAYER_3;
|
|
|
|
|
2014-01-04 17:00:08 +04:00
|
|
|
// Calculate the MSS
|
|
|
|
p.Mss = OvsCalcTcpMss(s, se, c);
|
|
|
|
Debug("MSS=%u\n", p.Mss);
|
|
|
|
|
|
|
|
// Start an IPC connection
|
|
|
|
se->IpcAsync = NewIPCAsync(s->Cedar, &p, s->SockEvent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Peek a NULL-terminated string from the FIFO
|
|
|
|
UINT OvsPeekStringFromFifo(FIFO *f, char *str, UINT str_size)
|
|
|
|
{
|
|
|
|
UINT i;
|
|
|
|
bool ok = false;
|
|
|
|
// Validate arguments
|
|
|
|
if (f == NULL || str == NULL || str_size == 0)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
StrCpy(str, str_size, "");
|
|
|
|
|
2020-05-12 01:06:59 +03:00
|
|
|
for (i = 0; i < MIN(str_size, FifoSize(f)); i++)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
|
|
|
char c = *(((char *)FifoPtr(f)) + i);
|
|
|
|
|
|
|
|
if (c != 0)
|
|
|
|
{
|
|
|
|
str[i] = c;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
str[i] = 0;
|
|
|
|
i++;
|
|
|
|
ok = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ok == false)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set session parameters
|
|
|
|
void OvsSetupSessionParameters(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_CHANNEL *c, OPENVPN_KEY_METHOD_2 *data)
|
|
|
|
{
|
|
|
|
LIST *o;
|
|
|
|
BUF *b;
|
2014-11-18 06:05:48 +03:00
|
|
|
char opt_str[MAX_SIZE];
|
2018-11-03 18:14:56 +03:00
|
|
|
char *cipher_name, *md_name;
|
2014-01-04 17:00:08 +04:00
|
|
|
// Validate arguments
|
|
|
|
if (s == NULL || se == NULL || c == NULL || data == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Copy(&c->ClientKey, data, sizeof(OPENVPN_KEY_METHOD_2));
|
|
|
|
|
|
|
|
// Parse the parameter string
|
|
|
|
Debug("Parsing Option Str: %s\n", data->OptionString);
|
|
|
|
|
|
|
|
OvsLog(s, se, c, "LO_OPTION_STR_RECV", data->OptionString);
|
|
|
|
|
2018-04-06 00:04:58 +03:00
|
|
|
if (c->ClientCert.X != NULL)
|
|
|
|
{
|
|
|
|
if (c->ClientCert.X->subject_name != NULL)
|
|
|
|
{
|
|
|
|
OvsLog(s, se, c, "LO_CLIENT_CERT", c->ClientCert.X->subject_name->CommonName);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
OvsLog(s, se, c, "LO_CLIENT_CERT", "(unknown CN)");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (!c->ClientCert.PreverifyErr)
|
|
|
|
{
|
|
|
|
OvsLog(s, se, c, "LO_CLIENT_NO_CERT");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
OvsLog(s, se, c, "LO_CLIENT_UNVERIFIED_CERT", c->ClientCert.PreverifyErrMessage);
|
|
|
|
}
|
|
|
|
|
2014-11-18 06:05:48 +03:00
|
|
|
Zero(opt_str, sizeof(opt_str));
|
|
|
|
StrCpy(opt_str, sizeof(opt_str), data->OptionString);
|
|
|
|
if (s->Cedar != NULL && (IsEmptyStr(opt_str) || StartWith(opt_str, "V0 UNDEF") || InStr(opt_str, ",") == false))
|
|
|
|
{
|
2020-07-20 00:45:12 +03:00
|
|
|
StrCpy(opt_str, sizeof(opt_str), s->DefaultClientOption);
|
2014-11-18 06:05:48 +03:00
|
|
|
}
|
|
|
|
|
2018-10-06 23:41:35 +03:00
|
|
|
o = NewEntryList(opt_str, ",", " \t");
|
2014-01-04 17:00:08 +04:00
|
|
|
|
|
|
|
if (se->Mode == OPENVPN_MODE_UNKNOWN)
|
|
|
|
{
|
|
|
|
UINT mtu;
|
|
|
|
// Layer
|
2018-10-06 23:41:35 +03:00
|
|
|
if (StrCmpi(EntryListStrValue(o, "dev-type"), "tun") == 0)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
|
|
|
// L3
|
|
|
|
se->Mode = OPENVPN_MODE_L3;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// L2
|
|
|
|
se->Mode = OPENVPN_MODE_L2;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Link MTU
|
2018-10-06 23:41:35 +03:00
|
|
|
mtu = EntryListIntValue(o, "link-mtu");
|
2014-01-04 17:00:08 +04:00
|
|
|
if (mtu == 0)
|
|
|
|
{
|
|
|
|
mtu = OPENVPN_MTU_LINK;
|
|
|
|
}
|
|
|
|
se->LinkMtu = mtu;
|
|
|
|
|
|
|
|
// Tun MTU
|
2018-10-06 23:41:35 +03:00
|
|
|
mtu = EntryListIntValue(o, "tun-mtu");
|
2014-01-04 17:00:08 +04:00
|
|
|
if (mtu == 0)
|
|
|
|
{
|
|
|
|
mtu = OPENVPN_MTU_TUN;
|
|
|
|
}
|
|
|
|
se->TunMtu = mtu;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Protocol
|
|
|
|
if (se->Protocol == OPENVPN_PROTOCOL_TCP)
|
|
|
|
{
|
|
|
|
// TCP
|
|
|
|
if (IsIP6(&se->ClientIp) == false)
|
|
|
|
{
|
|
|
|
StrCpy(c->Proto, sizeof(c->Proto), "TCPv4_SERVER");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
StrCpy(c->Proto, sizeof(c->Proto), "TCPv6_SERVER");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// UDP
|
|
|
|
if (IsIP6(&se->ClientIp) == false)
|
|
|
|
{
|
|
|
|
StrCpy(c->Proto, sizeof(c->Proto), "UDPv4");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
StrCpy(c->Proto, sizeof(c->Proto), "UDPv6");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Encryption algorithm
|
2018-10-06 23:41:35 +03:00
|
|
|
cipher_name = EntryListStrValue(o, "cipher");
|
2014-01-04 17:00:08 +04:00
|
|
|
|
|
|
|
// Hash algorithm
|
2018-11-03 18:14:56 +03:00
|
|
|
md_name = EntryListStrValue(o, "auth");
|
2014-01-04 17:00:08 +04:00
|
|
|
|
|
|
|
// Random number generation
|
|
|
|
Rand(c->ServerKey.Random1, sizeof(c->ServerKey.Random1));
|
|
|
|
Rand(c->ServerKey.Random2, sizeof(c->ServerKey.Random2));
|
|
|
|
|
|
|
|
// Generate the Master Secret
|
|
|
|
b = NewBuf();
|
|
|
|
WriteBuf(b, OPENVPN_PREMASTER_LABEL, StrLen(OPENVPN_PREMASTER_LABEL));
|
|
|
|
WriteBuf(b, c->ClientKey.Random1, sizeof(c->ClientKey.Random1));
|
|
|
|
WriteBuf(b, c->ServerKey.Random1, sizeof(c->ServerKey.Random1));
|
|
|
|
Enc_tls1_PRF(b->Buf, b->Size,
|
2020-05-12 01:06:59 +03:00
|
|
|
c->ClientKey.PreMasterSecret, sizeof(c->ClientKey.PreMasterSecret),
|
|
|
|
c->MasterSecret, sizeof(c->MasterSecret));
|
2014-01-04 17:00:08 +04:00
|
|
|
FreeBuf(b);
|
|
|
|
|
|
|
|
// Generate an Expansion Key
|
|
|
|
b = NewBuf();
|
|
|
|
WriteBuf(b, OPENVPN_EXPANSION_LABEL, StrLen(OPENVPN_EXPANSION_LABEL));
|
|
|
|
WriteBuf(b, c->ClientKey.Random2, sizeof(c->ClientKey.Random2));
|
|
|
|
WriteBuf(b, c->ServerKey.Random2, sizeof(c->ServerKey.Random2));
|
|
|
|
WriteBufInt64(b, se->ClientSessionId);
|
|
|
|
WriteBufInt64(b, se->ServerSessionId);
|
|
|
|
Enc_tls1_PRF(b->Buf, b->Size, c->MasterSecret, sizeof(c->MasterSecret),
|
2020-05-12 01:06:59 +03:00
|
|
|
c->ExpansionKey, sizeof(c->ExpansionKey));
|
2014-01-04 17:00:08 +04:00
|
|
|
FreeBuf(b);
|
|
|
|
|
2018-11-03 18:14:56 +03:00
|
|
|
// Set up the encryption algorithm
|
|
|
|
c->CipherEncrypt = OvsGetCipher(cipher_name);
|
|
|
|
c->CipherDecrypt = OvsGetCipher(cipher_name);
|
2014-01-04 17:00:08 +04:00
|
|
|
SetCipherKey(c->CipherDecrypt, c->ExpansionKey + 0, false);
|
|
|
|
SetCipherKey(c->CipherEncrypt, c->ExpansionKey + 128, true);
|
|
|
|
|
2018-11-03 18:14:56 +03:00
|
|
|
if (c->CipherDecrypt->IsAeadCipher)
|
|
|
|
{
|
|
|
|
// In AEAD mode the IV is composed by the packet ID and a part of the HMAC key
|
|
|
|
Copy(c->IvRecv + sizeof(c->LastDataPacketId), c->ExpansionKey + 64, c->CipherDecrypt->IvSize - sizeof(c->LastDataPacketId));
|
|
|
|
Copy(c->IvSend + sizeof(c->LastDataPacketId), c->ExpansionKey + 192, c->CipherEncrypt->IvSize - sizeof(c->LastDataPacketId));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Set up the hash algorithm
|
|
|
|
c->MdSend = OvsGetMd(md_name);
|
|
|
|
c->MdRecv = OvsGetMd(md_name);
|
|
|
|
SetMdKey(c->MdRecv, c->ExpansionKey + 64, c->MdRecv->Size);
|
|
|
|
SetMdKey(c->MdSend, c->ExpansionKey + 192, c->MdSend->Size);
|
|
|
|
}
|
2014-01-04 17:00:08 +04:00
|
|
|
|
2018-08-12 02:03:56 +03:00
|
|
|
// We pass the cipher name sent from the OpenVPN client, unless it's a different cipher, to prevent a message such as:
|
|
|
|
// WARNING: 'cipher' is used inconsistently, local='cipher AES-128-GCM', remote='cipher aes-128-gcm'
|
|
|
|
// It happens because OpenVPN uses "strcmp()" to compare the local and remote parameters:
|
|
|
|
// https://github.com/OpenVPN/openvpn/blob/a6fd48ba36ede465b0905a95568c3ec0d425ca71/src/openvpn/options.c#L3819-L3831
|
|
|
|
if (StrCmpi(cipher_name, c->CipherEncrypt->Name) != 0)
|
|
|
|
{
|
|
|
|
cipher_name = c->CipherEncrypt->Name;
|
|
|
|
}
|
|
|
|
|
2014-01-04 17:00:08 +04:00
|
|
|
// Generate the response option string
|
|
|
|
Format(c->ServerKey.OptionString, sizeof(c->ServerKey.OptionString),
|
2020-05-12 01:06:59 +03:00
|
|
|
"V4,dev-type %s,link-mtu %u,tun-mtu %u,proto %s,"
|
|
|
|
"cipher %s,auth %s,keysize %u,key-method 2,tls-server",
|
|
|
|
(se->Mode == OPENVPN_MODE_L2 ? "tap" : "tun"),
|
|
|
|
se->LinkMtu,
|
|
|
|
se->TunMtu,
|
|
|
|
c->Proto,
|
|
|
|
cipher_name, md_name, c->CipherEncrypt->KeySize * 8);
|
2018-11-03 18:14:56 +03:00
|
|
|
|
|
|
|
FreeEntryList(o);
|
2014-01-04 17:00:08 +04:00
|
|
|
|
2018-11-03 18:14:56 +03:00
|
|
|
Debug("OvsSetupSessionParameters(): Built OptionString: %s\n", c->ServerKey.OptionString);
|
2014-01-04 17:00:08 +04:00
|
|
|
OvsLog(s, se, c, "LO_OPTION_STR_SEND", c->ServerKey.OptionString);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the encryption algorithm
|
|
|
|
CIPHER *OvsGetCipher(char *name)
|
|
|
|
{
|
|
|
|
CIPHER *c = NULL;
|
|
|
|
|
2018-08-12 02:03:56 +03:00
|
|
|
// OpenVPN sends the cipher name in uppercase, even if it's not standard,
|
|
|
|
// thus we have to convert it to lowercase for EVP_get_cipherbyname().
|
|
|
|
char lowercase_name[MAX_SIZE];
|
|
|
|
StrCpy(lowercase_name, sizeof(lowercase_name), name);
|
|
|
|
StrLower(lowercase_name);
|
|
|
|
|
|
|
|
if (IsEmptyStr(lowercase_name) == false)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
2018-08-12 02:03:56 +03:00
|
|
|
c = NewCipher(lowercase_name);
|
2014-01-04 17:00:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (c == NULL)
|
|
|
|
{
|
|
|
|
c = NewCipher(OPENVPN_DEFAULT_CIPHER);
|
|
|
|
}
|
|
|
|
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the hash algorithm
|
|
|
|
MD *OvsGetMd(char *name)
|
|
|
|
{
|
|
|
|
MD *m = NULL;
|
|
|
|
|
2018-08-02 17:18:41 +03:00
|
|
|
if (IsEmptyStr(name) == false)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
|
|
|
m = NewMd(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m == NULL)
|
|
|
|
{
|
|
|
|
m = NewMd(OPENVPN_DEFAULT_MD);
|
|
|
|
}
|
|
|
|
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Build the data from KEY_METHOD2
|
|
|
|
BUF *OvsBuildKeyMethod2(OPENVPN_KEY_METHOD_2 *d)
|
|
|
|
{
|
|
|
|
BUF *b;
|
|
|
|
UCHAR uc;
|
|
|
|
// Validate arguments
|
|
|
|
if (d == NULL)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
b = NewBuf();
|
|
|
|
|
|
|
|
// Reserved
|
|
|
|
WriteBufInt(b, 0);
|
|
|
|
|
|
|
|
// Method
|
|
|
|
uc = 2;
|
|
|
|
WriteBuf(b, &uc, sizeof(UCHAR));
|
|
|
|
|
|
|
|
// Random1
|
|
|
|
WriteBuf(b, d->Random1, sizeof(d->Random1));
|
|
|
|
|
|
|
|
// Random2
|
|
|
|
WriteBuf(b, d->Random2, sizeof(d->Random2));
|
|
|
|
|
|
|
|
// Option String
|
|
|
|
OvsWriteStringToBuf(b, d->OptionString, sizeof(d->OptionString));
|
|
|
|
|
|
|
|
// Username
|
|
|
|
OvsWriteStringToBuf(b, d->Username, sizeof(d->Username));
|
|
|
|
|
|
|
|
// Password
|
|
|
|
OvsWriteStringToBuf(b, d->Password, sizeof(d->Password));
|
|
|
|
|
|
|
|
// PeerInfo
|
|
|
|
OvsWriteStringToBuf(b, d->PeerInfo, sizeof(d->PeerInfo));
|
|
|
|
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Append a string to buf
|
|
|
|
void OvsWriteStringToBuf(BUF *b, char *str, UINT max_size)
|
|
|
|
{
|
|
|
|
USHORT us;
|
|
|
|
UINT i;
|
|
|
|
char *tmp;
|
|
|
|
// Validate arguments
|
|
|
|
if (b == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (str == NULL)
|
|
|
|
{
|
|
|
|
str = "";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (StrLen(str) == 0)
|
|
|
|
{
|
|
|
|
us = 0;
|
|
|
|
WriteBuf(b, &us, sizeof(USHORT));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
i = StrSize(str);
|
|
|
|
i = MIN(i, max_size);
|
|
|
|
us = Endian16((USHORT)i);
|
|
|
|
WriteBuf(b, &us, sizeof(USHORT));
|
|
|
|
|
|
|
|
tmp = Malloc(i);
|
|
|
|
Copy(tmp, str, i);
|
|
|
|
tmp[i - 1] = 0;
|
|
|
|
WriteBuf(b, tmp, i);
|
|
|
|
|
|
|
|
Free(tmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse the KEY_METHOD2
|
|
|
|
UINT OvsParseKeyMethod2(OPENVPN_KEY_METHOD_2 *ret, UCHAR *data, UINT size, bool client_mode)
|
|
|
|
{
|
|
|
|
BUF *b;
|
|
|
|
UINT read_size = 0;
|
|
|
|
UINT ui;
|
|
|
|
UCHAR uc;
|
|
|
|
// Validate arguments
|
|
|
|
Zero(ret, sizeof(OPENVPN_KEY_METHOD_2));
|
|
|
|
if (ret == NULL || data == NULL || size == 0)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
b = NewBuf();
|
|
|
|
WriteBuf(b, data, size);
|
|
|
|
SeekBuf(b, 0, 0);
|
|
|
|
|
|
|
|
// Reserved
|
|
|
|
if (ReadBuf(b, &ui, sizeof(UINT)) == sizeof(UINT))
|
|
|
|
{
|
|
|
|
// Method
|
|
|
|
if (ReadBuf(b, &uc, sizeof(UCHAR)) == sizeof(UCHAR) && uc == 2)
|
|
|
|
{
|
|
|
|
// Pre Master Secret
|
|
|
|
if (client_mode == false || ReadBuf(b, ret->PreMasterSecret, sizeof(ret->PreMasterSecret)) == sizeof(ret->PreMasterSecret))
|
|
|
|
{
|
|
|
|
// Random1
|
|
|
|
if (ReadBuf(b, ret->Random1, sizeof(ret->Random1)) == sizeof(ret->Random1))
|
|
|
|
{
|
|
|
|
// Random2
|
|
|
|
if (ReadBuf(b, ret->Random2, sizeof(ret->Random2)) == sizeof(ret->Random2))
|
|
|
|
{
|
2017-10-18 12:24:21 +03:00
|
|
|
// String
|
|
|
|
if (OvsReadStringFromBuf(b, ret->OptionString, sizeof(ret->OptionString)) &&
|
2020-05-12 01:06:59 +03:00
|
|
|
OvsReadStringFromBuf(b, ret->Username, sizeof(ret->Username)) &&
|
|
|
|
OvsReadStringFromBuf(b, ret->Password, sizeof(ret->Password)))
|
|
|
|
{
|
|
|
|
if (!OvsReadStringFromBuf(b, ret->PeerInfo, sizeof(ret->PeerInfo)))
|
2018-05-04 00:31:07 +03:00
|
|
|
{
|
2020-05-12 01:06:59 +03:00
|
|
|
Zero(ret->PeerInfo, sizeof(ret->PeerInfo));
|
|
|
|
}
|
2017-10-18 12:24:21 +03:00
|
|
|
read_size = b->Current;
|
|
|
|
}
|
2014-01-04 17:00:08 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FreeBuf(b);
|
|
|
|
|
|
|
|
return read_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read a string from BUF
|
|
|
|
bool OvsReadStringFromBuf(BUF *b, char *str, UINT str_size)
|
|
|
|
{
|
|
|
|
USHORT us;
|
|
|
|
// Validate arguments
|
|
|
|
if (b == NULL || str == NULL)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ReadBuf(b, &us, sizeof(USHORT)) != sizeof(USHORT))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
us = Endian16(us);
|
|
|
|
|
|
|
|
if (us == 0)
|
|
|
|
{
|
|
|
|
StrCpy(str, str_size, "");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (us > str_size)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ReadBuf(b, str, us) != us)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (str[us - 1] != 0)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Transmission of control packet (Automatic segmentation with the maximum size)
|
|
|
|
void OvsSendControlPacketWithAutoSplit(OPENVPN_CHANNEL *c, UCHAR opcode, UCHAR *data, UINT data_size)
|
|
|
|
{
|
|
|
|
BUF *b;
|
|
|
|
// Validate arguments
|
|
|
|
if (c == NULL || (data_size != 0 && data == NULL))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
b = NewBuf();
|
|
|
|
WriteBuf(b, data, data_size);
|
|
|
|
SeekBuf(b, 0, 0);
|
|
|
|
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
UCHAR tmp[OPENVPN_CONTROL_PACKET_MAX_DATASIZE];
|
|
|
|
UINT size = ReadBuf(b, tmp, sizeof(tmp));
|
|
|
|
|
|
|
|
if (size == 0)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
OvsSendControlPacket(c, opcode, tmp, size);
|
|
|
|
//Debug(" *** CNT SEND %u\n", size);
|
|
|
|
}
|
|
|
|
|
|
|
|
FreeBuf(b);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Send the control packet
|
|
|
|
void OvsSendControlPacket(OPENVPN_CHANNEL *c, UCHAR opcode, UCHAR *data, UINT data_size)
|
2019-10-22 05:14:05 +03:00
|
|
|
{
|
|
|
|
OvsSendControlPacketEx(c, opcode, data, data_size, false);
|
|
|
|
}
|
|
|
|
void OvsSendControlPacketEx(OPENVPN_CHANNEL *c, UCHAR opcode, UCHAR *data, UINT data_size, bool no_resend)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
|
|
|
OPENVPN_CONTROL_PACKET *p;
|
|
|
|
// Validate arguments
|
|
|
|
if (c == NULL || (data_size != 0 && data == NULL))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
p = ZeroMalloc(sizeof(OPENVPN_CONTROL_PACKET));
|
|
|
|
|
2019-10-22 05:14:05 +03:00
|
|
|
p->NoResend = no_resend;
|
|
|
|
|
2014-01-04 17:00:08 +04:00
|
|
|
p->OpCode = opcode;
|
|
|
|
p->PacketId = c->NextSendPacketId++;
|
|
|
|
|
|
|
|
if (data != NULL)
|
|
|
|
{
|
|
|
|
p->Data = Clone(data, data_size);
|
|
|
|
p->DataSize = data_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
p->NextSendTime = 0;
|
|
|
|
|
|
|
|
Add(c->SendControlPacketList, p);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release the control packet being transmitted
|
|
|
|
void OvsFreeControlPacket(OPENVPN_CONTROL_PACKET *p)
|
|
|
|
{
|
|
|
|
// Validate arguments
|
|
|
|
if (p == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (p->Data != NULL)
|
|
|
|
{
|
|
|
|
Free(p->Data);
|
|
|
|
}
|
|
|
|
|
|
|
|
Free(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get a list of packet ID to be responded
|
|
|
|
UINT OvsGetAckReplyList(OPENVPN_CHANNEL *c, UINT *ret)
|
|
|
|
{
|
|
|
|
UINT i;
|
|
|
|
LIST *o = NULL;
|
|
|
|
UINT num;
|
|
|
|
// Validate arguments
|
|
|
|
if (c == NULL || ret == NULL)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
num = MIN(LIST_NUM(c->AckReplyList), OPENVPN_MAX_NUMACK);
|
|
|
|
|
2020-05-12 01:06:59 +03:00
|
|
|
for (i = 0; i < num; i++)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
|
|
|
UINT *v = LIST_DATA(c->AckReplyList, i);
|
|
|
|
|
|
|
|
if (o == NULL)
|
|
|
|
{
|
|
|
|
o = NewListFast(NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
Add(o, v);
|
|
|
|
|
|
|
|
ret[i] = *v;
|
|
|
|
}
|
|
|
|
|
2020-05-12 01:06:59 +03:00
|
|
|
for (i = 0; i < LIST_NUM(o); i++)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
|
|
|
UINT *v = LIST_DATA(o, i);
|
|
|
|
|
|
|
|
Delete(c->AckReplyList, v);
|
|
|
|
|
|
|
|
Free(v);
|
|
|
|
}
|
|
|
|
|
|
|
|
ReleaseList(o);
|
|
|
|
|
|
|
|
return num;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release the channel
|
|
|
|
void OvsFreeChannel(OPENVPN_CHANNEL *c)
|
|
|
|
{
|
|
|
|
UINT i;
|
|
|
|
// Validate arguments
|
|
|
|
if (c == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c->SslPipe != NULL)
|
|
|
|
{
|
|
|
|
FreeSslPipe(c->SslPipe);
|
|
|
|
}
|
|
|
|
|
|
|
|
ReleaseIntList(c->AckReplyList);
|
|
|
|
|
2020-05-12 01:06:59 +03:00
|
|
|
for (i = 0; i < LIST_NUM(c->SendControlPacketList); i++)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
|
|
|
OPENVPN_CONTROL_PACKET *p = LIST_DATA(c->SendControlPacketList, i);
|
|
|
|
|
|
|
|
OvsFreeControlPacket(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
ReleaseList(c->SendControlPacketList);
|
|
|
|
|
|
|
|
FreeCipher(c->CipherDecrypt);
|
|
|
|
FreeCipher(c->CipherEncrypt);
|
|
|
|
|
|
|
|
FreeMd(c->MdRecv);
|
|
|
|
FreeMd(c->MdSend);
|
|
|
|
|
2018-04-06 00:04:58 +03:00
|
|
|
if (c->ClientCert.X != NULL)
|
|
|
|
{
|
|
|
|
FreeX(c->ClientCert.X);
|
|
|
|
}
|
|
|
|
|
2014-01-04 17:00:08 +04:00
|
|
|
Free(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a new channel
|
|
|
|
OPENVPN_CHANNEL *OvsNewChannel(OPENVPN_SESSION *se, UCHAR key_id)
|
|
|
|
{
|
|
|
|
OPENVPN_CHANNEL *c;
|
|
|
|
// Validate arguments
|
|
|
|
if (se == NULL)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
c = ZeroMalloc(sizeof(OPENVPN_CHANNEL));
|
|
|
|
|
|
|
|
c->Session = se;
|
|
|
|
c->Server = se->Server;
|
|
|
|
|
|
|
|
c->Status = OPENVPN_CHANNEL_STATUS_INIT;
|
|
|
|
|
|
|
|
c->AckReplyList = NewIntList(true);
|
|
|
|
|
|
|
|
c->SendControlPacketList = NewListFast(NULL);
|
|
|
|
|
|
|
|
c->KeyId = key_id;
|
|
|
|
|
2018-11-03 18:14:56 +03:00
|
|
|
Rand(c->IvSend, sizeof(c->IvSend));
|
|
|
|
Rand(c->IvRecv, sizeof(c->IvRecv));
|
2014-01-04 17:00:08 +04:00
|
|
|
|
|
|
|
//c->NextRekey = se->Server->Now + (UINT64)5000;
|
|
|
|
|
|
|
|
se->LastCreatedChannelIndex = key_id;
|
|
|
|
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a new server-side channel ID
|
|
|
|
UINT64 OvsNewServerSessionId(OPENVPN_SERVER *s)
|
|
|
|
{
|
|
|
|
// Validate arguments
|
|
|
|
if (s == NULL)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
UINT64 id = Rand64();
|
|
|
|
UINT i;
|
|
|
|
bool exists = false;
|
|
|
|
|
|
|
|
if (id == 0 || id == (UINT64)(0xFFFFFFFFFFFFFFFFULL))
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-05-12 01:06:59 +03:00
|
|
|
for (i = 0; i < LIST_NUM(s->SessionList); i++)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
|
|
|
OPENVPN_SESSION *se = LIST_DATA(s->SessionList, i);
|
|
|
|
if (se->ServerSessionId == id)
|
|
|
|
{
|
|
|
|
exists = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (exists == false)
|
|
|
|
{
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Build and submit the OpenVPN data packet
|
|
|
|
void OvsSendDataPacket(OPENVPN_CHANNEL *c, UCHAR key_id, UINT data_packet_id, void *data, UINT data_size)
|
|
|
|
{
|
2018-11-03 18:14:56 +03:00
|
|
|
const UCHAR op = ((OPENVPN_P_DATA_V1 << 3) & 0xF8) | (key_id & 0x07);
|
2014-01-04 17:00:08 +04:00
|
|
|
UCHAR *dest_data;
|
|
|
|
UINT dest_size;
|
|
|
|
// Validate arguments
|
|
|
|
if (c == NULL || data == NULL || data_size == 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-11-03 18:14:56 +03:00
|
|
|
// [ xxx ] = unprotected
|
|
|
|
// [ - xxx - ] = authenticated
|
|
|
|
// [ * xxx * ] = encrypted and authenticated
|
2014-01-04 17:00:08 +04:00
|
|
|
|
2018-11-03 18:14:56 +03:00
|
|
|
if (c->CipherEncrypt->IsAeadCipher)
|
|
|
|
{
|
|
|
|
// [ opcode ] [ - packet ID - ] [ TAG ] [ * packet payload * ]
|
|
|
|
UCHAR tag[16];
|
2014-01-04 17:00:08 +04:00
|
|
|
|
2018-11-03 18:14:56 +03:00
|
|
|
// Update variable part (packet ID) of IV
|
|
|
|
WRITE_UINT(c->IvSend, data_packet_id);
|
2014-01-04 17:00:08 +04:00
|
|
|
|
2018-11-03 18:14:56 +03:00
|
|
|
// Prepare a buffer to store the results
|
|
|
|
dest_data = Malloc(sizeof(op) + sizeof(data_packet_id) + sizeof(tag) + data_size + 256);
|
2014-01-04 17:00:08 +04:00
|
|
|
|
2018-11-03 18:14:56 +03:00
|
|
|
// Set data size to the maximum known
|
|
|
|
dest_size = sizeof(op) + sizeof(data_packet_id) + sizeof(tag);
|
2014-01-04 17:00:08 +04:00
|
|
|
|
2018-11-03 18:14:56 +03:00
|
|
|
// Write opcode
|
|
|
|
dest_data[0] = op;
|
2014-01-04 17:00:08 +04:00
|
|
|
|
2018-11-03 18:14:56 +03:00
|
|
|
// Write packet ID
|
|
|
|
WRITE_UINT(dest_data + sizeof(op), data_packet_id);
|
|
|
|
|
|
|
|
// Write encrypted payload
|
|
|
|
dest_size += OvsEncrypt(c->CipherEncrypt, NULL, c->IvSend, tag, dest_data + dest_size, data, data_size, c->IvSend, sizeof(data_packet_id));
|
|
|
|
|
|
|
|
// Write authentication tag
|
|
|
|
Copy(dest_data + sizeof(op) + sizeof(data_packet_id), tag, sizeof(tag));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// [ opcode ] [ HMAC ] [ - IV - ] [ * packet ID * ] [ * packet payload * ]
|
|
|
|
UINT encrypted_size = sizeof(data_packet_id) + data_size;
|
|
|
|
UCHAR *encrypted_data = ZeroMalloc(encrypted_size);
|
|
|
|
WRITE_UINT(encrypted_data, data_packet_id);
|
|
|
|
Copy(encrypted_data + sizeof(data_packet_id), data, data_size);
|
|
|
|
|
|
|
|
// Prepare a buffer to store the results
|
|
|
|
dest_data = Malloc(sizeof(op) + c->MdSend->Size + c->CipherEncrypt->IvSize + encrypted_size + 256);
|
|
|
|
|
|
|
|
// Set data size to the maximum known
|
|
|
|
dest_size = sizeof(op);
|
|
|
|
|
|
|
|
// Write opcode
|
|
|
|
dest_data[0] = op;
|
2014-01-04 17:00:08 +04:00
|
|
|
|
2018-11-03 18:14:56 +03:00
|
|
|
// Write IV, encrypted packet ID and payload
|
|
|
|
dest_size += OvsEncrypt(c->CipherEncrypt, c->MdSend, c->IvSend, NULL, dest_data + sizeof(op), encrypted_data, encrypted_size, NULL, 0);
|
|
|
|
|
|
|
|
Free(encrypted_data);
|
|
|
|
|
|
|
|
// Update the IV
|
|
|
|
Copy(c->IvSend, dest_data + dest_size - c->CipherEncrypt->IvSize, c->CipherEncrypt->IvSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
OvsSendPacketRawNow(c->Server, c->Session, dest_data, dest_size);
|
2014-01-04 17:00:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Build an OpenVPN control packet
|
|
|
|
BUF *OvsBuildPacket(OPENVPN_PACKET *p)
|
|
|
|
{
|
|
|
|
BUF *b;
|
|
|
|
UCHAR uc;
|
|
|
|
UINT num_ack;
|
|
|
|
// Validate arguments
|
|
|
|
if (p == NULL)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
b = NewBuf();
|
|
|
|
|
|
|
|
// OpCode + KeyID
|
|
|
|
uc = ((p->OpCode << 3) & 0xF8) | (p->KeyId & 0x07);
|
|
|
|
WriteBufChar(b, uc);
|
|
|
|
|
|
|
|
if (p->OpCode == OPENVPN_P_DATA_V1)
|
|
|
|
{
|
|
|
|
// Data Packet
|
|
|
|
WriteBuf(b, p->Data, p->DataSize);
|
|
|
|
SeekBuf(b, 0, 0);
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sender Channel ID
|
|
|
|
WriteBufInt64(b, p->MySessionId);
|
|
|
|
|
|
|
|
// NumAck
|
|
|
|
num_ack = MIN(p->NumAck, OPENVPN_MAX_NUMACK);
|
|
|
|
WriteBufChar(b, (UCHAR)num_ack);
|
|
|
|
|
|
|
|
if (p->NumAck >= 1)
|
|
|
|
{
|
|
|
|
UINT i;
|
|
|
|
|
2020-05-12 01:06:59 +03:00
|
|
|
for (i = 0; i < num_ack; i++)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
|
|
|
WriteBufInt(b, (UCHAR)p->AckPacketId[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Received Channel ID
|
|
|
|
WriteBufInt64(b, p->YourSessionId);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (p->OpCode != OPENVPN_P_ACK_V1)
|
|
|
|
{
|
|
|
|
// Packet ID
|
|
|
|
WriteBufInt(b, p->PacketId);
|
|
|
|
|
|
|
|
// Payload
|
|
|
|
if (p->DataSize >= 1 && p->Data != NULL)
|
|
|
|
{
|
|
|
|
WriteBuf(b, p->Data, p->DataSize);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SeekBuf(b, 0, 0);
|
|
|
|
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse the OpenVPN packet
|
|
|
|
OPENVPN_PACKET *OvsParsePacket(UCHAR *data, UINT size)
|
|
|
|
{
|
|
|
|
UCHAR uc;
|
|
|
|
OPENVPN_PACKET *ret = NULL;
|
|
|
|
// Validate arguments
|
|
|
|
if (data == NULL || size == 0)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = ZeroMalloc(sizeof(OPENVPN_PACKET));
|
|
|
|
|
|
|
|
uc = *((UCHAR *)data);
|
|
|
|
data++;
|
|
|
|
size--;
|
|
|
|
|
|
|
|
ret->OpCode = ((uc & 0xF8) >> 3) & 0x1F;
|
|
|
|
ret->KeyId = uc & 0x07;
|
|
|
|
|
|
|
|
if (ret->OpCode == OPENVPN_P_DATA_V1)
|
|
|
|
{
|
|
|
|
// Data packet
|
|
|
|
ret->DataSize = size;
|
|
|
|
ret->Data = Clone(data, size);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sender Channel ID
|
|
|
|
if (size < sizeof(UINT64))
|
|
|
|
{
|
|
|
|
goto LABEL_ERROR;
|
|
|
|
}
|
|
|
|
ret->MySessionId = READ_UINT64(data);
|
|
|
|
data += sizeof(UINT64);
|
|
|
|
size -= sizeof(UINT64);
|
|
|
|
|
|
|
|
// ACK
|
|
|
|
if (size < 1)
|
|
|
|
{
|
|
|
|
goto LABEL_ERROR;
|
|
|
|
}
|
|
|
|
uc = *((UCHAR *)data);
|
|
|
|
data++;
|
|
|
|
size--;
|
|
|
|
|
|
|
|
ret->NumAck = uc;
|
|
|
|
|
|
|
|
if (ret->NumAck > 4)
|
|
|
|
{
|
|
|
|
goto LABEL_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret->NumAck >= 1)
|
|
|
|
{
|
|
|
|
UINT i;
|
|
|
|
|
|
|
|
if (size < (sizeof(UINT) * (UINT)ret->NumAck + sizeof(UINT64)))
|
|
|
|
{
|
|
|
|
goto LABEL_ERROR;
|
|
|
|
}
|
|
|
|
|
2020-05-12 01:06:59 +03:00
|
|
|
for (i = 0; i < ret->NumAck; i++)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
|
|
|
UINT ui;
|
|
|
|
|
|
|
|
ui = READ_UINT(data);
|
|
|
|
|
|
|
|
ret->AckPacketId[i] = ui;
|
|
|
|
|
|
|
|
data += sizeof(UINT);
|
|
|
|
size -= sizeof(UINT);
|
|
|
|
}
|
|
|
|
|
|
|
|
ret->YourSessionId = READ_UINT64(data);
|
|
|
|
data += sizeof(UINT64);
|
|
|
|
size -= sizeof(UINT64);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret->OpCode != OPENVPN_P_ACK_V1)
|
|
|
|
{
|
|
|
|
// Read the Packet ID Because in the case of other than ACK
|
|
|
|
if (size < sizeof(UINT))
|
|
|
|
{
|
|
|
|
goto LABEL_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret->PacketId = READ_UINT(data);
|
|
|
|
data += sizeof(UINT);
|
|
|
|
size -= sizeof(UINT);
|
|
|
|
|
|
|
|
// Payload
|
|
|
|
ret->DataSize = size;
|
|
|
|
if (size >= 1)
|
|
|
|
{
|
|
|
|
ret->Data = Clone(data, size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
LABEL_ERROR:
|
2018-08-30 22:50:53 +03:00
|
|
|
OvsFreePacket(ret);
|
2014-01-04 17:00:08 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release the OpenVPN packet
|
|
|
|
void OvsFreePacket(OPENVPN_PACKET *p)
|
|
|
|
{
|
|
|
|
// Validate arguments
|
|
|
|
if (p == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (p->Data != NULL)
|
|
|
|
{
|
|
|
|
Free(p->Data);
|
|
|
|
}
|
|
|
|
|
|
|
|
Free(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the session does not exist, create a session
|
|
|
|
OPENVPN_SESSION *OvsFindOrCreateSession(OPENVPN_SERVER *s, IP *server_ip, UINT server_port, IP *client_ip, UINT client_port, UINT protocol)
|
|
|
|
{
|
|
|
|
OPENVPN_SESSION *se;
|
|
|
|
// Validate arguments
|
|
|
|
if (s == NULL || server_ip == NULL || server_port == 0 || client_ip == NULL || client_port == 0)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
se = OvsSearchSession(s, server_ip, server_port, client_ip, client_port, protocol);
|
|
|
|
if (se == NULL)
|
|
|
|
{
|
|
|
|
se = OvsNewSession(s, server_ip, server_port, client_ip, client_port, protocol);
|
|
|
|
|
|
|
|
if (se != NULL)
|
|
|
|
{
|
|
|
|
Insert(s->SessionList, se);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return se;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the number of sessions currently connected from the IP address of the client
|
|
|
|
UINT OvsGetNumSessionByClientIp(OPENVPN_SERVER *s, IP *ip)
|
|
|
|
{
|
|
|
|
UINT i;
|
|
|
|
UINT ret = 0;
|
|
|
|
// Validate arguments
|
|
|
|
if (s == NULL || ip == NULL)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-05-12 01:06:59 +03:00
|
|
|
for (i = 0; i < LIST_NUM(s->SessionList); i++)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
|
|
|
OPENVPN_SESSION *se = LIST_DATA(s->SessionList, i);
|
|
|
|
|
|
|
|
if (CmpIpAddr(&se->ClientIp, ip) == 0)
|
|
|
|
{
|
|
|
|
ret++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a new session
|
|
|
|
OPENVPN_SESSION *OvsNewSession(OPENVPN_SERVER *s, IP *server_ip, UINT server_port, IP *client_ip, UINT client_port, UINT protocol)
|
|
|
|
{
|
|
|
|
OPENVPN_SESSION *se;
|
|
|
|
char server_ip_str[MAX_SIZE];
|
|
|
|
char client_ip_str[MAX_SIZE];
|
|
|
|
// Validate arguments
|
|
|
|
if (s == NULL || server_ip == NULL || server_port == 0 || client_ip == NULL || client_port == 0)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (OvsGetNumSessionByClientIp(s, client_ip) > OPENVPN_QUOTA_MAX_NUM_SESSIONS_PER_IP)
|
|
|
|
{
|
|
|
|
// Number of sessions from the same IP address too many
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (LIST_NUM(s->SessionList) > OPENVPN_QUOTA_MAX_NUM_SESSIONS)
|
|
|
|
{
|
|
|
|
// Too many OpenVPN sessions
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
se = ZeroMalloc(sizeof(OPENVPN_SESSION));
|
|
|
|
|
|
|
|
se->Server = s;
|
|
|
|
|
|
|
|
Copy(&se->ClientIp, client_ip, sizeof(IP));
|
|
|
|
se->ClientPort = client_port;
|
|
|
|
|
|
|
|
Copy(&se->ServerIp, server_ip, sizeof(IP));
|
|
|
|
se->ServerPort = server_port;
|
|
|
|
|
2020-07-20 00:45:12 +03:00
|
|
|
se->ObfuscationMode = s->Obfuscation ? INFINITE : OPENVPN_SCRAMBLE_MODE_DISABLED;
|
2018-11-13 00:32:37 +03:00
|
|
|
|
2014-01-04 17:00:08 +04:00
|
|
|
se->LastCommTick = s->Now;
|
|
|
|
|
|
|
|
se->Protocol = protocol;
|
|
|
|
|
|
|
|
se->ServerSessionId = OvsNewServerSessionId(se->Server);
|
|
|
|
|
|
|
|
se->CreatedTick = s->Now;
|
|
|
|
|
|
|
|
se->Id = s->NextSessionId;
|
|
|
|
s->NextSessionId++;
|
|
|
|
|
|
|
|
IPToStr(server_ip_str, sizeof(server_ip_str), server_ip);
|
|
|
|
IPToStr(client_ip_str, sizeof(client_ip_str), client_ip);
|
|
|
|
Debug("OpenVPN New Session: %s:%u -> %s:%u Proto=%u\n", server_ip_str, server_port,
|
2020-05-12 01:06:59 +03:00
|
|
|
client_ip_str, client_port, protocol);
|
2014-01-04 17:00:08 +04:00
|
|
|
|
|
|
|
return se;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release the session
|
|
|
|
void OvsFreeSession(OPENVPN_SESSION *se)
|
|
|
|
{
|
|
|
|
UINT i;
|
|
|
|
// Validate arguments
|
|
|
|
if (se == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If there is IP addresses which is got from a DHCP server in the session, release it
|
|
|
|
if (se->Ipc != NULL)
|
|
|
|
{
|
|
|
|
if (se->Mode == OPENVPN_MODE_L3)
|
|
|
|
{
|
|
|
|
if (se->IpcAsync != NULL)
|
|
|
|
{
|
|
|
|
IP dhcp_ip;
|
|
|
|
|
|
|
|
UINTToIP(&dhcp_ip, se->IpcAsync->L3ClientAddressOption.ServerAddress);
|
|
|
|
|
|
|
|
IPCDhcpFreeIP(se->Ipc, &dhcp_ip);
|
2020-05-12 01:06:59 +03:00
|
|
|
IPC_PROTO_SET_STATUS(se->Ipc, IPv6State, IPC_PROTO_STATUS_CLOSED);
|
|
|
|
IPCProcessL3EventsIPv4Only(se->Ipc);
|
2014-01-04 17:00:08 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release the channel
|
2020-05-12 01:06:59 +03:00
|
|
|
for (i = 0; i < OPENVPN_NUM_CHANNELS; i++)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
|
|
|
OPENVPN_CHANNEL *c = se->Channels[i];
|
|
|
|
|
|
|
|
if (c != NULL)
|
|
|
|
{
|
|
|
|
OvsFreeChannel(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release the IPC
|
|
|
|
if (se->Ipc != NULL)
|
|
|
|
{
|
|
|
|
FreeIPC(se->Ipc);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (se->IpcAsync != NULL)
|
|
|
|
{
|
|
|
|
FreeIPCAsync(se->IpcAsync);
|
|
|
|
}
|
|
|
|
|
|
|
|
Free(se);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Search the session from the endpoint information
|
|
|
|
OPENVPN_SESSION *OvsSearchSession(OPENVPN_SERVER *s, IP *server_ip, UINT server_port, IP *client_ip, UINT client_port, UINT protocol)
|
|
|
|
{
|
|
|
|
OPENVPN_SESSION *se;
|
|
|
|
OPENVPN_SESSION t;
|
|
|
|
// Validate arguments
|
|
|
|
if (s == NULL || server_ip == NULL || server_port == 0 || client_ip == NULL || client_port == 0)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
Copy(&t.ClientIp, client_ip, sizeof(IP));
|
|
|
|
t.ClientPort = client_port;
|
|
|
|
Copy(&t.ServerIp, server_ip, sizeof(IP));
|
|
|
|
t.ServerPort = server_port;
|
|
|
|
t.Protocol = protocol;
|
|
|
|
|
|
|
|
se = Search(s->SessionList, &t);
|
|
|
|
|
|
|
|
return se;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Receive packets in the OpenVPN server
|
2020-05-11 09:23:29 +03:00
|
|
|
void OvsRecvPacket(OPENVPN_SERVER *s, LIST *recv_packet_list, UINT protocol)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
|
|
|
UINT i, j;
|
|
|
|
LIST *delete_session_list = NULL;
|
|
|
|
// Validate arguments
|
|
|
|
if (s == NULL || recv_packet_list == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
s->Now = Tick64();
|
|
|
|
|
|
|
|
// Process for all sessions
|
2020-05-12 01:06:59 +03:00
|
|
|
for (i = 0; i < LIST_NUM(s->SessionList); i++)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
|
|
|
OPENVPN_SESSION *se = LIST_DATA(s->SessionList, i);
|
|
|
|
|
|
|
|
if (se->Ipc != NULL)
|
|
|
|
{
|
|
|
|
if (se->Mode == OPENVPN_MODE_L3)
|
|
|
|
{
|
|
|
|
// Flush the ARP table of the IPC
|
|
|
|
IPCFlushArpTableEx(se->Ipc, s->Now);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Process received packets
|
2020-05-12 01:06:59 +03:00
|
|
|
for (i = 0; i < LIST_NUM(recv_packet_list); i++)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
|
|
|
UDPPACKET *p = LIST_DATA(recv_packet_list, i);
|
|
|
|
|
2020-05-11 09:23:29 +03:00
|
|
|
OvsProceccRecvPacket(s, p, protocol);
|
2014-01-04 17:00:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Treat for all sessions and all channels
|
2020-05-12 01:06:59 +03:00
|
|
|
for (i = 0; i < LIST_NUM(s->SessionList); i++)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
|
|
|
OPENVPN_CHANNEL *latest_channel = NULL;
|
|
|
|
UINT64 max_tick = 0;
|
|
|
|
OPENVPN_SESSION *se = LIST_DATA(s->SessionList, i);
|
|
|
|
bool is_disconnected = false;
|
|
|
|
|
|
|
|
if (se->Ipc != NULL)
|
|
|
|
{
|
|
|
|
if (se->Mode == OPENVPN_MODE_L3)
|
|
|
|
{
|
2020-05-12 01:06:59 +03:00
|
|
|
IPCProcessL3EventsIPv4Only(se->Ipc);
|
2014-01-04 17:00:08 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-12 01:06:59 +03:00
|
|
|
for (j = 0; j < OPENVPN_NUM_CHANNELS; j++)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
|
|
|
OPENVPN_CHANNEL *c = se->Channels[j];
|
|
|
|
|
|
|
|
if (c != NULL)
|
|
|
|
{
|
|
|
|
if (c->RekeyInitiated == false && ((c->NextRekey <= s->Now && c->NextRekey != 0) || (c->LastDataPacketId >= OPENVPN_MAX_PACKET_ID_FOR_TRIGGER_REKEY)))
|
|
|
|
{
|
|
|
|
OPENVPN_CHANNEL *c2;
|
|
|
|
// Send a soft reset by creating a new channel
|
|
|
|
UINT next_channel_id = se->LastCreatedChannelIndex + 1;
|
|
|
|
if (next_channel_id >= OPENVPN_NUM_CHANNELS)
|
|
|
|
{
|
|
|
|
next_channel_id = 1;
|
|
|
|
}
|
|
|
|
if (se->Channels[next_channel_id] != NULL)
|
|
|
|
{
|
|
|
|
// Release when there is a channel data already
|
|
|
|
OvsFreeChannel(se->Channels[next_channel_id]);
|
|
|
|
se->Channels[next_channel_id] = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a new channel
|
|
|
|
c2 = OvsNewChannel(se, (UCHAR)next_channel_id);
|
|
|
|
c2->IsInitiatorServer = true;
|
|
|
|
se->Channels[next_channel_id] = c2;
|
|
|
|
Debug("OpenVPN New Channel for Re-Keying :%u\n", next_channel_id);
|
|
|
|
OvsLog(s, se, c, "LO_INITIATE_REKEY");
|
|
|
|
|
|
|
|
// Send a soft reset
|
|
|
|
OvsSendControlPacket(c2, OPENVPN_P_CONTROL_SOFT_RESET_V1, NULL, 0);
|
|
|
|
|
|
|
|
c->RekeyInitiated = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c != NULL)
|
|
|
|
{
|
|
|
|
switch (c->Status)
|
|
|
|
{
|
|
|
|
case OPENVPN_CHANNEL_STATUS_TLS_VPN_CONNECTING:
|
|
|
|
// Check whether the connection process completed if there is a channel running a VPN connection process
|
|
|
|
if (se->IpcAsync != NULL)
|
|
|
|
{
|
|
|
|
if (se->IpcAsync->Done)
|
|
|
|
{
|
|
|
|
if (se->IpcAsync->Ipc != NULL)
|
|
|
|
{
|
2014-03-20 00:45:05 +04:00
|
|
|
char option_str[4096];
|
2014-01-04 17:00:08 +04:00
|
|
|
char l3_options[MAX_SIZE];
|
|
|
|
|
|
|
|
// Successful in VPN connection
|
|
|
|
Debug("OpenVPN Channel %u Established (new key).\n", j);
|
|
|
|
OvsLog(s, se, c, "LO_CHANNEL_ESTABLISHED");
|
|
|
|
|
|
|
|
// Return the PUSH_REPLY
|
|
|
|
Format(option_str, sizeof(option_str),
|
2020-05-12 01:06:59 +03:00
|
|
|
"PUSH_REPLY,ping %u,ping-restart %u",
|
2021-04-21 09:29:30 +03:00
|
|
|
s->PingSendInterval / 1000,
|
|
|
|
s->Timeout / 1000);
|
2014-01-04 17:00:08 +04:00
|
|
|
|
|
|
|
if (se->Mode == OPENVPN_MODE_L3)
|
|
|
|
{
|
|
|
|
// Add such as the IP address that was acquired from the DHCP server
|
|
|
|
// if the L3 mode to the option character string
|
|
|
|
DHCP_OPTION_LIST *cao = &se->IpcAsync->L3ClientAddressOption;
|
|
|
|
char ip_client[64];
|
|
|
|
char ip_subnet_mask[64];
|
|
|
|
char ip_dns1[64];
|
|
|
|
char ip_dns2[64];
|
|
|
|
char ip_wins1[64];
|
|
|
|
char ip_wins2[64];
|
|
|
|
char ip_defgw[64];
|
|
|
|
|
|
|
|
ClearStr(ip_dns1, sizeof(ip_dns1));
|
|
|
|
ClearStr(ip_dns2, sizeof(ip_dns2));
|
|
|
|
ClearStr(ip_wins1, sizeof(ip_wins1));
|
|
|
|
ClearStr(ip_wins2, sizeof(ip_wins2));
|
|
|
|
ClearStr(ip_defgw, sizeof(ip_defgw));
|
|
|
|
|
|
|
|
IPToStr32(ip_client, sizeof(ip_client),
|
2020-05-12 01:06:59 +03:00
|
|
|
cao->ClientAddress);
|
2014-01-04 17:00:08 +04:00
|
|
|
|
|
|
|
IPToStr32(ip_subnet_mask, sizeof(ip_subnet_mask),
|
2020-05-12 01:06:59 +03:00
|
|
|
cao->SubnetMask);
|
2014-01-04 17:00:08 +04:00
|
|
|
|
2018-08-15 03:39:33 +03:00
|
|
|
Format(l3_options, sizeof(l3_options),
|
2020-05-12 01:06:59 +03:00
|
|
|
",topology subnet");
|
2018-08-15 03:39:33 +03:00
|
|
|
StrCat(option_str, sizeof(option_str), l3_options);
|
|
|
|
|
2014-01-04 17:00:08 +04:00
|
|
|
Format(l3_options, sizeof(l3_options),
|
2020-05-12 01:06:59 +03:00
|
|
|
",ifconfig %s %s",
|
|
|
|
ip_client,
|
|
|
|
ip_subnet_mask);
|
2014-01-04 17:00:08 +04:00
|
|
|
StrCat(option_str, sizeof(option_str), l3_options);
|
|
|
|
|
|
|
|
// Domain name
|
|
|
|
if (IsEmptyStr(cao->DomainName) == false)
|
|
|
|
{
|
|
|
|
Format(l3_options, sizeof(l3_options),
|
2020-05-12 01:06:59 +03:00
|
|
|
",dhcp-option DOMAIN %s", cao->DomainName);
|
2014-01-04 17:00:08 +04:00
|
|
|
StrCat(option_str, sizeof(option_str), l3_options);
|
|
|
|
}
|
|
|
|
|
|
|
|
// DNS server address 1
|
|
|
|
if (cao->DnsServer != 0)
|
|
|
|
{
|
|
|
|
char ip_str[64];
|
|
|
|
IPToStr32(ip_str, sizeof(ip_str), cao->DnsServer);
|
|
|
|
Format(l3_options, sizeof(l3_options),
|
2020-05-12 01:06:59 +03:00
|
|
|
",dhcp-option DNS %s", ip_str);
|
2014-01-04 17:00:08 +04:00
|
|
|
StrCat(option_str, sizeof(option_str), l3_options);
|
|
|
|
|
|
|
|
StrCpy(ip_dns1, sizeof(ip_dns1), ip_str);
|
|
|
|
}
|
|
|
|
|
|
|
|
// DNS server address 2
|
|
|
|
if (cao->DnsServer2 != 0)
|
|
|
|
{
|
|
|
|
char ip_str[64];
|
|
|
|
IPToStr32(ip_str, sizeof(ip_str), cao->DnsServer2);
|
|
|
|
Format(l3_options, sizeof(l3_options),
|
2020-05-12 01:06:59 +03:00
|
|
|
",dhcp-option DNS %s", ip_str);
|
2014-01-04 17:00:08 +04:00
|
|
|
StrCat(option_str, sizeof(option_str), l3_options);
|
|
|
|
|
|
|
|
StrCpy(ip_dns2, sizeof(ip_dns2), ip_str);
|
|
|
|
}
|
|
|
|
|
|
|
|
// WINS address 1
|
|
|
|
if (cao->WinsServer != 0)
|
|
|
|
{
|
|
|
|
char ip_str[64];
|
|
|
|
IPToStr32(ip_str, sizeof(ip_str), cao->WinsServer);
|
|
|
|
Format(l3_options, sizeof(l3_options),
|
2020-05-12 01:06:59 +03:00
|
|
|
",dhcp-option WINS %s", ip_str);
|
2014-01-04 17:00:08 +04:00
|
|
|
StrCat(option_str, sizeof(option_str), l3_options);
|
|
|
|
|
|
|
|
StrCpy(ip_wins1, sizeof(ip_wins1), ip_str);
|
|
|
|
}
|
|
|
|
|
|
|
|
// WINS address 2
|
|
|
|
if (cao->WinsServer2 != 0)
|
|
|
|
{
|
|
|
|
char ip_str[64];
|
|
|
|
IPToStr32(ip_str, sizeof(ip_str), cao->WinsServer2);
|
|
|
|
Format(l3_options, sizeof(l3_options),
|
2020-05-12 01:06:59 +03:00
|
|
|
",dhcp-option WINS %s", ip_str);
|
2014-01-04 17:00:08 +04:00
|
|
|
StrCat(option_str, sizeof(option_str), l3_options);
|
|
|
|
|
|
|
|
StrCpy(ip_wins2, sizeof(ip_wins2), ip_str);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Default gateway
|
|
|
|
if (cao->Gateway != 0)
|
|
|
|
{
|
2018-08-15 03:39:33 +03:00
|
|
|
char ip_str[64];
|
|
|
|
IPToStr32(ip_str, sizeof(ip_str), cao->Gateway);
|
2014-01-04 17:00:08 +04:00
|
|
|
Format(l3_options, sizeof(l3_options),
|
2020-05-12 01:06:59 +03:00
|
|
|
",route-gateway %s,redirect-gateway def1", ip_str);
|
2014-01-04 17:00:08 +04:00
|
|
|
StrCat(option_str, sizeof(option_str), l3_options);
|
|
|
|
|
2018-08-15 03:39:33 +03:00
|
|
|
StrCpy(ip_defgw, sizeof(ip_defgw), ip_str);
|
2014-01-04 17:00:08 +04:00
|
|
|
}
|
2014-03-20 00:45:05 +04:00
|
|
|
else
|
|
|
|
{
|
2014-06-06 01:53:20 +04:00
|
|
|
#if 0 // Currently disabled
|
2014-03-20 00:45:05 +04:00
|
|
|
// If the default gateway is not specified, add the static routing table
|
|
|
|
// entry for the local IP subnet
|
|
|
|
IP local_network;
|
|
|
|
IP client_ip;
|
|
|
|
IP subnet_mask;
|
|
|
|
|
|
|
|
UINTToIP(&client_ip, cao->ClientAddress);
|
|
|
|
UINTToIP(&subnet_mask, cao->SubnetMask);
|
|
|
|
|
|
|
|
Zero(&local_network, sizeof(IP));
|
|
|
|
IPAnd4(&local_network, &client_ip, &subnet_mask);
|
|
|
|
|
|
|
|
Format(l3_options, sizeof(l3_options),
|
2020-05-12 01:06:59 +03:00
|
|
|
",route %r %r vpn_gateway",
|
|
|
|
&local_network,
|
|
|
|
&cao->SubnetMask);
|
2014-03-20 00:45:05 +04:00
|
|
|
|
|
|
|
StrCat(option_str, sizeof(option_str), l3_options);
|
2014-06-06 01:53:20 +04:00
|
|
|
#endif
|
2014-03-20 00:45:05 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Classless routing table
|
|
|
|
if (cao->ClasslessRoute.NumExistingRoutes >= 1)
|
|
|
|
{
|
|
|
|
UINT i;
|
2020-05-12 01:06:59 +03:00
|
|
|
for (i = 0; i < MAX_DHCP_CLASSLESS_ROUTE_ENTRIES; i++)
|
2014-03-20 00:45:05 +04:00
|
|
|
{
|
|
|
|
DHCP_CLASSLESS_ROUTE *r = &cao->ClasslessRoute.Entries[i];
|
|
|
|
|
|
|
|
if (r->Exists)
|
|
|
|
{
|
|
|
|
Format(l3_options, sizeof(l3_options),
|
2020-05-12 01:06:59 +03:00
|
|
|
",route %r %r vpn_gateway",
|
|
|
|
&r->Network, &r->SubnetMask);
|
2014-03-20 00:45:05 +04:00
|
|
|
|
|
|
|
StrCat(option_str, sizeof(option_str), l3_options);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-01-04 17:00:08 +04:00
|
|
|
|
|
|
|
OvsLog(s, se, c, "LP_SET_IPV4_PARAM",
|
2020-05-12 01:06:59 +03:00
|
|
|
ip_client, ip_subnet_mask, ip_defgw, ip_dns1, ip_dns2, ip_wins1, ip_wins2);
|
2014-01-04 17:00:08 +04:00
|
|
|
}
|
2018-12-01 10:20:30 +03:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// OpenVPN L2 mode. To fix the bug of OpenVPN 2.4.6 and particular version of kernel mode TAP driver
|
|
|
|
// on Linux, the TAP device must be up after the OpenVPN client is connected.
|
|
|
|
// However there is no direct push instruction to do so to OpenVPN client.
|
|
|
|
// Therefore we push the dummy IPv4 address (RFC7600) to the OpenVPN client.
|
2020-07-20 00:45:12 +03:00
|
|
|
if (s->PushDummyIPv4AddressOnL2Mode)
|
2018-12-01 10:20:30 +03:00
|
|
|
{
|
|
|
|
StrCat(option_str, sizeof(option_str), ",ifconfig 192.0.0.8 255.255.255.240");
|
|
|
|
}
|
|
|
|
}
|
2014-01-04 17:00:08 +04:00
|
|
|
|
2020-04-04 09:37:19 +03:00
|
|
|
// From https://community.openvpn.net/openvpn/wiki/Openvpn23ManPage:
|
|
|
|
//
|
|
|
|
// --block-outside-dns
|
|
|
|
// Block DNS servers on other network adapters to prevent DNS leaks.
|
|
|
|
// This option prevents any application from accessing TCP or UDP port 53 except one inside the tunnel.
|
|
|
|
// It uses Windows Filtering Platform (WFP) and works on Windows Vista or later.
|
|
|
|
// This option is considered unknown on non-Windows platforms and unsupported on Windows XP, resulting in fatal error.
|
|
|
|
// You may want to use --setenv opt or --ignore-unknown-option (not suitable for Windows XP) to ignore said error.
|
|
|
|
// Note that pushing unknown options from server does not trigger fatal errors.
|
|
|
|
StrCat(option_str, sizeof(option_str), ",block-outside-dns");
|
|
|
|
|
2014-01-04 17:00:08 +04:00
|
|
|
WriteFifo(c->SslPipe->SslInOut->SendFifo, option_str, StrSize(option_str));
|
|
|
|
|
|
|
|
Debug("Push Str: %s\n", option_str);
|
|
|
|
OvsLog(s, se, c, "LO_PUSH_REPLY", option_str);
|
|
|
|
|
|
|
|
StrCpy(se->PushReplyStr, sizeof(se->PushReplyStr), option_str);
|
|
|
|
|
|
|
|
se->Ipc = se->IpcAsync->Ipc;
|
|
|
|
se->IpcAsync->Ipc = NULL;
|
|
|
|
|
|
|
|
s->SessionEstablishedCount++;
|
|
|
|
|
|
|
|
// Set a Sock Event of IPC to Sock Event of the UDP Listener
|
|
|
|
IPCSetSockEventWhenRecvL2Packet(se->Ipc, s->SockEvent);
|
|
|
|
|
|
|
|
// State transition
|
|
|
|
c->Status = OPENVPN_CHANNEL_STATUS_ESTABLISHED;
|
|
|
|
c->EstablishedTick = s->Now;
|
|
|
|
se->Established = true;
|
|
|
|
se->LastCommTick = Tick64();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
char *str;
|
|
|
|
|
|
|
|
if (se->IpcAsync->DhcpAllocFailed)
|
|
|
|
{
|
|
|
|
OvsLog(s, se, c, "LP_DHCP_REQUEST_NG");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Failed to connect VPN
|
|
|
|
Debug("OpenVPN Channel %u Failed.\n", j);
|
|
|
|
OvsLog(s, se, c, "LO_CHANNEL_FAILED");
|
|
|
|
|
|
|
|
// Return the AUTH_FAILED
|
|
|
|
str = "AUTH_FAILED";
|
|
|
|
WriteFifo(c->SslPipe->SslInOut->SendFifo, str, StrSize(str));
|
|
|
|
|
|
|
|
s->SessionEstablishedCount++;
|
|
|
|
|
|
|
|
// State transition
|
|
|
|
c->Status = OPENVPN_CHANNEL_STATUS_DISCONNECTED;
|
|
|
|
|
|
|
|
FreeIPCAsync(se->IpcAsync);
|
|
|
|
se->IpcAsync = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OPENVPN_CHANNEL_STATUS_ESTABLISHED:
|
|
|
|
// Monitor the IPC whether not disconnected when there is a VPN connection completed channel
|
|
|
|
if (IsIPCConnected(se->Ipc) == false)
|
|
|
|
{
|
|
|
|
// Send the RESTART since IPC is disconnected
|
|
|
|
char *str = "RESTART";
|
|
|
|
Debug("OpenVPN Channel %u Disconnected by HUB.\n", j);
|
|
|
|
|
|
|
|
OvsLog(s, se, c, "LO_CHANNEL_DISCONNECTED_BY_HUB");
|
|
|
|
|
|
|
|
WriteFifo(c->SslPipe->SslInOut->SendFifo, str, StrSize(str));
|
|
|
|
|
|
|
|
// State transition
|
|
|
|
c->Status = OPENVPN_CHANNEL_STATUS_DISCONNECTED;
|
|
|
|
|
|
|
|
// Set the session to disconnected state
|
|
|
|
se->Established = false;
|
|
|
|
se->LastCommTick = s->Now;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c != NULL)
|
|
|
|
{
|
|
|
|
// If there is a packet to be transmitted physically in SSL, send it
|
|
|
|
if (c->SslPipe != NULL && SyncSslPipe(c->SslPipe))
|
|
|
|
{
|
|
|
|
if (FifoSize(c->SslPipe->RawOut->RecvFifo) >= 1)
|
|
|
|
{
|
|
|
|
Debug("RawOut Fifo Size (c=%u): %u\n", c->KeyId, FifoSize(c->SslPipe->RawOut->RecvFifo));
|
|
|
|
|
|
|
|
OvsSendControlPacketWithAutoSplit(c, OPENVPN_P_CONTROL_V1,
|
2020-05-12 01:06:59 +03:00
|
|
|
FifoPtr(c->SslPipe->RawOut->RecvFifo),
|
|
|
|
FifoSize(c->SslPipe->RawOut->RecvFifo));
|
2014-01-04 17:00:08 +04:00
|
|
|
|
|
|
|
ReadFifo(c->SslPipe->RawOut->RecvFifo, NULL, FifoSize(c->SslPipe->RawOut->RecvFifo));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c != NULL)
|
|
|
|
{
|
|
|
|
UINT num;
|
|
|
|
UINT acks[OPENVPN_MAX_NUMACK];
|
|
|
|
UINT k;
|
|
|
|
|
|
|
|
// Packet transmission
|
2020-05-12 01:06:59 +03:00
|
|
|
for (k = 0; k < LIST_NUM(c->SendControlPacketList); k++)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
|
|
|
OPENVPN_CONTROL_PACKET *cp = LIST_DATA(c->SendControlPacketList, k);
|
|
|
|
|
|
|
|
if (cp->NextSendTime <= s->Now)
|
|
|
|
{
|
2019-10-22 05:14:05 +03:00
|
|
|
if (cp->NoResend == false || cp->NumSent == 0) // To address the UDP reflection amplification attack: https://github.com/SoftEtherVPN/SoftEtherVPN/issues/1001
|
|
|
|
{
|
|
|
|
OPENVPN_PACKET *p;
|
|
|
|
|
|
|
|
cp->NumSent++;
|
2014-01-04 17:00:08 +04:00
|
|
|
|
2019-10-22 05:14:05 +03:00
|
|
|
num = OvsGetAckReplyList(c, acks);
|
2014-01-04 17:00:08 +04:00
|
|
|
|
2019-10-22 05:14:05 +03:00
|
|
|
p = OvsNewControlPacket(cp->OpCode, j, se->ServerSessionId, num, acks,
|
2020-05-12 01:06:59 +03:00
|
|
|
se->ClientSessionId, cp->PacketId, cp->DataSize, cp->Data);
|
2014-01-04 17:00:08 +04:00
|
|
|
|
2019-10-22 05:14:05 +03:00
|
|
|
OvsSendPacketNow(s, se, p);
|
2014-01-04 17:00:08 +04:00
|
|
|
|
2019-10-22 05:14:05 +03:00
|
|
|
OvsFreePacket(p);
|
2014-01-04 17:00:08 +04:00
|
|
|
|
2019-10-22 05:14:05 +03:00
|
|
|
cp->NextSendTime = s->Now + (UINT64)OPENVPN_CONTROL_PACKET_RESEND_INTERVAL;
|
2014-01-04 17:00:08 +04:00
|
|
|
|
2019-10-22 05:14:05 +03:00
|
|
|
AddInterrupt(s->Interrupt, cp->NextSendTime);
|
|
|
|
}
|
2014-01-04 17:00:08 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the response with an ACK-only packet is required, respond such that
|
|
|
|
num = OvsGetAckReplyList(c, acks);
|
|
|
|
|
|
|
|
if (num >= 1)
|
|
|
|
{
|
|
|
|
OPENVPN_PACKET *p = OvsNewControlPacket(OPENVPN_P_ACK_V1, j, se->ServerSessionId,
|
2020-05-12 01:06:59 +03:00
|
|
|
num, acks, se->ClientSessionId, 0, 0, NULL);
|
2014-01-04 17:00:08 +04:00
|
|
|
|
|
|
|
OvsSendPacketNow(s, se, p);
|
|
|
|
|
|
|
|
OvsFreePacket(p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (se->Ipc != NULL)
|
|
|
|
{
|
|
|
|
if (se->Mode == OPENVPN_MODE_L3)
|
|
|
|
{
|
|
|
|
if (se->IpcAsync != NULL)
|
|
|
|
{
|
|
|
|
// Update DHCP address
|
|
|
|
if (se->IpcAsync->L3NextDhcpRenewTick <= s->Now)
|
|
|
|
{
|
|
|
|
IP ip;
|
|
|
|
|
|
|
|
se->IpcAsync->L3NextDhcpRenewTick = s->Now + se->IpcAsync->L3DhcpRenewInterval;
|
|
|
|
|
|
|
|
UINTToIP(&ip, se->IpcAsync->L3ClientAddressOption.ServerAddress);
|
|
|
|
|
|
|
|
IPCDhcpRenewIP(se->Ipc, &ip);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-12 01:06:59 +03:00
|
|
|
IPCProcessL3EventsIPv4Only(se->Ipc);
|
2014-01-04 17:00:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
IPCProcessInterrupts(se->Ipc);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Choose the latest channel in all established channels
|
2020-05-12 01:06:59 +03:00
|
|
|
for (j = 0; j < OPENVPN_NUM_CHANNELS; j++)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
|
|
|
OPENVPN_CHANNEL *c = se->Channels[j];
|
|
|
|
|
|
|
|
if (c != NULL)
|
|
|
|
{
|
|
|
|
if (c->Status == OPENVPN_CHANNEL_STATUS_ESTABLISHED)
|
|
|
|
{
|
|
|
|
if (max_tick <= c->EstablishedTick)
|
|
|
|
{
|
|
|
|
max_tick = c->EstablishedTick;
|
|
|
|
latest_channel = c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (se->Established == false)
|
|
|
|
{
|
|
|
|
latest_channel = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Send the data using the latest channel (when there is no transmission channel, suck out the queue simply)
|
|
|
|
if (se->Mode == OPENVPN_MODE_L2)
|
|
|
|
{
|
|
|
|
// Get an Ethernet frame from IPC
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
BLOCK *b = IPCRecvL2(se->Ipc);
|
|
|
|
if (b == NULL)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (latest_channel != NULL && s->SupressSendPacket == false)
|
|
|
|
{
|
|
|
|
OvsSendDataPacket(latest_channel, latest_channel->KeyId, ++latest_channel->LastDataPacketId, b->Buf, b->Size);
|
|
|
|
}
|
|
|
|
|
|
|
|
FreeBlock(b);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Get an IPv4 packet from IPC
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
BLOCK *b = IPCRecvIPv4(se->Ipc);
|
|
|
|
if (b == NULL)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (latest_channel != NULL && s->SupressSendPacket == false)
|
|
|
|
{
|
|
|
|
OvsSendDataPacket(latest_channel, latest_channel->KeyId, ++latest_channel->LastDataPacketId, b->Buf, b->Size);
|
|
|
|
}
|
|
|
|
|
|
|
|
FreeBlock(b);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Send a Ping
|
|
|
|
if (latest_channel != NULL)
|
|
|
|
{
|
|
|
|
if ((se->NextPingSendTick == 0) || (se->NextPingSendTick <= s->Now))
|
|
|
|
{
|
2021-04-21 09:29:30 +03:00
|
|
|
se->NextPingSendTick = s->Now + s->PingSendInterval;
|
2014-01-04 17:00:08 +04:00
|
|
|
|
|
|
|
OvsSendDataPacket(latest_channel, latest_channel->KeyId, ++latest_channel->LastDataPacketId,
|
2020-05-12 01:06:59 +03:00
|
|
|
ping_signature, sizeof(ping_signature));
|
2014-01-04 17:00:08 +04:00
|
|
|
|
|
|
|
AddInterrupt(s->Interrupt, se->NextPingSendTick);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((se->Established == false) && (s->Now >= (se->CreatedTick + (UINT64)OPENVPN_NEW_SESSION_DEADLINE_TIMEOUT)))
|
|
|
|
{
|
|
|
|
is_disconnected = true;
|
|
|
|
}
|
|
|
|
|
2021-04-21 09:29:30 +03:00
|
|
|
if (se->Established && (s->Now >= (se->LastCommTick + s->Timeout)))
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
|
|
|
is_disconnected = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_disconnected)
|
|
|
|
{
|
|
|
|
if (delete_session_list == NULL)
|
|
|
|
{
|
|
|
|
delete_session_list = NewListFast(NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
Add(delete_session_list, se);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (delete_session_list != NULL)
|
|
|
|
{
|
|
|
|
UINT i;
|
|
|
|
|
2020-05-12 01:06:59 +03:00
|
|
|
for (i = 0; i < LIST_NUM(delete_session_list); i++)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
|
|
|
OPENVPN_SESSION *se = LIST_DATA(delete_session_list, i);
|
|
|
|
|
|
|
|
Debug("Deleting Session %p\n", se);
|
|
|
|
|
|
|
|
OvsFreeSession(se);
|
|
|
|
|
|
|
|
s->DisconnectCount++;
|
|
|
|
|
|
|
|
Delete(s->SessionList, se);
|
|
|
|
}
|
|
|
|
|
|
|
|
ReleaseList(delete_session_list);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Send the packet now
|
|
|
|
void OvsSendPacketNow(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_PACKET *p)
|
|
|
|
{
|
|
|
|
BUF *b;
|
|
|
|
UINT i;
|
|
|
|
// Validate arguments
|
|
|
|
if (s == NULL || se == NULL || p == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Debug("Sending Opcode=%u ", p->OpCode);
|
|
|
|
if (p->NumAck >= 1)
|
|
|
|
{
|
|
|
|
Debug("Sending ACK Packet IDs (c=%u): ", p->KeyId);
|
2020-05-12 01:06:59 +03:00
|
|
|
for (i = 0; i < p->NumAck; i++)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
|
|
|
Debug("%u ", p->AckPacketId[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Debug("\n");
|
|
|
|
|
|
|
|
b = OvsBuildPacket(p);
|
|
|
|
|
|
|
|
OvsSendPacketRawNow(s, se, b->Buf, b->Size);
|
|
|
|
|
|
|
|
Free(b);
|
|
|
|
}
|
|
|
|
void OvsSendPacketRawNow(OPENVPN_SERVER *s, OPENVPN_SESSION *se, void *data, UINT size)
|
|
|
|
{
|
|
|
|
UDPPACKET *u;
|
|
|
|
|
|
|
|
// Validate arguments
|
|
|
|
if (s == NULL || se == NULL || data == NULL || size == 0)
|
|
|
|
{
|
|
|
|
Free(data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-11-13 00:32:37 +03:00
|
|
|
// Scramble the packet
|
|
|
|
switch (se->ObfuscationMode)
|
|
|
|
{
|
|
|
|
case OPENVPN_SCRAMBLE_MODE_DISABLED:
|
|
|
|
break;
|
|
|
|
case OPENVPN_SCRAMBLE_MODE_XORMASK:
|
2020-07-20 00:45:12 +03:00
|
|
|
OvsDataXorMask(data, size, s->ObfuscationMask, StrLen(s->ObfuscationMask));
|
2018-11-13 00:32:37 +03:00
|
|
|
break;
|
|
|
|
case OPENVPN_SCRAMBLE_MODE_XORPTRPOS:
|
|
|
|
OvsDataXorPtrPos(data, size);
|
|
|
|
break;
|
|
|
|
case OPENVPN_SCRAMBLE_MODE_REVERSE:
|
|
|
|
OvsDataReverse(data, size);
|
|
|
|
break;
|
|
|
|
case OPENVPN_SCRAMBLE_MODE_OBFUSCATE:
|
|
|
|
OvsDataXorPtrPos(data, size);
|
|
|
|
OvsDataReverse(data, size);
|
|
|
|
OvsDataXorPtrPos(data, size);
|
2020-07-20 00:45:12 +03:00
|
|
|
OvsDataXorMask(data, size, s->ObfuscationMask, StrLen(s->ObfuscationMask));
|
2018-11-13 00:32:37 +03:00
|
|
|
}
|
|
|
|
|
2014-01-04 17:00:08 +04:00
|
|
|
u = NewUdpPacket(&se->ServerIp, se->ServerPort, &se->ClientIp, se->ClientPort,
|
2020-05-12 01:06:59 +03:00
|
|
|
data, size);
|
2014-01-04 17:00:08 +04:00
|
|
|
|
|
|
|
Add(s->SendPacketList, u);
|
|
|
|
}
|
|
|
|
// Create a new OpenVPN control packet
|
|
|
|
OPENVPN_PACKET *OvsNewControlPacket(UCHAR opcode, UCHAR key_id, UINT64 my_channel_id, UINT num_ack,
|
2020-05-12 01:06:59 +03:00
|
|
|
UINT *ack_packet_ids, UINT64 your_channel_id, UINT packet_id,
|
|
|
|
UINT data_size, UCHAR *data)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
|
|
|
OPENVPN_PACKET *p = ZeroMalloc(sizeof(OPENVPN_PACKET));
|
|
|
|
UINT i;
|
|
|
|
|
|
|
|
p->OpCode = opcode;
|
|
|
|
p->KeyId = key_id;
|
|
|
|
p->MySessionId = my_channel_id;
|
|
|
|
p->NumAck = num_ack;
|
|
|
|
|
2020-05-12 01:06:59 +03:00
|
|
|
for (i = 0; i < MIN(num_ack, OPENVPN_MAX_NUMACK); i++)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
|
|
|
p->AckPacketId[i] = ack_packet_ids[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
p->YourSessionId = your_channel_id;
|
|
|
|
p->PacketId = packet_id;
|
|
|
|
|
|
|
|
if (data_size != 0 && data != NULL)
|
|
|
|
{
|
|
|
|
p->Data = Clone(data, data_size);
|
|
|
|
p->DataSize = data_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Comparison function of the entries in the session list
|
|
|
|
int OvsCompareSessionList(void *p1, void *p2)
|
|
|
|
{
|
|
|
|
OPENVPN_SESSION *s1, *s2;
|
|
|
|
int i;
|
|
|
|
// Validate arguments
|
|
|
|
if (p1 == NULL || p2 == NULL)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
s1 = *(OPENVPN_SESSION **)p1;
|
|
|
|
s2 = *(OPENVPN_SESSION **)p2;
|
|
|
|
if (s1 == NULL || s2 == NULL)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-04-07 22:24:55 +03:00
|
|
|
i = Cmp(&s1->Protocol, &s2->Protocol, sizeof(s1->Protocol));
|
2014-01-04 17:00:08 +04:00
|
|
|
if (i != 0)
|
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
i = CmpIpAddr(&s1->ClientIp, &s2->ClientIp);
|
|
|
|
if (i != 0)
|
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
i = COMPARE_RET(s1->ClientPort, s2->ClientPort);
|
|
|
|
if (i != 0)
|
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
i = CmpIpAddr(&s1->ServerIp, &s2->ServerIp);
|
|
|
|
if (i != 0)
|
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
i = COMPARE_RET(s1->ServerPort, s2->ServerPort);
|
|
|
|
if (i != 0)
|
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a new OpenVPN server
|
2020-07-20 00:45:12 +03:00
|
|
|
OPENVPN_SERVER *NewOpenVpnServer(const LIST *options, CEDAR *cedar, INTERRUPT_MANAGER *interrupt, SOCK_EVENT *sock_event)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
2020-07-20 00:45:12 +03:00
|
|
|
UINT i;
|
2014-01-04 17:00:08 +04:00
|
|
|
OPENVPN_SERVER *s;
|
2020-07-20 00:45:12 +03:00
|
|
|
|
|
|
|
if (options == NULL || cedar == NULL || interrupt == NULL || sock_event == NULL)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
s = ZeroMalloc(sizeof(OPENVPN_SERVER));
|
|
|
|
|
2020-07-20 00:45:12 +03:00
|
|
|
for (i = 0; i < LIST_NUM(options); ++i)
|
|
|
|
{
|
|
|
|
const PROTO_OPTION *option = LIST_DATA(options, i);
|
|
|
|
if (StrCmp(option->Name, "DefaultClientOption") == 0)
|
|
|
|
{
|
|
|
|
s->DefaultClientOption = CopyStr(option->String);
|
|
|
|
}
|
|
|
|
else if (StrCmp(option->Name, "Obfuscation") == 0)
|
|
|
|
{
|
|
|
|
s->Obfuscation = option->Bool;
|
|
|
|
}
|
|
|
|
else if (StrCmp(option->Name, "ObfuscationMask") == 0)
|
|
|
|
{
|
|
|
|
s->ObfuscationMask = CopyStr(option->String);
|
|
|
|
}
|
2021-04-21 09:29:30 +03:00
|
|
|
else if (StrCmp(option->Name, "PingSendInterval") == 0)
|
|
|
|
{
|
|
|
|
s->PingSendInterval = option->UInt32;
|
|
|
|
}
|
2020-07-20 00:45:12 +03:00
|
|
|
else if (StrCmp(option->Name, "PushDummyIPv4AddressOnL2Mode") == 0)
|
|
|
|
{
|
|
|
|
s->PushDummyIPv4AddressOnL2Mode = option->Bool;
|
|
|
|
}
|
2021-04-21 09:29:30 +03:00
|
|
|
else if (StrCmp(option->Name, "Timeout") == 0)
|
|
|
|
{
|
|
|
|
s->Timeout = option->UInt32;
|
|
|
|
}
|
2020-07-20 00:45:12 +03:00
|
|
|
}
|
|
|
|
|
2014-01-04 17:00:08 +04:00
|
|
|
s->Cedar = cedar;
|
|
|
|
s->Interrupt = interrupt;
|
2019-07-26 08:58:22 +03:00
|
|
|
s->SockEvent = sock_event;
|
2014-01-04 17:00:08 +04:00
|
|
|
|
|
|
|
s->SessionList = NewList(OvsCompareSessionList);
|
2019-07-26 08:58:22 +03:00
|
|
|
s->RecvPacketList = NewListFast(NULL);
|
2014-01-04 17:00:08 +04:00
|
|
|
s->SendPacketList = NewListFast(NULL);
|
|
|
|
|
|
|
|
s->Now = Tick64();
|
2020-05-11 08:07:04 +03:00
|
|
|
s->Giveup = s->Now + OPENVPN_NEW_SESSION_DEADLINE_TIMEOUT;
|
2014-01-04 17:00:08 +04:00
|
|
|
|
|
|
|
s->NextSessionId = 1;
|
|
|
|
|
2020-05-11 09:23:29 +03:00
|
|
|
s->Dh = DhNewFromBits(cedar->DhParamBits);
|
2014-01-04 17:00:08 +04:00
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release the OpenVPN server
|
|
|
|
void FreeOpenVpnServer(OPENVPN_SERVER *s)
|
|
|
|
{
|
|
|
|
UINT i;
|
|
|
|
// Validate arguments
|
|
|
|
if (s == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-07-26 08:58:22 +03:00
|
|
|
// Release the sessions list
|
|
|
|
for (i = 0; i < LIST_NUM(s->SessionList); ++i)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
|
|
|
OPENVPN_SESSION *se = LIST_DATA(s->SessionList, i);
|
|
|
|
OvsFreeSession(se);
|
|
|
|
}
|
|
|
|
|
|
|
|
ReleaseList(s->SessionList);
|
|
|
|
|
2019-07-26 08:58:22 +03:00
|
|
|
// Release the incoming packets list
|
|
|
|
for (i = 0; i < LIST_NUM(s->RecvPacketList); ++i)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
2019-07-26 08:58:22 +03:00
|
|
|
UDPPACKET *p = LIST_DATA(s->RecvPacketList, i);
|
2014-01-04 17:00:08 +04:00
|
|
|
FreeUdpPacket(p);
|
|
|
|
}
|
|
|
|
|
2019-07-26 08:58:22 +03:00
|
|
|
ReleaseList(s->RecvPacketList);
|
2014-01-04 17:00:08 +04:00
|
|
|
|
2019-07-26 08:58:22 +03:00
|
|
|
// Release the outgoing packets list
|
|
|
|
for (i = 0; i < LIST_NUM(s->SendPacketList); ++i)
|
2014-01-04 17:00:08 +04:00
|
|
|
{
|
2019-07-26 08:58:22 +03:00
|
|
|
UDPPACKET *p = LIST_DATA(s->SendPacketList, i);
|
|
|
|
FreeUdpPacket(p);
|
2014-01-04 17:00:08 +04:00
|
|
|
}
|
|
|
|
|
2019-07-26 08:58:22 +03:00
|
|
|
ReleaseList(s->SendPacketList);
|
|
|
|
|
2014-01-04 17:00:08 +04:00
|
|
|
DhFree(s->Dh);
|
|
|
|
|
2020-07-20 00:45:12 +03:00
|
|
|
Free(s->DefaultClientOption);
|
|
|
|
Free(s->ObfuscationMask);
|
|
|
|
|
2014-01-04 17:00:08 +04:00
|
|
|
Free(s);
|
|
|
|
}
|