diff --git a/src/Cedar/Proto_L2TP.c b/src/Cedar/Proto_L2TP.c index 960103ca..edf1b94f 100644 --- a/src/Cedar/Proto_L2TP.c +++ b/src/Cedar/Proto_L2TP.c @@ -1995,6 +1995,7 @@ UINT CalcL2TPMss(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, L2TP_SESSION *s) // Start the L2TP thread void StartL2TPThread(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, L2TP_SESSION *s) { + PPP_SESSION* underlyingSession; // Validate arguments if (l2tp == NULL || t == NULL || s == NULL) { @@ -2023,9 +2024,11 @@ void StartL2TPThread(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, L2TP_SESSION *s) } // Create a PPP thread - s->Thread = NewPPPSession(l2tp->Cedar, &t->ClientIp, t->ClientPort, &t->ServerIp, t->ServerPort, + underlyingSession = NewPPPSession(l2tp->Cedar, &t->ClientIp, t->ClientPort, &t->ServerIp, t->ServerPort, s->TubeSend, s->TubeRecv, L2TP_IPC_POSTFIX, tmp, t->HostName, l2tp->CryptName, CalcL2TPMss(l2tp, t, s)); + s->Thread = underlyingSession->SessionThread; + s->PPPSession = underlyingSession; } } @@ -2122,8 +2125,21 @@ void L2TPProcessInterrupts(L2TP_SERVER *l2tp) { L2TP_TUNNEL *t = LIST_DATA(l2tp->TunnelList, i); LIST *delete_session_list = NULL; + UINT64 l2tpTimeout = L2TP_TUNNEL_TIMEOUT; - if ((l2tp->Now >= (t->LastRecvTick + (UINT64)L2TP_TUNNEL_TIMEOUT)) && t->Timedout == false) + // If we got on ANY session a higher timeout than the default L2TP tunnel timeout, increase it + for (i = 0; i < LIST_NUM(t->SessionList); i++) + { + L2TP_SESSION* s = LIST_DATA(t->SessionList, i); + + if (s->PPPSession != NULL && s->PPPSession->DataTimeout > l2tpTimeout) + { + l2tpTimeout = s->PPPSession->DataTimeout; + } + } + + + if ((l2tp->Now >= (t->LastRecvTick + (UINT64)l2tpTimeout)) && t->Timedout == false) { // Disconnect the tunnel forcibly if data can not be received for a certain period of time t->Timedout = true; diff --git a/src/Cedar/Proto_L2TP.h b/src/Cedar/Proto_L2TP.h index 1cd9767b..9d83f66b 100644 --- a/src/Cedar/Proto_L2TP.h +++ b/src/Cedar/Proto_L2TP.h @@ -169,6 +169,7 @@ struct L2TP_SESSION UINT64 DisconnectTimeout; // Disconnection completion time-out bool HasThread; // Whether have a thread THREAD *Thread; // Thread + PPP_SESSION* PPPSession; // Underlying PPP session TUBE *TubeSend; // Tube of PPP to L2TP direction TUBE *TubeRecv; // Tube of L2TP to PPP direction UINT PseudowireType; // Type of L2TPv3 virtual line diff --git a/src/Cedar/Proto_PPP.c b/src/Cedar/Proto_PPP.c index 1bf4528f..cee81ad6 100644 --- a/src/Cedar/Proto_PPP.c +++ b/src/Cedar/Proto_PPP.c @@ -386,13 +386,22 @@ void PPPThread(THREAD *thread, void *param) } // Time-out inspection - if ((p->LastRecvTime + (UINT64)PPP_DATA_TIMEOUT) <= now) + if ((p->LastRecvTime + (UINT64)p->DataTimeout) <= now) { // Communication time-out occurs PPPLog(p, "LP_DATA_TIMEOUT"); break; } + // Maximum PPP session time of the user reached inspection + if (p->UserConnectionTick != 0 && p->UserConnectionTimeout != 0 && + p->UserConnectionTick + p->UserConnectionTimeout <= now) + { + // User connection time-out occurs + PPPLog(p, "LP_USER_TIMEOUT"); + break; + } + // Terminate if the PPP disconnected if (p->IsTerminateReceived) { @@ -444,7 +453,7 @@ void PPPThread(THREAD *thread, void *param) // Entry point // Create a new PPP session -THREAD *NewPPPSession(CEDAR *cedar, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port, TUBE *send_tube, TUBE *recv_tube, char *postfix, char *client_software_name, char *client_hostname, char *crypt_name, UINT adjust_mss) +PPP_SESSION *NewPPPSession(CEDAR *cedar, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port, TUBE *send_tube, TUBE *recv_tube, char *postfix, char *client_software_name, char *client_hostname, char *crypt_name, UINT adjust_mss) { PPP_SESSION *p; THREAD *t; @@ -474,6 +483,10 @@ THREAD *NewPPPSession(CEDAR *cedar, IP *client_ip, UINT client_port, IP *server_ p->MsChapV2_ErrorCode = 691; p->EapClient = NULL; + p->DataTimeout = PPP_DATA_TIMEOUT; + p->PacketRecvTimeout = PPP_PACKET_RECV_TIMEOUT; + p->UserConnectionTimeout = 0; + p->Cedar = cedar; AddRef(cedar->ref); @@ -510,7 +523,9 @@ THREAD *NewPPPSession(CEDAR *cedar, IP *client_ip, UINT client_port, IP *server_ // Thread creation t = NewThread(PPPThread, p); - return t; + p->SessionThread = t; + + return p; } // PPP processing functions @@ -1292,6 +1307,13 @@ bool PPPProcessPAPRequestPacket(PPP_SESSION *p, PPP_PACKET* pp) if (ipc != NULL) { p->Ipc = ipc; + + // Setting user timeouts + p->PacketRecvTimeout = (UINT64)p->Ipc->Policy->TimeOut * 1000 * 3 / 4; // setting to 3/4 of the user timeout + p->DataTimeout = (UINT64)p->Ipc->Policy->TimeOut * 1000; + p->UserConnectionTimeout = (UINT64)p->Ipc->Policy->AutoDisconnect * 1000; + p->UserConnectionTick = Tick64(); + p->AuthOk = true; } else @@ -1889,7 +1911,7 @@ bool PPPSendAndRetransmitRequest(PPP_SESSION *p, USHORT protocol, PPP_LCP *c) resend->Id = pp->Lcp->Id; resend->Packet = pp; resend->ResendTime = now + PPP_PACKET_RESEND_INTERVAL; - resend->TimeoutTime = now + PPP_PACKET_RECV_TIMEOUT; + resend->TimeoutTime = now + p->PacketRecvTimeout; Add(p->SentReqPacketList, resend); @@ -1946,7 +1968,7 @@ LABEL_LOOP: if (async == false) { - d = TubeRecvSync(p->TubeRecv, PPP_PACKET_RECV_TIMEOUT); + d = TubeRecvSync(p->TubeRecv, p->PacketRecvTimeout); } else { @@ -2499,9 +2521,17 @@ bool PPPParseMSCHAP2ResponsePacket(PPP_SESSION* p, PPP_PACKET* pp) { p->Ipc = ipc; + // Setting user timeouts + p->PacketRecvTimeout = (UINT64)p->Ipc->Policy->TimeOut * 1000 * 3 / 4; // setting to 3/4 of the user timeout + p->DataTimeout = (UINT64)p->Ipc->Policy->TimeOut * 1000; + p->UserConnectionTimeout = (UINT64)p->Ipc->Policy->AutoDisconnect * 1000; + p->UserConnectionTick = Tick64(); + Copy(p->MsChapV2_ServerResponse, ipc->MsChapV2_ServerResponse, 20); ok = true; + + p->AuthOk = true; } } else diff --git a/src/Cedar/Proto_PPP.h b/src/Cedar/Proto_PPP.h index afd9bfd8..79c338e9 100644 --- a/src/Cedar/Proto_PPP.h +++ b/src/Cedar/Proto_PPP.h @@ -32,11 +32,11 @@ //// Constants // Time-out value -#define PPP_PACKET_RECV_TIMEOUT (30 * 1000) // Timeout until the next packet is received -#define PPP_PACKET_RESEND_INTERVAL (5 * 1000) // Retransmission interval of the last packet +#define PPP_PACKET_RECV_TIMEOUT (15 * 1000) // Timeout until the next packet is received (3/4 of default policy) +#define PPP_PACKET_RESEND_INTERVAL (3 * 1000) // Retransmission interval of the last packet #define PPP_TERMINATE_TIMEOUT 2000 // Timeout value to complete disconnection after requesting to disconnect in the PPP #define PPP_ECHO_SEND_INTERVAL 4792 // Transmission interval of PPP Echo Request -#define PPP_DATA_TIMEOUT (60 * 1000) // Communication time-out +#define PPP_DATA_TIMEOUT (20 * 1000) // Communication time-out (from default policy) // MRU #define PPP_MRU_DEFAULT 1500 // Default value @@ -238,6 +238,13 @@ struct PPP_SESSION PPP_PACKET *CurrentPacket; LIST *DelayedPackets; + + UINT64 PacketRecvTimeout; + UINT64 DataTimeout; + UINT64 UserConnectionTimeout; + UINT64 UserConnectionTick; + + THREAD* SessionThread; // Thread of the PPP session }; @@ -248,7 +255,7 @@ struct PPP_SESSION void PPPThread(THREAD *thread, void *param); // Entry point -THREAD *NewPPPSession(CEDAR *cedar, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port, TUBE *send_tube, TUBE *recv_tube, char *postfix, char *client_software_name, char *client_hostname, char *crypt_name, UINT adjust_mss); +PPP_SESSION *NewPPPSession(CEDAR *cedar, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port, TUBE *send_tube, TUBE *recv_tube, char *postfix, char *client_software_name, char *client_hostname, char *crypt_name, UINT adjust_mss); // PPP processing functions bool PPPRejectUnsupportedPacket(PPP_SESSION *p, PPP_PACKET *pp); diff --git a/src/Cedar/Proto_SSTP.c b/src/Cedar/Proto_SSTP.c index cd9c7e86..83abc3bf 100644 --- a/src/Cedar/Proto_SSTP.c +++ b/src/Cedar/Proto_SSTP.c @@ -97,6 +97,8 @@ void SstpProcessControlPacket(SSTP_SERVER *s, SSTP_PACKET *p) // Process the SSTP received data packet void SstpProcessDataPacket(SSTP_SERVER *s, SSTP_PACKET *p) { + PPP_SESSION* underlyingSession; + // Validate arguments if (s == NULL || p == NULL || p->IsControl) { @@ -108,9 +110,11 @@ void SstpProcessDataPacket(SSTP_SERVER *s, SSTP_PACKET *p) if (s->PPPThread == NULL) { // Create a thread to initialize the new PPP module - s->PPPThread = NewPPPSession(s->Cedar, &s->ClientIp, s->ClientPort, &s->ServerIp, s->ServerPort, + underlyingSession = NewPPPSession(s->Cedar, &s->ClientIp, s->ClientPort, &s->ServerIp, s->ServerPort, s->TubeSend, s->TubeRecv, SSTP_IPC_POSTFIX, SSTP_IPC_CLIENT_NAME, s->ClientHostName, s->ClientCipherName, 0); + s->PPPSession = underlyingSession; + s->PPPThread = underlyingSession->SessionThread; } // Pass the received data to the PPP module @@ -177,6 +181,7 @@ void SstpSendPacket(SSTP_SERVER *s, SSTP_PACKET *p) // Process the timer interrupt void SstpProcessInterrupt(SSTP_SERVER *s) { + UINT64 sstpTimeout = SSTP_TIMEOUT; // Validate arguments if (s == NULL) { @@ -261,7 +266,12 @@ void SstpProcessInterrupt(SSTP_SERVER *s) } } - if ((s->LastRecvTick + (UINT64)SSTP_TIMEOUT) <= s->Now) + if (s->PPPSession != NULL && s->PPPSession->DataTimeout > sstpTimeout) + { + sstpTimeout = s->PPPSession->DataTimeout; + } + + if ((s->LastRecvTick + sstpTimeout) <= s->Now) { // Disconnect the SSTP because a timeout occurred SstpAbort(s); diff --git a/src/Cedar/Proto_SSTP.h b/src/Cedar/Proto_SSTP.h index ed722734..522c0056 100644 --- a/src/Cedar/Proto_SSTP.h +++ b/src/Cedar/Proto_SSTP.h @@ -16,7 +16,7 @@ #define SSTP_IPC_POSTFIX "SSTP" #define SSTP_ECHO_SEND_INTERVAL_MIN 2500 // Transmission interval of Echo Request (minimum) #define SSTP_ECHO_SEND_INTERVAL_MAX 4792 // Transmission interval of Echo Request (maximum) -#define SSTP_TIMEOUT 10000 // Communication time-out of SSTP +#define SSTP_TIMEOUT 20 * 1000 // Communication time-out of SSTP (from default policy) // SSTP Message Type #define SSTP_MSG_CALL_CONNECT_REQUEST 0x0001 @@ -116,6 +116,7 @@ struct SSTP_SERVER UINT64 LastRecvTick; // Tick when some data has received at the end bool FlushRecvTube; // Flag whether to flush the reception tube UINT EstablishedCount; // Number of session establishment + PPP_SESSION* PPPSession; // Underlying PPP Session };