|
|
@@ -16,6 +16,171 @@ bool GetNoSstp()
|
|
|
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
|
|
|
void SstpProcessControlPacket(SSTP_SERVER *s, SSTP_PACKET *p)
|
|
|
{
|
|
|
@@ -829,39 +994,28 @@ void SstpFreePacket(SSTP_PACKET *p)
|
|
|
}
|
|
|
|
|
|
// Create a SSTP server
|
|
|
-SSTP_SERVER *NewSstpServer(CEDAR *cedar, IP *client_ip, UINT client_port, IP *server_ip,
|
|
|
- UINT server_port, SOCK_EVENT *se,
|
|
|
- char *client_host_name, char *crypt_name)
|
|
|
+SSTP_SERVER *NewSstpServer(CEDAR *cedar, INTERRUPT_MANAGER *im, SOCK_EVENT *se, const char *cipher, const char *hostname)
|
|
|
{
|
|
|
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);
|
|
|
- StrCpy(s->ClientCipherName, sizeof(s->ClientCipherName), crypt_name);
|
|
|
+ s->Now = Tick64();
|
|
|
+ s->LastRecvTick = s->Now;
|
|
|
|
|
|
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);
|
|
|
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->SendQueue = NewQueueFast();
|
|
|
|
|
|
- s->Interrupt = NewInterruptManager();
|
|
|
-
|
|
|
return s;
|
|
|
}
|
|
|
|
|
|
@@ -907,242 +1061,8 @@ void FreeSstpServer(SSTP_SERVER *s)
|
|
|
ReleaseQueue(s->RecvQueue);
|
|
|
ReleaseQueue(s->SendQueue);
|
|
|
|
|
|
- ReleaseSockEvent(s->SockEvent);
|
|
|
-
|
|
|
- FreeInterruptManager(s->Interrupt);
|
|
|
-
|
|
|
- ReleaseCedar(s->Cedar);
|
|
|
-
|
|
|
ReleaseTube(s->TubeSend);
|
|
|
ReleaseTube(s->TubeRecv);
|
|
|
|
|
|
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;
|
|
|
-}
|
|
|
-
|