// 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 *s = ZeroMalloc(sizeof(SSTP_SERVER)); s->LastRecvTick = Tick64(); StrCpy(s->ClientHostName, sizeof(s->ClientHostName), client_host_name); StrCpy(s->ClientCipherName, sizeof(s->ClientCipherName), crypt_name); s->Cedar = cedar; AddRef(s->Cedar->ref); 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; }
// Check whether the specified IP address is in Non-SSL connection list bool IsInNoSsl(CEDAR *c, IP *ip) { bool ret = false; // Validate arguments if (c == NULL || ip == NULL) { return false; } LockList(c->NonSslList); { NON_SSL *n = SearchNoSslList(c, ip); if (n != NULL) { if (n->EntryExpires > Tick64() && n->Count > NON_SSL_MIN_COUNT) { n->EntryExpires = Tick64() + (UINT64)NON_SSL_ENTRY_EXPIRES; ret = true; } } } UnlockList(c->NonSslList); return ret; }
// Wait for a event until the cancel flag becomes true bool WaitEx(EVENT *e, UINT timeout, volatile bool *cancel) { bool dummy_bool = false; UINT64 start, giveup; // Validate arguments if (cancel == NULL) { cancel = &dummy_bool; } start = Tick64(); if (timeout == INFINITE || timeout == 0x7FFFFFFF) { giveup = 0; } else { giveup = start + (UINT64)timeout; } while (true) { UINT64 now = Tick64(); UINT interval_to_giveup = (UINT)(giveup - now); if (giveup == 0) { interval_to_giveup = INFINITE; } else { if (now >= giveup) { // Time-out occurs return false; } } interval_to_giveup = MIN(interval_to_giveup, 25); if (*cancel) { // Cancel flag is set to true. Time-out occurs return false; } if (e != NULL) { if (Wait(e, interval_to_giveup)) { // Event is set return true; } } else { SleepThread(interval_to_giveup); } } }
// Initialize the client-side bool UdpAccelInitClient(UDP_ACCEL *a, UCHAR *server_key, IP *server_ip, UINT server_port, UINT server_cookie, UINT client_cookie, IP *server_ip_2) { char tmp[MAX_SIZE]; // Validate arguments if (a == NULL || server_key == NULL || server_ip == NULL || server_port == 0) { return false; } IPToStr(tmp, sizeof(tmp), server_ip); Debug("UdpAccelInitClient: server_ip=%s, server_port=%u, server_cookie=%u, client_cookie=%u\n", tmp, server_port, server_cookie, client_cookie); if (IsIP6(server_ip) != a->IsIPv6) { return false; } Copy(a->YourKey, server_key, UDP_ACCELERATION_COMMON_KEY_SIZE); Copy(&a->YourIp, server_ip, sizeof(IP)); Copy(&a->YourIp2, server_ip_2, sizeof(IP)); a->YourPort = server_port; a->Now = Tick64(); a->MyCookie = client_cookie; a->YourCookie = server_cookie; a->Inited = true; return true; }
// Delete old entries in Non-SSL connection list void DeleteOldNoSsl(CEDAR *c) { UINT i; LIST *o; // Validate arguments if (c == NULL) { return; } o = NewListFast(NULL); for (i = 0;i < LIST_NUM(c->NonSslList);i++) { NON_SSL *n = LIST_DATA(c->NonSslList, i); if (n->EntryExpires <= Tick64()) { Add(o, n); } } for (i = 0;i < LIST_NUM(o);i++) { NON_SSL *n = LIST_DATA(o, i); Delete(c->NonSslList, n); Free(n); } ReleaseList(o); }
// Send an IP packet void L3SendIp(L3IF *f, L3PACKET *p) { L3ARPENTRY *a = NULL; bool broadcast = false; IPV4_HEADER *ip; bool for_me = false; // Validate arguments if (f == NULL || p == NULL) { return; } if (p->Packet->TypeL3 != L3_IPV4) { return; } ip = p->Packet->L3.IPv4Header; // Determining whether it's a broadcast if (p->NextHopIp == 0xffffffff || ((p->NextHopIp & f->SubnetMask) == (f->IpAddress & f->SubnetMask)) && ((p->NextHopIp & (~f->SubnetMask)) == (~f->SubnetMask))) { broadcast = true; } if (broadcast == false && ip->DstIP == f->IpAddress) { // me? } else if (broadcast == false) { // Examine whether the ARP entry contains this in the case of unicast a = L3SearchArpTable(f, p->NextHopIp); if (a == NULL) { // Since It is not in the ARP table, // insert it into the IP waiting list without sending immediately p->Expire = Tick64() + IP_WAIT_FOR_ARP_TIMEOUT; Insert(f->IpWaitList, p); // Issue an ARP query L3SendArp(f, p->NextHopIp); return; } } if (for_me == false) { // Send the IP packet L3SendIpNow(f, a, p); } // Release the packet Free(p->Packet->PacketData); FreePacket(p->Packet); Free(p); }
// Register in the ARP table void L3InsertArpTable(L3IF *f, UINT ip, UCHAR *mac) { L3ARPENTRY *a, t; // Validate arguments if (f == NULL || ip == 0 || ip == 0xffffffff || mac == NULL) { return; } Zero(&t, sizeof(t)); t.IpAddress = ip; a = Search(f->ArpTable, &t); if (a == NULL) { // Since this is not registered, register this a = ZeroMalloc(sizeof(L3ARPENTRY)); a->IpAddress = ip; Copy(a->MacAddress, mac, 6); Insert(f->ArpTable, a); } // Extend the expiration date a->Expire = Tick64() + ARP_ENTRY_EXPIRES; // Send waiting IP packets L3SendWaitingIp(f, mac, ip, a); }
// Issue an ARP query void L3SendArp(L3IF *f, UINT ip) { L3ARPWAIT t, *w; // Validate arguments if (f == NULL || ip == 0 || ip == 0xffffffff) { return; } // Examine whether it has not already registered Zero(&t, sizeof(t)); t.IpAddress = ip; w = Search(f->ArpWaitTable, &t); if (w != NULL) { // Do not do anything because it is already registered in the waiting list return; } else { // Register in the waiting list newly w = ZeroMalloc(sizeof(L3ARPWAIT)); w->Expire = Tick64() + ARP_REQUEST_GIVEUP; w->IpAddress = ip; Insert(f->ArpWaitTable, w); } }
// Polling for the ARP resolution waiting list void L3PollingArpWaitTable(L3IF *f) { UINT i; LIST *o = NULL; // Validate arguments if (f == NULL) { return; } for (i = 0;i < LIST_NUM(f->ArpWaitTable);i++) { L3ARPWAIT *w = LIST_DATA(f->ArpWaitTable, i); if (w->Expire <= Tick64()) { // The ARP request entry is expired if (o == NULL) { o = NewListFast(NULL); } Insert(o, w); } else if ((w->LastSentTime + ARP_REQUEST_TIMEOUT) <= Tick64()) { // Send a next ARP request packet w->LastSentTime = Tick64(); L3SendArpRequestNow(f, w->IpAddress); } } if (o != NULL) { for (i = 0;i < LIST_NUM(o);i++) { L3ARPWAIT *w = LIST_DATA(o, i); Delete(f->ArpWaitTable, w); Free(w); } ReleaseList(o); } }
// Clear old ARP table entries void L3DeleteOldArpTable(L3IF *f) { UINT i; LIST *o = NULL; // Validate arguments if (f == NULL) { return; } if ((f->LastDeleteOldArpTable + ARP_ENTRY_POLLING_TIME) > Tick64()) { return; } f->LastDeleteOldArpTable = Tick64(); for (i = 0;i < LIST_NUM(f->ArpTable);i++) { L3ARPENTRY *a = LIST_DATA(f->ArpTable, i); if (a->Expire <= Tick64()) { // Expired if (o == NULL) { o = NewListFast(NULL); } Insert(o, a); } } if (o != NULL) { for (i = 0;i < LIST_NUM(o);i++) { L3ARPENTRY *a = LIST_DATA(o, i); Delete(f->ArpTable, a); Free(a); } ReleaseList(o); } }
// Get the high-resolution time UINT64 TickHighres64() { #ifdef OS_WIN32 return (UINT64)(MsGetHiResTimeSpan(MsGetHiResCounter()) * 1000.0f); #else // OS_WIN32 return Tick64(); #endif // OS_WIN32 }
// Packet generation thread void NullPacketGenerateThread(THREAD *t, void *param) { NULL_LAN *n = (NULL_LAN *)param; UINT64 end_tick = Tick64() + (UINT64)(60 * 1000); UINT seq = 0; // Validate arguments if (t == NULL || param == NULL) { return; } while (true) { /*if (Tick64() >= end_tick) { break; }*/ Wait(n->Event, Rand32() % 1500); if (n->Halt) { break; } LockQueue(n->PacketQueue); { UCHAR *data; BLOCK *b; UINT size = Rand32() % 1500 + 14; UCHAR dst_mac[6]; NullGenerateMacAddress(n->MacAddr, n->Id, seq); //NullGenerateMacAddress(dst_mac, n->Id + 1, 0); //StrToMac(dst_mac, "00-1B-21-A9-47-E6"); StrToMac(dst_mac, "00-AC-7A-EF-83-FD"); data = Malloc(size); Copy(data, null_lan_broadcast_address, 6); //Copy(data, dst_mac, 6); Copy(data + 6, n->MacAddr, 6); b = NewBlock(data, size, 0); InsertQueue(n->PacketQueue, b); } UnlockQueue(n->PacketQueue); Cancel(n->Cancel); //seq++; } }
// Release the packet adapter void VLanPaFree(SESSION *s) { VLAN *v; ROUTE_TRACKING *t; // Validate arguments if ((s == NULL) || ((v = s->PacketAdapter->Param) == NULL)) { return; } // Release the IP address if you are using DHCP if (IsNt()) { char tmp[MAX_SIZE]; MS_ADAPTER *a; UINT64 now = Tick64(); UINT64 suspend_tick = MsGetSuspendModeBeginTick(); if (suspend_tick == 0 || (suspend_tick + (UINT64)(30 * 1000)) < now) { Format(tmp, sizeof(tmp), VLAN_ADAPTER_NAME_TAG, v->InstanceName); a = MsGetAdapter(tmp); if (a != NULL) { if (a->UseDhcp) { bool ret = Win32ReleaseAddressByGuidEx(a->Guid, 50); Debug("*** Win32ReleaseAddressByGuid = %u\n", ret); } MsFreeAdapter(a); } } } t = v->RouteState; // End the virtual LAN card FreeVLan(v); // End the routing table tracking if (s->ClientModeAndUseVLan) { RouteTrackingStop(s, t); } s->PacketAdapter->Param = NULL; }
// Create a new EtherIP server ETHERIP_SERVER *NewEtherIPServer(CEDAR *cedar, IPSEC_SERVER *ipsec, IKE_SERVER *ike, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port, char *crypt_name, bool is_tunnel_mode, UINT crypt_block_size, char *client_id, UINT id) { ETHERIP_SERVER *s; // Validate arguments if (cedar == NULL || ipsec == NULL || ike == NULL || client_ip == NULL || server_ip == NULL || client_id == NULL) { return NULL; } s = ZeroMalloc(sizeof(ETHERIP_SERVER)); s->Ref = NewRef(); s->Id = id; s->Cedar = cedar; AddRef(s->Cedar->ref); s->IPsec = ipsec; s->Ike = ike; s->IsTunnelMode = is_tunnel_mode; StrCpy(s->ClientId, sizeof(s->ClientId), client_id); s->SendPacketList = NewList(NULL); s->Now = Tick64(); s->Lock = NewLock(); Copy(&s->ClientIP, client_ip, sizeof(IP)); s->ClientPort = client_port; Copy(&s->ServerIP, server_ip, sizeof(IP)); s->ServerPort = server_port; StrCpy(s->CryptName, sizeof(s->CryptName), crypt_name); s->CryptBlockSize = crypt_block_size; EtherIPLog(s, "LE_START_MODULE"); return s; }
// Clear the IP waiting list void L3DeleteOldIpWaitList(L3IF *f) { UINT i; LIST *o = NULL; // Validate arguments if (f == NULL) { return; } for (i = 0;i < LIST_NUM(f->IpWaitList);i++) { L3PACKET *p = LIST_DATA(f->IpWaitList, i); if (p->Expire <= Tick64()) { if (o == NULL) { o = NewListFast(NULL); } Insert(o, p); } } if (o != NULL) { for (i = 0;i < LIST_NUM(o);i++) { L3PACKET *p = LIST_DATA(o, i); Delete(f->IpWaitList, p); Free(p->Packet->PacketData); FreePacket(p->Packet); Free(p); } ReleaseList(o); } }
// Create a new key void DCGenNewKey(UCHAR *key) { BUF *b; UINT64 tick; UCHAR hash[SHA1_SIZE]; UCHAR rand[SHA1_SIZE]; UINT i; // Validate arguments if (key == NULL) { return; } b = NewBuf(); Rand(rand, sizeof(rand)); WriteBuf(b, rand, sizeof(rand)); tick = TickHighres64(); WriteBufInt64(b, tick); tick = Tick64(); WriteBufInt64(b, tick); tick = SystemTime64(); WriteBufInt64(b, tick); GetCurrentMachineIpProcessHash(hash); WriteBuf(b, hash, sizeof(hash)); HashSha1(key, b->Buf, b->Size); Rand(rand, sizeof(rand)); for (i = 0;i < SHA1_SIZE;i++) { key[i] = key[i] ^ rand[i]; } FreeBuf(b); }
// Add new entry to Non-SSL connection list bool AddNoSsl(CEDAR *c, IP *ip) { NON_SSL *n; bool ret = true; // Validate arguments if (c == NULL || ip == NULL) { return true; } LockList(c->NonSslList); { DeleteOldNoSsl(c); n = SearchNoSslList(c, ip); if (n == NULL) { n = ZeroMalloc(sizeof(NON_SSL)); Copy(&n->IpAddress, ip, sizeof(IP)); n->Count = 0; Add(c->NonSslList, n); } n->EntryExpires = Tick64() + (UINT64)NON_SSL_ENTRY_EXPIRES; n->Count++; if (n->Count > NON_SSL_MIN_COUNT) { ret = false; } } UnlockList(c->NonSslList); return ret; }
// IPC connection processing thread void EtherIPIpcConnectThread(THREAD *t, void *p) { ETHERIP_SERVER *s; IPC *ipc = NULL; UINT error_code = 0; char tmp[MAX_SIZE]; ETHERIP_ID id; // Validate arguments if (t == NULL || p == NULL) { return; } s = (ETHERIP_SERVER *)p; GetHostName(tmp, sizeof(tmp), &s->ClientIP); // Get the setting of the virtual HUB to be connected based on the client ID presented if (SearchEtherIPId(s->Ike->IPsec, &id, s->ClientId) == false && SearchEtherIPId(s->Ike->IPsec, &id, "*") == false) { // Failed to get the settings for the virtual HUB Debug("Not Found: EtherIP Settings for Client ID \"%s\".\n", s->ClientId); EtherIPLog(s, "LE_NO_SETTING", s->ClientId); } else { UINT mss = CalcEtherIPTcpMss(s); char client_name[MAX_SIZE]; if (s->L2TPv3 == false) { StrCpy(client_name, sizeof(client_name), ETHERIP_CLIENT_NAME); } else { if (IsEmptyStr(s->VendorName)) { StrCpy(client_name, sizeof(client_name), ETHERIP_L2TPV3_CLIENT_NAME); } else { Format(client_name, sizeof(client_name), ETHERIP_L2TPV3_CLIENT_NAME_EX, s->VendorName); } } // Execution of IPC connection process EtherIPLog(s, "LE_START_IPC", id.HubName, id.UserName, mss); ipc = NewIPC(s->Cedar, client_name, (s->L2TPv3 ? ETHERIP_L2TPV3_POSTFIX : ETHERIP_POSTFIX), id.HubName, id.UserName, id.Password, &error_code, &s->ClientIP, s->ClientPort, &s->ServerIP, s->ServerPort, tmp, s->CryptName, true, mss); if (ipc != NULL) { Copy(&s->CurrentEtherIPIdSetting, &id, sizeof(ETHERIP_ID)); EtherIPLog(s, "LE_IPC_CONNECT_OK", id.HubName); } else { EtherIPLog(s, "LE_IPC_CONNECT_ERROR", id.HubName, error_code, _E(error_code)); } } Lock(s->Lock); { // Set the results ReleaseThread(s->IpcConnectThread); s->IpcConnectThread = NULL; s->Ipc = ipc; s->LastConnectFailedTick = Tick64(); } Unlock(s->Lock); // Hit the event to cause interrupt SetSockEvent(s->SockEvent); // Release the EtherIP object that is hold by this thread ReleaseEtherIPServer(s); }
// Attempts Radius authentication (with specifying retry interval and multiple server) bool RadiusLogin(CONNECTION *c, char *server, UINT port, UCHAR *secret, UINT secret_size, wchar_t *username, char *password, UINT interval, UCHAR *mschap_v2_server_response_20) { UCHAR random[MD5_SIZE]; UCHAR id; BUF *encrypted_password = NULL; BUF *user_name = NULL; //IP ip; bool ret = false; TOKEN_LIST *token; UINT i; LIST *ip_list; IPC_MSCHAP_V2_AUTHINFO mschap; bool is_mschap; char client_ip_str[MAX_SIZE]; static UINT packet_id = 0; // Validate arguments if (server == NULL || port == 0 || (secret_size != 0 && secret == NULL) || username == NULL || password == NULL) { return false; } Zero(client_ip_str, sizeof(client_ip_str)); if (c != NULL && c->FirstSock != NULL) { IPToStr(client_ip_str, sizeof(client_ip_str), &c->FirstSock->RemoteIP); } // Parse the MS-CHAP v2 authentication data Zero(&mschap, sizeof(mschap)); is_mschap = ParseAndExtractMsChapV2InfoFromPassword(&mschap, password); // Split the server into tokens token = ParseToken(server, " ,;\t"); // Get the IP address of the server ip_list = NewListFast(NULL); for(i = 0; i < token->NumTokens; i++) { IP *tmp_ip = Malloc(sizeof(IP)); if (GetIP(tmp_ip, token->Token[i])) { Add(ip_list, tmp_ip); } else if (GetIPEx(tmp_ip, token->Token[i], true)) { Add(ip_list, tmp_ip); } else { Free(tmp_ip); } } FreeToken(token); if(LIST_NUM(ip_list) == 0) { ReleaseList(ip_list); return false; } // Random number generation Rand(random, sizeof(random)); // ID generation id = (UCHAR)(packet_id % 254 + 1); packet_id++; if (is_mschap == false) { // Encrypt the password encrypted_password = RadiusEncryptPassword(password, random, secret, secret_size); if (encrypted_password == NULL) { // Encryption failure ReleaseList(ip_list); return false; } } // Generate the user name packet user_name = RadiusCreateUserName(username); if (user_name != NULL) { // Generate a password packet BUF *user_password = (is_mschap ? NULL : RadiusCreateUserPassword(encrypted_password->Buf, encrypted_password->Size)); BUF *nas_id = RadiusCreateNasId(CEDAR_SERVER_STR); if (is_mschap || user_password != NULL) { UINT64 start; UINT64 next_send_time; UCHAR tmp[MAX_SIZE]; UINT recv_buf_size = 32768; UCHAR *recv_buf = MallocEx(recv_buf_size, true); // Generate an UDP packet BUF *p = NewBuf(); UCHAR type = 1; SOCK *sock; USHORT sz = 0; UINT pos = 0; BOOL *finish = ZeroMallocEx(sizeof(BOOL) * LIST_NUM(ip_list), true); Zero(tmp, sizeof(tmp)); WriteBuf(p, &type, 1); WriteBuf(p, &id, 1); WriteBuf(p, &sz, 2); WriteBuf(p, random, 16); WriteBuf(p, user_name->Buf, user_name->Size); if (is_mschap == false) { UINT ui; // PAP WriteBuf(p, user_password->Buf, user_password->Size); WriteBuf(p, nas_id->Buf, nas_id->Size); // Service-Type ui = Endian32(2); RadiusAddValue(p, 6, 0, 0, &ui, sizeof(ui)); // NAS-Port-Type ui = Endian32(5); RadiusAddValue(p, 61, 0, 0, &ui, sizeof(ui)); // Tunnel-Type ui = Endian32(1); RadiusAddValue(p, 64, 0, 0, &ui, sizeof(ui)); // Tunnel-Medium-Type ui = Endian32(1); RadiusAddValue(p, 65, 0, 0, &ui, sizeof(ui)); // Calling-Station-Id RadiusAddValue(p, 31, 0, 0, client_ip_str, StrLen(client_ip_str)); // Tunnel-Client-Endpoint RadiusAddValue(p, 66, 0, 0, client_ip_str, StrLen(client_ip_str)); } else { // MS-CHAP v2 static UINT session_id = 0; USHORT us; UINT ui; char *ms_ras_version = "MSRASV5.20"; UCHAR ms_chapv2_response[50]; // Acct-Session-Id us = Endian16(session_id % 254 + 1); session_id++; RadiusAddValue(p, 44, 0, 0, &us, sizeof(us)); // NAS-IP-Address if (c != NULL && c->FirstSock != NULL && c->FirstSock->IPv6 == false) { ui = IPToUINT(&c->FirstSock->LocalIP); RadiusAddValue(p, 4, 0, 0, &ui, sizeof(ui)); } // Service-Type ui = Endian32(2); RadiusAddValue(p, 6, 0, 0, &ui, sizeof(ui)); // MS-RAS-Vendor ui = Endian32(311); RadiusAddValue(p, 26, 311, 9, &ui, sizeof(ui)); // MS-RAS-Version RadiusAddValue(p, 26, 311, 18, ms_ras_version, StrLen(ms_ras_version)); // NAS-Port-Type ui = Endian32(5); RadiusAddValue(p, 61, 0, 0, &ui, sizeof(ui)); // Tunnel-Type ui = Endian32(1); RadiusAddValue(p, 64, 0, 0, &ui, sizeof(ui)); // Tunnel-Medium-Type ui = Endian32(1); RadiusAddValue(p, 65, 0, 0, &ui, sizeof(ui)); // Calling-Station-Id RadiusAddValue(p, 31, 0, 0, client_ip_str, StrLen(client_ip_str)); // Tunnel-Client-Endpoint RadiusAddValue(p, 66, 0, 0, client_ip_str, StrLen(client_ip_str)); // MS-RAS-Client-Version RadiusAddValue(p, 26, 311, 35, ms_ras_version, StrLen(ms_ras_version)); // MS-RAS-Client-Name RadiusAddValue(p, 26, 311, 34, client_ip_str, StrLen(client_ip_str)); // MS-CHAP-Challenge RadiusAddValue(p, 26, 311, 11, mschap.MsChapV2_ServerChallenge, sizeof(mschap.MsChapV2_ServerChallenge)); // MS-CHAP2-Response Zero(ms_chapv2_response, sizeof(ms_chapv2_response)); Copy(ms_chapv2_response + 2, mschap.MsChapV2_ClientChallenge, 16); Copy(ms_chapv2_response + 2 + 16 + 8, mschap.MsChapV2_ClientResponse, 24); RadiusAddValue(p, 26, 311, 25, ms_chapv2_response, sizeof(ms_chapv2_response)); // NAS-ID WriteBuf(p, nas_id->Buf, nas_id->Size); } SeekBuf(p, 0, 0); WRITE_USHORT(((UCHAR *)p->Buf) + 2, (USHORT)p->Size); // Create a socket sock = NewUDPEx(0, IsIP6(LIST_DATA(ip_list, pos))); // Transmission process start start = Tick64(); if(interval < RADIUS_RETRY_INTERVAL) { interval = RADIUS_RETRY_INTERVAL; } else if(interval > RADIUS_RETRY_TIMEOUT) { interval = RADIUS_RETRY_TIMEOUT; } next_send_time = start + (UINT64)interval; while (true) { UINT server_port; UINT recv_size; //IP server_ip; SOCKSET set; UINT64 now; SEND_RETRY: //SendTo(sock, &ip, port, p->Buf, p->Size); SendTo(sock, LIST_DATA(ip_list, pos), port, p->Buf, p->Size); Debug("send to host:%u\n", pos); next_send_time = Tick64() + (UINT64)interval; RECV_RETRY: now = Tick64(); if (next_send_time <= now) { // Switch the host to refer pos++; pos = pos % LIST_NUM(ip_list); goto SEND_RETRY; } if ((start + RADIUS_RETRY_TIMEOUT) < now) { // Time-out break; } InitSockSet(&set); AddSockSet(&set, sock); Select(&set, (UINT)(next_send_time - now), NULL, NULL); recv_size = RecvFrom(sock, LIST_DATA(ip_list, pos), &server_port, recv_buf, recv_buf_size); if (recv_size == 0) { Debug("Radius recv_size 0\n"); finish[pos] = TRUE; for(i = 0; i < LIST_NUM(ip_list); i++) { if(finish[i] == FALSE) { // Switch the host to refer pos++; pos = pos % LIST_NUM(ip_list); goto SEND_RETRY; } } // Failure break; } else if (recv_size == SOCK_LATER) { // Waiting goto RECV_RETRY; } else { // Check such as the IP address if (/*Cmp(&server_ip, &ip, sizeof(IP)) != 0 || */server_port != port) { goto RECV_RETRY; } // Success if (recv_buf[0] == 2) { ret = true; if (is_mschap && mschap_v2_server_response_20 != NULL) { // Cutting corners Zurukko UCHAR signature[] = {0x1A, 0x33, 0x00, 0x00, 0x01, 0x37, 0x1A, 0x2D, 0x00, 0x53, 0x3D, }; UINT i = SearchBin(recv_buf, 0, recv_buf_size, signature, sizeof(signature)); if (i == INFINITE || ((i + sizeof(signature) + 40) > recv_buf_size)) { ret = false; } else { char tmp[MAX_SIZE]; BUF *b; Zero(tmp, sizeof(tmp)); Copy(tmp, recv_buf + i + sizeof(signature), 40); b = StrToBin(tmp); if (b != NULL && b->Size == 20) { WHERE; Copy(mschap_v2_server_response_20, b->Buf, 20); } else { WHERE; ret = false; } FreeBuf(b); } } } break; } } Free(finish); // Release the socket ReleaseSock(sock); FreeBuf(p); FreeBuf(user_password); Free(recv_buf); } FreeBuf(nas_id); FreeBuf(user_name); } // Release the ip_list for(i = 0; i < LIST_NUM(ip_list); i++) { IP *tmp_ip = LIST_DATA(ip_list, i); Free(tmp_ip); } ReleaseList(ip_list); // Release the memory FreeBuf(encrypted_password); return ret; }
// DDNS client thread void DCThread(THREAD *thread, void *param) { DDNS_CLIENT *c; INTERRUPT_MANAGER *interrput; UINT last_ip_hash = 0; void *route_change_poller = NULL; bool last_time_ip_changed = false; UINT last_azure_ddns_trigger_int = 0; UINT last_vgs_ddns_trigger_int = 0; UINT n; INTERNET_SETTING last_t; // Validate arguments if (thread == NULL || param == NULL) { return; } c = (DDNS_CLIENT *)param; interrput = NewInterruptManager(); route_change_poller = NewRouteChange(); IsRouteChanged(route_change_poller); Zero(&last_t, sizeof(last_t)); n = 0; while (c->Halt == false) { UINT ip_hash = GetHostIPAddressHash32(); UINT interval; UINT64 now = Tick64(); bool ip_changed = false; bool azure_client_triggered = false; bool internet_setting_changed = false; bool vgs_server_triggered = false; if (c->Cedar->Server != NULL && c->Cedar->Server->AzureClient != NULL) { if (c->Cedar->Server->AzureClient->DDnsTriggerInt != last_azure_ddns_trigger_int) { azure_client_triggered = true; last_azure_ddns_trigger_int = c->Cedar->Server->AzureClient->DDnsTriggerInt; last_time_ip_changed = false; Debug("DDNS Thread Triggered by AzureClient.\n"); } } if (Cmp(&last_t, &c->InternetSetting, sizeof(INTERNET_SETTING)) != 0) { Copy(&last_t, &c->InternetSetting, sizeof(INTERNET_SETTING)); internet_setting_changed = true; last_time_ip_changed = false; } if (ip_hash != last_ip_hash) { last_time_ip_changed = false; Debug("DDNS Thread Triggered by IP Hash Changed.\n"); } if ((ip_hash != last_ip_hash) || (IsRouteChanged(route_change_poller)) || azure_client_triggered || internet_setting_changed || vgs_server_triggered) { if (last_time_ip_changed == false) { // Call all getting functions from the beginning if the routing // table or the IP address of this host has changed c->NextRegisterTick_IPv4 = 0; c->NextRegisterTick_IPv6 = 0; c->NextGetMyIpTick_IPv4 = 0; c->NextGetMyIpTick_IPv6 = 0; last_ip_hash = ip_hash; last_time_ip_changed = true; ip_changed = true; Debug("DDNS Internet Condition Changed.\n"); } } else { last_time_ip_changed = false; } if ((n++) >= 1) { // Self IPv4 address acquisition if (c->NextGetMyIpTick_IPv4 == 0 || now >= c->NextGetMyIpTick_IPv4) { UINT next_interval; char ip[MAX_SIZE]; Zero(ip, sizeof(ip)); c->Err_IPv4_GetMyIp = DCGetMyIp(c, false, ip, sizeof(ip), NULL); if (c->Err_IPv4_GetMyIp == ERR_NO_ERROR) { if (StrCmpi(c->LastMyIPv4, ip) != 0) { ip_changed = true; StrCpy(c->LastMyIPv4, sizeof(c->LastMyIPv4), ip); } next_interval = GenRandInterval(DDNS_GETMYIP_INTERVAL_OK_MIN, DDNS_GETMYIP_INTERVAL_OK_MAX); } else { if (IsEmptyStr(c->LastMyIPv4) == false) { ip_changed = true; } Zero(c->LastMyIPv4, sizeof(c->LastMyIPv4)); next_interval = GenRandInterval(DDNS_GETMYIP_INTERVAL_NG_MIN, DDNS_GETMYIP_INTERVAL_NG_MAX); } c->NextGetMyIpTick_IPv4 = Tick64() + (UINT64)next_interval; AddInterrupt(interrput, c->NextGetMyIpTick_IPv4); } // Self IPv6 address acquisition if (c->NextGetMyIpTick_IPv6 == 0 || now >= c->NextGetMyIpTick_IPv6) { UINT next_interval; char ip[MAX_SIZE]; Zero(ip, sizeof(ip)); c->Err_IPv6_GetMyIp = DCGetMyIp(c, true, ip, sizeof(ip), NULL); if (c->Err_IPv6_GetMyIp == ERR_NO_ERROR) { if (StrCmpi(c->LastMyIPv6, ip) != 0) { ip_changed = true; StrCpy(c->LastMyIPv6, sizeof(c->LastMyIPv6), ip); } next_interval = GenRandInterval(DDNS_GETMYIP_INTERVAL_OK_MIN, DDNS_GETMYIP_INTERVAL_OK_MAX); } else { if (IsEmptyStr(c->LastMyIPv6) == false) { ip_changed = true; } Zero(c->LastMyIPv6, sizeof(c->LastMyIPv6)); next_interval = GenRandInterval(DDNS_GETMYIP_INTERVAL_NG_MIN, DDNS_GETMYIP_INTERVAL_NG_MAX); } c->NextGetMyIpTick_IPv6 = Tick64() + (UINT64)next_interval; AddInterrupt(interrput, c->NextGetMyIpTick_IPv6); } } if (ip_changed) { c->NextRegisterTick_IPv4 = 0; c->NextRegisterTick_IPv6 = 0; } // IPv4 host registration if (c->NextRegisterTick_IPv4 == 0 || now >= c->NextRegisterTick_IPv4) { UINT next_interval; c->Err_IPv4 = DCRegister(c, false, NULL, NULL); if (c->Err_IPv4 == ERR_NO_ERROR) { next_interval = GenRandInterval(DDNS_REGISTER_INTERVAL_OK_MIN, DDNS_REGISTER_INTERVAL_OK_MAX); } else { next_interval = GenRandInterval(DDNS_REGISTER_INTERVAL_NG_MIN, DDNS_REGISTER_INTERVAL_NG_MAX); } //next_interval = 0; c->NextRegisterTick_IPv4 = Tick64() + (UINT64)next_interval; if (true) { DDNS_CLIENT_STATUS st; DCGetStatus(c, &st); SiApplyAzureConfig(c->Cedar->Server, &st); } AddInterrupt(interrput, c->NextRegisterTick_IPv4); } if (c->Halt) { break; } // IPv6 host registration if (c->NextRegisterTick_IPv6 == 0 || now >= c->NextRegisterTick_IPv6) { UINT next_interval; c->Err_IPv6 = DCRegister(c, true, NULL, NULL); if (c->Err_IPv6 == ERR_NO_ERROR) { next_interval = GenRandInterval(DDNS_REGISTER_INTERVAL_OK_MIN, DDNS_REGISTER_INTERVAL_OK_MAX); } else { next_interval = GenRandInterval(DDNS_REGISTER_INTERVAL_NG_MIN, DDNS_REGISTER_INTERVAL_NG_MAX); } c->NextRegisterTick_IPv6 = Tick64() + (UINT64)next_interval; if (true) { DDNS_CLIENT_STATUS st; DCGetStatus(c, &st); SiApplyAzureConfig(c->Cedar->Server, &st); } AddInterrupt(interrput, c->NextRegisterTick_IPv6); } interval = GetNextIntervalForInterrupt(interrput); interval = MIN(interval, 1234); if (n == 1) { interval = MIN(interval, 0); } if (c->Halt) { break; } if (c->KeyChanged) { c->KeyChanged = false; c->NextRegisterTick_IPv4 = c->NextRegisterTick_IPv6 = 0; interval = 0; } if (last_time_ip_changed) { if (c->Cedar->Server != NULL && c->Cedar->Server->AzureClient != NULL) { c->Cedar->Server->AzureClient->IpStatusRevision++; } } Wait(c->Event, interval); } FreeRouteChange(route_change_poller); FreeInterruptManager(interrput); }
// Create Cedar object CEDAR *NewCedar(X *server_x, K *server_k) { CEDAR *c; char tmp[MAX_SIZE]; char tmp2[MAX_SIZE]; char *beta_str; CedarForceLink(); c = ZeroMalloc(sizeof(CEDAR)); c->CurrentActiveLinks = NewCounter(); c->AcceptingSockets = NewCounter(); c->CedarSuperLock = NewLock(); c->CurrentRegionLock = NewLock(); StrCpy(c->OpenVPNDefaultClientOption, sizeof(c->OpenVPNDefaultClientOption), OVPN_DEF_CLIENT_OPTION_STRING); #ifdef BETA_NUMBER c->Beta = BETA_NUMBER; #endif // BETA_NUMBER InitNoSslList(c); c->AssignedBridgeLicense = NewCounter(); c->AssignedClientLicense = NewCounter(); c->CurrentTcpQueueSizeLock = NewLock(); c->QueueBudgetLock = NewLock(); c->FifoBudgetLock = NewLock(); Rand(c->UniqueId, sizeof(c->UniqueId)); c->CreatedTick = Tick64(); c->lock = NewLock(); c->ref = NewRef(); c->OpenVPNPublicPortsLock = NewLock(); c->CurrentTcpConnections = GetNumTcpConnectionsCounter(); c->ListenerList = NewList(CompareListener); c->UDPEntryList = NewList(CompareUDPEntry); c->HubList = NewList(CompareHub); c->ConnectionList = NewList(CompareConnection); c->ConnectionIncrement = NewCounter(); c->CurrentSessions = NewCounter(); if (server_k && server_x) { c->ServerK = CloneK(server_k); c->ServerX = CloneX(server_x); } c->Version = CEDAR_VER; c->Build = CEDAR_BUILD; c->ServerStr = CopyStr(CEDAR_SERVER_STR); GetMachineName(tmp, sizeof(tmp)); c->MachineName = CopyStr(tmp); c->HttpUserAgent = CopyStr(DEFAULT_USER_AGENT); c->HttpAccept = CopyStr(DEFAULT_ACCEPT); c->HttpAcceptLanguage = CopyStr("ja"); c->HttpAcceptEncoding = CopyStr(DEFAULT_ENCODING); c->Traffic = NewTraffic(); c->TrafficLock = NewLock(); c->CaList = NewList(CompareCert); c->TrafficDiffList = NewList(NULL); SetCedarCipherList(c, "RC4-MD5"); c->ClientId = _II("CLIENT_ID"); c->UdpPortList = NewIntList(false); InitNetSvcList(c); InitLocalBridgeList(c); InitCedarLayer3(c); c->WebUI = WuNewWebUI(c); #ifdef ALPHA_VERSION beta_str = "Alpha"; #else // ALPHA_VERSION #ifndef RELEASE_CANDIDATE beta_str = "Beta"; #else // RELEASE_CANDIDATE beta_str = "Release Candidate"; #endif // RELEASE_CANDIDATE #endif // ALPHA_VERSION ToStr(tmp2, c->Beta); Format(tmp, sizeof(tmp), "Version %u.%02u Build %u %s %s (%s)", CEDAR_VER / 100, CEDAR_VER - (CEDAR_VER / 100) * 100, CEDAR_BUILD, c->Beta == 0 ? "" : beta_str, c->Beta == 0 ? "" : tmp2, _SS("LANGSTR")); Trim(tmp); if (true) { SYSTEMTIME st; Zero(&st, sizeof(st)); st.wYear = BUILD_DATE_Y; st.wMonth = BUILD_DATE_M; st.wDay = BUILD_DATE_D; c->BuiltDate = SystemToUINT64(&st); } c->VerString = CopyStr(tmp); Format(tmp, sizeof(tmp), "Compiled %04u/%02u/%02u %02u:%02u:%02u by %s at %s", BUILD_DATE_Y, BUILD_DATE_M, BUILD_DATE_D, BUILD_DATE_HO, BUILD_DATE_MI, BUILD_DATE_SE, BUILDER_NAME, BUILD_PLACE); c->BuildInfo = CopyStr(tmp); return c; }
// Process IP packets void L3RecvIp(L3IF *f, PKT *p, bool self) { IPV4_HEADER *ip; UINT header_size; UINT next_hop = 0; L3IF *dst; L3PACKET *packet; UINT new_ttl = 0; // Validate arguments if (f == NULL || p == NULL) { return; } ip = p->L3.IPv4Header; header_size = IPV4_GET_HEADER_LEN(p->L3.IPv4Header) * 4; // Calculate the checksum if (IpCheckChecksum(ip) == false) { // The checksum does not match goto FREE_PACKET; } // Register in the ARP table L3KnownArp(f, ip->SrcIP, p->MacAddressSrc); if (p->BroadcastPacket) { // Not to route in the case of broadcast packet goto FREE_PACKET; } // Calculate the TTL if (ip->TimeToLive >= 1) { new_ttl = ip->TimeToLive - 1; } else { new_ttl = 0; } if (new_ttl == 0) { if (ip->DstIP != f->IpAddress) { UINT src_packet_size = p->PacketSize - sizeof(MAC_HEADER); UINT icmp_packet_total_size = sizeof(MAC_HEADER) + sizeof(IPV4_HEADER) + sizeof(ICMP_HEADER) + 4 + header_size + 8; UCHAR *buf; IPV4_HEADER *ipv4; ICMP_HEADER *icmpv4; UCHAR *data; PKT *pkt; UINT data_size = MIN(p->PacketSize - header_size, header_size + 8); // Generate an ICMP message that means that the TTL has expired buf = ZeroMalloc(icmp_packet_total_size); ipv4 = (IPV4_HEADER *)(buf + sizeof(MAC_HEADER)); icmpv4 = (ICMP_HEADER *)(buf + sizeof(MAC_HEADER) + sizeof(IPV4_HEADER)); data = buf + sizeof(MAC_HEADER) + sizeof(IPV4_HEADER) + sizeof(ICMP_HEADER) + 4; IPV4_SET_VERSION(ipv4, 4); IPV4_SET_HEADER_LEN(ipv4, sizeof(IPV4_HEADER) / 4); ipv4->TotalLength = Endian16((USHORT)(icmp_packet_total_size - sizeof(MAC_HEADER))); ipv4->TimeToLive = 0xff; ipv4->Protocol = IP_PROTO_ICMPV4; ipv4->SrcIP = f->IpAddress; ipv4->DstIP = ip->SrcIP; ipv4->Checksum = IpChecksum(ipv4, sizeof(IPV4_HEADER)); icmpv4->Type = 11; Copy(data, ip, data_size); icmpv4->Checksum = IpChecksum(icmpv4, sizeof(ICMP_HEADER) + data_size + 4); buf[12] = 0x08; buf[13] = 0x00; pkt = ParsePacket(buf, icmp_packet_total_size); if (pkt == NULL) { Free(buf); } else { L3RecvIp(f, pkt, true); } // Discard the packet body whose the TTL has expired goto FREE_PACKET; } } // Rewrite the TTL p->L3.IPv4Header->TimeToLive = (UCHAR)new_ttl; // Get the interface corresponding to the destination IP address dst = L3GetNextIf(f->Switch, ip->DstIP, &next_hop); if (dst == NULL && self == false) { UINT src_packet_size = p->PacketSize - sizeof(MAC_HEADER); UINT icmp_packet_total_size = sizeof(MAC_HEADER) + sizeof(IPV4_HEADER) + sizeof(ICMP_HEADER) + 4 + header_size + 8; UCHAR *buf; IPV4_HEADER *ipv4; ICMP_HEADER *icmpv4; UCHAR *data; PKT *pkt; UINT data_size = MIN(p->PacketSize - header_size, header_size + 8); // Respond with ICMP that indicates that no route can be found buf = ZeroMalloc(icmp_packet_total_size); ipv4 = (IPV4_HEADER *)(buf + sizeof(MAC_HEADER)); icmpv4 = (ICMP_HEADER *)(buf + sizeof(MAC_HEADER) + sizeof(IPV4_HEADER)); data = buf + sizeof(MAC_HEADER) + sizeof(IPV4_HEADER) + sizeof(ICMP_HEADER) + 4; IPV4_SET_VERSION(ipv4, 4); IPV4_SET_HEADER_LEN(ipv4, sizeof(IPV4_HEADER) / 4); ipv4->TotalLength = Endian16((USHORT)(icmp_packet_total_size - sizeof(MAC_HEADER))); ipv4->TimeToLive = 0xff; ipv4->Protocol = IP_PROTO_ICMPV4; ipv4->SrcIP = f->IpAddress; ipv4->DstIP = ip->SrcIP; ipv4->Checksum = IpChecksum(ipv4, sizeof(IPV4_HEADER)); icmpv4->Type = 3; Copy(data, ip, data_size); icmpv4->Checksum = IpChecksum(icmpv4, sizeof(ICMP_HEADER) + data_size + 4); buf[12] = 0x08; buf[13] = 0x00; pkt = ParsePacket(buf, icmp_packet_total_size); if (pkt == NULL) { Free(buf); } else { L3RecvIp(f, pkt, true); } // Discard the packet body whose route can not be found goto FREE_PACKET; } if (dst != NULL && ip->DstIP == dst->IpAddress) { bool free_packet = true; // IP packet addressed to myself has arrived if (p->TypeL4 == L4_ICMPV4) { ICMP_HEADER *icmp = p->L4.ICMPHeader; if (icmp->Type == ICMP_TYPE_ECHO_REQUEST) { // Reply by rewriting the source and destination of the IP packet UINT src_ip, dst_ip; src_ip = p->L3.IPv4Header->DstIP; dst_ip = p->L3.IPv4Header->SrcIP; p->L3.IPv4Header->DstIP = dst_ip; p->L3.IPv4Header->SrcIP = src_ip; ip->TimeToLive = 0xff; // Recalculates the checksum ip->FlagsAndFlagmentOffset[0] = ip->FlagsAndFlagmentOffset[1] = 0; icmp->Checksum = 0; icmp->Type = ICMP_TYPE_ECHO_RESPONSE; icmp->Checksum = IpChecksum(icmp, p->PacketSize - sizeof(MAC_HEADER) - header_size); dst = L3GetNextIf(f->Switch, ip->DstIP, &next_hop); free_packet = false; } } if (free_packet) { goto FREE_PACKET; } } if (dst == NULL) { // The destination does not exist goto FREE_PACKET; } // Recalculate the IP checksum ip->Checksum = 0; ip->Checksum = IpChecksum(ip, header_size); // Treat as a Layer-3 packet packet = ZeroMalloc(sizeof(L3PACKET)); packet->Expire = Tick64() + IP_WAIT_FOR_ARP_TIMEOUT; packet->NextHopIp = next_hop; packet->Packet = p; // Store to the destination session L3StoreIpPacketToIf(f, dst, packet); return; FREE_PACKET: // Release the packet Free(p->PacketData); FreePacket(p); return; }
// Beacon transmission void L3PollingBeacon(L3IF *f) { // Validate arguments if (f == NULL) { return; } if (f->LastBeaconSent == 0 || (f->LastBeaconSent + BEACON_SEND_INTERVAL) <= Tick64()) { UINT dest_ip; UCHAR *udp_buf; UINT udp_buf_size; ARPV4_HEADER arp; IPV4_HEADER *ip; UDP_HEADER *udp; static char beacon_str[] = "PacketiX VPN Virtual Layer-3 Switch Beacon"; // Send an UDP dest_ip = (f->IpAddress & f->SubnetMask) | (~f->SubnetMask); udp_buf_size = sizeof(IPV4_HEADER) + sizeof(UDP_HEADER) + sizeof(beacon_str); udp_buf = ZeroMalloc(udp_buf_size); ip = (IPV4_HEADER *)udp_buf; udp = (UDP_HEADER *)(udp_buf + sizeof(IPV4_HEADER)); udp->DstPort = Endian16(7); udp->SrcPort = Endian16(7); udp->PacketLength = Endian16(sizeof(UDP_HEADER) + sizeof(beacon_str)); Copy(udp_buf + sizeof(IPV4_HEADER) + sizeof(UDP_HEADER), beacon_str, sizeof(beacon_str)); udp->Checksum = CalcChecksumForIPv4(f->IpAddress, dest_ip, 0x11, udp, sizeof(UDP_HEADER) + sizeof(beacon_str), 0); ip->DstIP = dest_ip; IPV4_SET_VERSION(ip, 4); IPV4_SET_HEADER_LEN(ip, (IP_HEADER_SIZE / 4)); ip->TypeOfService = DEFAULT_IP_TOS; ip->TotalLength = Endian16((USHORT)(udp_buf_size)); ip->TimeToLive = DEFAULT_IP_TTL; ip->Protocol = IP_PROTO_UDP; ip->SrcIP = f->IpAddress; ip->Checksum = IpChecksum(ip, IP_HEADER_SIZE); L3SendL2Now(f, broadcast, f->MacAddress, MAC_PROTO_IPV4, udp_buf, udp_buf_size); Free(udp_buf); // Build the ARP header arp.HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET); arp.ProtocolType = Endian16(MAC_PROTO_IPV4); arp.HardwareSize = 6; arp.ProtocolSize = 4; arp.Operation = Endian16(ARP_OPERATION_RESPONSE); Copy(arp.SrcAddress, f->MacAddress, 6); arp.SrcIP = f->IpAddress; arp.TargetAddress[0] = arp.TargetAddress[1] = arp.TargetAddress[2] = arp.TargetAddress[3] = arp.TargetAddress[4] = arp.TargetAddress[5] = 0xff; arp.TargetIP = dest_ip; // Transmission L3SendL2Now(f, broadcast, f->MacAddress, MAC_PROTO_ARPV4, &arp, sizeof(arp)); f->LastBeaconSent = Tick64(); } }
// Routing table tracking main void RouteTrackingMain(SESSION *s) { ROUTE_TRACKING *t; UINT64 now; ROUTE_TABLE *table; ROUTE_ENTRY *rs; bool changed = false; bool check = false; bool any_modified = false; // Validate arguments if (s == NULL) { return; } if (s->ClientModeAndUseVLan == false) { return; } // Get the state t = ((VLAN *)s->PacketAdapter->Param)->RouteState; if (t == NULL) { return; } // Current time PROBE_STR("RouteTrackingMain 1"); now = Tick64(); if (t->RouteChange != NULL) { if (t->NextRouteChangeCheckTime == 0 || t->NextRouteChangeCheckTime <= now) { t->NextRouteChangeCheckTime = now + 1000ULL; check = IsRouteChanged(t->RouteChange); if (check) { Debug("*** Routing Table Changed ***\n"); t->NextTrackingTime = 0; } } } if (t->NextTrackingTime != 0 && t->NextTrackingTime > now) { if (s->UseUdpAcceleration && s->UdpAccel != NULL && s->UdpAccel->NatT_IP_Changed) { // Check always if the IP address of the NAT-T server has changed } else { PROBE_STR("RouteTrackingMain 2"); return; } } PROBE_STR("RouteTrackingMain 3"); if (s->UseUdpAcceleration && s->UdpAccel != NULL) { IP nat_t_ip; s->UdpAccel->NatT_IP_Changed = false; Zero(&nat_t_ip, sizeof(nat_t_ip)); Lock(s->UdpAccel->NatT_Lock); { Copy(&nat_t_ip, &s->UdpAccel->NatT_IP, sizeof(IP)); } Unlock(s->UdpAccel->NatT_Lock); // Add a route to the NAT-T server if (IsZeroIp(&nat_t_ip) == false) { if (t->RouteToNatTServer == NULL) { if (t->RouteToEight != NULL) { ROUTE_ENTRY *e = Clone(t->RouteToEight, sizeof(ROUTE_ENTRY)); char ip_str[64]; char ip_str2[64]; Copy(&e->DestIP, &nat_t_ip, sizeof(IP)); e->Metric = e->OldIfMetric; IPToStr(ip_str, sizeof(ip_str), &e->DestIP); IPToStr(ip_str2, sizeof(ip_str2), &e->GatewayIP); t->RouteToNatTServer = e; if (AddRouteEntry(t->RouteToNatTServer)) { Debug("Adding Static Route to %s via %s metric %u: ok.\n", ip_str, ip_str2, e->Metric); } else { FreeRouteEntry(t->RouteToNatTServer); t->RouteToNatTServer = NULL; } } } } } // Get the current routing table table = GetRouteTable(); rs = t->RouteToServer; if (table != NULL) { UINT i; bool route_to_server_erased = true; bool is_vlan_want_to_be_default_gateway = false; UINT vlan_default_gatewat_metric = 0; UINT other_if_default_gateway_metric_min = INFINITE; // Get whether the routing table have been changed if (t->LastRoutingTableHash != table->HashedValue) { t->LastRoutingTableHash = table->HashedValue; changed = true; } //DebugPrintRouteTable(table); // Scan the routing table for (i = 0;i < table->NumEntry;i++) { ROUTE_ENTRY *e = table->Entry[i]; if (rs != NULL) { if (CmpIpAddr(&e->DestIP, &rs->DestIP) == 0 && CmpIpAddr(&e->DestMask, &rs->DestMask) == 0 // && CmpIpAddr(&e->GatewayIP, &rs->GatewayIP) == 0 // && e->InterfaceID == rs->InterfaceID && // e->LocalRouting == rs->LocalRouting && // e->Metric == rs->Metric ) { // Routing entry to the server that added at the time of connection is found route_to_server_erased = false; } } // Search for the default gateway if (IPToUINT(&e->DestIP) == 0 && IPToUINT(&e->DestMask) == 0) { Debug("e->InterfaceID = %u, t->VLanInterfaceId = %u\n", e->InterfaceID, t->VLanInterfaceId); if (e->InterfaceID == t->VLanInterfaceId) { // The virtual LAN card think that he want to be a default gateway is_vlan_want_to_be_default_gateway = true; vlan_default_gatewat_metric = e->Metric; if (vlan_default_gatewat_metric >= 2 && t->OldDefaultGatewayMetric == (vlan_default_gatewat_metric - 1)) { // Restore because the PPP server rewrites // the routing table selfishly DeleteRouteEntry(e); e->Metric--; AddRouteEntry(e); Debug("** Restore metric destroyed by PPP.\n"); any_modified = true; } // Keep this entry if (t->DefaultGatewayByVLan != NULL) { // Delete if there is one added last time FreeRouteEntry(t->DefaultGatewayByVLan); } t->DefaultGatewayByVLan = ZeroMalloc(sizeof(ROUTE_ENTRY)); Copy(t->DefaultGatewayByVLan, e, sizeof(ROUTE_ENTRY)); t->OldDefaultGatewayMetric = vlan_default_gatewat_metric; } else { // There are default gateway other than the virtual LAN card // Save the metric value of the default gateway if (other_if_default_gateway_metric_min > e->Metric) { // Ignore the metric value of all PPP connection in the case of Windows Vista if (MsIsVista() == false || e->PPPConnection == false) { other_if_default_gateway_metric_min = e->Metric; } else { // a PPP is used to Connect to the network // in using Windows Vista t->VistaAndUsingPPP = true; } } } } } if (t->VistaAndUsingPPP) { if (t->DefaultGatewayByVLan != NULL) { if (is_vlan_want_to_be_default_gateway) { if (t->VistaOldDefaultGatewayByVLan == NULL || Cmp(t->VistaOldDefaultGatewayByVLan, t->DefaultGatewayByVLan, sizeof(ROUTE_ENTRY)) != 0) { ROUTE_ENTRY *e; // Add the route of 0.0.0.0/1 and 128.0.0.0/1 // to the system if the virtual LAN card should be // the default gateway in the case of the connection // using PPP in Windows Vista if (t->VistaOldDefaultGatewayByVLan != NULL) { FreeRouteEntry(t->VistaOldDefaultGatewayByVLan); } if (t->VistaDefaultGateway1 != NULL) { DeleteRouteEntry(t->VistaDefaultGateway1); FreeRouteEntry(t->VistaDefaultGateway1); DeleteRouteEntry(t->VistaDefaultGateway2); FreeRouteEntry(t->VistaDefaultGateway2); } t->VistaOldDefaultGatewayByVLan = Clone(t->DefaultGatewayByVLan, sizeof(ROUTE_ENTRY)); e = Clone(t->DefaultGatewayByVLan, sizeof(ROUTE_ENTRY)); SetIP(&e->DestIP, 0, 0, 0, 0); SetIP(&e->DestMask, 128, 0, 0, 0); t->VistaDefaultGateway1 = e; e = Clone(t->DefaultGatewayByVLan, sizeof(ROUTE_ENTRY)); SetIP(&e->DestIP, 128, 0, 0, 0); SetIP(&e->DestMask, 128, 0, 0, 0); t->VistaDefaultGateway2 = e; AddRouteEntry(t->VistaDefaultGateway1); AddRouteEntry(t->VistaDefaultGateway2); Debug("Vista PPP Fix Route Table Added.\n"); any_modified = true; } } else { if (t->VistaOldDefaultGatewayByVLan != NULL) { FreeRouteEntry(t->VistaOldDefaultGatewayByVLan); t->VistaOldDefaultGatewayByVLan = NULL; } if (t->VistaDefaultGateway1 != NULL) { Debug("Vista PPP Fix Route Table Deleted.\n"); DeleteRouteEntry(t->VistaDefaultGateway1); FreeRouteEntry(t->VistaDefaultGateway1); DeleteRouteEntry(t->VistaDefaultGateway2); FreeRouteEntry(t->VistaDefaultGateway2); any_modified = true; t->VistaDefaultGateway1 = t->VistaDefaultGateway2 = NULL; } } } } // If the virtual LAN card want to be the default gateway and // there is no LAN card with smaller metric of 0.0.0.0/0 than // the virtual LAN card, delete other default gateway entries // to elect the virtual LAN card as the default gateway // Debug("is_vlan_want_to_be_default_gateway = %u, rs = %u, route_to_server_erased = %u, other_if_default_gateway_metric_min = %u, vlan_default_gatewat_metric = %u\n", // is_vlan_want_to_be_default_gateway, rs, route_to_server_erased, other_if_default_gateway_metric_min, vlan_default_gatewat_metric); if (is_vlan_want_to_be_default_gateway && (rs != NULL && route_to_server_erased == false) && other_if_default_gateway_metric_min >= vlan_default_gatewat_metric) { // Scan the routing table again for (i = 0;i < table->NumEntry;i++) { ROUTE_ENTRY *e = table->Entry[i]; if (e->InterfaceID != t->VLanInterfaceId) { if (IPToUINT(&e->DestIP) == 0 && IPToUINT(&e->DestMask) == 0) { char str[64]; // Default gateway is found ROUTE_ENTRY *r = ZeroMalloc(sizeof(ROUTE_ENTRY)); Copy(r, e, sizeof(ROUTE_ENTRY)); // Put in the queue InsertQueue(t->DeletedDefaultGateway, r); // Delete this gateway entry once DeleteRouteEntry(e); IPToStr(str, sizeof(str), &e->GatewayIP); Debug("Default Gateway %s Deleted.\n", str); any_modified = true; } } } } if (rs != NULL && route_to_server_erased) { // Physical entry to the server has disappeared Debug("Route to Server entry ERASED !!!\n"); // Forced disconnection (reconnection enabled) s->RetryFlag = true; s->Halt = true; } // Release the routing table FreeRouteTable(table); } // Set the time to perform the next track if (t->NextTrackingTimeAdd == 0 || changed) { t->NextTrackingTimeAdd = TRACKING_INTERVAL_INITIAL; } else { UINT64 max_value = TRACKING_INTERVAL_MAX; if (t->RouteChange != NULL) { max_value = TRACKING_INTERVAL_MAX_RC; } t->NextTrackingTimeAdd += TRACKING_INTERVAL_ADD; if (t->NextTrackingTimeAdd >= max_value) { t->NextTrackingTimeAdd = max_value; } } //Debug("t->NextTrackingTimeAdd = %I64u\n", t->NextTrackingTimeAdd); t->NextTrackingTime = now + t->NextTrackingTimeAdd; if (any_modified) { // Clear the DNS cache Win32FlushDnsCache(); } }
// Create a new UDP acceleration function UDP_ACCEL *NewUdpAccel(CEDAR *cedar, IP *ip, bool client_mode, bool random_port, bool no_nat_t) { UDP_ACCEL *a; SOCK *s; UINT max_udp_size; bool is_in_cedar_port_list = false; if (IsZeroIP(ip)) { ip = NULL; } if (client_mode || random_port) { // Use a appropriate vacant port number in the case of using random port or client mode s = NewUDPEx3(0, ip); } else { // Specify in the range in the case of server mode UINT i; s = NULL; LockList(cedar->UdpPortList); { for (i = UDP_SERVER_PORT_LOWER;i <= UDP_SERVER_PORT_HIGHER;i++) { if (IsIntInList(cedar->UdpPortList, i) == false) { s = NewUDPEx3(i, ip); if (s != NULL) { is_in_cedar_port_list = true; break; } } } if (s == NULL) { // Leave the port selection to the OS because the available port is not found within the range s = NewUDPEx3(0, ip); } if (s != NULL && is_in_cedar_port_list) { AddIntDistinct(cedar->UdpPortList, i); } } UnlockList(cedar->UdpPortList); } if (s == NULL) { return NULL; } a = ZeroMalloc(sizeof(UDP_ACCEL)); a->Cedar = cedar; AddRef(a->Cedar->ref); a->NoNatT = no_nat_t; a->NatT_TranId = Rand64(); a->CreatedTick = Tick64(); a->IsInCedarPortList = is_in_cedar_port_list; a->ClientMode = client_mode; a->Now = Tick64(); a->UdpSock = s; Rand(a->MyKey, sizeof(a->MyKey)); Rand(a->YourKey, sizeof(a->YourKey)); Copy(&a->MyIp, ip, sizeof(IP)); a->MyPort = s->LocalPort; a->IsIPv6 = IsIP6(ip); if (a->IsIPv6) { a->NoNatT = true; } a->RecvBlockQueue = NewQueue(); Rand(a->NextIv, sizeof(a->NextIv)); do { a->MyCookie = Rand32(); } while (a->MyCookie == 0); do { a->YourCookie = Rand32(); } while (a->MyCookie == 0 || a->MyCookie == a->YourCookie); // Calculate the maximum transmittable UDP packet size max_udp_size = MTU_FOR_PPPOE; if (a->IsIPv6 == false) { // IPv4 max_udp_size -= 20; } else { // IPv6 max_udp_size -= 40; } // UDP max_udp_size -= 8; a->MaxUdpPacketSize = max_udp_size; Debug("Udp Accel My Port = %u\n", a->MyPort); // Initialize the NAT-T server IP address acquisition thread a->NatT_Lock = NewLock(); a->NatT_HaltEvent = NewEvent(); if (a->NoNatT == false) { a->NatT_GetIpThread = NewThread(NatT_GetIpThread, a); } return a; }
// VPN Azure client main thread void AcMainThread(THREAD *thread, void *param) { AZURE_CLIENT *ac = (AZURE_CLIENT *)param; UINT last_ip_revision = INFINITE; UINT64 last_reconnect_tick = 0; UINT64 next_reconnect_interval = AZURE_CONNECT_INITIAL_RETRY_INTERVAL; UINT num_reconnect_retry = 0; UINT64 next_ddns_retry_tick = 0; bool last_connect_ok = false; // Validate arguments if (ac == NULL || thread == NULL) { return; } while (ac->Halt == false) { UINT64 now = Tick64(); bool connect_was_ok = false; // Wait for enabling VPN Azure function if (ac->IsEnabled) { // VPN Azure is enabled DDNS_CLIENT_STATUS st; bool connect_now = false; bool azure_ip_changed = false; Lock(ac->Lock); { Copy(&st, &ac->DDnsStatus, sizeof(DDNS_CLIENT_STATUS)); if (StrCmpi(st.CurrentAzureIp, ac->DDnsStatusCopy.CurrentAzureIp) != 0) { if (IsEmptyStr(st.CurrentAzureIp) == false) { // Destination IP address is changed connect_now = true; num_reconnect_retry = 0; } } if (StrCmpi(st.CurrentHostName, ac->DDnsStatusCopy.CurrentHostName) != 0) { // DDNS host name is changed connect_now = true; num_reconnect_retry = 0; } Copy(&ac->DDnsStatusCopy, &st, sizeof(DDNS_CLIENT_STATUS)); } Unlock(ac->Lock); if (last_ip_revision != ac->IpStatusRevision) { last_ip_revision = ac->IpStatusRevision; connect_now = true; num_reconnect_retry = 0; } if (last_reconnect_tick == 0 || (now >= (last_reconnect_tick + next_reconnect_interval))) { UINT r; last_reconnect_tick = now; num_reconnect_retry++; next_reconnect_interval = (UINT64)num_reconnect_retry * AZURE_CONNECT_INITIAL_RETRY_INTERVAL; next_reconnect_interval = MIN(next_reconnect_interval, AZURE_CONNECT_MAX_RETRY_INTERVAL); r = (UINT)next_reconnect_interval; r = GenRandInterval(r / 2, r); next_reconnect_interval = r; connect_now = true; } if (IsEmptyStr(st.CurrentAzureIp) == false && IsEmptyStr(st.CurrentHostName) == false) { if (connect_now) { SOCK *s; char *host = NULL; UINT port = AZURE_SERVER_PORT; Debug("VPN Azure: Connecting to %s...\n", st.CurrentAzureIp); if (ParseHostPort(st.CurrentAzureIp, &host, &port, AZURE_SERVER_PORT)) { if (st.InternetSetting.ProxyType == PROXY_DIRECT) { s = ConnectEx2(host, port, 0, (bool *)&ac->Halt); } else { s = WpcSockConnect2(host, port, &st.InternetSetting, NULL, AZURE_VIA_PROXY_TIMEOUT); } if (s != NULL) { PACK *p; UINT64 established_tick = 0; Debug("VPN Azure: Connected.\n"); SetTimeout(s, AZURE_PROTOCOL_CONTROL_TIMEOUT_DEFAULT); Lock(ac->Lock); { ac->CurrentSock = s; ac->IsConnected = true; StrCpy(ac->ConnectingAzureIp, sizeof(ac->ConnectingAzureIp), st.CurrentAzureIp); } Unlock(ac->Lock); SendAll(s, AZURE_PROTOCOL_CONTROL_SIGNATURE, StrLen(AZURE_PROTOCOL_CONTROL_SIGNATURE), false); // Receive parameter p = RecvPackWithHash(s); if (p != NULL) { UCHAR c; AZURE_PARAM param; bool hostname_changed = false; Zero(¶m, sizeof(param)); param.ControlKeepAlive = PackGetInt(p, "ControlKeepAlive"); param.ControlTimeout = PackGetInt(p, "ControlTimeout"); param.DataTimeout = PackGetInt(p, "DataTimeout"); param.SslTimeout = PackGetInt(p, "SslTimeout"); FreePack(p); param.ControlKeepAlive = MAKESURE(param.ControlKeepAlive, 1000, AZURE_SERVER_MAX_KEEPALIVE); param.ControlTimeout = MAKESURE(param.ControlTimeout, 1000, AZURE_SERVER_MAX_TIMEOUT); param.DataTimeout = MAKESURE(param.DataTimeout, 1000, AZURE_SERVER_MAX_TIMEOUT); param.SslTimeout = MAKESURE(param.SslTimeout, 1000, AZURE_SERVER_MAX_TIMEOUT); Lock(ac->Lock); { Copy(&ac->AzureParam, ¶m, sizeof(AZURE_PARAM)); } Unlock(ac->Lock); SetTimeout(s, param.ControlTimeout); // Send parameter p = NewPack(); PackAddStr(p, "CurrentHostName", st.CurrentHostName); PackAddStr(p, "CurrentAzureIp", st.CurrentAzureIp); PackAddInt64(p, "CurrentAzureTimestamp", st.CurrentAzureTimestamp); PackAddStr(p, "CurrentAzureSignature", st.CurrentAzureSignature); Lock(ac->Lock); { if (StrCmpi(st.CurrentHostName, ac->DDnsStatus.CurrentHostName) != 0) { hostname_changed = true; } } Unlock(ac->Lock); if (hostname_changed == false) { if (SendPackWithHash(s, p)) { // Receive result if (RecvAll(s, &c, 1, false)) { if (c && ac->Halt == false) { connect_was_ok = true; established_tick = Tick64(); AcWaitForRequest(ac, s, ¶m); } } } } FreePack(p); } else { WHERE; } Debug("VPN Azure: Disconnected.\n"); Lock(ac->Lock); { ac->IsConnected = false; ac->CurrentSock = NULL; ClearStr(ac->ConnectingAzureIp, sizeof(ac->ConnectingAzureIp)); } Unlock(ac->Lock); if (established_tick != 0) { if ((established_tick + (UINT64)AZURE_CONNECT_MAX_RETRY_INTERVAL) <= Tick64()) { // If the connected time exceeds the AZURE_CONNECT_MAX_RETRY_INTERVAL, reset the retry counter. last_reconnect_tick = 0; num_reconnect_retry = 0; next_reconnect_interval = AZURE_CONNECT_INITIAL_RETRY_INTERVAL; } } Disconnect(s); ReleaseSock(s); } else { Debug("VPN Azure: Error: Connect Failed.\n"); } Free(host); } } } } else { last_reconnect_tick = 0; num_reconnect_retry = 0; next_reconnect_interval = AZURE_CONNECT_INITIAL_RETRY_INTERVAL; } if (ac->Halt) { break; } if (connect_was_ok) { // If connection goes out after connected, increment connection success count to urge DDNS client query next_ddns_retry_tick = Tick64() + MIN((UINT64)DDNS_VPN_AZURE_CONNECT_ERROR_DDNS_RETRY_TIME_DIFF * (UINT64)(num_reconnect_retry + 1), (UINT64)DDNS_VPN_AZURE_CONNECT_ERROR_DDNS_RETRY_TIME_DIFF_MAX); } if ((next_ddns_retry_tick != 0) && (Tick64() >= next_ddns_retry_tick)) { next_ddns_retry_tick = 0; ac->DDnsTriggerInt++; } Wait(ac->Event, rand() % 1000); } }
// Send multiple packets void EthPutPackets(ETH *e, UINT num, void **datas, UINT *sizes) { UINT i, total_size; UCHAR *buf; UINT write_pointer; UINT err = 0; // Validate arguments if (e == NULL || num == 0 || datas == NULL || sizes == NULL) { return; } if (e->HasFatalError) { return; } if (e->SuAdapter != NULL) { bool ok = true; // Send packets with SeLow for (i = 0;i < num;i++) { UCHAR *data = datas[i]; UINT size = sizes[i]; if (ok) { // Actually, only enqueuing ok = SuPutPacket(e->SuAdapter, data, size); } if (ok == false) { // Free memory on write error Free(data); } } if (ok) { // Send all data in queue at once ok = SuPutPacket(e->SuAdapter, NULL, 0); } if (ok == false) { // Error occurred e->HasFatalError = true; } return; } if (IsWin32BridgeWithSee() == false) { if (e->LastSetSingleCpu == 0 || (e->LastSetSingleCpu + 10000) <= Tick64()) { e->LastSetSingleCpu = Tick64(); MsSetThreadSingleCpu(); } } // Calculate buffer size total_size = 0; for (i = 0;i < num;i++) { void *data = datas[i]; UINT size = sizes[i]; if (data != NULL && size >= 14 && size <= MAX_PACKET_SIZE) { total_size += size + sizeof(struct dump_bpf_hdr); } } buf = MallocFast(total_size * 100 / 75 + 1600); write_pointer = 0; // Enqueue for (i = 0;i < num;i++) { void *data = datas[i]; UINT size = sizes[i]; if (data != NULL && size >= 14 && size <= MAX_PACKET_SIZE) { struct dump_bpf_hdr *h; h = (struct dump_bpf_hdr *)(buf + write_pointer); Zero(h, sizeof(struct dump_bpf_hdr)); h->caplen = h->len = size; write_pointer += sizeof(struct dump_bpf_hdr); Copy(buf + write_pointer, data, size); write_pointer += size; PROBE_DATA2("EthPutPackets", data, size); } // Free original buffer Free(data); } // Send if (total_size != 0) { err = wp->PacketSendPackets(e->Adapter, buf, total_size, true); } Free(buf); if (err == 0x7FFFFFFF) { // Critical error (infinite loop) occurred on sending e->HasFatalError = true; } }
// Process the timer interrupt void SstpProcessInterrupt(SSTP_SERVER *s) { // Validate arguments if (s == NULL) { return; } s->Now = Tick64(); s->FlushRecvTube = false; // Process the received packet while (true) { BLOCK *b = GetNext(s->RecvQueue); SSTP_PACKET *p; if (b == NULL) { break; } p = SstpParsePacket(b->Buf, b->Size); if (p == NULL) { // Disconnect the SSTP since a bad packet received SstpAbort(s); } else { // Process the received packet SstpProcessPacket(s, p); SstpFreePacket(p); } FreeBlock(b); } if (s->FlushRecvTube) { TubeFlush(s->TubeRecv); } // Transmit a packet that the PPP module is trying to send via the SSTP while (true) { TUBEDATA *d = TubeRecvAsync(s->TubeSend); SSTP_PACKET *p; if (d == NULL) { break; } p = SstpNewDataPacket(d->Data, d->DataSize); SstpSendPacket(s, p); SstpFreePacket(p); FreeTubeData(d); } if (s->Status == SSTP_SERVER_STATUS_ESTABLISHED) { if (s->Disconnecting == false && s->Aborting == false) { // Periodic transmission of Echo Request if (s->NextSendEchoRequestTick == 0 || s->NextSendEchoRequestTick <= s->Now) { UINT64 next_interval = (UINT64)(SSTP_ECHO_SEND_INTERVAL_MIN + Rand32() % (SSTP_ECHO_SEND_INTERVAL_MAX - SSTP_ECHO_SEND_INTERVAL_MIN)); SSTP_PACKET *p; s->NextSendEchoRequestTick = s->Now + next_interval; AddInterrupt(s->Interrupt, s->NextSendEchoRequestTick); p = SstpNewControlPacket(SSTP_MSG_ECHO_REQUEST); SstpSendPacket(s, p); SstpFreePacket(p); } } } if ((s->LastRecvTick + (UINT64)SSTP_TIMEOUT) <= s->Now) { // Disconnect the SSTP because a timeout occurred SstpAbort(s); s->Disconnected = true; } if (IsTubeConnected(s->TubeRecv) == false || IsTubeConnected(s->TubeSend) == false) { // Disconnect the SSTP since the PPP module is disconnected SstpDisconnect(s); } if (s->Disconnecting) { // Normal disconnection process if (s->DisconnectSent == false) { // Send a Disconnect SSTP_PACKET *ret = SstpNewControlPacket(s->DisconnectRecved ? SSTP_MSG_CALL_DISCONNECT_ACK : SSTP_MSG_CALL_DISCONNECT); SstpSendPacket(s, ret); SstpFreePacket(ret); s->DisconnectSent = true; } } if (s->Aborting) { // Abnormal disconnection processing if (s->AbortSent == false) { // Send the Abort SSTP_PACKET *ret = SstpNewControlPacket(SSTP_MSG_CALL_ABORT); SstpSendPacket(s, ret); SstpFreePacket(ret); s->AbortSent = true; } } if (s->DisconnectSent && s->DisconnectRecved) { // Disconnect after exchanging the Disconnect each other s->Disconnected = true; } if (s->AbortSent && s->AbortReceived) { // Disconnect after exchanging the Abort each other s->Disconnected = true; } }
SU *SuInitEx(UINT wait_for_bind_complete_tick) { void *h; SU *u; UINT read_size; bool flag = false; UINT64 giveup_tick = 0; static bool flag2 = false; // flag2 must be global if (SuIsSupportedOs(false) == false) { // Unsupported OS return NULL; } LABEL_RETRY: // Open the device driver h = CreateFileA(SL_BASIC_DEVICE_FILENAME_WIN32, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (h == INVALID_HANDLE_VALUE) { Debug("CreateFileA(%s) Failed.\n", SL_BASIC_DEVICE_FILENAME_WIN32); // Start the service if it fails to start the device driver if (flag == false) { if (MsStartService(SL_PROTOCOL_NAME) == false) { Debug("MsStartService(%s) Failed.\n", SL_PROTOCOL_NAME); if (MsIsWindows10()) { if (flag2 == false) { flag2 = true; if (SuInstallDriver(true)) { goto LABEL_RETRY; } } } } else { Debug("MsStartService(%s) Ok.\n", SL_PROTOCOL_NAME); flag = true; goto LABEL_RETRY; } } return NULL; } //Debug("CreateFileA(%s) Ok.\n", SL_BASIC_DEVICE_FILENAME_WIN32); u = ZeroMalloc(sizeof(SU)); giveup_tick = Tick64() + (UINT64)wait_for_bind_complete_tick; if (wait_for_bind_complete_tick == 0) { if (ReadFile(h, &u->AdapterInfoList, sizeof(u->AdapterInfoList), &read_size, NULL) == false || u->AdapterInfoList.Signature != SL_SIGNATURE) { // Signature reception failure Debug("Bad Signature.\n"); Free(u); CloseHandle(h); return NULL; } } else { while (giveup_tick >= Tick64()) { // Wait until the enumeration is completed if (ReadFile(h, &u->AdapterInfoList, sizeof(u->AdapterInfoList), &read_size, NULL) == false || u->AdapterInfoList.Signature != SL_SIGNATURE) { // Signature reception failure Debug("Bad Signature.\n"); Free(u); CloseHandle(h); return NULL; } if (u->AdapterInfoList.EnumCompleted) { // Complete enumeration Debug("Bind Completed! %u\n", u->AdapterInfoList.EnumCompleted); break; } // Incomplete enumeration Debug("Waiting for Bind Complete.\n"); SleepThread(25); } } u->hFile = h; return u; }
// Read the string table bool LoadTableMain(wchar_t *filename) { BUF *b; UINT64 t1, t2; UCHAR hash[MD5_SIZE]; // Validate arguments if (filename == NULL) { return false; } if (MayaquaIsMinimalMode()) { return true; } if (UniStrCmpi(old_table_name, filename) == 0) { // Already loaded return true; } t1 = Tick64(); // Open the file b = ReadDumpW(filename); if (b == NULL) { char tmp[MAX_SIZE]; StrCpy(tmp, sizeof(tmp), "Error: Can't read string tables (file not found).\r\nPlease check hamcore.se2.\r\n\r\n(First, reboot the computer. If this problem occurs again, please reinstall VPN software files.)"); Alert(tmp, NULL); exit(-1); return false; } Hash(hash, b->Buf, b->Size, false); if (LoadUnicodeCache(filename, b->Size, hash) == false) { if (LoadTableFromBuf(b) == false) { FreeBuf(b); return false; } SaveUnicodeCache(filename, b->Size, hash); //Debug("Unicode Source: strtable.stb\n"); } else { //Debug("Unicode Source: unicode_cache\n"); } FreeBuf(b); SetLocale(_UU("DEFAULE_LOCALE")); UniStrCpy(old_table_name, sizeof(old_table_name), filename); t2 = Tick64(); if (StrCmpi(_SS("STRTABLE_ID"), STRTABLE_ID) != 0) { char tmp[MAX_SIZE]; Format(tmp, sizeof(tmp), "Error: Can't read string tables (invalid version: '%s'!='%s').\r\nPlease check hamcore.se2.\r\n\r\n(First, reboot the computer. If this problem occurs again, please reinstall VPN software files.)", _SS("STRTABLE_ID"), STRTABLE_ID); Alert(tmp, NULL); exit(-1); return false; } //Debug("Unicode File Read Cost: %u (%u Lines)\n", (UINT)(t2 - t1), LIST_NUM(TableList)); return true; }