// Complete receiving management command void NiFreeAdminAccept(NAT *n) { // Validate arguments if (n == NULL) { return; } n->Halt = true; Disconnect(n->AdminListenSock); Set(n->HaltEvent); while (true) { if (WaitThread(n->AdminAcceptThread, 1000) == false) { Disconnect(n->AdminListenSock); } else { break; } } ReleaseThread(n->AdminAcceptThread); ReleaseSock(n->AdminListenSock); }
// Thread that processes the accepted TCP connection void TCPAcceptedThread(THREAD *t, void *param) { TCP_ACCEPTED_PARAM *data; LISTENER *r; SOCK *s; CONNECTION *c; bool flag1; char tmp[128]; // Validate arguments if (t == NULL || param == NULL) { return; } // Initialize data = (TCP_ACCEPTED_PARAM *)param; r = data->r; s = data->s; AddRef(r->ref); AddRef(s->ref); // Create a connection c = NewServerConnection(r->Cedar, s, t); // Register to Cedar as a transient connection AddConnection(c->Cedar, c); NoticeThreadInit(t); AcceptInit(s); StrCpy(c->ClientHostname, sizeof(c->ClientHostname), s->RemoteHostname); IPToStr(tmp, sizeof(tmp), &s->RemoteIP); if (IS_SPECIAL_PORT(s->RemotePort) == false) { SLog(r->Cedar, "LS_LISTENER_ACCEPT", r->Port, tmp, s->RemoteHostname, s->RemotePort); } // Reception ConnectionAccept(c); flag1 = c->flag1; // Release SLog(r->Cedar, "LS_CONNECTION_END_1", c->Name); ReleaseConnection(c); // Release if (flag1 == false) { Debug("%s %u flag1 == false\n", __FILE__, __LINE__); IPToStr(tmp, sizeof(tmp), &s->RemoteIP); if (IS_SPECIAL_PORT(s->RemotePort) == false) { SLog(r->Cedar, "LS_LISTENER_DISCONNECT", tmp, s->RemotePort); } Disconnect(s); } ReleaseSock(s); ReleaseListener(r); }
// An UDP packet has been received void UDPReceivedPacket(CEDAR *cedar, SOCK *s, IP *ip, UINT port, void *data, UINT size) { SESSION *session; UINT *key32; UCHAR *buf; CONNECTION *c; // Validate arguments if (s == NULL || ip == NULL || data == NULL || size == 0 || cedar == NULL) { return; } if (size < 16) { // Ignore since the packet size is not enough return; } buf = (UCHAR *)data; key32 = (UINT *)(buf + 4); // Get the session from the Key32 value session = GetSessionFromUDPEntry(cedar, Endian32(*key32)); if (session == NULL) { Debug("Invalid UDP Session Key 32: 0x%X\n", *key32); return; } c = session->Connection; // Write the data PutUDPPacketData(c, buf, size); // Rewrite the UDP socket associated with the connection Lock(c->lock); { if (c->Protocol == CONNECTION_UDP) { if (c->Udp->s != s) { if (c->Udp->s != NULL) { ReleaseSock(c->Udp->s); } AddRef(s->ref); c->Udp->s = s; } Copy(&c->Udp->ip, ip, sizeof(UINT)); c->Udp->port = port; } } Unlock(c->lock); // Invoke the Cancel Cancel(session->Cancel1); // Release the session ReleaseSession(session); }
// Set current configuration to VPN Azure client void AcApplyCurrentConfig(AZURE_CLIENT *ac, DDNS_CLIENT_STATUS *ddns_status) { bool disconnect_now = false; SOCK *disconnect_sock = NULL; // Validate arguments if (ac == NULL) { return; } // Get current DDNS configuration Lock(ac->Lock); { if (ddns_status != NULL) { if (StrCmpi(ac->DDnsStatus.CurrentHostName, ddns_status->CurrentHostName) != 0) { // If host name is changed, disconnect current data connection disconnect_now = true; } if (Cmp(&ac->DDnsStatus.InternetSetting, &ddns_status->InternetSetting, sizeof(INTERNET_SETTING)) != 0) { // If proxy setting is changed, disconnect current data connection disconnect_now = true; } Copy(&ac->DDnsStatus, ddns_status, sizeof(DDNS_CLIENT_STATUS)); } if (ac->IsEnabled == false) { // If VPN Azure client is disabled, disconnect current data connection disconnect_now = true; } if (disconnect_now) { if (ac->CurrentSock != NULL) { disconnect_sock = ac->CurrentSock; AddRef(disconnect_sock->ref); } } } Unlock(ac->Lock); if (disconnect_sock != NULL) { Disconnect(disconnect_sock); ReleaseSock(disconnect_sock); } Set(ac->Event); }
// Release the stack void FreeNativeStack(NATIVE_STACK *a) { // Validate arguments if (a == NULL) { return; } if (a->Ipc != NULL && IsZero(&a->CurrentDhcpOptionList, sizeof(a->CurrentDhcpOptionList)) == false) { IP dhcp_server; UINTToIP(&dhcp_server, a->CurrentDhcpOptionList.ServerAddress); IPCDhcpFreeIP(a->Ipc, &dhcp_server); SleepThread(200); } a->Halt = true; Cancel(a->Cancel); Disconnect(a->Sock1); Disconnect(a->Sock2); WaitThread(a->MainThread, INFINITE); ReleaseThread(a->MainThread); CloseEth(a->Eth); FreeIPC(a->Ipc); NsStopIpTablesTracking(a); ReleaseCancel(a->Cancel); ReleaseSock(a->Sock1); ReleaseSock(a->Sock2); ReleaseCedar(a->Cedar); Free(a); }
// Release the UDP acceleration function void FreeUdpAccel(UDP_ACCEL *a) { // Validate arguments if (a == NULL) { return; } while (true) { BLOCK *b = GetNext(a->RecvBlockQueue); if (b == NULL) { break; } FreeBlock(b); } ReleaseQueue(a->RecvBlockQueue); ReleaseSock(a->UdpSock); if (a->IsInCedarPortList) { LockList(a->Cedar->UdpPortList); { DelInt(a->Cedar->UdpPortList, a->MyPort); } UnlockList(a->Cedar->UdpPortList); } // Release of NAT-T related a->NatT_Halt = true; Set(a->NatT_HaltEvent); if (a->NatT_GetIpThread != NULL) { WaitThread(a->NatT_GetIpThread, INFINITE); ReleaseThread(a->NatT_GetIpThread); } ReleaseEvent(a->NatT_HaltEvent); DeleteLock(a->NatT_Lock); ReleaseCedar(a->Cedar); Free(a); }
// RPC の解放 void RpcFree(RPC *rpc) { // 引数チェック if (rpc == NULL) { return; } Disconnect(rpc->Sock); ReleaseSock(rpc->Sock); DeleteLock(rpc->Lock); Free(rpc); }
// Release the RPC void RpcFree(RPC *rpc) { // Validate arguments if (rpc == NULL) { return; } Disconnect(rpc->Sock); ReleaseSock(rpc->Sock); DeleteLock(rpc->Lock); Free(rpc); }
// Listener stop void ElStopListener(EL *e) { UINT i; THREAD **threads; SOCK **socks; UINT num_threads, num_socks; // Validate arguments if (e == NULL) { return; } StopAllListener(e->Cedar); LockList(e->AdminThreadList); { threads = ToArray(e->AdminThreadList); num_threads = LIST_NUM(e->AdminThreadList); DeleteAll(e->AdminThreadList); socks = ToArray(e->AdminSockList); num_socks = LIST_NUM(e->AdminSockList); DeleteAll(e->AdminSockList); } UnlockList(e->AdminThreadList); for (i = 0;i < num_socks;i++) { Disconnect(socks[i]); ReleaseSock(socks[i]); } for (i = 0;i < num_threads;i++) { WaitThread(threads[i], INFINITE); ReleaseThread(threads[i]); } Free(threads); Free(socks); ReleaseList(e->AdminSockList); ReleaseList(e->AdminThreadList); ReleaseListener(e->Listener); }
// Free VPN Azure client void FreeAzureClient(AZURE_CLIENT *ac) { SOCK *disconnect_sock = NULL; // Validate arguments if (ac == NULL) { return; } ac->Halt = true; Lock(ac->Lock); { if (ac->CurrentSock != NULL) { disconnect_sock = ac->CurrentSock; AddRef(disconnect_sock->ref); } } Unlock(ac->Lock); if (disconnect_sock != NULL) { Disconnect(disconnect_sock); ReleaseSock(disconnect_sock); } Set(ac->Event); // Stop main thread WaitThread(ac->MainThread, INFINITE); ReleaseThread(ac->MainThread); ReleaseEvent(ac->Event); DeleteLock(ac->Lock); Free(ac); }
// Cleanup the listener void CleanupListener(LISTENER *r) { UINT i = 0; // Validate arguments if (r == NULL) { return; } if (r->Sock != NULL) { ReleaseSock(r->Sock); } DeleteLock(r->lock); ReleaseThread(r->Thread); ReleaseEvent(r->Event); ReleaseCedar(r->Cedar); Free(r); }
// RPC client connect UINT EcConnect(char *host, UINT port, char *password, RPC **rpc) { SOCK *s; UCHAR password_hash[SHA1_SIZE]; UCHAR rand[SHA1_SIZE]; UCHAR response[SHA1_SIZE]; bool retcode; // Validate arguments if (host == NULL) { host = "localhost"; } if (port == 0) { port = EL_ADMIN_PORT; } if (password == NULL) { password = ""; } if (rpc == NULL) { return ERR_INTERNAL_ERROR; } // Connect to the server s = Connect(host, port); if (s == NULL) { // Connection failure return ERR_CONNECT_FAILED; } SetTimeout(s, 5000); // Hash the password Hash(password_hash, password, StrLen(password), true); // Receive the random number Zero(rand, sizeof(rand)); RecvAll(s, rand, sizeof(rand), false); SecurePassword(response, password_hash, rand); // Send a response SendAll(s, response, sizeof(response), false); // Receive results retcode = false; if (RecvAll(s, &retcode, sizeof(retcode), false) == false) { // Disconnect ReleaseSock(s); return ERR_PROTOCOL_ERROR; } retcode = Endian32(retcode); if (retcode == false) { // Password incorrect ReleaseSock(s); return ERR_AUTH_FAILED; } // Successful connection SetTimeout(s, INFINITE); *rpc = StartRpcClient(s, NULL); ReleaseSock(s); return ERR_NO_ERROR; }
// UDP listener main loop void ListenerUDPMainLoop(LISTENER *r) { UCHAR *data; // Validate arguments if (r == NULL) { return; } Debug("ListenerUDPMainLoop Starts.\n"); r->Status = LISTENER_STATUS_TRYING; while (true) { // Try to listen on the UDP port while (true) { // Stop flag inspection if (r->Halt) { // Stop return; } Debug("NewUDP()\n"); r->Sock = NewUDP(r->Port); if (r->Sock != NULL) { // Wait success break; } // Wait failure Debug("Failed to NewUDP.\n"); Wait(r->Event, LISTEN_RETRY_TIME); // Stop flag inspection if (r->Halt) { Debug("UDP Halt.\n"); return; } } r->Status = LISTENER_STATUS_LISTENING; Debug("Start Listening at UDP Port %u.\n", r->Sock->LocalPort); // Stop flag inspection if (r->Halt) { // Stop goto STOP; } // Allocate the buffer area data = Malloc(UDP_PACKET_SIZE); // Read the next packet while (true) { IP src_ip; UINT src_port; UINT size; SOCKSET set; InitSockSet(&set); AddSockSet(&set, r->Sock); Select(&set, SELECT_TIME, NULL, NULL); size = RecvFrom(r->Sock, &src_ip, &src_port, data, UDP_PACKET_SIZE); if (((size == 0) && (r->Sock->IgnoreRecvErr == false)) || r->Halt) { // Error has occurred STOP: Disconnect(r->Sock); ReleaseSock(r->Sock); r->Sock = NULL; Debug("UDP Listen Stopped.\n"); Free(data); break; } // Received an UDP packet if (size != SOCK_LATER) { UDPReceivedPacket(r->Cedar, r->Sock, &src_ip, src_port, data, size); } } } }
// 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); } }
// Wait for connection request void AcWaitForRequest(AZURE_CLIENT *ac, SOCK *s, AZURE_PARAM *param) { // Validate arguments if (ac == NULL || s == NULL || param == NULL) { return; } while (ac->Halt == false) { UCHAR uc; // Receive 1 byte if (RecvAll(s, &uc, 1, false) == 0) { break; } if (uc != 0) { // Receive a Pack PACK *p = RecvPackWithHash(s); if (p == NULL) { break; } else { // Verify contents of Pack char opcode[MAX_SIZE]; char cipher_name[MAX_SIZE]; char hostname[MAX_SIZE]; PackGetStr(p, "opcode", opcode, sizeof(opcode)); PackGetStr(p, "cipher_name", cipher_name, sizeof(cipher_name)); PackGetStr(p, "hostname", hostname, sizeof(hostname)); if (StrCmpi(opcode, "relay") == 0) { IP client_ip, server_ip; UINT client_port; UINT server_port; UCHAR session_id[SHA1_SIZE]; if (PackGetIp(p, "client_ip", &client_ip) && PackGetIp(p, "server_ip", &server_ip) && PackGetData2(p, "session_id", session_id, sizeof(session_id))) { client_port = PackGetInt(p, "client_port"); server_port = PackGetInt(p, "server_port"); if (client_port != 0 && server_port != 0) { SOCK *ns; Debug("Connect Request from %r:%u\n", &client_ip, client_port); // Create new socket and connect VPN Azure Server if (ac->DDnsStatusCopy.InternetSetting.ProxyType == PROXY_DIRECT) { ns = ConnectEx2(ac->DDnsStatusCopy.CurrentAzureIp, AZURE_SERVER_PORT, 0, (bool *)&ac->Halt); } else { ns = WpcSockConnect2(ac->DDnsStatusCopy.CurrentAzureIp, AZURE_SERVER_PORT, &ac->DDnsStatusCopy.InternetSetting, NULL, AZURE_VIA_PROXY_TIMEOUT); } if (ns == NULL) { Debug("Connect Error.\n"); } else { Debug("Connected to the relay server.\n"); SetTimeout(ns, param->DataTimeout); if (StartSSLEx(ns, NULL, NULL, true, 0, NULL)) { // Check certification char server_cert_hash_str[MAX_SIZE]; UCHAR server_cert_hash[SHA1_SIZE]; Zero(server_cert_hash, sizeof(server_cert_hash)); GetXDigest(ns->RemoteX, server_cert_hash, true); BinToStr(server_cert_hash_str, sizeof(server_cert_hash_str), server_cert_hash, SHA1_SIZE); if (IsEmptyStr(ac->DDnsStatusCopy.AzureCertHash) || StrCmpi(server_cert_hash_str, ac->DDnsStatusCopy.AzureCertHash) == 0) { if (SendAll(ns, AZURE_PROTOCOL_DATA_SIANGTURE, 24, true)) { PACK *p2 = NewPack(); PackAddStr(p2, "hostname", hostname); PackAddData(p2, "session_id", session_id, sizeof(session_id)); if (SendPackWithHash(ns, p2)) { UCHAR uc; if (RecvAll(ns, &uc, 1, true) != false) { if (uc != 0) { SOCK *accept_sock = GetReverseListeningSock(ac->Cedar); if (accept_sock != NULL) { AddRef(ns->ref); SetTimeout(ns, INFINITE); Copy(&ns->Reverse_MyServerGlobalIp, &server_ip, sizeof(IP)); ns->Reverse_MyServerPort = server_port; InjectNewReverseSocketToAccept(accept_sock, ns, &client_ip, client_port); ReleaseSock(accept_sock); } } } } FreePack(p2); } } } ReleaseSock(ns); } } } } FreePack(p); } } // Send 1 byte uc = 0; if (SendAll(s, &uc, 1, false) == 0) { break; } } }
// 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; }
// TCP listener main loop void ListenerTCPMainLoop(LISTENER *r) { SOCK *new_sock; SOCK *s; // Validate arguments if (r == NULL) { return; } Debug("ListenerTCPMainLoop Starts.\n"); r->Status = LISTENER_STATUS_TRYING; while (true) { bool first_failed = true; Debug("Status = LISTENER_STATUS_TRYING\n"); r->Status = LISTENER_STATUS_TRYING; // Try to Listen while (true) { UINT interval; // Stop flag inspection if (r->Halt) { // Stop return; } s = NULL; if (r->Protocol == LISTENER_TCP) { if (r->ShadowIPv6 == false) { s = ListenEx2(r->Port, r->LocalOnly, r->EnableConditionalAccept); } else { s = ListenEx6(r->Port, r->LocalOnly); } } else if (r->Protocol == LISTENER_INPROC) { s = ListenInProc(); } else if (r->Protocol == LISTENER_RUDP) { s = ListenRUDPEx(VPN_RUDP_SVC_NAME, NULL, ListenerRUDPRpcRecvProc, NULL, 0, false, false, r->NatTGlobalUdpPort, r->RandPortId); } else if (r->Protocol == LISTENER_ICMP) { s = ListenRUDP(VPN_RUDP_SVC_NAME, NULL, ListenerRUDPRpcRecvProc, NULL, MAKE_SPECIAL_PORT(IP_PROTO_ICMPV4), true, false); } else if (r->Protocol == LISTENER_DNS) { s = ListenRUDP(VPN_RUDP_SVC_NAME, NULL, ListenerRUDPRpcRecvProc, NULL, 53, true, true); } else if (r->Protocol == LISTENER_REVERSE) { s = ListenReverse(); } if (s != NULL) { // Listen success AddRef(s->ref); Lock(r->lock); { r->Sock = s; } Unlock(r->lock); if (r->ShadowIPv6 == false && r->Protocol == LISTENER_TCP) { SLog(r->Cedar, "LS_LISTENER_START_2", r->Port); } break; } // Listen failure if (first_failed) { first_failed = false; if (r->ShadowIPv6 == false && r->Protocol == LISTENER_TCP) { SLog(r->Cedar, "LS_LISTENER_START_3", r->Port, LISTEN_RETRY_TIME / 1000); } } interval = LISTEN_RETRY_TIME; if (r->ShadowIPv6) { if (IsIPv6Supported() == false) { interval = LISTEN_RETRY_TIME_NOIPV6; Debug("IPv6 is not supported.\n"); } } Wait(r->Event, interval); // Stop flag inspection if (r->Halt) { // Stop Debug("Listener Halt.\n"); return; } } r->Status = LISTENER_STATUS_LISTENING; Debug("Status = LISTENER_STATUS_LISTENING\n"); // Stop flag inspection if (r->Halt) { // Stop goto STOP; } // Accpet loop while (true) { // Accept Debug("Accept()\n"); new_sock = Accept(s); if (new_sock != NULL) { // Accept success Debug("Accepted.\n"); TCPAccepted(r, new_sock); ReleaseSock(new_sock); } else { STOP: Debug("Accept Canceled.\n"); // Failed to accept (socket is destroyed) // Close the listening socket Disconnect(s); ReleaseSock(s); s = NULL; Lock(r->lock); { if (r->Sock != NULL) { s = r->Sock; r->Sock = NULL; } } Unlock(r->lock); if (s != NULL) { ReleaseSock(s); } s = NULL; break; } } // Stop flag inspection if (r->Halt) { // Stop Debug("Listener Halt.\n"); return; } } }
// Connection for NAT administrator RPC *NatAdminConnect(CEDAR *cedar, char *hostname, UINT port, void *hashed_password, UINT *err) { UCHAR secure_password[SHA1_SIZE]; UCHAR random[SHA1_SIZE]; SOCK *sock; RPC *rpc; PACK *p; UINT error; // Validate arguments if (cedar == NULL || hostname == NULL || port == 0 || hashed_password == NULL || err == NULL) { if (err != NULL) { *err = ERR_INTERNAL_ERROR; } return NULL; } // Connection sock = Connect(hostname, port); if (sock == NULL) { *err = ERR_CONNECT_FAILED; return NULL; } if (StartSSL(sock, NULL, NULL) == false) { *err = ERR_PROTOCOL_ERROR; ReleaseSock(sock); return NULL; } SetTimeout(sock, 5000); p = HttpClientRecv(sock); if (p == NULL) { *err = ERR_DISCONNECTED; ReleaseSock(sock); return NULL; } if (PackGetData2(p, "auth_random", random, SHA1_SIZE) == false) { FreePack(p); *err = ERR_PROTOCOL_ERROR; ReleaseSock(sock); return NULL; } FreePack(p); SecurePassword(secure_password, hashed_password, random); p = NewPack(); PackAddData(p, "secure_password", secure_password, SHA1_SIZE); if (HttpClientSend(sock, p) == false) { FreePack(p); *err = ERR_DISCONNECTED; ReleaseSock(sock); return NULL; } FreePack(p); p = HttpClientRecv(sock); if (p == NULL) { *err = ERR_DISCONNECTED; ReleaseSock(sock); return NULL; } error = GetErrorFromPack(p); FreePack(p); if (error != ERR_NO_ERROR) { *err = error; ReleaseSock(sock); return NULL; } SetTimeout(sock, TIMEOUT_INFINITE); rpc = StartRpcClient(sock, NULL); ReleaseSock(sock); return rpc; }
// Management port Listen thread void NiListenThread(THREAD *thread, void *param) { NAT *n = (NAT *)param; SOCK *a; UINT i; bool b = false; // Validate arguments if (thread == NULL || param == NULL) { return; } // Initialize the management list n->AdminList = NewList(NULL); while (true) { a = Listen(DEFAULT_NAT_ADMIN_PORT); if (b == false) { b = true; NoticeThreadInit(thread); } if (a != NULL) { break; } Wait(n->HaltEvent, NAT_ADMIN_PORT_LISTEN_INTERVAL); if (n->Halt) { return; } } n->AdminListenSock = a; AddRef(a->ref); // Waiting while (true) { SOCK *s = Accept(a); THREAD *t; NAT_ADMIN *admin; if (s == NULL) { break; } if (n->Halt) { ReleaseSock(s); break; } admin = ZeroMalloc(sizeof(NAT_ADMIN)); admin->Nat = n; admin->Sock = s; t = NewThread(NiAdminThread, admin); WaitThreadInit(t); ReleaseThread(t); } // Disconnect all management connections LockList(n->AdminList); { for (i = 0;i < LIST_NUM(n->AdminList);i++) { NAT_ADMIN *a = LIST_DATA(n->AdminList, i); Disconnect(a->Sock); WaitThread(a->Thread, INFINITE); ReleaseThread(a->Thread); ReleaseSock(a->Sock); Free(a); } } UnlockList(n->AdminList); ReleaseList(n->AdminList); ReleaseSock(a); }
// Shutdown the Listener void StopListener(LISTENER *r) { UINT port; SOCK *s = NULL; // Validate arguments if (r == NULL) { return; } Lock(r->lock); if (r->Halt) { Unlock(r->lock); return; } // Stop flag set r->Halt = true; if (r->Sock != NULL) { s = r->Sock; AddRef(s->ref); } Unlock(r->lock); port = r->Port; if (r->ShadowIPv6 == false && r->Protocol == LISTENER_TCP) { SLog(r->Cedar, "LS_LISTENER_STOP_1", port); } // Close the socket if (s != NULL) { Disconnect(s); ReleaseSock(s); s = NULL; } // Set the event Set(r->Event); // Wait for stopping the thread WaitThread(r->Thread, INFINITE); // Stop the shadow listener if (r->ShadowIPv6 == false) { if (r->ShadowListener != NULL) { StopListener(r->ShadowListener); ReleaseListener(r->ShadowListener); r->ShadowListener = NULL; } } if (r->ShadowIPv6 == false && r->Protocol == LISTENER_TCP) { SLog(r->Cedar, "LS_LISTENER_STOP_2", port); } }
// Listener thread void ElListenerProc(THREAD *thread, void *param) { TCP_ACCEPTED_PARAM *data = (TCP_ACCEPTED_PARAM *)param; EL *e; SOCK *s; UCHAR rand[SHA1_SIZE]; UCHAR pass1[SHA1_SIZE], pass2[SHA1_SIZE]; // Validate arguments if (data == NULL || thread == NULL) { return; } e = (EL *)data->r->ThreadParam; s = data->s; AddRef(s->ref); SetTimeout(s, 5000); LockList(e->AdminThreadList); { AddRef(thread->ref); AddRef(s->ref); Insert(e->AdminThreadList, thread); Insert(e->AdminSockList, s); } UnlockList(e->AdminThreadList); NoticeThreadInit(thread); // Submit a challenge Rand(rand, sizeof(rand)); SendAll(s, rand, sizeof(rand), false); // Receive a response SecurePassword(pass1, e->HashedPassword, rand); Zero(pass2, sizeof(pass2)); RecvAll(s, pass2, sizeof(pass2), false); if (Cmp(pass1, pass2, SHA1_SIZE) != 0) { // Password incorrect bool code = false; code = Endian32(code); SendAll(s, &code, sizeof(code), false); } else { // Password match bool code = true; RPC *r; code = Endian32(code); SendAll(s, &code, sizeof(code), false); SetTimeout(s, INFINITE); // Start operation as a RPC server r = StartRpcServer(s, ElRpcServer, e); RpcServer(r); RpcFree(r); } Disconnect(s); ReleaseSock(s); LockList(e->AdminThreadList); { if (Delete(e->AdminThreadList, thread)) { ReleaseThread(thread); } if (Delete(e->AdminSockList, s)) { ReleaseSock(s); } } UnlockList(e->AdminThreadList); }
BUF *HttpRequestEx2(URL_DATA *data, INTERNET_SETTING *setting, UINT timeout_connect, UINT timeout_comm, UINT *error_code, bool check_ssl_trust, char *post_data, WPC_RECV_CALLBACK *recv_callback, void *recv_callback_param, void *sha1_cert_hash, bool *cancel, UINT max_recv_size, char *header_name, char *header_value) { WPC_CONNECT con; SOCK *s; HTTP_HEADER *h; bool use_http_proxy = false; char target[MAX_SIZE * 4]; char *send_str; BUF *send_buf; BUF *recv_buf; UINT http_error_code; char len_str[100]; UINT content_len; void *socket_buffer; UINT socket_buffer_size = WPC_RECV_BUF_SIZE; UINT num_continue = 0; INTERNET_SETTING wt_setting; // Validate arguments if (data == NULL) { return NULL; } if (setting == NULL) { Zero(&wt_setting, sizeof(wt_setting)); setting = &wt_setting; } if (error_code == NULL) { static UINT ret = 0; error_code = &ret; } if (timeout_comm == 0) { timeout_comm = WPC_TIMEOUT; } // Connection Zero(&con, sizeof(con)); StrCpy(con.HostName, sizeof(con.HostName), data->HostName); con.Port = data->Port; con.ProxyType = setting->ProxyType; StrCpy(con.ProxyHostName, sizeof(con.ProxyHostName), setting->ProxyHostName); con.ProxyPort = setting->ProxyPort; StrCpy(con.ProxyUsername, sizeof(con.ProxyUsername), setting->ProxyUsername); StrCpy(con.ProxyPassword, sizeof(con.ProxyPassword), setting->ProxyPassword); if (setting->ProxyType != PROXY_HTTP || data->Secure) { use_http_proxy = false; StrCpy(target, sizeof(target), data->Target); } else { use_http_proxy = true; CreateUrl(target, sizeof(target), data); } if (use_http_proxy == false) { // If the connection is not via HTTP Proxy, or is a SSL connection even via HTTP Proxy s = WpcSockConnectEx(&con, error_code, timeout_connect, cancel); } else { // If the connection is not SSL via HTTP Proxy s = TcpConnectEx3(con.ProxyHostName, con.ProxyPort, timeout_connect, cancel, NULL, true, NULL, false, false, NULL); if (s == NULL) { *error_code = ERR_PROXY_CONNECT_FAILED; } } if (s == NULL) { return NULL; } if (data->Secure) { // Start the SSL communication if (StartSSLEx(s, NULL, NULL, true, 0, NULL) == false) { // SSL connection failed *error_code = ERR_PROTOCOL_ERROR; Disconnect(s); ReleaseSock(s); return NULL; } if (sha1_cert_hash != NULL) { UCHAR hash[SHA1_SIZE]; Zero(hash, sizeof(hash)); GetXDigest(s->RemoteX, hash, true); if (Cmp(hash, sha1_cert_hash, SHA1_SIZE) != 0) { // Destination certificate hash mismatch *error_code = ERR_CERT_NOT_TRUSTED; Disconnect(s); ReleaseSock(s); return NULL; } } } // Timeout setting SetTimeout(s, timeout_comm); // Generate a request h = NewHttpHeader(data->Method, target, use_http_proxy ? "HTTP/1.0" : "HTTP/1.1"); AddHttpValue(h, NewHttpValue("Keep-Alive", HTTP_KEEP_ALIVE)); AddHttpValue(h, NewHttpValue("Connection", "Keep-Alive")); AddHttpValue(h, NewHttpValue("Accept-Language", "ja")); AddHttpValue(h, NewHttpValue("User-Agent", WPC_USER_AGENT)); AddHttpValue(h, NewHttpValue("Pragma", "no-cache")); AddHttpValue(h, NewHttpValue("Cache-Control", "no-cache")); AddHttpValue(h, NewHttpValue("Host", data->HeaderHostName)); if (IsEmptyStr(header_name) == false && IsEmptyStr(header_value) == false) { AddHttpValue(h, NewHttpValue(header_name, header_value)); } if (IsEmptyStr(data->Referer) == false) { AddHttpValue(h, NewHttpValue("Referer", data->Referer)); } if (StrCmpi(data->Method, WPC_HTTP_POST_NAME) == 0) { ToStr(len_str, StrLen(post_data)); AddHttpValue(h, NewHttpValue("Content-Type", "application/x-www-form-urlencoded")); AddHttpValue(h, NewHttpValue("Content-Length", len_str)); } if (IsEmptyStr(data->AdditionalHeaderName) == false && IsEmptyStr(data->AdditionalHeaderValue) == false) { AddHttpValue(h, NewHttpValue(data->AdditionalHeaderName, data->AdditionalHeaderValue)); } if (use_http_proxy) { AddHttpValue(h, NewHttpValue("Proxy-Connection", "Keep-Alive")); if (IsEmptyStr(setting->ProxyUsername) == false || IsEmptyStr(setting->ProxyPassword) == false) { char auth_tmp_str[MAX_SIZE], auth_b64_str[MAX_SIZE * 2]; char basic_str[MAX_SIZE * 2]; // Generate the authentication string Format(auth_tmp_str, sizeof(auth_tmp_str), "%s:%s", setting->ProxyUsername, setting->ProxyPassword); // Base64 encode Zero(auth_b64_str, sizeof(auth_b64_str)); Encode64(auth_b64_str, auth_tmp_str); Format(basic_str, sizeof(basic_str), "Basic %s", auth_b64_str); AddHttpValue(h, NewHttpValue("Proxy-Authorization", basic_str)); } } send_str = HttpHeaderToStr(h); FreeHttpHeader(h); send_buf = NewBuf(); WriteBuf(send_buf, send_str, StrLen(send_str)); Free(send_str); // Append to the sending data in the case of POST if (StrCmpi(data->Method, WPC_HTTP_POST_NAME) == 0) { WriteBuf(send_buf, post_data, StrLen(post_data)); } // Send if (SendAll(s, send_buf->Buf, send_buf->Size, s->SecureMode) == false) { Disconnect(s); ReleaseSock(s); FreeBuf(send_buf); *error_code = ERR_DISCONNECTED; return NULL; } FreeBuf(send_buf); CONT: // Receive h = RecvHttpHeader(s); if (h == NULL) { Disconnect(s); ReleaseSock(s); *error_code = ERR_DISCONNECTED; return NULL; } http_error_code = 0; if (StrLen(h->Method) == 8) { if (Cmp(h->Method, "HTTP/1.", 7) == 0) { http_error_code = ToInt(h->Target); } } *error_code = ERR_NO_ERROR; switch (http_error_code) { case 401: case 407: // Proxy authentication error *error_code = ERR_PROXY_AUTH_FAILED; break; case 404: // 404 File Not Found *error_code = ERR_OBJECT_NOT_FOUND; break; case 100: // Continue num_continue++; if (num_continue >= 10) { goto DEF; } FreeHttpHeader(h); goto CONT; case 200: // Success break; default: // Protocol error DEF: *error_code = ERR_PROTOCOL_ERROR; break; } if (*error_code != ERR_NO_ERROR) { // An error has occured Disconnect(s); ReleaseSock(s); FreeHttpHeader(h); return NULL; } // Get the length of the content content_len = GetContentLength(h); if (max_recv_size != 0) { content_len = MIN(content_len, max_recv_size); } FreeHttpHeader(h); socket_buffer = Malloc(socket_buffer_size); // Receive the content recv_buf = NewBuf(); while (true) { UINT recvsize = MIN(socket_buffer_size, content_len - recv_buf->Size); UINT size; if (recv_callback != NULL) { if (recv_callback(recv_callback_param, content_len, recv_buf->Size, recv_buf) == false) { // Cancel the reception *error_code = ERR_USER_CANCEL; goto RECV_CANCEL; } } if (recvsize == 0) { break; } size = Recv(s, socket_buffer, recvsize, s->SecureMode); if (size == 0) { // Disconnected *error_code = ERR_DISCONNECTED; RECV_CANCEL: FreeBuf(recv_buf); Free(socket_buffer); Disconnect(s); ReleaseSock(s); return NULL; } WriteBuf(recv_buf, socket_buffer, size); } SeekBuf(recv_buf, 0, 0); Free(socket_buffer); Disconnect(s); ReleaseSock(s); // Transmission return recv_buf; }
// Management thread void NiAdminThread(THREAD *thread, void *param) { NAT_ADMIN *a = (NAT_ADMIN *)param; NAT *n; SOCK *s; UCHAR random[SHA1_SIZE]; UINT err; // Validate arguments if (thread == NULL || param == NULL) { return; } // Random number generation Rand(random, sizeof(random)); a->Thread = thread; AddRef(a->Thread->ref); s = a->Sock; AddRef(s->ref); n = a->Nat; LockList(n->AdminList); { Add(n->AdminList, a); } UnlockList(n->AdminList); NoticeThreadInit(thread); err = ERR_AUTH_FAILED; if (StartSSL(s, n->AdminX, n->AdminK)) { PACK *p; // Send the random number p = NewPack(); PackAddData(p, "auth_random", random, sizeof(random)); if (HttpServerSend(s, p)) { PACK *p; // Receive a password p = HttpServerRecv(s); if (p != NULL) { UCHAR secure_password[SHA1_SIZE]; UCHAR secure_check[SHA1_SIZE]; if (PackGetData2(p, "secure_password", secure_password, sizeof(secure_password))) { SecurePassword(secure_check, n->HashedPassword, random); if (Cmp(secure_check, secure_password, SHA1_SIZE) == 0) { UCHAR test[SHA1_SIZE]; // Password match Hash(test, "", 0, true); SecurePassword(test, test, random); #if 0 if (Cmp(test, secure_check, SHA1_SIZE) == 0 && s->RemoteIP.addr[0] != 127) { // A client can not connect from the outside with blank password err = ERR_NULL_PASSWORD_LOCAL_ONLY; } else #endif { // Successful connection err = ERR_NO_ERROR; NiAdminMain(n, s); } } } FreePack(p); } } FreePack(p); if (err != ERR_NO_ERROR) { p = PackError(err); HttpServerSend(s, p); FreePack(p); } } Disconnect(s); ReleaseSock(s); }
// 管理スレッド void NiAdminThread(THREAD *thread, void *param) { NAT_ADMIN *a = (NAT_ADMIN *)param; NAT *n; SOCK *s; UCHAR random[SHA1_SIZE]; UINT err; // 引数チェック if (thread == NULL || param == NULL) { return; } // 乱数生成 Rand(random, sizeof(random)); a->Thread = thread; AddRef(a->Thread->ref); s = a->Sock; AddRef(s->ref); n = a->Nat; LockList(n->AdminList); { Add(n->AdminList, a); } UnlockList(n->AdminList); NoticeThreadInit(thread); err = ERR_AUTH_FAILED; if (StartSSL(s, n->AdminX, n->AdminK)) { PACK *p; // 乱数を送信する p = NewPack(); PackAddData(p, "auth_random", random, sizeof(random)); if (HttpServerSend(s, p)) { PACK *p; // パスワードを受け取る p = HttpServerRecv(s); if (p != NULL) { UCHAR secure_password[SHA1_SIZE]; UCHAR secure_check[SHA1_SIZE]; if (PackGetData2(p, "secure_password", secure_password, sizeof(secure_password))) { SecurePassword(secure_check, n->HashedPassword, random); if (Cmp(secure_check, secure_password, SHA1_SIZE) == 0) { UCHAR test[SHA1_SIZE]; // パスワード一致 Hash(test, "", 0, true); SecurePassword(test, test, random); #if 0 if (Cmp(test, secure_check, SHA1_SIZE) == 0 && s->RemoteIP.addr[0] != 127) { // 空白パスワードは外部から接続できない err = ERR_NULL_PASSWORD_LOCAL_ONLY; } else #endif { // 接続成功 err = ERR_NO_ERROR; NiAdminMain(n, s); } } } FreePack(p); } } FreePack(p); if (err != ERR_NO_ERROR) { p = PackError(err); HttpServerSend(s, p); FreePack(p); } } Disconnect(s); ReleaseSock(s); }