// SoftEther VPN Source Code // Cedar Communication Module // // SoftEther VPN Server, Client and Bridge are free software under GPLv2. // // Copyright (c) Daiyuu Nobori, Ph.D.. // Copyright (c) SoftEther VPN Project, University of Tsukuba, Japan. // Copyright (c) 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. // Bridge.c // Ethernet Bridge Program (Local Bridge) #include #define BRIDGE_C #ifdef WIN32 #define OS_WIN32 #endif #ifdef OS_WIN32 // Win32 #include "BridgeWin32.c" #else // Unix #include "BridgeUnix.c" #endif // OS_WIN32 // Hash the list of current Ethernet devices UINT GetEthDeviceHash() { #ifdef OS_UNIX // UNIX UINT num; UINT i; char tmp[4096]; UCHAR hash[SHA1_SIZE]; TOKEN_LIST *t = GetEthList(); num = t->NumTokens; tmp[0] = 0; for (i = 0;i < t->NumTokens;i++) { StrCat(tmp, sizeof(tmp), t->Token[i]); } FreeToken(t); Hash(hash, tmp, StrLen(tmp), true); Copy(&num, hash, sizeof(UINT)); return num; #else // OS_UNIX // Win32 UINT ret = 0; MS_ADAPTER_LIST *a = MsCreateAdapterListEx(true); UINT num; UINT i; char tmp[4096]; UCHAR hash[SHA1_SIZE]; tmp[0] = 0; if (a != NULL) { for (i = 0;i < a->Num;i++) { StrCat(tmp, sizeof(tmp), a->Adapters[i]->Title); } } MsFreeAdapterList(a); Hash(hash, tmp, StrLen(tmp), true); Copy(&num, hash, sizeof(UINT)); return num; #endif // OS_UNIX } // Get whether WinPcap is needed bool IsNeedWinPcap() { if (IsBridgeSupported() == false) { // Not in Windows return false; } else { // Windows if (IsEthSupported()) { // Already success to access the Ethernet device return false; } else { // Failed to access the Ethernet device return true; } } } // Get whether the local-bridging is supported by current OS bool IsBridgeSupported() { UINT type = GetOsInfo()->OsType; if (OS_IS_WINDOWS(type)) { if (IsEthSupported()) { return true; } else { bool ret = false; #ifdef OS_WIN32 ret = MsIsAdmin(); #endif // OS_WIN32 return ret; } } else { return IsEthSupported(); } } // Delete a local-bridge bool DeleteLocalBridge(CEDAR *c, char *hubname, char *devicename) { bool ret = false; // Validate arguments if (c == NULL || hubname == NULL || devicename == NULL) { return false; } LockList(c->HubList); { LockList(c->LocalBridgeList); { UINT i; for (i = 0;i < LIST_NUM(c->LocalBridgeList);i++) { LOCALBRIDGE *br = LIST_DATA(c->LocalBridgeList, i); if (StrCmpi(br->HubName, hubname) == 0) { if (StrCmpi(br->DeviceName, devicename) == 0) { if (br->Bridge != NULL) { BrFreeBridge(br->Bridge); br->Bridge = NULL; } Delete(c->LocalBridgeList, br); Free(br); ret = true; break; } } } } UnlockList(c->LocalBridgeList); } UnlockList(c->HubList); return ret; } // Add a local-bridge void AddLocalBridge(CEDAR *c, char *hubname, char *devicename, bool local, bool monitor, bool tapmode, char *tapaddr, bool limit_broadcast) { UINT i; HUB *h = NULL; LOCALBRIDGE *br = NULL; // Validate arguments if (c == NULL || hubname == NULL || devicename == NULL) { return; } if (OS_IS_UNIX(GetOsInfo()->OsType) == false) { tapmode = false; } LockList(c->HubList); { LockList(c->LocalBridgeList); { bool exists = false; // Ensure that the same configuration local-bridge doesn't exist already for (i = 0;i < LIST_NUM(c->LocalBridgeList);i++) { LOCALBRIDGE *br = LIST_DATA(c->LocalBridgeList, i); if (StrCmpi(br->DeviceName, devicename) == 0) { if (StrCmpi(br->HubName, hubname) == 0) { if (br->TapMode == tapmode) { exists = true; } } } } if (exists == false) { // Add configuration br = ZeroMalloc(sizeof(LOCALBRIDGE)); StrCpy(br->HubName, sizeof(br->HubName), hubname); StrCpy(br->DeviceName, sizeof(br->DeviceName), devicename); br->Bridge = NULL; br->Local = local; br->TapMode = tapmode; br->LimitBroadcast = limit_broadcast; br->Monitor = monitor; if (br->TapMode) { if (tapaddr != NULL && IsZero(tapaddr, 6) == false) { Copy(br->TapMacAddress, tapaddr, 6); } else { GenMacAddress(br->TapMacAddress); } } Add(c->LocalBridgeList, br); // Find the hub for (i = 0;i < LIST_NUM(c->HubList);i++) { HUB *hub = LIST_DATA(c->HubList, i); if (StrCmpi(hub->Name, br->HubName) == 0) { h = hub; AddRef(h->ref); break; } } } } UnlockList(c->LocalBridgeList); } UnlockList(c->HubList); // Start the local-bridge immediately if (h != NULL && br != NULL && h->Type != HUB_TYPE_FARM_DYNAMIC) { Lock(h->lock_online); { if (h->Offline == false) { LockList(c->LocalBridgeList); { if (IsInList(c->LocalBridgeList, br)) { if (br->Bridge == NULL) { br->Bridge = BrNewBridge(h, br->DeviceName, NULL, br->Local, br->Monitor, br->TapMode, br->TapMacAddress, br->LimitBroadcast, br); } } } UnlockList(c->LocalBridgeList); } } Unlock(h->lock_online); } ReleaseHub(h); } // Initialize the local-bridge list void InitLocalBridgeList(CEDAR *c) { // Validate arguments if (c == NULL) { return; } c->LocalBridgeList = NewList(NULL); } // Free the local-bridge list void FreeLocalBridgeList(CEDAR *c) { UINT i; // Validate arguments if (c == NULL) { return; } for (i = 0;i < LIST_NUM(c->LocalBridgeList);i++) { LOCALBRIDGE *br = LIST_DATA(c->LocalBridgeList, i); Free(br); } ReleaseList(c->LocalBridgeList); c->LocalBridgeList = NULL; } // Bridging thread void BrBridgeThread(THREAD *thread, void *param) { BRIDGE *b; CONNECTION *c; SESSION *s; HUB *h; char name[MAX_SIZE]; // Validate arguments if (thread == NULL || param == NULL) { return; } b = (BRIDGE *)param; // Create a connection object c = NewServerConnection(b->Cedar, NULL, thread); c->Protocol = CONNECTION_HUB_BRIDGE; // Create a session object s = NewServerSession(b->Cedar, c, b->Hub, BRIDGE_USER_NAME, b->Policy); HLog(b->Hub, "LH_START_BRIDGE", b->Name, s->Name); StrCpy(name, sizeof(name), b->Name); h = b->Hub; AddRef(h->ref); s->BridgeMode = true; s->Bridge = b; c->Session = s; ReleaseConnection(c); // Dummy user name for local-bridge s->Username = CopyStr(BRIDGE_USER_NAME_PRINT); b->Session = s; AddRef(s->ref); // Notify completion NoticeThreadInit(thread); // Main procedure of the session Debug("Bridge %s Start.\n", b->Name); SessionMain(s); Debug("Bridge %s Stop.\n", b->Name); HLog(h, "LH_STOP_BRIDGE", name); ReleaseHub(h); ReleaseSession(s); } // Free the local-bridge object void BrFreeBridge(BRIDGE *b) { // Validate arguments if (b == NULL) { return; } if (b->ParentLocalBridge != NULL) { b->ParentLocalBridge = NULL; } // Stop session thread StopSession(b->Session); ReleaseSession(b->Session); Free(b); } // Create new local-bridge BRIDGE *BrNewBridge(HUB *h, char *name, POLICY *p, bool local, bool monitor, bool tapmode, char *tapaddr, bool limit_broadcast, LOCALBRIDGE *parent_local_bridge) { BRIDGE *b; POLICY *policy; THREAD *t; // Validate arguments if (h == NULL || name == NULL || parent_local_bridge == NULL) { return NULL; } if (p == NULL) { policy = ClonePolicy(GetDefaultPolicy()); } else { policy = ClonePolicy(p); } b = ZeroMalloc(sizeof(BRIDGE)); b->Cedar = h->Cedar; b->Hub = h; StrCpy(b->Name, sizeof(b->Name), name); b->Policy = policy; b->Local = local; b->Monitor = monitor; b->TapMode = tapmode; b->LimitBroadcast = limit_broadcast; b->ParentLocalBridge = parent_local_bridge; if (b->TapMode) { if (tapaddr != NULL && IsZero(tapaddr, 6) == false) { Copy(b->TapMacAddress, tapaddr, 6); } else { GenMacAddress(b->TapMacAddress); } } if (monitor) { // Enabling monitoring mode policy->MonitorPort = true; } if (b->LimitBroadcast == false) { // Disable broadcast limiter policy->NoBroadcastLimiter = true; } // Start thread t = NewThread(BrBridgeThread, b); WaitThreadInit(t); ReleaseThread(t); return b; } // Raw IP bridge is supported only on Linux bool IsRawIpBridgeSupported() { #ifdef UNIX_LINUX return true; #else // UNIX_LINUX return false; #endif // UNIX_LINUX }