mirror of
https://github.com/SoftEtherVPN/SoftEtherVPN.git
synced 2024-11-22 17:39:53 +03:00
Merge PR #1171: Cedar: handle SSTP through Proto, minor improvements
This commit is contained in:
commit
3baf4674e7
@ -2936,7 +2936,7 @@ void ConnectionAccept(CONNECTION *c)
|
|||||||
if (c->Cedar != NULL && c->Cedar->Server != NULL)
|
if (c->Cedar != NULL && c->Cedar->Server != NULL)
|
||||||
{
|
{
|
||||||
PROTO *proto = c->Cedar->Server->Proto;
|
PROTO *proto = c->Cedar->Server->Proto;
|
||||||
if (proto && ProtoHandleConnection(proto, s) == true)
|
if (proto && ProtoHandleConnection(proto, s, NULL) == true)
|
||||||
{
|
{
|
||||||
c->Type = CONNECTION_TYPE_OTHER;
|
c->Type = CONNECTION_TYPE_OTHER;
|
||||||
goto FINAL;
|
goto FINAL;
|
||||||
|
@ -133,6 +133,8 @@ PROTO *ProtoNew(CEDAR *cedar)
|
|||||||
|
|
||||||
// OpenVPN
|
// OpenVPN
|
||||||
ProtoImplAdd(proto, OvsGetProtoImpl());
|
ProtoImplAdd(proto, OvsGetProtoImpl());
|
||||||
|
// SSTP
|
||||||
|
ProtoImplAdd(proto, SstpGetProtoImpl());
|
||||||
|
|
||||||
proto->UdpListener = NewUdpListener(ProtoHandleDatagrams, proto, &cedar->Server->ListenIP);
|
proto->UdpListener = NewUdpListener(ProtoHandleDatagrams, proto, &cedar->Server->ListenIP);
|
||||||
|
|
||||||
@ -187,7 +189,7 @@ PROTO_IMPL *ProtoImplDetect(PROTO *proto, const PROTO_MODE mode, const UCHAR *da
|
|||||||
for (i = 0; i < LIST_NUM(proto->Impls); ++i)
|
for (i = 0; i < LIST_NUM(proto->Impls); ++i)
|
||||||
{
|
{
|
||||||
PROTO_IMPL *impl = LIST_DATA(proto->Impls, i);
|
PROTO_IMPL *impl = LIST_DATA(proto->Impls, i);
|
||||||
if (impl->IsPacketForMe(mode, data, size) == false)
|
if (impl->IsPacketForMe == NULL || impl->IsPacketForMe(mode, data, size) == false)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -220,7 +222,7 @@ PROTO_SESSION *ProtoNewSession(PROTO *proto, PROTO_IMPL *impl, const IP *src_ip,
|
|||||||
session->SockEvent = NewSockEvent();
|
session->SockEvent = NewSockEvent();
|
||||||
session->InterruptManager = NewInterruptManager();
|
session->InterruptManager = NewInterruptManager();
|
||||||
|
|
||||||
if (impl->Init != NULL && impl->Init(&session->Param, proto->Cedar, session->InterruptManager, session->SockEvent) == false)
|
if (impl->Init != NULL && impl->Init(&session->Param, proto->Cedar, session->InterruptManager, session->SockEvent, NULL, NULL) == false)
|
||||||
{
|
{
|
||||||
Debug("ProtoNewSession(): failed to initialize %s\n", impl->Name());
|
Debug("ProtoNewSession(): failed to initialize %s\n", impl->Name());
|
||||||
|
|
||||||
@ -309,10 +311,10 @@ bool ProtoSetUdpPorts(PROTO *proto, const LIST *ports)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ProtoHandleConnection(PROTO *proto, SOCK *sock)
|
bool ProtoHandleConnection(PROTO *proto, SOCK *sock, const char *protocol)
|
||||||
{
|
{
|
||||||
|
const PROTO_IMPL *impl = NULL;
|
||||||
void *impl_data = NULL;
|
void *impl_data = NULL;
|
||||||
const PROTO_IMPL *impl;
|
|
||||||
|
|
||||||
UCHAR *buf;
|
UCHAR *buf;
|
||||||
TCP_RAW_DATA *recv_raw_data;
|
TCP_RAW_DATA *recv_raw_data;
|
||||||
@ -325,6 +327,20 @@ bool ProtoHandleConnection(PROTO *proto, SOCK *sock)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (protocol != NULL)
|
||||||
|
{
|
||||||
|
UINT i;
|
||||||
|
for (i = 0; i < LIST_NUM(proto->Impls); ++i)
|
||||||
|
{
|
||||||
|
const PROTO_IMPL *tmp = LIST_DATA(proto->Impls, i);
|
||||||
|
if (StrCmp(tmp->Name(), protocol) == 0)
|
||||||
|
{
|
||||||
|
impl = tmp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
UCHAR tmp[PROTO_CHECK_BUFFER_SIZE];
|
UCHAR tmp[PROTO_CHECK_BUFFER_SIZE];
|
||||||
if (Peek(sock, tmp, sizeof(tmp)) == 0)
|
if (Peek(sock, tmp, sizeof(tmp)) == 0)
|
||||||
@ -333,16 +349,17 @@ bool ProtoHandleConnection(PROTO *proto, SOCK *sock)
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl = ProtoImplDetect(proto, PROTO_MODE_TCP, tmp, sizeof(tmp));
|
impl = ProtoImplDetect(proto, PROTO_MODE_TCP, tmp, sizeof(tmp));
|
||||||
|
}
|
||||||
|
|
||||||
if (impl == NULL)
|
if (impl == NULL)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
im = NewInterruptManager();
|
im = NewInterruptManager();
|
||||||
se = NewSockEvent();
|
se = NewSockEvent();
|
||||||
|
|
||||||
if (impl->Init != NULL && impl->Init(&impl_data, proto->Cedar, im, se) == false)
|
if (impl->Init != NULL && impl->Init(&impl_data, proto->Cedar, im, se, sock->CipherName, sock->RemoteHostname) == false)
|
||||||
{
|
{
|
||||||
Debug("ProtoHandleConnection(): failed to initialize %s\n", impl->Name());
|
Debug("ProtoHandleConnection(): failed to initialize %s\n", impl->Name());
|
||||||
FreeInterruptManager(im);
|
FreeInterruptManager(im);
|
||||||
@ -368,7 +385,7 @@ bool ProtoHandleConnection(PROTO *proto, SOCK *sock)
|
|||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
const UINT ret = Recv(sock, buf, PROTO_TCP_BUFFER_SIZE, false);
|
const UINT ret = Recv(sock, buf, PROTO_TCP_BUFFER_SIZE, sock->SecureMode);
|
||||||
|
|
||||||
if (ret == SOCK_LATER)
|
if (ret == SOCK_LATER)
|
||||||
{
|
{
|
||||||
@ -396,7 +413,7 @@ bool ProtoHandleConnection(PROTO *proto, SOCK *sock)
|
|||||||
// Send data to the TCP socket
|
// Send data to the TCP socket
|
||||||
while (FifoSize(send_fifo) >= 1)
|
while (FifoSize(send_fifo) >= 1)
|
||||||
{
|
{
|
||||||
const UINT ret = Send(sock, FifoPtr(send_fifo), FifoSize(send_fifo), false);
|
const UINT ret = Send(sock, FifoPtr(send_fifo), FifoSize(send_fifo), sock->SecureMode);
|
||||||
|
|
||||||
if (ret == SOCK_LATER)
|
if (ret == SOCK_LATER)
|
||||||
{
|
{
|
||||||
@ -416,8 +433,6 @@ bool ProtoHandleConnection(PROTO *proto, SOCK *sock)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl->BufferLimit(impl_data, FifoSize(send_fifo) > MAX_BUFFERING_PACKET_SIZE);
|
|
||||||
|
|
||||||
if (stop)
|
if (stop)
|
||||||
{
|
{
|
||||||
// Error or disconnection occurs
|
// Error or disconnection occurs
|
||||||
|
@ -24,13 +24,12 @@ typedef struct PROTO
|
|||||||
|
|
||||||
typedef struct PROTO_IMPL
|
typedef struct PROTO_IMPL
|
||||||
{
|
{
|
||||||
bool (*Init)(void **param, CEDAR *cedar, INTERRUPT_MANAGER *im, SOCK_EVENT *se);
|
bool (*Init)(void **param, CEDAR *cedar, INTERRUPT_MANAGER *im, SOCK_EVENT *se, const char *cipher, const char *hostname);
|
||||||
void (*Free)(void *param);
|
void (*Free)(void *param);
|
||||||
char *(*Name)();
|
char *(*Name)();
|
||||||
bool (*IsPacketForMe)(const PROTO_MODE mode, const UCHAR *data, const UINT size);
|
bool (*IsPacketForMe)(const PROTO_MODE mode, const UCHAR *data, const UINT size);
|
||||||
bool (*ProcessData)(void *param, TCP_RAW_DATA *in, FIFO *out);
|
bool (*ProcessData)(void *param, TCP_RAW_DATA *in, FIFO *out);
|
||||||
bool (*ProcessDatagrams)(void *param, LIST *in, LIST *out);
|
bool (*ProcessDatagrams)(void *param, LIST *in, LIST *out);
|
||||||
void (*BufferLimit)(void *param, const bool reached);
|
|
||||||
} PROTO_IMPL;
|
} PROTO_IMPL;
|
||||||
|
|
||||||
typedef struct PROTO_SESSION
|
typedef struct PROTO_SESSION
|
||||||
@ -68,7 +67,7 @@ void ProtoDeleteSession(PROTO_SESSION *session);
|
|||||||
bool ProtoSetListenIP(PROTO *proto, const IP *ip);
|
bool ProtoSetListenIP(PROTO *proto, const IP *ip);
|
||||||
bool ProtoSetUdpPorts(PROTO *proto, const LIST *ports);
|
bool ProtoSetUdpPorts(PROTO *proto, const LIST *ports);
|
||||||
|
|
||||||
bool ProtoHandleConnection(PROTO *proto, SOCK *sock);
|
bool ProtoHandleConnection(PROTO *proto, SOCK *sock, const char *protocol);
|
||||||
void ProtoHandleDatagrams(UDPLISTENER *listener, LIST *datagrams);
|
void ProtoHandleDatagrams(UDPLISTENER *listener, LIST *datagrams);
|
||||||
void ProtoSessionThread(THREAD *thread, void *param);
|
void ProtoSessionThread(THREAD *thread, void *param);
|
||||||
|
|
||||||
|
@ -23,20 +23,21 @@ PROTO_IMPL *OvsGetProtoImpl()
|
|||||||
OvsName,
|
OvsName,
|
||||||
OvsIsPacketForMe,
|
OvsIsPacketForMe,
|
||||||
OvsProcessData,
|
OvsProcessData,
|
||||||
OvsProcessDatagrams,
|
OvsProcessDatagrams
|
||||||
OvsBufferLimit,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return &impl;
|
return &impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OvsInit(void **param, CEDAR *cedar, INTERRUPT_MANAGER *im, SOCK_EVENT *se)
|
bool OvsInit(void **param, CEDAR *cedar, INTERRUPT_MANAGER *im, SOCK_EVENT *se, const char *cipher, const char *hostname)
|
||||||
{
|
{
|
||||||
if (param == NULL || cedar == NULL || im == NULL || se == NULL)
|
if (param == NULL || cedar == NULL || im == NULL || se == NULL)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Debug("OvsInit(): cipher: %s, hostname: %s\n", cipher, hostname);
|
||||||
|
|
||||||
*param = NewOpenVpnServer(cedar, im, se);
|
*param = NewOpenVpnServer(cedar, im, se);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -185,6 +186,8 @@ bool OvsProcessData(void *param, TCP_RAW_DATA *in, FIFO *out)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
server->SupressSendPacket = FifoSize(out) > MAX_BUFFERING_PACKET_SIZE;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,16 +232,6 @@ bool OvsProcessDatagrams(void *param, LIST *in, LIST *out)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OvsBufferLimit(void *param, const bool reached)
|
|
||||||
{
|
|
||||||
if (param == NULL)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
((OPENVPN_SERVER *)param)->SupressSendPacket = reached;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write the OpenVPN log
|
// Write the OpenVPN log
|
||||||
void OvsLog(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_CHANNEL *c, char *name, ...)
|
void OvsLog(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_CHANNEL *c, char *name, ...)
|
||||||
{
|
{
|
||||||
|
@ -209,13 +209,12 @@ struct OPENVPN_SERVER
|
|||||||
|
|
||||||
//// Function prototype
|
//// Function prototype
|
||||||
PROTO_IMPL *OvsGetProtoImpl();
|
PROTO_IMPL *OvsGetProtoImpl();
|
||||||
bool OvsInit(void **param, CEDAR *cedar, INTERRUPT_MANAGER *im, SOCK_EVENT *se);
|
bool OvsInit(void **param, CEDAR *cedar, INTERRUPT_MANAGER *im, SOCK_EVENT *se, const char *cipher, const char *hostname);
|
||||||
void OvsFree(void *param);
|
void OvsFree(void *param);
|
||||||
char *OvsName();
|
char *OvsName();
|
||||||
bool OvsIsPacketForMe(const PROTO_MODE mode, const UCHAR *data, const UINT size);
|
bool OvsIsPacketForMe(const PROTO_MODE mode, const UCHAR *data, const UINT size);
|
||||||
bool OvsProcessData(void *param, TCP_RAW_DATA *in, FIFO *out);
|
bool OvsProcessData(void *param, TCP_RAW_DATA *in, FIFO *out);
|
||||||
bool OvsProcessDatagrams(void *param, LIST *in, LIST *out);
|
bool OvsProcessDatagrams(void *param, LIST *in, LIST *out);
|
||||||
void OvsBufferLimit(void *param, const bool reached);
|
|
||||||
bool OvsIsOk(void *param);
|
bool OvsIsOk(void *param);
|
||||||
UINT OvsEstablishedSessions(void *param);
|
UINT OvsEstablishedSessions(void *param);
|
||||||
|
|
||||||
|
@ -16,6 +16,171 @@ bool GetNoSstp()
|
|||||||
return g_no_sstp;
|
return g_no_sstp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PROTO_IMPL *SstpGetProtoImpl()
|
||||||
|
{
|
||||||
|
static PROTO_IMPL impl =
|
||||||
|
{
|
||||||
|
SstpInit,
|
||||||
|
SstpFree,
|
||||||
|
SstpName,
|
||||||
|
NULL,
|
||||||
|
SstpProcessData,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
return &impl;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SstpInit(void **param, struct CEDAR *cedar, INTERRUPT_MANAGER *im, SOCK_EVENT *se, const char *cipher, const char *hostname)
|
||||||
|
{
|
||||||
|
if (param == NULL || cedar == NULL || im == NULL || se == NULL)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug("SstpInit(): cipher: %s, hostname: %s\n", cipher, hostname);
|
||||||
|
|
||||||
|
*param = NewSstpServer(cedar, im, se, cipher, hostname);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SstpFree(void *param)
|
||||||
|
{
|
||||||
|
FreeSstpServer(param);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *SstpName()
|
||||||
|
{
|
||||||
|
return "SSTP";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SstpProcessData(void *param, TCP_RAW_DATA *in, FIFO *out)
|
||||||
|
{
|
||||||
|
FIFO *recv_fifo;
|
||||||
|
bool disconnected = false;
|
||||||
|
SSTP_SERVER *server = param;
|
||||||
|
|
||||||
|
if (server == NULL || in == NULL || out == NULL)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (server->Status == SSTP_SERVER_STATUS_NOT_INITIALIZED)
|
||||||
|
{
|
||||||
|
HTTP_HEADER *header;
|
||||||
|
char *header_str, date_str[MAX_SIZE];
|
||||||
|
|
||||||
|
GetHttpDateStr(date_str, sizeof(date_str), SystemTime64());
|
||||||
|
|
||||||
|
header = NewHttpHeader("HTTP/1.1", "200", "OK");
|
||||||
|
AddHttpValue(header, NewHttpValue("Content-Length", "18446744073709551615"));
|
||||||
|
AddHttpValue(header, NewHttpValue("Server", "Microsoft-HTTPAPI/2.0"));
|
||||||
|
AddHttpValue(header, NewHttpValue("Date", date_str));
|
||||||
|
|
||||||
|
header_str = HttpHeaderToStr(header);
|
||||||
|
|
||||||
|
FreeHttpHeader(header);
|
||||||
|
|
||||||
|
if (header_str == NULL)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteFifo(out, header_str, StrLen(header_str));
|
||||||
|
|
||||||
|
Free(header_str);
|
||||||
|
|
||||||
|
Copy(&server->ClientIp, &in->SrcIP, sizeof(server->ClientIp));
|
||||||
|
server->ClientPort = in->SrcPort;
|
||||||
|
Copy(&server->ServerIp, &in->DstIP, sizeof(server->ServerIp));
|
||||||
|
server->ServerPort = in->DstPort;
|
||||||
|
|
||||||
|
server->Status = SSTP_SERVER_STATUS_REQUEST_PENGING;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
recv_fifo = in->Data;
|
||||||
|
|
||||||
|
while (recv_fifo->size >= 4)
|
||||||
|
{
|
||||||
|
UCHAR *first4;
|
||||||
|
bool ok = false;
|
||||||
|
UINT read_size = 0;
|
||||||
|
|
||||||
|
// Read 4 bytes from the beginning of the received queue.
|
||||||
|
first4 = ((UCHAR *)recv_fifo->p) + recv_fifo->pos;
|
||||||
|
if (first4[0] == SSTP_VERSION_1)
|
||||||
|
{
|
||||||
|
const USHORT len = READ_USHORT(first4 + 2) & 0xFFF;
|
||||||
|
if (len >= 4)
|
||||||
|
{
|
||||||
|
ok = true;
|
||||||
|
|
||||||
|
if (recv_fifo->size >= len)
|
||||||
|
{
|
||||||
|
UCHAR *data;
|
||||||
|
BLOCK *b;
|
||||||
|
|
||||||
|
read_size = len;
|
||||||
|
data = Malloc(read_size);
|
||||||
|
|
||||||
|
ReadFifo(recv_fifo, data, read_size);
|
||||||
|
|
||||||
|
b = NewBlock(data, read_size, 0);
|
||||||
|
|
||||||
|
InsertQueue(server->RecvQueue, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (read_size == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ok == false)
|
||||||
|
{
|
||||||
|
// Bad packet received, trigger disconnection.
|
||||||
|
disconnected = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the timer interrupt
|
||||||
|
SstpProcessInterrupt(server);
|
||||||
|
|
||||||
|
if (server->Disconnected)
|
||||||
|
{
|
||||||
|
disconnected = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
BLOCK *b = GetNext(server->SendQueue);
|
||||||
|
if (b == NULL)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Discard the data block if the transmission queue's size is greater than ~2.5 MB.
|
||||||
|
if (b->PriorityQoS || (FifoSize(out) <= MAX_BUFFERING_PACKET_SIZE))
|
||||||
|
{
|
||||||
|
WriteFifo(out, b->Buf, b->Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
FreeBlock(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (disconnected)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Process the SSTP control packet reception
|
// Process the SSTP control packet reception
|
||||||
void SstpProcessControlPacket(SSTP_SERVER *s, SSTP_PACKET *p)
|
void SstpProcessControlPacket(SSTP_SERVER *s, SSTP_PACKET *p)
|
||||||
{
|
{
|
||||||
@ -829,39 +994,28 @@ void SstpFreePacket(SSTP_PACKET *p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a SSTP server
|
// Create a SSTP server
|
||||||
SSTP_SERVER *NewSstpServer(CEDAR *cedar, IP *client_ip, UINT client_port, IP *server_ip,
|
SSTP_SERVER *NewSstpServer(CEDAR *cedar, INTERRUPT_MANAGER *im, SOCK_EVENT *se, const char *cipher, const char *hostname)
|
||||||
UINT server_port, SOCK_EVENT *se,
|
|
||||||
char *client_host_name, char *crypt_name)
|
|
||||||
{
|
{
|
||||||
SSTP_SERVER *s = ZeroMalloc(sizeof(SSTP_SERVER));
|
SSTP_SERVER *s = ZeroMalloc(sizeof(SSTP_SERVER));
|
||||||
|
|
||||||
s->LastRecvTick = Tick64();
|
s->Status = SSTP_SERVER_STATUS_NOT_INITIALIZED;
|
||||||
|
|
||||||
StrCpy(s->ClientHostName, sizeof(s->ClientHostName), client_host_name);
|
s->Now = Tick64();
|
||||||
StrCpy(s->ClientCipherName, sizeof(s->ClientCipherName), crypt_name);
|
s->LastRecvTick = s->Now;
|
||||||
|
|
||||||
s->Cedar = cedar;
|
s->Cedar = cedar;
|
||||||
AddRef(s->Cedar->ref);
|
s->Interrupt = im;
|
||||||
|
s->SockEvent = se;
|
||||||
|
|
||||||
|
StrCpy(s->ClientHostName, sizeof(s->ClientHostName), hostname);
|
||||||
|
StrCpy(s->ClientCipherName, sizeof(s->ClientCipherName), cipher);
|
||||||
|
|
||||||
NewTubePair(&s->TubeSend, &s->TubeRecv, 0);
|
NewTubePair(&s->TubeSend, &s->TubeRecv, 0);
|
||||||
SetTubeSockEvent(s->TubeSend, se);
|
SetTubeSockEvent(s->TubeSend, se);
|
||||||
|
|
||||||
s->Now = Tick64();
|
|
||||||
|
|
||||||
Copy(&s->ClientIp, client_ip, sizeof(IP));
|
|
||||||
s->ClientPort = client_port;
|
|
||||||
Copy(&s->ServerIp, server_ip, sizeof(IP));
|
|
||||||
s->ServerPort = server_port;
|
|
||||||
|
|
||||||
s->SockEvent = se;
|
|
||||||
|
|
||||||
AddRef(s->SockEvent->ref);
|
|
||||||
|
|
||||||
s->RecvQueue = NewQueueFast();
|
s->RecvQueue = NewQueueFast();
|
||||||
s->SendQueue = NewQueueFast();
|
s->SendQueue = NewQueueFast();
|
||||||
|
|
||||||
s->Interrupt = NewInterruptManager();
|
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -907,242 +1061,8 @@ void FreeSstpServer(SSTP_SERVER *s)
|
|||||||
ReleaseQueue(s->RecvQueue);
|
ReleaseQueue(s->RecvQueue);
|
||||||
ReleaseQueue(s->SendQueue);
|
ReleaseQueue(s->SendQueue);
|
||||||
|
|
||||||
ReleaseSockEvent(s->SockEvent);
|
|
||||||
|
|
||||||
FreeInterruptManager(s->Interrupt);
|
|
||||||
|
|
||||||
ReleaseCedar(s->Cedar);
|
|
||||||
|
|
||||||
ReleaseTube(s->TubeSend);
|
ReleaseTube(s->TubeSend);
|
||||||
ReleaseTube(s->TubeRecv);
|
ReleaseTube(s->TubeRecv);
|
||||||
|
|
||||||
Free(s);
|
Free(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle the communication of SSTP protocol
|
|
||||||
bool ProcessSstpHttps(CEDAR *cedar, SOCK *s, SOCK_EVENT *se)
|
|
||||||
{
|
|
||||||
UINT tmp_size = 65536;
|
|
||||||
UCHAR *tmp_buf;
|
|
||||||
FIFO *recv_fifo;
|
|
||||||
FIFO *send_fifo;
|
|
||||||
SSTP_SERVER *sstp;
|
|
||||||
bool ret = false;
|
|
||||||
// Validate arguments
|
|
||||||
if (cedar == NULL || s == NULL || se == NULL)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp_buf = Malloc(tmp_size);
|
|
||||||
recv_fifo = NewFifo();
|
|
||||||
send_fifo = NewFifo();
|
|
||||||
|
|
||||||
sstp = NewSstpServer(cedar, &s->RemoteIP, s->RemotePort, &s->LocalIP, s->LocalPort, se,
|
|
||||||
s->RemoteHostname, s->CipherName);
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
UINT r;
|
|
||||||
bool is_disconnected = false;
|
|
||||||
bool state_changed = false;
|
|
||||||
|
|
||||||
// Receive data over SSL
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
r = Recv(s, tmp_buf, tmp_size, true);
|
|
||||||
if (r == 0)
|
|
||||||
{
|
|
||||||
// SSL is disconnected
|
|
||||||
is_disconnected = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (r == SOCK_LATER)
|
|
||||||
{
|
|
||||||
// Data is not received any more
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Queue the received data
|
|
||||||
WriteFifo(recv_fifo, tmp_buf, r);
|
|
||||||
state_changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (recv_fifo->size >= 4)
|
|
||||||
{
|
|
||||||
UCHAR *first4;
|
|
||||||
UINT read_size = 0;
|
|
||||||
bool ok = false;
|
|
||||||
// Read 4 bytes from the beginning of the receive queue
|
|
||||||
first4 = ((UCHAR *)recv_fifo->p) + recv_fifo->pos;
|
|
||||||
if (first4[0] == SSTP_VERSION_1)
|
|
||||||
{
|
|
||||||
USHORT len = READ_USHORT(first4 + 2) & 0xFFF;
|
|
||||||
if (len >= 4)
|
|
||||||
{
|
|
||||||
ok = true;
|
|
||||||
|
|
||||||
if (recv_fifo->size >= len)
|
|
||||||
{
|
|
||||||
UCHAR *data;
|
|
||||||
BLOCK *b;
|
|
||||||
|
|
||||||
read_size = len;
|
|
||||||
data = Malloc(read_size);
|
|
||||||
|
|
||||||
ReadFifo(recv_fifo, data, read_size);
|
|
||||||
|
|
||||||
b = NewBlock(data, read_size, 0);
|
|
||||||
|
|
||||||
InsertQueue(sstp->RecvQueue, b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (read_size == 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ok == false)
|
|
||||||
{
|
|
||||||
// Disconnect the connection since a bad packet received
|
|
||||||
is_disconnected = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process the timer interrupt
|
|
||||||
SstpProcessInterrupt(sstp);
|
|
||||||
|
|
||||||
if (sstp->Disconnected)
|
|
||||||
{
|
|
||||||
is_disconnected = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Put the transmission data that SSTP module has generated into the transmission queue
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
BLOCK *b = GetNext(sstp->SendQueue);
|
|
||||||
|
|
||||||
if (b == NULL)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// When transmit a data packet, If there are packets of more than about
|
|
||||||
// 2.5 MB in the transmission queue of the TCP, discard without transmission
|
|
||||||
if (b->PriorityQoS || (send_fifo->size <= MAX_BUFFERING_PACKET_SIZE))
|
|
||||||
{
|
|
||||||
WriteFifo(send_fifo, b->Buf, b->Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
FreeBlock(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Data is transmitted over SSL
|
|
||||||
while (send_fifo->size != 0)
|
|
||||||
{
|
|
||||||
r = Send(s, ((UCHAR *)send_fifo->p) + send_fifo->pos, send_fifo->size, true);
|
|
||||||
if (r == 0)
|
|
||||||
{
|
|
||||||
// SSL is disconnected
|
|
||||||
is_disconnected = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (r == SOCK_LATER)
|
|
||||||
{
|
|
||||||
// Can not send any more
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Advance the transmission queue by the amount of the transmitted
|
|
||||||
ReadFifo(send_fifo, NULL, r);
|
|
||||||
state_changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_disconnected)
|
|
||||||
{
|
|
||||||
// Disconnected
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for the next state change
|
|
||||||
if (state_changed == false)
|
|
||||||
{
|
|
||||||
UINT select_time = SELECT_TIME;
|
|
||||||
UINT r = GetNextIntervalForInterrupt(sstp->Interrupt);
|
|
||||||
WaitSockEvent(se, MIN(r, select_time));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sstp != NULL && sstp->EstablishedCount >= 1)
|
|
||||||
{
|
|
||||||
ret = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
FreeSstpServer(sstp);
|
|
||||||
|
|
||||||
ReleaseFifo(recv_fifo);
|
|
||||||
ReleaseFifo(send_fifo);
|
|
||||||
Free(tmp_buf);
|
|
||||||
|
|
||||||
YieldCpu();
|
|
||||||
Disconnect(s);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Accept the SSTP connection
|
|
||||||
bool AcceptSstp(CONNECTION *c)
|
|
||||||
{
|
|
||||||
SOCK *s;
|
|
||||||
HTTP_HEADER *h;
|
|
||||||
char date_str[MAX_SIZE];
|
|
||||||
bool ret;
|
|
||||||
bool ret2 = false;
|
|
||||||
SOCK_EVENT *se;
|
|
||||||
// Validate arguments
|
|
||||||
if (c == NULL)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
s = c->FirstSock;
|
|
||||||
|
|
||||||
GetHttpDateStr(date_str, sizeof(date_str), SystemTime64());
|
|
||||||
|
|
||||||
// Return a response
|
|
||||||
h = NewHttpHeader("HTTP/1.1", "200", "OK");
|
|
||||||
AddHttpValue(h, NewHttpValue("Content-Length", "18446744073709551615"));
|
|
||||||
AddHttpValue(h, NewHttpValue("Server", "Microsoft-HTTPAPI/2.0"));
|
|
||||||
AddHttpValue(h, NewHttpValue("Date", date_str));
|
|
||||||
|
|
||||||
ret = PostHttp(s, h, NULL, 0);
|
|
||||||
|
|
||||||
FreeHttpHeader(h);
|
|
||||||
|
|
||||||
if (ret)
|
|
||||||
{
|
|
||||||
SetTimeout(s, INFINITE);
|
|
||||||
|
|
||||||
se = NewSockEvent();
|
|
||||||
|
|
||||||
JoinSockToSockEvent(s, se);
|
|
||||||
|
|
||||||
Debug("ProcessSstpHttps Start.\n");
|
|
||||||
ret2 = ProcessSstpHttps(c->Cedar, s, se);
|
|
||||||
Debug("ProcessSstpHttps End.\n");
|
|
||||||
|
|
||||||
ReleaseSockEvent(se);
|
|
||||||
}
|
|
||||||
|
|
||||||
Disconnect(s);
|
|
||||||
|
|
||||||
return ret2;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -61,6 +61,7 @@
|
|||||||
#define SSTP_SERVER_STATUS_REQUEST_PENGING 0 // Connection incomplete
|
#define SSTP_SERVER_STATUS_REQUEST_PENGING 0 // Connection incomplete
|
||||||
#define SSTP_SERVER_STATUS_CONNECTED_PENDING 1 // Connection completed. Authentication incomplete
|
#define SSTP_SERVER_STATUS_CONNECTED_PENDING 1 // Connection completed. Authentication incomplete
|
||||||
#define SSTP_SERVER_STATUS_ESTABLISHED 2 // Connection completed. Communication available
|
#define SSTP_SERVER_STATUS_ESTABLISHED 2 // Connection completed. Communication available
|
||||||
|
#define SSTP_SERVER_STATUS_NOT_INITIALIZED INFINITE // Connection not accepted yet.
|
||||||
|
|
||||||
// Length of Nonce
|
// Length of Nonce
|
||||||
#define SSTP_NONCE_SIZE 32 // 256 bits
|
#define SSTP_NONCE_SIZE 32 // 256 bits
|
||||||
@ -121,12 +122,13 @@ struct SSTP_SERVER
|
|||||||
|
|
||||||
|
|
||||||
//// Function prototype
|
//// Function prototype
|
||||||
bool AcceptSstp(CONNECTION *c);
|
PROTO_IMPL *SstpGetProtoImpl();
|
||||||
bool ProcessSstpHttps(CEDAR *cedar, SOCK *s, SOCK_EVENT *se);
|
bool SstpInit(void **param, struct CEDAR *cedar, INTERRUPT_MANAGER *im, SOCK_EVENT *se, const char *cipher, const char *hostname);
|
||||||
|
void SstpFree(void *param);
|
||||||
|
char *SstpName();
|
||||||
|
bool SstpProcessData(void *param, TCP_RAW_DATA *in, FIFO *out);
|
||||||
|
|
||||||
SSTP_SERVER *NewSstpServer(CEDAR *cedar, IP *client_ip, UINT client_port, IP *server_ip,
|
SSTP_SERVER *NewSstpServer(CEDAR *cedar, INTERRUPT_MANAGER *im, SOCK_EVENT *se, const char *cipher, const char *hostname);
|
||||||
UINT server_port, SOCK_EVENT *se,
|
|
||||||
char *client_host_name, char *crypt_name);
|
|
||||||
void FreeSstpServer(SSTP_SERVER *s);
|
void FreeSstpServer(SSTP_SERVER *s);
|
||||||
void SstpProcessInterrupt(SSTP_SERVER *s);
|
void SstpProcessInterrupt(SSTP_SERVER *s);
|
||||||
SSTP_PACKET *SstpParsePacket(UCHAR *data, UINT size);
|
SSTP_PACKET *SstpParsePacket(UCHAR *data, UINT size);
|
||||||
|
@ -5891,7 +5891,7 @@ bool ServerDownloadSignature(CONNECTION *c, char **error_detail_str)
|
|||||||
// Accept the SSTP connection
|
// Accept the SSTP connection
|
||||||
c->Type = CONNECTION_TYPE_OTHER;
|
c->Type = CONNECTION_TYPE_OTHER;
|
||||||
|
|
||||||
sstp_ret = AcceptSstp(c);
|
sstp_ret = ProtoHandleConnection(server->Proto, s, "SSTP");
|
||||||
|
|
||||||
c->Err = ERR_DISCONNECTED;
|
c->Err = ERR_DISCONNECTED;
|
||||||
FreeHttpHeader(h);
|
FreeHttpHeader(h);
|
||||||
|
Loading…
Reference in New Issue
Block a user