1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204 |
- // SoftEther VPN Source Code
- // Cedar Communication Module
- //
- // SoftEther VPN Server, Client and Bridge are free software under GPLv2.
- //
- // Copyright (c) 2012-2014 Daiyuu Nobori.
- // Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
- // Copyright (c) 2012-2014 SoftEther Corporation.
- //
- // All Rights Reserved.
- //
- // http://www.softether.org/
- //
- // Author: Daiyuu Nobori
- // Comments: Tetsuo Sugiyama, Ph.D.
- //
- // This program is free software; you can redistribute it and/or
- // modify it under the terms of the GNU General Public License
- // version 2 as published by the Free Software Foundation.
- //
- // This program is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- //
- // You should have received a copy of the GNU General Public License version 2
- // along with this program; if not, write to the Free Software
- // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- //
- // THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
- // AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
- //
- //
- // THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
- // UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
- // MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
- // SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
- // SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
- // CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
- // DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
- // MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
- // SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
- // CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
- // EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
- // JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
- // AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
- // THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
- //
- // USE ONLY IN JAPAN. DO NOT USE THIS SOFTWARE IN ANOTHER COUNTRY UNLESS
- // YOU HAVE A CONFIRMATION THAT THIS SOFTWARE DOES NOT VIOLATE ANY
- // CRIMINAL LAWS OR CIVIL RIGHTS IN THAT PARTICULAR COUNTRY. USING THIS
- // SOFTWARE IN OTHER COUNTRIES IS COMPLETELY AT YOUR OWN RISK. THE
- // SOFTETHER VPN PROJECT HAS DEVELOPED AND DISTRIBUTED THIS SOFTWARE TO
- // COMPLY ONLY WITH THE JAPANESE LAWS AND EXISTING CIVIL RIGHTS INCLUDING
- // PATENTS WHICH ARE SUBJECTS APPLY IN JAPAN. OTHER COUNTRIES' LAWS OR
- // CIVIL RIGHTS ARE NONE OF OUR CONCERNS NOR RESPONSIBILITIES. WE HAVE
- // NEVER INVESTIGATED ANY CRIMINAL REGULATIONS, CIVIL LAWS OR
- // INTELLECTUAL PROPERTY RIGHTS INCLUDING PATENTS IN ANY OF OTHER 200+
- // COUNTRIES AND TERRITORIES. BY NATURE, THERE ARE 200+ REGIONS IN THE
- // WORLD, WITH DIFFERENT LAWS. IT IS IMPOSSIBLE TO VERIFY EVERY
- // COUNTRIES' LAWS, REGULATIONS AND CIVIL RIGHTS TO MAKE THE SOFTWARE
- // COMPLY WITH ALL COUNTRIES' LAWS BY THE PROJECT. EVEN IF YOU WILL BE
- // SUED BY A PRIVATE ENTITY OR BE DAMAGED BY A PUBLIC SERVANT IN YOUR
- // COUNTRY, THE DEVELOPERS OF THIS SOFTWARE WILL NEVER BE LIABLE TO
- // RECOVER OR COMPENSATE SUCH DAMAGES, CRIMINAL OR CIVIL
- // RESPONSIBILITIES. NOTE THAT THIS LINE IS NOT LICENSE RESTRICTION BUT
- // JUST A STATEMENT FOR WARNING AND DISCLAIMER.
- //
- //
- // SOURCE CODE CONTRIBUTION
- // ------------------------
- //
- // Your contribution to SoftEther VPN Project is much appreciated.
- // Please send patches to us through GitHub.
- // Read the SoftEther VPN Patch Acceptance Policy in advance:
- // http://www.softether.org/5-download/src/9.patch
- //
- //
- // DEAR SECURITY EXPERTS
- // ---------------------
- //
- // If you find a bug or a security vulnerability please kindly inform us
- // about the problem immediately so that we can fix the security problem
- // to protect a lot of users around the world as soon as possible.
- //
- // Our e-mail address for security reports is:
- // softether-vpn-security [at] softether.org
- //
- // Please note that the above e-mail address is not a technical support
- // inquiry address. If you need technical assistance, please visit
- // http://www.softether.org/ and ask your question on the users forum.
- //
- // Thank you for your cooperation.
- //
- //
- // NO MEMORY OR RESOURCE LEAKS
- // ---------------------------
- //
- // The memory-leaks and resource-leaks verification under the stress
- // test has been passed before release this source code.
- // UdpAccel.c
- // UDP acceleration function
- #include "CedarPch.h"
- // 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)
- {
- }
- }
- }
- // Send a packet block
- void UdpAccelSendBlock(UDP_ACCEL *a, BLOCK *b)
- {
- // Validate arguments
- if (a == NULL || b == NULL)
- {
- return;
- }
- UdpAccelSend(a, b->Buf, b->Size, b->Compressed, a->MaxUdpPacketSize, b->PriorityQoS);
- }
- // Calculate the best MSS
- UINT UdpAccelCalcMss(UDP_ACCEL *a)
- {
- UINT ret;
- // Validate arguments
- if (a == NULL)
- {
- return 0;
- }
- ret = MTU_FOR_PPPOE;
- // IPv4
- if (a->IsIPv6)
- {
- ret -= 40;
- }
- else
- {
- ret -= 20;
- }
- // UDP
- ret -= 8;
- if (a->PlainTextMode == false)
- {
- // IV
- ret -= UDP_ACCELERATION_PACKET_IV_SIZE;
- }
- // Cookie
- ret -= sizeof(UINT);
- // My Tick
- ret -= sizeof(UINT64);
- // Your Tick
- ret -= sizeof(UINT64);
- // Size
- ret -= sizeof(USHORT);
- // Compress Flag
- ret -= sizeof(UCHAR);
- if (a->PlainTextMode == false)
- {
- // Verify
- ret -= UDP_ACCELERATION_PACKET_IV_SIZE;
- }
- // Ethernet header (communication packets)
- ret -= 14;
- // IPv4 Header (communication packets)
- ret -= 20;
- // TCP header (communication packet)
- ret -= 20;
- return ret;
- }
- // 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);
- }
- // 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;
- }
- // Process the received packet
- BLOCK *UdpAccelProcessRecvPacket(UDP_ACCEL *a, UCHAR *buf, UINT size, IP *src_ip, UINT src_port)
- {
- UCHAR key[UDP_ACCELERATION_PACKET_KEY_SIZE];
- UCHAR *iv;
- CRYPT *c;
- UINT64 my_tick, your_tick;
- UINT inner_size;
- UCHAR *inner_data = NULL;
- UINT pad_size;
- UCHAR *verify;
- bool compress_flag;
- BLOCK *b = NULL;
- UINT cookie;
- // Validate arguments
- if (a == NULL || buf == NULL || size == 0 || src_ip == NULL)
- {
- return NULL;
- }
- if (a->PlainTextMode == false)
- {
- // IV
- if (size < UDP_ACCELERATION_PACKET_IV_SIZE)
- {
- return NULL;
- }
- iv = buf;
- buf += UDP_ACCELERATION_PACKET_IV_SIZE;
- size -= UDP_ACCELERATION_PACKET_IV_SIZE;
- // Calculate the key
- UdpAccelCalcKey(key, a->YourKey, iv);
- if (false)
- {
- char tmp1[256];
- char tmp2[256];
- char tmp3[256];
- BinToStr(tmp1, sizeof(tmp1), a->YourKey, sizeof(a->YourKey));
- BinToStr(tmp2, sizeof(tmp2), iv, UDP_ACCELERATION_PACKET_IV_SIZE);
- BinToStr(tmp3, sizeof(tmp3), key, sizeof(key));
- Debug("Your Key: %s\n"
- "IV : %s\n"
- "Comm Key: %s\n",
- tmp1, tmp2, tmp3);
- }
- // Decryption
- c = NewCrypt(key, UDP_ACCELERATION_PACKET_KEY_SIZE);
- Encrypt(c, buf, buf, size);
- FreeCrypt(c);
- }
- // Cookie
- if (size < sizeof(UINT))
- {
- return NULL;
- }
- cookie = READ_UINT(buf);
- buf += sizeof(UINT);
- size -= sizeof(UINT);
- if (cookie != a->MyCookie)
- {
- return NULL;
- }
- // My Tick
- if (size < sizeof(UINT64))
- {
- return NULL;
- }
- my_tick = READ_UINT64(buf);
- buf += sizeof(UINT64);
- size -= sizeof(UINT64);
- // Your Tick
- if (size < sizeof(UINT64))
- {
- return NULL;
- }
- your_tick = READ_UINT64(buf);
- buf += sizeof(UINT64);
- size -= sizeof(UINT64);
- // inner_size
- if (size < sizeof(USHORT))
- {
- return NULL;
- }
- inner_size = READ_USHORT(buf);
- buf += sizeof(USHORT);
- size -= sizeof(USHORT);
- // compress_flag
- if (size < sizeof(UCHAR))
- {
- return NULL;
- }
- compress_flag = *((UCHAR *)buf);
- buf += sizeof(UCHAR);
- size -= sizeof(UCHAR);
- if (size < inner_size)
- {
- return NULL;
- }
- // inner_data
- if (inner_size >= 1)
- {
- inner_data = buf;
- buf += inner_size;
- size -= inner_size;
- }
- if (a->PlainTextMode == false)
- {
- // padding
- if (size < UDP_ACCELERATION_PACKET_IV_SIZE)
- {
- return false;
- }
- pad_size = size - UDP_ACCELERATION_PACKET_IV_SIZE;
- buf += pad_size;
- size -= pad_size;
- // verify
- if (size != UDP_ACCELERATION_PACKET_IV_SIZE)
- {
- return NULL;
- }
- verify = buf;
- if (IsZero(verify, UDP_ACCELERATION_PACKET_IV_SIZE) == false)
- {
- return NULL;
- }
- }
- if (my_tick < a->LastRecvYourTick)
- {
- if ((a->LastRecvYourTick - my_tick) >= ((UINT64)UDP_ACCELERATION_WINDOW_SIZE_MSEC))
- {
- return NULL;
- }
- }
- a->LastRecvMyTick = MAX(a->LastRecvMyTick, your_tick);
- a->LastRecvYourTick = MAX(a->LastRecvYourTick, my_tick);
- if (inner_size >= 1)
- {
- b = NewBlock(Clone(inner_data, inner_size), inner_size, compress_flag ? -1 : 0);
- }
- if (a->LastSetSrcIpAndPortTick < a->LastRecvYourTick)
- {
- a->LastSetSrcIpAndPortTick = a->LastRecvYourTick;
- Copy(&a->YourIp, src_ip, sizeof(IP));
- a->YourPort = src_port;
- }
- if (a->LastRecvMyTick != 0)
- {
- if ((a->LastRecvMyTick + (UINT64)(UDP_ACCELERATION_WINDOW_SIZE_MSEC)) >= a->Now)
- {
- a->LastRecvTick = a->Now;
- a->IsReachedOnce = true;
- if (a->FirstStableReceiveTick == 0)
- {
- a->FirstStableReceiveTick = a->Now;
- }
- }
- }
- return b;
- }
- // Calculate the key
- void UdpAccelCalcKey(UCHAR *key, UCHAR *common_key, UCHAR *iv)
- {
- UCHAR tmp[UDP_ACCELERATION_COMMON_KEY_SIZE + UDP_ACCELERATION_PACKET_IV_SIZE];
- // Validate arguments
- if (key == NULL || common_key == NULL || iv == NULL)
- {
- return;
- }
- Copy(tmp, common_key, UDP_ACCELERATION_COMMON_KEY_SIZE);
- Copy(tmp + UDP_ACCELERATION_COMMON_KEY_SIZE, iv, UDP_ACCELERATION_PACKET_IV_SIZE);
- HashSha1(key, tmp, sizeof(tmp));
- }
- // Set the current time
- void UdpAccelSetTick(UDP_ACCEL *a, UINT64 tick64)
- {
- // Validate arguments
- if (a == NULL)
- {
- return;
- }
- a->Now = tick64;
- }
- // Initialize the server-side
- bool UdpAccelInitServer(UDP_ACCEL *a, UCHAR *client_key, IP *client_ip, UINT client_port, IP *client_ip_2)
- {
- char tmp[MAX_SIZE];
- // Validate arguments
- if (a == NULL || client_key == NULL)
- {
- return false;
- }
- IPToStr(tmp, sizeof(tmp), client_ip);
- Debug("UdpAccelInitServer: client_ip=%s, client_port=%u, server_cookie=%u, client_cookie=%u\n", tmp, client_port,
- a->MyCookie, a->YourCookie);
- if (IsIP6(client_ip) != a->IsIPv6)
- {
- return false;
- }
- Copy(a->YourKey, client_key, UDP_ACCELERATION_COMMON_KEY_SIZE);
- Copy(&a->YourIp, client_ip, sizeof(IP));
- Copy(&a->YourIp2, client_ip_2, sizeof(IP));
- a->YourPort = client_port;
- a->Now = Tick64();
- a->Inited = true;
- return true;
- }
- // 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;
- }
- // 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;
- }
- // 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);
- }
- }
- // 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);
- }
- // Developed by SoftEther VPN Project at University of Tsukuba in Japan.
- // Department of Computer Science has dozens of overly-enthusiastic geeks.
- // Join us: http://www.tsukuba.ac.jp/english/admission/
|