// NAT-T server IP address acquisition thread void NatT_GetIpThread(THREAD *thread, void *param) { UDP_ACCEL *a; char hostname[MAX_SIZE]; static IP dummy_ip = {0}; UINT num_retry = 0; // Validate arguments if (thread == NULL || param == NULL) { return; } a = (UDP_ACCEL *)param; if (IsZeroIP(&dummy_ip)) { SetIP(&dummy_ip, 11, Rand8(), Rand8(), Rand8()); } RUDPGetRegisterHostNameByIP(hostname, sizeof(hostname), &dummy_ip); while (a->NatT_Halt == false) { IP ip; UINT wait_time = UDP_NAT_T_GET_IP_INTERVAL; // Get the IP address bool ret = GetIP4Ex(&ip, hostname, 0, &a->NatT_Halt); if (ret && (IsZeroIp(&ip) == false)) { char tmp[128]; // Success to get Lock(a->NatT_Lock); { Copy(&a->NatT_IP, &ip, sizeof(IP)); } Unlock(a->NatT_Lock); IPToStr(tmp, sizeof(tmp), &ip); Debug("NAT-T IP Address Resolved: %s = %s\n", hostname, tmp); a->NatT_IP_Changed = true; break; } // Fail to get num_retry++; wait_time = (UINT)(MIN((UINT64)UDP_NAT_T_GET_IP_INTERVAL * (UINT64)num_retry, (UINT64)UDP_NAT_T_GET_IP_INTERVAL_MAX)); Wait(a->NatT_HaltEvent, wait_time); } }
// Determine whether transmission is possible bool UdpAccelIsSendReady(UDP_ACCEL *a, bool check_keepalive) { UINT64 timeout_value; // Validate arguments if (a == NULL) { return false; } if (a->Inited == false) { return false; } if (a->YourPort == 0) { return false; } if (IsZeroIp(&a->YourIp)) { return false; } timeout_value = UDP_ACCELERATION_KEEPALIVE_TIMEOUT; if (a->FastDetect) { timeout_value = UDP_ACCELERATION_KEEPALIVE_TIMEOUT_FAST; } if (check_keepalive) { if (a->LastRecvTick == 0 || ((a->LastRecvTick + timeout_value) < a->Now)) { a->FirstStableReceiveTick = 0; return false; } else { if ((a->FirstStableReceiveTick + (UINT64)UDP_ACCELERATION_REQUIRE_CONTINUOUS) <= a->Now) { return true; } else { return false; } } } return true; }
// NAT-T server IP address acquisition thread void NatT_GetIpThread(THREAD *thread, void *param) { UDP_ACCEL *a; char hostname[MAX_SIZE]; // Validate arguments if (thread == NULL || param == NULL) { return; } a = (UDP_ACCEL *)param; RUDPGetRegisterHostNameByIP(hostname, sizeof(hostname), NULL); while (a->NatT_Halt == false) { IP ip; // Get the IP address bool ret = GetIP4Ex(&ip, hostname, 0, &a->NatT_Halt); if (ret && (IsZeroIp(&ip) == false)) { char tmp[128]; // Success to get Lock(a->NatT_Lock); { Copy(&a->NatT_IP, &ip, sizeof(IP)); } Unlock(a->NatT_Lock); IPToStr(tmp, sizeof(tmp), &ip); Debug("NAT-T IP Address Resolved: %s = %s\n", hostname, tmp); a->NatT_IP_Changed = true; break; } // Fail to get Wait(a->NatT_HaltEvent, UDP_NAT_T_GET_IP_INTERVAL); } }
// 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(); } }
// Polling process void UdpAccelPoll(UDP_ACCEL *a) { UCHAR *tmp = a->TmpBuf; IP nat_t_ip; UINT num_ignore_errors = 0; // Validate arguments if (a == NULL) { return; } Lock(a->NatT_Lock); { Copy(&nat_t_ip, &a->NatT_IP, sizeof(IP)); } Unlock(a->NatT_Lock); if (IsZeroIp(&nat_t_ip) == false) { // Release the thread which gets the IP address of the NAT-T server because it is no longer needed if (a->NatT_GetIpThread != NULL) { WaitThread(a->NatT_GetIpThread, INFINITE); ReleaseThread(a->NatT_GetIpThread); a->NatT_GetIpThread = NULL; } } // Receive a new UDP packet while (true) { IP src_ip; UINT src_port; UINT ret; ret = RecvFrom(a->UdpSock, &src_ip, &src_port, tmp, UDP_ACCELERATION_TMP_BUF_SIZE); if (ret != 0 && ret != SOCK_LATER) { if (a->UseUdpIpQuery && a->UdpIpQueryPacketSize >= 8 && CmpIpAddr(&a->UdpIpQueryHost, &src_ip) == 0 && src_port == a->UdpIpQueryPort) { // Receive a response of the query for IP and port number IP my_ip = {0}; UINT myport = 0; BUF *b = MemToBuf(a->UdpIpQueryPacketData, a->UdpIpQueryPacketSize); FreeBuf(b); } else if (IsZeroIp(&nat_t_ip) == false && CmpIpAddr(&nat_t_ip, &src_ip) == 0 && src_port == UDP_NAT_T_PORT) { // Receive a response from the NAT-T server IP my_ip; UINT myport; if (RUDPParseIPAndPortStr(tmp, ret, &my_ip, &myport)) { if (myport >= 1 && myport <= 65535) { if (a->MyPortByNatTServer != myport) { a->MyPortByNatTServer = myport; a->MyPortByNatTServerChanged = true; a->CommToNatT_NumFail = 0; Debug("NAT-T: MyPort = %u\n", myport); } } } /* BUF *b = NewBuf(); PACK *p; WriteBuf(b, tmp, ret); SeekBufToBegin(b); p = BufToPack(b); if (p != NULL) { if (PackCmpStr(p, "opcode", "query_for_nat_traversal")) { if (PackGetBool(p, "ok")) { if (PackGetInt64(p, "tran_id") == a->NatT_TranId) { UINT myport = PackGetInt(p, "your_port"); if (myport >= 1 && myport <= 65535) { if (a->MyPortByNatTServer != myport) { a->MyPortByNatTServer = myport; a->MyPortByNatTServerChanged = true; Debug("NAT-T: MyPort = %u\n", myport); } } } } } FreePack(p); } FreeBuf(b);*/ } else { BLOCK *b = UdpAccelProcessRecvPacket(a, tmp, ret, &src_ip, src_port); //Debug("UDP Recv: %u %u %u\n", ret, (b == NULL ? 0 : b->Size), (b == NULL ? 0 : b->Compressed)); /*if (b != NULL) { char tmp[MAX_SIZE * 10]; BinToStr(tmp, sizeof(tmp), b->Buf, b->Size); Debug("Recv Pkt: %s\n", tmp); }*/ if (b != NULL) { // Receive a packet InsertQueue(a->RecvBlockQueue, b); } } } else { if (ret == 0) { if (a->UdpSock->IgnoreRecvErr == false) { // Serious UDP reception error occurs a->FatalError = true; break; } if ((num_ignore_errors++) >= MAX_NUM_IGNORE_ERRORS) { a->FatalError = true; break; } } else { // SOCK_LATER break; } } } // Send a Keep-Alive packet if (a->NextSendKeepAlive == 0 || (a->NextSendKeepAlive <= a->Now) || a->YourPortByNatTServerChanged) { a->YourPortByNatTServerChanged = false; if (UdpAccelIsSendReady(a, false)) { UINT rand_interval; if (a->FastDetect == false) { rand_interval = rand() % (UDP_ACCELERATION_KEEPALIVE_INTERVAL_MAX - UDP_ACCELERATION_KEEPALIVE_INTERVAL_MIN) + UDP_ACCELERATION_KEEPALIVE_INTERVAL_MIN; } else { rand_interval = rand() % (UDP_ACCELERATION_KEEPALIVE_INTERVAL_MAX_FAST - UDP_ACCELERATION_KEEPALIVE_INTERVAL_MIN_FAST) + UDP_ACCELERATION_KEEPALIVE_INTERVAL_MIN_FAST; } a->NextSendKeepAlive = a->Now + (UINT64)rand_interval; //Debug("UDP KeepAlive\n"); UdpAccelSend(a, NULL, 0, false, 1000, false); } } // Send a NAT-T request packet (Only if the connection by UDP has not be established yet) if (a->NoNatT == false) { // In the usual case if (IsZeroIp(&nat_t_ip) == false) { if (UdpAccelIsSendReady(a, true) == false) { if (a->NextPerformNatTTick == 0 || (a->NextPerformNatTTick <= a->Now)) { UINT rand_interval; UCHAR c = 'B'; a->CommToNatT_NumFail++; rand_interval = UDP_NAT_T_INTERVAL_INITIAL * MIN(a->CommToNatT_NumFail, UDP_NAT_T_INTERVAL_FAIL_MAX); //PACK *p = NewPack(); //BUF *b; if (a->MyPortByNatTServer != 0) { rand_interval = GenRandInterval(UDP_NAT_T_INTERVAL_MIN, UDP_NAT_T_INTERVAL_MAX); } a->NextPerformNatTTick = a->Now + (UINT64)rand_interval; // Generate the request packet /*PackAddStr(p, "description", UDP_NAT_T_SIGNATURE); PackAddStr(p, "opcode", "query_for_nat_traversal"); PackAddInt64(p, "tran_id", a->NatT_TranId); b = PackToBuf(p); FreePack(p);*/ // Send the request packet SendTo(a->UdpSock, &nat_t_ip, UDP_NAT_T_PORT, &c, 1); //FreeBuf(b); } } else { a->NextPerformNatTTick = 0; a->CommToNatT_NumFail = 0; } } } else { // NAT_T is disabled, but there is a reference host (such as VGC) if (a->UseUdpIpQuery || a->UseSuperRelayQuery) { } } }