// SoftEther VPN Source Code - Developer Edition Master Branch // Cedar Communication Module // BridgeWin32.c // Ethernet Bridge Program (Win32) #include #ifdef BRIDGE_C #include #include #include #include #include #include #include #include #include #include #include #include #include static WP *wp = NULL; static LIST *eth_list = NULL; static LOCK *eth_list_lock = NULL; static bool is_see_mode = false; static bool is_using_selow = false; static bool enable_selow = true; static bool g_bridge_win32_show_all_if = false; #define LOAD_DLL_ADDR(name) \ { \ void *addr = GetProcAddress(h, #name); \ Copy(&wp->name, &addr, sizeof(void *)); \ } // Set the flag which indicates whether using SeLow void Win32SetEnableSeLow(bool b) { enable_selow = b; } // Get the flag which indicates whether using SeLow bool Win32GetEnableSeLow() { return enable_selow; } // Set the flag which indicates whether enumerating all interfaces void Win32EthSetShowAllIf(bool b) { g_bridge_win32_show_all_if = b; } // Get the flag which indicates whether enumerating all interfaces bool Win32EthGetShowAllIf() { return g_bridge_win32_show_all_if; } // Compare Ethernet device list int CmpRpcEnumEthVLan(void *p1, void *p2) { RPC_ENUM_ETH_VLAN_ITEM *v1, *v2; if (p1 == NULL || p2 == NULL) { return 0; } v1 = *((RPC_ENUM_ETH_VLAN_ITEM **)p1); v2 = *((RPC_ENUM_ETH_VLAN_ITEM **)p2); if (v1 == NULL || v2 == NULL) { return 0; } return StrCmpi(v1->DeviceName, v2->DeviceName); } // Get the value of MTU (Not supported in Windows) UINT EthGetMtu(ETH *e) { return 0; } // Set the value of MTU (Not supported in Windows) bool EthSetMtu(ETH *e, UINT mtu) { return false; } // Check whether setting MEU value (Not supported in Windows) bool EthIsChangeMtuSupported(ETH *e) { return false; } // Set the state of VLAN tag pass-through bool SetVLanEnableStatus(char *title, bool enable) { RPC_ENUM_ETH_VLAN t; RPC_ENUM_ETH_VLAN_ITEM *e; bool ret = false; char key[MAX_SIZE]; char tcpkey[MAX_SIZE]; char short_key[MAX_SIZE]; // Validate arguments if (title == NULL) { return false; } Zero(&t, sizeof(t)); if (EnumEthVLanWin32(&t) == false) { return false; } e = FindEthVLanItem(&t, title); if (e != NULL) { if (GetClassRegKeyWin32(key, sizeof(key), short_key, sizeof(short_key), e->Guid)) { if (StrCmpi(e->DriverType, "Intel") == 0) { if (enable) { MsRegWriteStr(REG_LOCAL_MACHINE, key, "VlanFiltering", "0"); MsRegWriteStr(REG_LOCAL_MACHINE, key, "TaggingMode", "0"); MsRegWriteInt(REG_LOCAL_MACHINE, key, "MonitorMode", 1); MsRegWriteInt(REG_LOCAL_MACHINE, key, "MonitorModeEnabled", 1); } else { if (MsRegReadInt(REG_LOCAL_MACHINE, key, "TaggingMode") == 0) { MsRegDeleteValue(REG_LOCAL_MACHINE, key, "TaggingMode"); } if (MsRegReadInt(REG_LOCAL_MACHINE, key, "MonitorMode") == 1) { MsRegDeleteValue(REG_LOCAL_MACHINE, key, "MonitorMode"); } if (MsRegReadInt(REG_LOCAL_MACHINE, key, "MonitorModeEnabled") == 1) { MsRegDeleteValue(REG_LOCAL_MACHINE, key, "MonitorModeEnabled"); } } ret = true; } else if (StrCmpi(e->DriverType, "Broadcom") == 0) { if (enable) { MsRegWriteStr(REG_LOCAL_MACHINE, key, "PreserveVlanInfoInRxPacket", "1"); } else { MsRegDeleteValue(REG_LOCAL_MACHINE, key, "PreserveVlanInfoInRxPacket"); } ret = true; } else if (StrCmpi(e->DriverType, "Marvell") == 0) { if (enable) { MsRegWriteInt(REG_LOCAL_MACHINE, key, "SkDisableVlanStrip", 1); } else { MsRegDeleteValue(REG_LOCAL_MACHINE, key, "SkDisableVlanStrip"); } ret = true; } Format(tcpkey, sizeof(tcpkey), "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\%s", e->Guid); if (enable) { if (MsRegIsValue(REG_LOCAL_MACHINE, tcpkey, "MTU") == false) { MsRegWriteInt(REG_LOCAL_MACHINE, tcpkey, "MTU", 1500); } } else { UINT mtu = MsRegReadInt(REG_LOCAL_MACHINE, tcpkey, "MTU"); if (mtu == 1500) { MsRegDeleteValue(REG_LOCAL_MACHINE, tcpkey, "MTU"); } } } } FreeRpcEnumEthVLan(&t); return ret; } // Find Ethernet device RPC_ENUM_ETH_VLAN_ITEM *FindEthVLanItem(RPC_ENUM_ETH_VLAN *t, char *name) { UINT i; // Validate arguments if (t == NULL || name == NULL) { return NULL; } for (i = 0;i < t->NumItem;i++) { if (StrCmpi(t->Items[i].DeviceName, name) == 0) { return &t->Items[i]; } } return NULL; } // Get the state of VLAN tag pass-through void GetVLanEnableStatus(RPC_ENUM_ETH_VLAN_ITEM *e) { char key[MAX_SIZE]; char short_key[MAX_SIZE]; char tcpkey[MAX_SIZE]; // Validate arguments if (e == NULL) { return; } e->Enabled = false; if (e->Support == false) { return; } if (GetClassRegKeyWin32(key, sizeof(key), short_key, sizeof(short_key), e->Guid) == false) { return; } Format(tcpkey, sizeof(tcpkey), "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\%s", e->Guid); if (StrCmpi(e->DriverType, "Intel") == 0) { char *VlanFiltering = MsRegReadStr(REG_LOCAL_MACHINE, key, "VlanFiltering"); UINT MonitorMode = MsRegReadInt(REG_LOCAL_MACHINE, key, "MonitorMode"); UINT MonitorModeEnabled = MsRegReadInt(REG_LOCAL_MACHINE, key, "MonitorModeEnabled"); char *TaggingMode = MsRegReadStr(REG_LOCAL_MACHINE, key, "TaggingMode"); if (StrCmpi(VlanFiltering, "0") == 0 && MonitorMode == 1 && MonitorModeEnabled == 1 && StrCmpi(TaggingMode, "0") == 0) { e->Enabled = true; } Free(VlanFiltering); Free(TaggingMode); } else if (StrCmpi(e->DriverType, "Broadcom") == 0) { char *PreserveVlanInfoInRxPacket = MsRegReadStr(REG_LOCAL_MACHINE, key, "PreserveVlanInfoInRxPacket"); if (StrCmpi(PreserveVlanInfoInRxPacket, "1") == 0) { e->Enabled = true; } Free(PreserveVlanInfoInRxPacket); } else if (StrCmpi(e->DriverType, "Marvell") == 0) { DWORD SkDisableVlanStrip = MsRegReadInt(REG_LOCAL_MACHINE, key, "SkDisableVlanStrip"); if (SkDisableVlanStrip == 1) { e->Enabled = true; } } if (MsRegIsValue(REG_LOCAL_MACHINE, tcpkey, "MTU") == false) { e->Enabled = false; } } // Get VLAN tag pass-through availability of the device void GetVLanSupportStatus(RPC_ENUM_ETH_VLAN_ITEM *e) { BUF *b; char filename[MAX_SIZE]; void *wow; // Validate arguments if (e == NULL) { return; } wow = MsDisableWow64FileSystemRedirection(); // Read the device driver file CombinePath(filename, sizeof(filename), MsGetSystem32Dir(), "drivers"); CombinePath(filename, sizeof(filename), filename, e->DriverName); b = ReadDump(filename); if (b != NULL) { char intel1[] = "VlanFiltering"; char intel2[] = "V\0l\0a\0n\0F\0i\0l\0t\0e\0r\0i\0n\0g"; char intel3[] = "MonitorMode"; char intel4[] = "M\0o\0n\0i\0t\0o\0r\0M\0o\0d\0e"; char intel5[] = "TaggingMode"; char intel6[] = "T\0a\0g\0g\0i\0n\0g\0M\0o\0d\0e"; char broadcom1[] = "PreserveVlanInfoInRxPacket"; char broadcom2[] = "P\0r\0e\0s\0e\0r\0v\0e\0V\0l\0a\0n\0I\0n\0f\0o\0I\0n\0R\0x\0P\0a\0c\0k\0e\0t"; char marvell1[] = "SkDisableVlanStrip"; char marvell2[] = "S\0k\0D\0i\0s\0a\0b\0l\0e\0V\0l\0a\0n\0S\0t\0r\0i\0p"; char *driver_type = ""; if (SearchBin(b->Buf, 0, b->Size, intel1, sizeof(intel1)) != INFINITE || SearchBin(b->Buf, 0, b->Size, intel2, sizeof(intel2)) != INFINITE || SearchBin(b->Buf, 0, b->Size, intel3, sizeof(intel3)) != INFINITE || SearchBin(b->Buf, 0, b->Size, intel4, sizeof(intel4)) != INFINITE || SearchBin(b->Buf, 0, b->Size, intel5, sizeof(intel5)) != INFINITE || SearchBin(b->Buf, 0, b->Size, intel6, sizeof(intel6)) != INFINITE) { driver_type = "Intel"; } else if (SearchBin(b->Buf, 0, b->Size, broadcom1, sizeof(broadcom1)) != INFINITE || SearchBin(b->Buf, 0, b->Size, broadcom2, sizeof(broadcom2)) != INFINITE) { driver_type = "Broadcom"; } else if (SearchBin(b->Buf, 0, b->Size, marvell1, sizeof(marvell1)) != INFINITE || SearchBin(b->Buf, 0, b->Size, marvell2, sizeof(marvell2)) != INFINITE) { driver_type = "Marvell"; } if (IsEmptyStr(driver_type) == false) { StrCpy(e->DriverType, sizeof(e->DriverType), driver_type); e->Support = true; } FreeBuf(b); } MsRestoreWow64FileSystemRedirection(wow); } // Get the device instance id from short_key char *SearchDeviceInstanceIdFromShortKey(char *short_key) { char *ret = NULL; TOKEN_LIST *t1; // Validate arguments if (short_key == NULL) { return NULL; } t1 = MsRegEnumKey(REG_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Enum"); if (t1 != NULL) { TOKEN_LIST *t2; char tmp[MAX_SIZE]; UINT i; for (i = 0;i < t1->NumTokens;i++) { Format(tmp, sizeof(tmp), "SYSTEM\\CurrentControlSet\\Enum\\%s", t1->Token[i]); t2 = MsRegEnumKey(REG_LOCAL_MACHINE, tmp); if (t2 != NULL) { TOKEN_LIST *t3; UINT i; for (i = 0;i < t2->NumTokens;i++) { char tmp2[MAX_SIZE]; Format(tmp2, sizeof(tmp2), "%s\\%s", tmp, t2->Token[i]); t3 = MsRegEnumKey(REG_LOCAL_MACHINE, tmp2); if (t3 != NULL) { UINT i; for (i = 0;i < t3->NumTokens;i++) { char tmp3[MAX_SIZE]; char *s; Format(tmp3, sizeof(tmp3), "%s\\%s", tmp2, t3->Token[i]); s = MsRegReadStr(REG_LOCAL_MACHINE, tmp3, "Driver"); if (s != NULL) { if (StrCmpi(s, short_key) == 0) { if (ret != NULL) { Free(ret); } ret = CopyStr(tmp3 + StrLen("SYSTEM\\CurrentControlSet\\Enum\\")); } Free(s); } } FreeToken(t3); } } FreeToken(t2); } } FreeToken(t1); } return ret; } // Get VLAN tag pass-through availability of all devices bool EnumEthVLanWin32(RPC_ENUM_ETH_VLAN *t) { UINT i; LIST *o; // Validate arguments if (t == NULL) { return false; } Zero(t, sizeof(RPC_ENUM_ETH_VLAN)); if (IsEthSupported() == false) { return false; } // Get device list Lock(eth_list_lock); InitEthAdaptersList(); o = NewListFast(CmpRpcEnumEthVLan); for (i = 0;i < LIST_NUM(eth_list);i++) { WP_ADAPTER *a = LIST_DATA(eth_list, i); if (IsEmptyStr(a->Guid) == false) { char class_key[MAX_SIZE]; char short_key[MAX_SIZE]; if (GetClassRegKeyWin32(class_key, sizeof(class_key), short_key, sizeof(short_key), a->Guid)) { char *device_instance_id = MsRegReadStr(REG_LOCAL_MACHINE, class_key, "DeviceInstanceID"); if (IsEmptyStr(device_instance_id)) { Free(device_instance_id); device_instance_id = SearchDeviceInstanceIdFromShortKey(short_key); } if (IsEmptyStr(device_instance_id) == false) { char device_key[MAX_SIZE]; char *service_name; Format(device_key, sizeof(device_key), "SYSTEM\\CurrentControlSet\\Enum\\%s", device_instance_id); service_name = MsRegReadStr(REG_LOCAL_MACHINE, device_key, "Service"); if (IsEmptyStr(service_name) == false) { char service_key[MAX_SIZE]; char *sys; Format(service_key, sizeof(service_key), "SYSTEM\\CurrentControlSet\\services\\%s", service_name); sys = MsRegReadStr(REG_LOCAL_MACHINE, service_key, "ImagePath"); if (IsEmptyStr(sys) == false) { char sysname[MAX_PATH]; GetFileNameFromFilePath(sysname, sizeof(sysname), sys); Trim(sysname); if (EndWith(sysname, ".sys")) { // device found RPC_ENUM_ETH_VLAN_ITEM *e = ZeroMalloc(sizeof(RPC_ENUM_ETH_VLAN_ITEM)); StrCpy(e->DeviceName, sizeof(e->DeviceName), a->Title); StrCpy(e->Guid, sizeof(e->Guid), a->Guid); StrCpy(e->DeviceInstanceId, sizeof(e->DeviceInstanceId), device_instance_id); StrCpy(e->DriverName, sizeof(e->DriverName), sysname); // Get VLAN tag pass-through availability of the device GetVLanSupportStatus(e); // Get current pass-through setting of the device GetVLanEnableStatus(e); Insert(o, e); } } Free(sys); } Free(service_name); } Free(device_instance_id); } } } t->NumItem = LIST_NUM(o); t->Items = ZeroMalloc(sizeof(RPC_ENUM_ETH_VLAN_ITEM) * i); for (i = 0;i < LIST_NUM(o);i++) { RPC_ENUM_ETH_VLAN_ITEM *e = LIST_DATA(o, i); Copy(&t->Items[i], e, sizeof(RPC_ENUM_ETH_VLAN_ITEM)); Free(e); } ReleaseList(o); Unlock(eth_list_lock); return true; } // Get registry key of the network class data by GUID bool GetClassRegKeyWin32(char *key, UINT key_size, char *short_key, UINT short_key_size, char *guid) { TOKEN_LIST *t; bool ret = false; UINT i; // Validate arguments if (key == NULL || short_key == NULL || guid == NULL) { return false; } t = MsRegEnumKey(REG_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"); if (t == NULL) { return false; } for (i = 0;i < t->NumTokens;i++) { char keyname[MAX_SIZE]; char *value; Format(keyname, sizeof(keyname), "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s", t->Token[i]); value = MsRegReadStr(REG_LOCAL_MACHINE, keyname, "NetCfgInstanceId"); if (StrCmpi(value, guid) == 0) { ret = true; StrCpy(key, key_size, keyname); Format(short_key, short_key_size, "{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s", t->Token[i]); } Free(value); } FreeToken(t); return ret; } // Send multiple packets void EthPutPackets(ETH *e, UINT num, void **datas, UINT *sizes) { UINT i, total_size; UCHAR *buf; UINT write_pointer; UINT err = 0; // Validate arguments if (e == NULL || num == 0 || datas == NULL || sizes == NULL) { return; } if (e->HasFatalError) { return; } if (e->SuAdapter != NULL) { bool ok = true; // Send packets with SeLow for (i = 0;i < num;i++) { UCHAR *data = datas[i]; UINT size = sizes[i]; if (ok) { // Actually, only enqueuing ok = SuPutPacket(e->SuAdapter, data, size); } if (ok == false) { // Free memory on write error Free(data); } } if (ok) { // Send all data in queue at once ok = SuPutPacket(e->SuAdapter, NULL, 0); } if (ok == false) { // Error occurred e->HasFatalError = true; } return; } if (IsWin32BridgeWithSee() == false) { if (e->LastSetSingleCpu == 0 || (e->LastSetSingleCpu + 10000) <= Tick64()) { e->LastSetSingleCpu = Tick64(); MsSetThreadSingleCpu(); } } // Calculate buffer size total_size = 0; for (i = 0;i < num;i++) { void *data = datas[i]; UINT size = sizes[i]; if (data != NULL && size >= 14 && size <= MAX_PACKET_SIZE) { total_size += size + sizeof(struct dump_bpf_hdr); } } buf = MallocFast(total_size * 100 / 75 + 1600); write_pointer = 0; // Enqueue for (i = 0;i < num;i++) { void *data = datas[i]; UINT size = sizes[i]; if (data != NULL && size >= 14 && size <= MAX_PACKET_SIZE) { struct dump_bpf_hdr *h; h = (struct dump_bpf_hdr *)(buf + write_pointer); Zero(h, sizeof(struct dump_bpf_hdr)); h->caplen = h->len = size; write_pointer += sizeof(struct dump_bpf_hdr); Copy(buf + write_pointer, data, size); write_pointer += size; PROBE_DATA2("EthPutPackets", data, size); } // Free original buffer Free(data); } // Send if (total_size != 0) { err = wp->PacketSendPackets(e->Adapter, buf, total_size, true); } Free(buf); if (err == 0x7FFFFFFF) { // Critical error (infinite loop) occurred on sending e->HasFatalError = true; } } // Send a packet void EthPutPacket(ETH *e, void *data, UINT size) { // Validate arguments if (e == NULL || data == NULL || size == 0) { return; } EthPutPackets(e, 1, &data, &size); } // Read next packet UINT EthGetPacket(ETH *e, void **data) { BLOCK *b; bool flag = false; // Validate arguments if (e == NULL || data == NULL) { return INFINITE; } if (e->HasFatalError) { return INFINITE; } if (e->SuAdapter != NULL) { // Read packet with SeLow UINT size; if (SuGetNextPacket(e->SuAdapter, data, &size) == false) { // Error occurred e->HasFatalError = true; return INFINITE; } return size; } RETRY: // Check the presence of the packet in queue b = GetNext(e->PacketQueue); if (b != NULL) { UINT size; size = b->Size; *data = b->Buf; Free(b); if (e->PacketQueue->num_item == 0) { e->Empty = true; } return size; } if (e->Empty) { e->Empty = false; return 0; } if (flag == false) { // Try to get next packet PROBE_STR("EthGetPacket: PacketInitPacket"); wp->PacketInitPacket(e->Packet, e->Buffer, e->BufferSize); PROBE_STR("EthGetPacket: PacketReceivePacket"); if (wp->PacketReceivePacket(e->Adapter, e->Packet, false) == false) { // Failed return INFINITE; } else { UCHAR *buf; UINT total; UINT offset; buf = (UCHAR *)e->Packet->Buffer; total = e->Packet->ulBytesReceived; offset = 0; while (offset < total) { struct bpf_hdr *header; UINT packet_size; UCHAR *packet_data; header = (struct bpf_hdr *)(buf + offset); packet_size = header->bh_caplen; offset += header->bh_hdrlen; packet_data = buf + offset; offset = Packet_WORDALIGN(offset + packet_size); if (packet_size >= 14) { UCHAR *tmp; BLOCK *b; PROBE_DATA2("EthGetPacket: NewBlock", packet_data, packet_size); tmp = MallocFast(packet_size); Copy(tmp, packet_data, packet_size); b = NewBlock(tmp, packet_size, 0); InsertQueue(e->PacketQueue, b); } } flag = true; goto RETRY; } } // No more packet return 0; } // Get cancel object CANCEL *EthGetCancel(ETH *e) { // Validate arguments if (e == NULL) { return NULL; } AddRef(e->Cancel->ref); return e->Cancel; } // Close adapter void CloseEth(ETH *e) { BLOCK *b; // Validate arguments if (e == NULL) { return; } ReleaseCancel(e->Cancel); if (e->SuAdapter != NULL) { // Close SeLow adapter SuCloseAdapter(e->SuAdapter); SuFree(e->Su); } else { // Close SEE adapter wp->PacketCloseAdapter(e->Adapter); wp->PacketFreePacket(e->Packet); wp->PacketFreePacket(e->PutPacket); } while (b = GetNext(e->PacketQueue)) { FreeBlock(b); } ReleaseQueue(e->PacketQueue); Free(e->Name); Free(e->Title); Free(e->Buffer); Free(e); } // Search adapter with the name struct WP_ADAPTER *Win32EthSearch(char *name) { UINT i; UINT id; char simple_name[MAX_SIZE]; WP_ADAPTER *ret = NULL; id = Win32EthGetNameAndIdFromCombinedName(simple_name, sizeof(simple_name), name); if (id != 0) { UINT num_match = 0; // Search with ID when ID is specified for (i = 0;i < LIST_NUM(eth_list);i++) { WP_ADAPTER *a = LIST_DATA(eth_list, i); if (a->Id != 0 && a->Id == id) { ret = a; num_match++; } } if (num_match >= 2) { // If the ID matches to 2 or more devices, search with the name for (i = 0;i < LIST_NUM(eth_list);i++) { WP_ADAPTER *a = LIST_DATA(eth_list, i); if (a->Id != 0 && a->Id == id) { if (StrCmpi(a->Title, name) == 0) { ret = a; break; } } } } } else { // Search with name when ID is not specified for (i = 0;i < LIST_NUM(eth_list);i++) { WP_ADAPTER *a = LIST_DATA(eth_list, i); if (StrCmpi(a->Title, name) == 0) { ret = a; break; } } } return ret; } // Open adapter ETH *OpenEth(char *name, bool local, bool tapmode, char *tapaddr) { ETH *ret; void *p; p = MsDisableWow64FileSystemRedirection(); ret = OpenEthInternal(name, local, tapmode, tapaddr); MsRestoreWow64FileSystemRedirection(p); return ret; } ETH *OpenEthInternal(char *name, bool local, bool tapmode, char *tapaddr) { WP_ADAPTER *t; ETH *e; ADAPTER *a = NULL; HANDLE h; CANCEL *c; MS_ADAPTER *ms; char name_with_id[MAX_SIZE]; SU *su = NULL; SU_ADAPTER *su_adapter = NULL; // Validate arguments if (name == NULL || IsEthSupported() == false) { return NULL; } if (tapmode) { // Tap is not supported in Windows return NULL; } Lock(eth_list_lock); InitEthAdaptersList(); t = Win32EthSearch(name); if (t == NULL) { Unlock(eth_list_lock); return NULL; } Debug("OpenEthInternal: %s\n", t->Name); if (StartWith(t->Name, SL_ADAPTER_ID_PREFIX)) { // Open with SU su = SuInit(); if (su == NULL) { // Fail to initialize SU Unlock(eth_list_lock); return NULL; } su_adapter = SuOpenAdapter(su, t->Name); if (su_adapter == NULL) { // Fail to get adapter SuFree(su); Unlock(eth_list_lock); return NULL; } is_using_selow = true; } else { // Open with SEE a = wp->PacketOpenAdapter(t->Name); if (a == NULL) { Unlock(eth_list_lock); return NULL; } if (IsWin32BridgeWithSee() == false) { MsSetThreadSingleCpu(); } is_using_selow = false; } e = ZeroMalloc(sizeof(ETH)); e->Name = CopyStr(t->Name); Win32EthMakeCombinedName(name_with_id, sizeof(name_with_id), t->Title, t->Guid); e->Title = CopyStr(name_with_id); if (su_adapter != NULL) { // SU e->SuAdapter = su_adapter; e->Su = su; // Get event object h = e->SuAdapter->hEvent; c = NewCancelSpecial(h); e->Cancel = c; } else { // SEE e->Adapter = a; wp->PacketSetBuff(e->Adapter, BRIDGE_WIN32_ETH_BUFFER); wp->PacketSetHwFilter(e->Adapter, local ? 0x0080 : 0x0020); wp->PacketSetMode(e->Adapter, PACKET_MODE_CAPT); wp->PacketSetReadTimeout(e->Adapter, -1); wp->PacketSetNumWrites(e->Adapter, 1); if (wp->PacketSetLoopbackBehavior != NULL) { // Filter loopback packet in kernel if (GET_KETA(GetOsType(), 100) >= 3) { if (MsIsWindows8() == false) { // Enable for Windows XP, Server 2003 or later // But disable for Windows 8 or later bool ret = wp->PacketSetLoopbackBehavior(e->Adapter, 1); Debug("*** PacketSetLoopbackBehavior: %u\n", ret); e->LoopbackBlock = ret; } } } // Get event object h = wp->PacketGetReadEvent(e->Adapter); c = NewCancelSpecial(h); e->Cancel = c; e->Packet = wp->PacketAllocatePacket(); e->PutPacket = wp->PacketAllocatePacket(); } e->Buffer = Malloc(BRIDGE_WIN32_ETH_BUFFER); e->BufferSize = BRIDGE_WIN32_ETH_BUFFER; e->PacketQueue = NewQueue(); // Get MAC address by GUID ms = MsGetAdapterByGuid(t->Guid); if (ms != NULL) { if (ms->AddressSize == 6) { Copy(e->MacAddress, ms->Address, 6); } MsFreeAdapter(ms); } Unlock(eth_list_lock); return e; } // Generate a combined name from NIC name and GUID void Win32EthMakeCombinedName(char *dst, UINT dst_size, char *nicname, char *guid) { // Validate arguments if (dst == NULL || nicname == NULL || guid == NULL) { return; } if (IsEmptyStr(guid) == false) { Format(dst, dst_size, "%s (ID=%010u)", nicname, Win32EthGenIdFromGuid(guid)); } else { StrCpy(dst, dst_size, nicname); } } // Decompose combined name UINT Win32EthGetNameAndIdFromCombinedName(char *name, UINT name_size, char *str) { UINT ret = 0; char id_str[MAX_SIZE]; UINT len; // Validate arguments ClearStr(name, name_size); StrCpy(name, name_size, str); if (name == NULL || str == NULL) { return 0; } len = StrLen(str); if (len >= 16) { StrCpy(id_str, sizeof(id_str), str + len - 16); if (StartWith(id_str, " (ID=")) { if (EndWith(id_str, ")")) { char num[MAX_SIZE]; Zero(num, sizeof(num)); StrCpy(num, sizeof(num), id_str + 5); num[StrLen(num) - 1] = 0; ret = ToInt(num); if (ret != 0) { name[len - 16] = 0; } } } } return ret; } // Generate an ID from GUID UINT Win32EthGenIdFromGuid(char *guid) { char tmp[MAX_SIZE]; UCHAR hash[SHA1_SIZE]; UINT i; // Validate arguments if (guid == NULL) { return 0; } StrCpy(tmp, sizeof(tmp), guid); Trim(tmp); StrUpper(tmp); Sha1(hash, tmp, StrLen(tmp)); Copy(&i, hash, sizeof(UINT)); i = Endian32(i); if (i == 0) { i = 1; } return i; } // Get Ethernet adapter list TOKEN_LIST *GetEthList() { UINT v; return GetEthListEx(&v, true, false); } TOKEN_LIST *GetEthListEx(UINT *total_num_including_hidden, bool enum_normal, bool enum_rawip) { TOKEN_LIST *ret; UINT i; UINT j; UINT dummy_int; MS_ADAPTER_LIST *adapter_list; if (IsEthSupported() == false) { return NULL; } if (enum_normal == false) { return NullToken(); } if (total_num_including_hidden == NULL) { total_num_including_hidden = &dummy_int; } *total_num_including_hidden = 0; Lock(eth_list_lock); InitEthAdaptersList(); adapter_list = MsCreateAdapterList(); ret = ZeroMalloc(sizeof(TOKEN_LIST)); ret->NumTokens = LIST_NUM(eth_list); ret->Token = ZeroMalloc(sizeof(char *) * ret->NumTokens); j = 0; for (i = 0;i < ret->NumTokens;i++) { char tmp[MAX_SIZE]; WP_ADAPTER *a = LIST_DATA(eth_list, i); MS_ADAPTER *msa = NULL; bool show = true; if (Win32EthGetShowAllIf() == false) { msa = MsGetAdapterByGuidFromList(adapter_list, a->Guid); if (InStr(a->Title, "vpn client adapter")) { // Hide virtual NIC for VPN client show = false; } if (InStr(a->Title, "tunnel adapter")) { // Hide tunnel adapter show = false; } if (InStr(a->Title, "teredo tunnel")) { // Hide tunnel adapter show = false; } if (InStr(a->Title, "MS Tunnel Interface")) { // Hide tunnel adapter show = false; } if (InStr(a->Title, "pseudo-interface")) { // Hide tunnel adapter show = false; } } if (msa != NULL) { // Hide except physical Ethernet NIC if (msa->IsNotEthernetLan) { show = false; } MsFreeAdapter(msa); } Win32EthMakeCombinedName(tmp, sizeof(tmp), a->Title, a->Guid); if (show) { ret->Token[j++] = CopyStr(tmp); Debug("%s - %s\n", a->Guid, a->Title); } } *total_num_including_hidden = ret->NumTokens; ret->NumTokens = j; Unlock(eth_list_lock); MsFreeAdapterList(adapter_list); return ret; } // Compare the name of WP_ADAPTER int CompareWpAdapter(void *p1, void *p2) { int i; WP_ADAPTER *a1, *a2; if (p1 == NULL || p2 == NULL) { return 0; } a1 = *(WP_ADAPTER **)p1; a2 = *(WP_ADAPTER **)p2; if (a1 == NULL || a2 == NULL) { return 0; } i = StrCmpi(a1->Title, a2->Title); return i; } // Get whether the SeLow is used bool Win32IsUsingSeLow() { return is_using_selow; } // Get Ethernet adapter list LIST *GetEthAdapterList() { void *p; LIST *o; p = MsDisableWow64FileSystemRedirection(); o = GetEthAdapterListInternal(); MsRestoreWow64FileSystemRedirection(p); return o; } LIST *GetEthAdapterListInternal() { LIST *o; LIST *ret; UINT size; char *buf; UINT i, j; char *qos_tag = " (Microsoft's Packet Scheduler)"; SU *su = NULL; LIST *su_adapter_list = NULL; // Try to use SeLow if (enable_selow) { su = SuInit(); } o = NewListFast(CompareWpAdapter); size = 200000; buf = ZeroMalloc(size); // Try to enumerate with SeLow if (su != NULL) { su_adapter_list = SuGetAdapterList(su); if (su_adapter_list == NULL) { // Fail to enumerate SuFree(su); su = NULL; //WHERE; is_using_selow = false; } else { //WHERE; is_using_selow = true; } } else { is_using_selow = false; } if (su_adapter_list != NULL) { // If 1 or more adapters are enumerated by SeLow, create adapter list object UINT i; for (i = 0;i < LIST_NUM(su_adapter_list);i++) { SU_ADAPTER_LIST *t = LIST_DATA(su_adapter_list, i); WP_ADAPTER *a = ZeroMalloc(sizeof(WP_ADAPTER)); StrCpy(a->Name, sizeof(a->Name), t->Name); StrCpy(a->Guid, sizeof(a->Guid), t->Guid); StrCpy(a->Title, sizeof(a->Title), t->Info.FriendlyName); TrimCrlf(a->Title); Trim(a->Title); TrimCrlf(a->Title); Trim(a->Title); if (EndWith(a->Title, qos_tag)) { a->Title[StrLen(a->Title) - StrLen(qos_tag)] = 0; TrimCrlf(a->Title); Trim(a->Title); TrimCrlf(a->Title); Trim(a->Title); } Add(o, a); } } else { // When SeLow is not used, create adapter list with SEE or WinPcap if (wp->PacketGetAdapterNames(buf, &size) == false) { Free(buf); return o; } i = 0; if (true) { // Windows NT if (size >= 2 && buf[0] != 0 && buf[1] != 0) { goto ANSI_STR; } while (true) { wchar_t tmp[MAX_SIZE]; WP_ADAPTER *a; UniStrCpy(tmp, sizeof(tmp), L""); if (*((wchar_t *)(&buf[i])) == 0) { i += sizeof(wchar_t); break; } for (;*((wchar_t *)(&buf[i])) != 0;i += sizeof(wchar_t)) { wchar_t str[2]; str[0] = *((wchar_t *)(&buf[i])); str[1] = 0; UniStrCat(tmp, sizeof(tmp), str); } i += sizeof(wchar_t); a = ZeroMalloc(sizeof(WP_ADAPTER)); UniToStr(a->Name, sizeof(a->Name), tmp); Add(o, a); } } else { ANSI_STR: while (true) { char tmp[MAX_SIZE]; WP_ADAPTER *a; StrCpy(tmp, sizeof(tmp), ""); if (*((char *)(&buf[i])) == 0) { i += sizeof(char); break; } for (;*((char *)(&buf[i])) != 0;i += sizeof(char)) { char str[2]; str[0] = *((char *)(&buf[i])); str[1] = 0; StrCat(tmp, sizeof(tmp), str); } i += sizeof(char); a = ZeroMalloc(sizeof(WP_ADAPTER)); StrCpy(a->Name, sizeof(a->Name), tmp); Add(o, a); } } for (j = 0;j < LIST_NUM(o);j++) { WP_ADAPTER *a = LIST_DATA(o, j); StrCpy(a->Title, sizeof(a->Title), &buf[i]); i += StrSize(a->Title); TrimCrlf(a->Title); Trim(a->Title); TrimCrlf(a->Title); Trim(a->Title); if (EndWith(a->Title, qos_tag)) { a->Title[StrLen(a->Title) - StrLen(qos_tag)] = 0; TrimCrlf(a->Title); Trim(a->Title); TrimCrlf(a->Title); Trim(a->Title); } } } for (j = 0;j < LIST_NUM(o);j++) { // Extract GUID WP_ADAPTER *a = LIST_DATA(o, j); if (IsEmptyStr(a->Guid)) { StrCpy(a->Guid, sizeof(a->Guid), a->Name); ReplaceStr(a->Guid, sizeof(a->Guid), a->Guid, "\\Device\\SEE_", ""); ReplaceStr(a->Guid, sizeof(a->Guid), a->Guid, "\\Device\\NPF_", ""); ReplaceStr(a->Guid, sizeof(a->Guid), a->Guid, "\\Device\\PCD_", ""); } } // Sort if (su_adapter_list != NULL) { // Since adapter list made by SeLow is already sorted, don't sort here Sort(o); } ret = NewListFast(CompareWpAdapter); for (i = 0;i < LIST_NUM(o);i++) { WP_ADAPTER *a = LIST_DATA(o, i); ADAPTER *ad; bool is_ethernet = false; bool ok = false; if (SearchStrEx(a->Title, "ppp", 0, false) != INFINITE || SearchStrEx(a->Title, "wan", 0, false) != INFINITE || SearchStrEx(a->Title, "dialup", 0, false) != INFINITE || SearchStrEx(a->Title, "pptp", 0, false) != INFINITE || SearchStrEx(a->Title, "telepho", 0, false) != INFINITE || SearchStrEx(a->Title, "modem", 0, false) != INFINITE || SearchStrEx(a->Title, "ras", 0, false) != INFINITE) { Free(a); continue; } // Determine whether the adapter type is Ethernet if (su == NULL) { // Determine with See ad = wp->PacketOpenAdapter(a->Name); if (ad != NULL) { NetType type; if (wp->PacketGetNetType(ad, &type)) { if (type.LinkType == 0) { is_ethernet = true; } } wp->PacketCloseAdapter(ad); } } else { // In using SeLow, all devices should be Ethernet device is_ethernet = true; } if (is_ethernet) { // Add only Ethernet device char tmp[MAX_SIZE]; UINT k; StrCpy(tmp, sizeof(tmp), a->Title); for (k = 0;;k++) { if (k == 0) { StrCpy(tmp, sizeof(tmp), a->Title); } else { Format(tmp, sizeof(tmp), "%s (%u)", a->Title, k + 1); } ok = true; for (j = 0;j < LIST_NUM(ret);j++) { WP_ADAPTER *aa = LIST_DATA(ret, j); if (StrCmpi(aa->Title, tmp) == 0) { ok = false; } } if (ok) { break; } } StrCpy(a->Title, sizeof(a->Title), tmp); a->Id = Win32EthGenIdFromGuid(a->Guid); Add(ret, a); } if (ok == false) { Free(a); } } Free(buf); Sort(ret); ReleaseList(o); if (su != NULL) { SuFreeAdapterList(su_adapter_list); SuFree(su); } return ret; } // Initialize Ethernet adapter list void InitEthAdaptersList() { if (eth_list != NULL) { FreeEthAdaptersList(); eth_list = NULL; } eth_list = GetEthAdapterList(); } // Free Ethernet adapter list void FreeEthAdaptersList() { UINT i; if (eth_list == NULL) { return; } for (i = 0;i < LIST_NUM(eth_list);i++) { WP_ADAPTER *a = LIST_DATA(eth_list, i); Free(a); } ReleaseList(eth_list); eth_list = NULL; } // Is the SU supported bool Win32EthIsSuSupported() { bool ret = false; SU *su = SuInit(); if (su != NULL) { ret = true; } SuFree(su); return ret; } // Is the Ethernet supported bool IsEthSupported() { bool ret = IsEthSupportedInner(); if (ret == false) { ret = Win32EthIsSuSupported(); } return ret; } bool IsEthSupportedInner() { if (wp == NULL) { return false; } return wp->Inited; } // Is the PCD driver supported in current OS bool IsPcdSupported() { return !MsIsWindows10(); } // Save build number of PCD driver void SavePcdDriverBuild(UINT build) { MsRegWriteInt(REG_LOCAL_MACHINE, BRIDGE_WIN32_PCD_REGKEY, BRIDGE_WIN32_PCD_BUILDVALUE, build); } // Load build number of PCD driver UINT LoadPcdDriverBuild() { return MsRegReadInt(REG_LOCAL_MACHINE, BRIDGE_WIN32_PCD_REGKEY, BRIDGE_WIN32_PCD_BUILDVALUE); } // Try to install PCD driver HINSTANCE InstallPcdDriver() { HINSTANCE ret; void *p = MsDisableWow64FileSystemRedirection(); ret = InstallPcdDriverInternal(); MsRestoreWow64FileSystemRedirection(p); return ret; } HINSTANCE InstallPcdDriverInternal() { char tmp[MAX_PATH]; bool install_driver = true; HINSTANCE h; char *dll_filename; // Confirm whether the see.sys is installed in system32\drivers folder Format(tmp, sizeof(tmp), "%s\\drivers\\see.sys", MsGetSystem32Dir()); if (IsFileExists(tmp)) { // If driver file is exist, try to get build number from registry if (LoadPcdDriverBuild() >= CEDAR_VERSION_BUILD) { // Already latest driver is installed install_driver = false; } } if (install_driver) { char *src_filename = BRIDGE_WIN32_PCD_SYS; // If need to install the driver, confirm user is administrator if (MsIsAdmin() == false) { // Non administrator can't install driver return NULL; } if (MsIsX64()) { src_filename = BRIDGE_WIN32_PCD_SYS_X64; } // Copy see.sys if (FileCopy(src_filename, tmp) == false) { return NULL; } // Save build number SavePcdDriverBuild(CEDAR_VERSION_BUILD); } dll_filename = BRIDGE_WIN32_PCD_DLL; if (Is64()) { if (MsIsX64()) { dll_filename = BRIDGE_WIN32_PCD_DLL_X64; } } // Try to load see.dll and initialize h = MsLoadLibrary(dll_filename); if (h == NULL) { return NULL; } return h; } // Initialize Ethernet void InitEth() { HINSTANCE h; if (wp != NULL) { // Already initialized return; } eth_list_lock = NewLock(); wp = ZeroMalloc(sizeof(WP)); is_see_mode = false; if (IsPcdSupported()) { // PCD is supported in this OS h = InstallPcdDriver(); if (h != NULL) { // Try to initialize with PCD if (InitWpWithLoadLibrary(wp, h) == false) { Debug("InitEth: SEE Failed.\n"); FreeLibrary(h); } else { Debug("InitEth: SEE Loaded.\n"); is_see_mode = true; } } } if (wp->Inited == false) { // Try to initialize with Packet.dll of WinPcap h = LoadLibrary(BRIDGE_WIN32_PACKET_DLL); if (h != NULL) { if (InitWpWithLoadLibrary(wp, h) == false) { Debug("InitEth: Packet.dll Failed.\n"); FreeLibrary(h); } else { Debug("InitEth: Packet.dll Loaded.\n"); } } } } // Get whether local-bridge uses see.sys bool IsWin32BridgeWithSee() { return is_see_mode; } // Initialize WP structure with DLL bool InitWpWithLoadLibrary(WP *wp, HINSTANCE h) { TOKEN_LIST *o; UINT total_num = 0; // Validate arguments if (wp == NULL || h == NULL) { return false; } wp->Inited = true; wp->hPacketDll = h; LOAD_DLL_ADDR(PacketGetVersion); LOAD_DLL_ADDR(PacketGetDriverVersion); LOAD_DLL_ADDR(PacketSetMinToCopy); LOAD_DLL_ADDR(PacketSetNumWrites); LOAD_DLL_ADDR(PacketSetMode); LOAD_DLL_ADDR(PacketSetReadTimeout); LOAD_DLL_ADDR(PacketSetBpf); LOAD_DLL_ADDR(PacketSetSnapLen); LOAD_DLL_ADDR(PacketGetStats); LOAD_DLL_ADDR(PacketGetStatsEx); LOAD_DLL_ADDR(PacketSetBuff); LOAD_DLL_ADDR(PacketGetNetType); LOAD_DLL_ADDR(PacketOpenAdapter); LOAD_DLL_ADDR(PacketSendPacket); LOAD_DLL_ADDR(PacketSendPackets); LOAD_DLL_ADDR(PacketAllocatePacket); LOAD_DLL_ADDR(PacketInitPacket); LOAD_DLL_ADDR(PacketFreePacket); LOAD_DLL_ADDR(PacketReceivePacket); LOAD_DLL_ADDR(PacketSetHwFilter); LOAD_DLL_ADDR(PacketGetAdapterNames); LOAD_DLL_ADDR(PacketGetNetInfoEx); LOAD_DLL_ADDR(PacketRequest); LOAD_DLL_ADDR(PacketGetReadEvent); LOAD_DLL_ADDR(PacketSetDumpName); LOAD_DLL_ADDR(PacketSetDumpLimits); LOAD_DLL_ADDR(PacketSetDumpLimits); LOAD_DLL_ADDR(PacketIsDumpEnded); LOAD_DLL_ADDR(PacketStopDriver); LOAD_DLL_ADDR(PacketCloseAdapter); LOAD_DLL_ADDR(PacketSetLoopbackBehavior); if (wp->PacketSetMinToCopy == NULL || wp->PacketSetNumWrites == NULL || wp->PacketSetMode == NULL || wp->PacketSetReadTimeout == NULL || wp->PacketSetBuff == NULL || wp->PacketGetNetType == NULL || wp->PacketOpenAdapter == NULL || wp->PacketSendPacket == NULL || wp->PacketSendPackets == NULL || wp->PacketAllocatePacket == NULL || wp->PacketInitPacket == NULL || wp->PacketFreePacket == NULL || wp->PacketReceivePacket == NULL || wp->PacketSetHwFilter == NULL || wp->PacketGetAdapterNames == NULL || wp->PacketGetNetInfoEx == NULL || wp->PacketCloseAdapter == NULL) { RELEASE: wp->Inited = false; wp->hPacketDll = NULL; return false; } o = GetEthListEx(&total_num, true, false); if (o == NULL || total_num == 0) { FreeToken(o); goto RELEASE; } FreeToken(o); return true; } // Free Ethernet void FreeEth() { if (wp == NULL) { // Not initialized return; } // Free adapter list FreeEthAdaptersList(); if (wp->Inited) { // Free DLL FreeLibrary(wp->hPacketDll); } Free(wp); wp = NULL; DeleteLock(eth_list_lock); eth_list_lock = NULL; } // Get network connection name from Ethernet device name void GetEthNetworkConnectionName(wchar_t *dst, UINT size, char *device_name) { WP_ADAPTER *t; char *tmp = NULL, guid[MAX_SIZE]; wchar_t *ncname = NULL; UniStrCpy(dst, size, L""); // Validate arguments if (device_name == NULL || IsEthSupported() == false) { return; } Lock(eth_list_lock); InitEthAdaptersList(); t = Win32EthSearch(device_name); if (t == NULL) { Unlock(eth_list_lock); return; } tmp = CopyStr(t->Name); Unlock(eth_list_lock); if (IsEmptyStr(t->Guid) == false) { StrCpy(guid, sizeof(guid), t->Guid); Free(tmp); } else { ReplaceStr(guid, sizeof(guid), tmp, "\\Device\\SEE_", ""); Free(tmp); ReplaceStr(guid, sizeof(guid), guid, "\\Device\\NPF_", ""); ReplaceStr(guid, sizeof(guid), guid, "\\Device\\PCD_", ""); } if(guid == NULL) { return; } ncname = MsGetNetworkConnectionName(guid); if(ncname != NULL) { UniStrCpy(dst, size, ncname); } Free(ncname); } #endif // BRIDGE_C