// 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); } }
// Update the IP address list of the host void IPsecWin7UpdateHostIPAddressList(IPSEC_WIN7 *w) { LIST *o; UINT i; BUF *buf; UINT retsize; // Validate arguments if (w == NULL) { return; } o = GetHostIPAddressList(); if (o == NULL) { return; } buf = NewBuf(); for (i = 0;i < LIST_NUM(o);i++) { IP *ip = LIST_DATA(o, i); WFP_LOCAL_IP a; Zero(&a, sizeof(a)); // Exclude any IPs or localhost IP if (IsZeroIP(ip) == false && IsLocalHostIP(ip) == false) { if (IsIP4(ip)) { a.IpVersion = 4; Copy(a.IpAddress.IPv4Address, ip->addr, 4); } else { a.IpVersion = 6; Copy(a.IpAddress.IPv6Address, ip->ipv6_addr, 16); } WriteBuf(buf, &a, sizeof(WFP_LOCAL_IP)); } } if (WriteFile(w->hDriverFile, buf->Buf, buf->Size, &retsize, NULL) == false) { Debug("WriteFile to the driver failed. %u\n", GetLastError()); } FreeHostIPAddressList(o); FreeBuf(buf); }
// Start tracking of the routing table void RouteTrackingStart(SESSION *s) { VLAN *v; ROUTE_TRACKING *t; UINT if_id = 0; ROUTE_ENTRY *e; ROUTE_ENTRY *dns = NULL; ROUTE_ENTRY *route_to_real_server_global = NULL; char tmp[64]; UINT exclude_if_id = 0; bool already_exists = false; bool already_exists_by_other_account = false; IP eight; // Validate arguments if (s == NULL) { return; } v = (VLAN *)s->PacketAdapter->Param; if (v->RouteState != NULL) { return; } // Get the interface ID of the virtual LAN card if_id = GetInstanceId(v->InstanceName); Debug("[InstanceId of %s] = 0x%x\n", v->InstanceName, if_id); if (MsIsVista()) { // The routing table by the virtual LAN card body should be // excluded explicitly in Windows Vista exclude_if_id = if_id; } // Get the route to the server e = GetBestRouteEntryEx(&s->ServerIP, exclude_if_id); if (e == NULL) { // Acquisition failure Debug("Failed to get GetBestRouteEntry().\n"); return; } IPToStr(tmp, sizeof(tmp), &e->GatewayIP); Debug("GetBestRouteEntry() Succeed. [Gateway: %s]\n", tmp); // Add a route if (MsIsVista()) { e->Metric = e->OldIfMetric; } if (AddRouteEntryEx(e, &already_exists) == false) { FreeRouteEntry(e); e = NULL; } Debug("already_exists: %u\n", already_exists); if (already_exists) { if (s->Cedar->Client != NULL && s->Account != NULL) { UINT i; ACCOUNT *a; for (i = 0;i < LIST_NUM(s->Cedar->Client->AccountList);i++) { a = LIST_DATA(s->Cedar->Client->AccountList, i); Lock(a->lock); { SESSION *sess = a->ClientSession; if (sess != NULL && sess != s) { VLAN *v = sess->PacketAdapter->Param; if (v != NULL) { ROUTE_TRACKING *tr = v->RouteState; if (tr != NULL && e != NULL) { if (Cmp(tr->RouteToServer, e, sizeof(ROUTE_ENTRY)) == 0) { already_exists_by_other_account = true; } } } } } Unlock(a->lock); } } if (already_exists_by_other_account) { Debug("already_exists_by_other_account = %u\n", already_exists_by_other_account); already_exists = false; } } // Get the routing table to the DNS server // (If the DNS server is this PC itself, there's no need to get) if (IsZeroIP(&s->DefaultDns) == false) { if (IsMyIPAddress(&s->DefaultDns) == false) { dns = GetBestRouteEntryEx(&s->DefaultDns, exclude_if_id); if (dns == NULL) { // Getting failure Debug("Failed to get GetBestRouteEntry DNS.\n"); } else { // Add a route if (MsIsVista()) { dns->Metric = dns->OldIfMetric; if (AddRouteEntry(dns) == false) { FreeRouteEntry(dns); dns = NULL; } } } } } if (s->IsAzureSession && IsZeroIP(&s->AzureRealServerGlobalIp) == false) { // Add also a static route to the real server in the case of via VPN Azure if (IsMyIPAddress(&s->AzureRealServerGlobalIp) == false) { route_to_real_server_global = GetBestRouteEntryEx(&s->AzureRealServerGlobalIp, exclude_if_id); if (route_to_real_server_global != NULL) { if (MsIsVista()) { route_to_real_server_global->Metric = route_to_real_server_global->OldIfMetric; } if (AddRouteEntry(route_to_real_server_global) == false) { FreeRouteEntry(route_to_real_server_global); route_to_real_server_global = NULL; } } } } // Initialize if (s->Cedar->Client != NULL && s->Account != NULL) { Lock(s->Account->lock); } t = ZeroMalloc(sizeof(ROUTE_TRACKING)); v->RouteState = t; t->RouteToServerAlreadyExists = already_exists; t->RouteToServer = e; t->RouteToDefaultDns = dns; t->RouteToRealServerGlobal = route_to_real_server_global; t->VLanInterfaceId = if_id; t->NextTrackingTime = 0; t->DeletedDefaultGateway = NewQueue(); t->OldDefaultGatewayMetric = 0x7fffffff; if (s->Cedar->Client != NULL && s->Account != NULL) { Unlock(s->Account->lock); } // Get the route to 8.8.8.8 SetIP(&eight, 8, 8, 8, 8); t->RouteToEight = GetBestRouteEntryEx(&eight, exclude_if_id); // Get the current default DNS server to detect network changes GetDefaultDns(&t->OldDnsServer); // Get as soon as releasing the IP address in the case of using DHCP if (IsNt()) { char tmp[MAX_SIZE]; MS_ADAPTER *a; Format(tmp, sizeof(tmp), VLAN_ADAPTER_NAME_TAG, v->InstanceName); a = MsGetAdapter(tmp); if (a != NULL) { if (a->UseDhcp) { bool ret = Win32ReleaseAddressByGuidEx(a->Guid, 100); Debug("*** Win32ReleaseAddressByGuidEx = %u\n", ret); ret = Win32RenewAddressByGuidEx(a->Guid, 100); Debug("*** Win32RenewAddressByGuidEx = %u\n", ret); } MsFreeAdapter(a); } } else { // For Win9x Win32RenewDhcp9x(if_id); } // Clear the DNS cache Win32FlushDnsCache(); // Detect a change in the routing table (for only supported OS) t->RouteChange = NewRouteChange(); Debug("t->RouteChange = 0x%p\n", t->RouteChange); }
// 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; }
// Send void UdpAccelSend(UDP_ACCEL *a, UCHAR *data, UINT data_size, bool compressed, UINT max_size, bool high_priority) { UCHAR tmp[UDP_ACCELERATION_TMP_BUF_SIZE]; UCHAR *buf; UINT size; UCHAR key[UDP_ACCELERATION_PACKET_KEY_SIZE]; UINT64 ui64; USHORT us; UCHAR c; UINT current_size; UINT ui32; bool fatal_error = false; UINT r; // Validate arguments if (a == NULL || (data_size != 0 && data == NULL)) { return; } if (max_size == 0) { max_size = INFINITE; } buf = tmp; size = 0; // IV if (a->PlainTextMode == false) { // IV Copy(buf, a->NextIv, UDP_ACCELERATION_PACKET_IV_SIZE); buf += UDP_ACCELERATION_PACKET_IV_SIZE; size += UDP_ACCELERATION_PACKET_IV_SIZE; // Calculate the key UdpAccelCalcKey(key, a->MyKey, a->NextIv); if (false) { char tmp1[256]; char tmp2[256]; char tmp3[256]; BinToStr(tmp1, sizeof(tmp1), a->MyKey, sizeof(a->MyKey)); BinToStr(tmp2, sizeof(tmp2), a->NextIv, UDP_ACCELERATION_PACKET_IV_SIZE); BinToStr(tmp3, sizeof(tmp3), key, sizeof(key)); Debug("My Key : %s\n" "IV : %s\n" "Comm Key: %s\n", tmp1, tmp2, tmp3); } } // Cookie ui32 = Endian32(a->YourCookie); Copy(buf, &ui32, sizeof(UINT)); buf += sizeof(UINT); size += sizeof(UINT); // My Tick ui64 = Endian64(a->Now == 0 ? 1ULL : a->Now); Copy(buf, &ui64, sizeof(UINT64)); buf += sizeof(UINT64); size += sizeof(UINT64); // Your Tick ui64 = Endian64(a->LastRecvYourTick); Copy(buf, &ui64, sizeof(UINT64)); buf += sizeof(UINT64); size += sizeof(UINT64); // Size us = Endian16(data_size); Copy(buf, &us, sizeof(USHORT)); buf += sizeof(USHORT); size += sizeof(USHORT); // Compress Flag c = (compressed ? 1 : 0); Copy(buf, &c, sizeof(UCHAR)); buf += sizeof(UCHAR); size += sizeof(UCHAR); // Data if (data_size >= 1) { Copy(buf, data, data_size); buf += data_size; size += data_size; } if (a->PlainTextMode == false) { static UCHAR zero[UDP_ACCELERATION_PACKET_IV_SIZE] = {0}; CRYPT *c; current_size = UDP_ACCELERATION_PACKET_IV_SIZE + sizeof(UINT) + sizeof(UINT64) * 2 + sizeof(USHORT) + sizeof(UCHAR) + data_size + UDP_ACCELERATION_PACKET_IV_SIZE; if (current_size < max_size) { // Padding UCHAR pad[UDP_ACCELERATION_MAX_PADDING_SIZE]; UINT pad_size = MIN(max_size - current_size, UDP_ACCELERATION_MAX_PADDING_SIZE); pad_size = rand() % pad_size; Zero(pad, sizeof(pad)); Copy(buf, pad, pad_size); buf += pad_size; size += pad_size; } // Verify Copy(buf, zero, UDP_ACCELERATION_PACKET_IV_SIZE); buf += UDP_ACCELERATION_PACKET_IV_SIZE; size += UDP_ACCELERATION_PACKET_IV_SIZE; // Encryption c = NewCrypt(key, UDP_ACCELERATION_PACKET_KEY_SIZE); Encrypt(c, tmp + UDP_ACCELERATION_PACKET_IV_SIZE, tmp + UDP_ACCELERATION_PACKET_IV_SIZE, size - UDP_ACCELERATION_PACKET_IV_SIZE); FreeCrypt(c); // Next Iv Copy(a->NextIv, buf - UDP_ACCELERATION_PACKET_IV_SIZE, UDP_ACCELERATION_PACKET_IV_SIZE); } // Send SetSockHighPriority(a->UdpSock, high_priority); r = SendTo(a->UdpSock, &a->YourIp, a->YourPort, tmp, size); if (r == 0 && a->UdpSock->IgnoreSendErr == false) { fatal_error = true; Debug("Error: SendTo: %r %u %u\n", &a->YourIp, a->YourPort, size); WHERE; } if (data_size == 0) { if (UdpAccelIsSendReady(a, true) == false) { if ((a->YourPortByNatTServer != 0) && (a->YourPort != a->YourPortByNatTServer)) { r = SendTo(a->UdpSock, &a->YourIp, a->YourPortByNatTServer, tmp, size); if (r == 0 && a->UdpSock->IgnoreSendErr == false) { fatal_error = true; WHERE; } } } } if (data_size == 0) { if (IsZeroIP(&a->YourIp2) == false && CmpIpAddr(&a->YourIp, &a->YourIp2) != 0) { if (UdpAccelIsSendReady(a, true) == false) { // When the KeepAlive, if the opponent may be behind a NAT, // send the packet to the IP address of outside of the NAT r = SendTo(a->UdpSock, &a->YourIp2, a->YourPort, tmp, size); if (r == 0 && a->UdpSock->IgnoreSendErr == false) { fatal_error = true; WHERE; } if ((a->YourPortByNatTServer != 0) && (a->YourPort != a->YourPortByNatTServer)) { r = SendTo(a->UdpSock, &a->YourIp2, a->YourPortByNatTServer, tmp, size); if (r == 0 && a->UdpSock->IgnoreSendErr == false) { fatal_error = true; WHERE; } } } } } if (fatal_error) { a->FatalError = true; WHERE; } //Debug("UDP Send: %u\n", size); }