├── StreamDivert ├── socks.h ├── x64 │ └── Debug │ │ └── StreamDivert.vcxproj.FileListAbsolute.txt ├── socks.cpp ├── small.ico ├── StreamDivert.rc ├── StreamDivert.aps ├── StreamDivert.h ├── StreamDivert.ico ├── InboundDivertProxy.h ├── stdafx.cpp ├── targetver.h ├── interfaces.h ├── stdafx.h ├── sockutils.h ├── utils.h ├── Resource.h ├── config.h ├── WindowsFirewall.h ├── cfg.txt ├── ipaddr.h ├── StreamDivert.vcxproj.user ├── OutboundDivertProxy.h ├── InboundUDPDivertProxy.h ├── InboundICMPDivertProxy.h ├── InboundTCPDivertProxy.h ├── utils.cpp ├── BaseProxy.h ├── ReadMe.txt ├── SocksProxyServer.h ├── sockutils.cpp ├── ipaddr.cpp ├── config.cpp ├── StreamDivert.cpp ├── InboundICMPDivertProxy.cpp ├── StreamDivert.vcxproj.filters ├── InboundUDPDivertProxy.cpp ├── interfaces.cpp ├── OutboundDivertProxy.cpp ├── BaseProxy.cpp ├── StreamDivert.vcxproj ├── InboundTCPDivertProxy.cpp ├── WindowsFirewall.cpp ├── SocksProxyServer.cpp └── windivert.h ├── WinDivert ├── x64 │ ├── test.exe │ ├── netdump.exe │ ├── WinDivert.dll │ ├── WinDivert.lib │ ├── flowtrack.exe │ ├── netfilter.exe │ ├── passthru.exe │ ├── socketdump.exe │ ├── streamdump.exe │ ├── webfilter.exe │ ├── WinDivert32.sys │ ├── WinDivert64.sys │ └── windivertctl.exe └── x86 │ ├── test.exe │ ├── netdump.exe │ ├── WinDivert.dll │ ├── WinDivert.lib │ ├── flowtrack.exe │ ├── netfilter.exe │ ├── passthru.exe │ ├── socketdump.exe │ ├── streamdump.exe │ ├── webfilter.exe │ ├── WinDivert32.sys │ ├── WinDivert64.sys │ └── windivertctl.exe ├── .gitignore ├── StreamDivert.sln └── README.md /StreamDivert/socks.h: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /StreamDivert/x64/Debug/StreamDivert.vcxproj.FileListAbsolute.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /StreamDivert/socks.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "socks.h" 3 | -------------------------------------------------------------------------------- /StreamDivert/small.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jellever/StreamDivert/HEAD/StreamDivert/small.ico -------------------------------------------------------------------------------- /WinDivert/x64/test.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jellever/StreamDivert/HEAD/WinDivert/x64/test.exe -------------------------------------------------------------------------------- /WinDivert/x86/test.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jellever/StreamDivert/HEAD/WinDivert/x86/test.exe -------------------------------------------------------------------------------- /WinDivert/x64/netdump.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jellever/StreamDivert/HEAD/WinDivert/x64/netdump.exe -------------------------------------------------------------------------------- /WinDivert/x86/netdump.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jellever/StreamDivert/HEAD/WinDivert/x86/netdump.exe -------------------------------------------------------------------------------- /StreamDivert/StreamDivert.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jellever/StreamDivert/HEAD/StreamDivert/StreamDivert.rc -------------------------------------------------------------------------------- /WinDivert/x64/WinDivert.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jellever/StreamDivert/HEAD/WinDivert/x64/WinDivert.dll -------------------------------------------------------------------------------- /WinDivert/x64/WinDivert.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jellever/StreamDivert/HEAD/WinDivert/x64/WinDivert.lib -------------------------------------------------------------------------------- /WinDivert/x64/flowtrack.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jellever/StreamDivert/HEAD/WinDivert/x64/flowtrack.exe -------------------------------------------------------------------------------- /WinDivert/x64/netfilter.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jellever/StreamDivert/HEAD/WinDivert/x64/netfilter.exe -------------------------------------------------------------------------------- /WinDivert/x64/passthru.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jellever/StreamDivert/HEAD/WinDivert/x64/passthru.exe -------------------------------------------------------------------------------- /WinDivert/x64/socketdump.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jellever/StreamDivert/HEAD/WinDivert/x64/socketdump.exe -------------------------------------------------------------------------------- /WinDivert/x64/streamdump.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jellever/StreamDivert/HEAD/WinDivert/x64/streamdump.exe -------------------------------------------------------------------------------- /WinDivert/x64/webfilter.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jellever/StreamDivert/HEAD/WinDivert/x64/webfilter.exe -------------------------------------------------------------------------------- /WinDivert/x86/WinDivert.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jellever/StreamDivert/HEAD/WinDivert/x86/WinDivert.dll -------------------------------------------------------------------------------- /WinDivert/x86/WinDivert.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jellever/StreamDivert/HEAD/WinDivert/x86/WinDivert.lib -------------------------------------------------------------------------------- /WinDivert/x86/flowtrack.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jellever/StreamDivert/HEAD/WinDivert/x86/flowtrack.exe -------------------------------------------------------------------------------- /WinDivert/x86/netfilter.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jellever/StreamDivert/HEAD/WinDivert/x86/netfilter.exe -------------------------------------------------------------------------------- /WinDivert/x86/passthru.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jellever/StreamDivert/HEAD/WinDivert/x86/passthru.exe -------------------------------------------------------------------------------- /WinDivert/x86/socketdump.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jellever/StreamDivert/HEAD/WinDivert/x86/socketdump.exe -------------------------------------------------------------------------------- /WinDivert/x86/streamdump.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jellever/StreamDivert/HEAD/WinDivert/x86/streamdump.exe -------------------------------------------------------------------------------- /WinDivert/x86/webfilter.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jellever/StreamDivert/HEAD/WinDivert/x86/webfilter.exe -------------------------------------------------------------------------------- /StreamDivert/StreamDivert.aps: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jellever/StreamDivert/HEAD/StreamDivert/StreamDivert.aps -------------------------------------------------------------------------------- /StreamDivert/StreamDivert.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "resource.h" 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /StreamDivert/StreamDivert.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jellever/StreamDivert/HEAD/StreamDivert/StreamDivert.ico -------------------------------------------------------------------------------- /WinDivert/x64/WinDivert32.sys: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jellever/StreamDivert/HEAD/WinDivert/x64/WinDivert32.sys -------------------------------------------------------------------------------- /WinDivert/x64/WinDivert64.sys: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jellever/StreamDivert/HEAD/WinDivert/x64/WinDivert64.sys -------------------------------------------------------------------------------- /WinDivert/x64/windivertctl.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jellever/StreamDivert/HEAD/WinDivert/x64/windivertctl.exe -------------------------------------------------------------------------------- /WinDivert/x86/WinDivert32.sys: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jellever/StreamDivert/HEAD/WinDivert/x86/WinDivert32.sys -------------------------------------------------------------------------------- /WinDivert/x86/WinDivert64.sys: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jellever/StreamDivert/HEAD/WinDivert/x86/WinDivert64.sys -------------------------------------------------------------------------------- /WinDivert/x86/windivertctl.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jellever/StreamDivert/HEAD/WinDivert/x86/windivertctl.exe -------------------------------------------------------------------------------- /StreamDivert/InboundDivertProxy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include"ipaddr.h" 5 | 6 | 7 | struct ProxyConnectionWorkerData 8 | { 9 | SOCKET clientSock; 10 | sockaddr_in6 clientAddr; 11 | }; 12 | 13 | -------------------------------------------------------------------------------- /StreamDivert/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // StreamDivert.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /StreamDivert/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /StreamDivert/interfaces.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "ipaddr.h" 7 | 8 | 9 | #define WORKING_BUFFER_SIZE 15000 10 | #define MAX_TRIES 3 11 | 12 | 13 | 14 | void PrintInterfaceInfo(); 15 | bool GetInterfaceAddressByIdx(UINT16 ifIdx, IpAddr& addr, IPFamily family, bool onlyEnabled); -------------------------------------------------------------------------------- /StreamDivert/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | 10 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 11 | // Windows Header Files: 12 | #include 13 | 14 | // C RunTime Header Files 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | 21 | // TODO: reference additional headers your program requires here 22 | #include -------------------------------------------------------------------------------- /StreamDivert/sockutils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "ipaddr.h" 3 | 4 | 5 | int recvall(SOCKET sock, char* buffer, int len); 6 | bool recvallb(SOCKET sock, char* buffer, int len); 7 | 8 | int sendall(SOCKET sock, const char* buffer, int len); 9 | bool sendallb(SOCKET sock, const char* buffer, int len); 10 | 11 | bool recvstr(SOCKET sock, char* buf, int* len); 12 | 13 | 14 | struct ProxyTunnelWorkerData 15 | { 16 | SOCKET sockA; 17 | IpAddr sockAAddr; 18 | UINT16 sockAPort; 19 | SOCKET sockB; 20 | IpAddr sockBAddr; 21 | UINT16 sockBPort; 22 | }; 23 | 24 | void ProxyTunnelWorker(ProxyTunnelWorkerData* proxyTunnelWorkerData, std::string& logDesc); -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | -------------------------------------------------------------------------------- /StreamDivert/utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | void vmessage(const char* msg, va_list args); 6 | void verror(std::string msg, va_list args); 7 | void vwarning(std::string msg, va_list args); 8 | void vinfo(std::string msg, va_list args); 9 | void vdebug(std::string msg, va_list args); 10 | 11 | 12 | void error(std::string msg, ...); 13 | void warning(std::string msg, ...); 14 | void info(std::string msg, ...); 15 | void debug(std::string msg, ...); 16 | 17 | void joinStr(const std::vector& v, std::string& c, std::string& s); 18 | void joinStr(const std::set& v, std::string& c, std::string& s); 19 | 20 | std::string GetApplicationExecutablePath(); 21 | char* basename(char* filepath); -------------------------------------------------------------------------------- /StreamDivert/Resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by StreamDivert.rc 4 | // 5 | 6 | #define IDS_APP_TITLE 103 7 | 8 | #define IDR_MAINFRAME 128 9 | #define IDD_STREAMDIVERT_DIALOG 102 10 | #define IDD_ABOUTBOX 103 11 | #define IDM_ABOUT 104 12 | #define IDM_EXIT 105 13 | #define IDI_STREAMDIVERT 107 14 | #define IDI_SMALL 108 15 | #define IDC_STREAMDIVERT 109 16 | #define IDC_MYICON 2 17 | #ifndef IDC_STATIC 18 | #define IDC_STATIC -1 19 | #endif 20 | // Next default values for new objects 21 | // 22 | #ifdef APSTUDIO_INVOKED 23 | #ifndef APSTUDIO_READONLY_SYMBOLS 24 | 25 | #define _APS_NO_MFC 130 26 | #define _APS_NEXT_RESOURCE_VALUE 129 27 | #define _APS_NEXT_COMMAND_VALUE 32771 28 | #define _APS_NEXT_CONTROL_VALUE 1000 29 | #define _APS_NEXT_SYMED_VALUE 110 30 | #endif 31 | #endif 32 | -------------------------------------------------------------------------------- /StreamDivert/config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "ipaddr.h" 4 | #include 5 | #include 6 | 7 | enum InboundRelayEntryType 8 | { 9 | None, 10 | Divert, 11 | Socks 12 | }; 13 | 14 | struct InboundRelayEntry 15 | { 16 | InboundRelayEntryType type; 17 | std::string protocol; 18 | UINT16 localPort; 19 | IpAddr srcAddr; 20 | IpAddr forwardAddr; 21 | UINT16 forwardPort; 22 | }; 23 | 24 | struct OutboundRelayEntry 25 | { 26 | std::string protocol; 27 | IpAddr dstAddr; 28 | UINT16 dstPort; 29 | IpAddr forwardAddr; 30 | UINT forwardPort; 31 | UINT32 interfaceIdx; 32 | bool forceInterfaceIdx; 33 | }; 34 | 35 | 36 | 37 | struct RelayConfig 38 | { 39 | std::vector inboundRelayEntries; 40 | std::vector outboundRelayEntries; 41 | }; 42 | 43 | bool LoadConfig(std::string path, RelayConfig& result); 44 | -------------------------------------------------------------------------------- /StreamDivert/WindowsFirewall.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #pragma comment( lib, "ole32.lib" ) 11 | #pragma comment( lib, "oleaut32.lib" ) 12 | 13 | 14 | class WindowsFirewall 15 | { 16 | protected: 17 | INetFwProfile* profile; 18 | 19 | public: 20 | WindowsFirewall(); 21 | ~WindowsFirewall(); 22 | bool Initialize(); 23 | bool IsFirewallOn(bool& on); 24 | bool PortIsConfigured(long port, NET_FW_IP_PROTOCOL proto, bool& isConfigured); 25 | bool AddPort(long port, NET_FW_IP_PROTOCOL ipProtocol, std::string& name); 26 | bool RemovePort(long port, NET_FW_IP_PROTOCOL ipProtocol); 27 | bool IsApplicationConfigured(std::string path, bool& configured); 28 | bool AddApplication(std::string path, std::string name); 29 | bool RemoveApplication(std::string path); 30 | }; 31 | 32 | -------------------------------------------------------------------------------- /StreamDivert/cfg.txt: -------------------------------------------------------------------------------- 1 | //tcp < 445 10.0.1.50 -> 10.0.1.49 446 2 | //tcp < 445 0.0.0.0 -> fe80::20c:29ff:fe6f:88ff 445 3 | //tcp < 445 fe80::f477:846a:775d:d37 -> fe80::20c:29ff:fe6f:88ff 445 4 | //tcp < 445 fe80::f477:846a:775d:d37 -> 10.0.1.49 445 5 | //tcp < 445 0.0.0.0 -> socks 6 | 7 | 8 | //udp < 8080 10.0.1.50 -> 10.0.1.49 8081 9 | //udp < 8080 0.0.0.0 -> 10.0.1.49 8080 10 | 11 | //tcp > 8.8.8.8 80 -> 10.0.1.49 8081 12 | //tcp > 0.0.0.0 8080 -> 10.0.1.49 8080 13 | //tcp > fe80::f477:846a:775d:d37 80 -> fe80::20c:29ff:fe6f:88ff 8080 14 | 15 | 16 | 17 | tcp > 8.8.8.8 80 -> 8.8.8.8 80 force interface 9 18 | 19 | //This does NOT work 20 | //tcp > fe80::f477:846a:775d:d37 80 -> 10.0.1.49 8080 21 | //tcp > 8.8.8.8 80 -> fe80::20c:29ff:fe6f:88ff 8080 22 | 23 | 24 | //udp > 1.2.3.4 8080 -> 10.0.1.49 8081 25 | //udp > 0.0.0.0 8080 -> 10.0.1.49 8080 26 | //udp > 0.0.0.0 53 -> 10.0.1.49 8080 27 | 28 | //icmp < 10.0.1.50 -> 10.0.1.49 29 | //icmp < fe80::f477:846a:775d:d37 -> fe80::20c:29ff:fe6f:88ff 30 | //icmp < 0.0.0.0 -> 10.0.1.50 31 | //icmp > 0.0.0.0 -> 10.0.1.49 -------------------------------------------------------------------------------- /StreamDivert/ipaddr.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | enum IPFamily : int 7 | { 8 | Unknown = -1, 9 | IPv4 = 4, 10 | IPv6 = 6, 11 | }; 12 | 13 | 14 | const uint8_t ipv4_mapped_prefix[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff }; 15 | 16 | class IpAddr 17 | { 18 | protected: 19 | in6_addr m_addr; 20 | #if _DEBUG 21 | std::string addrStr; 22 | #endif 23 | void initIpv4(const in_addr& addr); 24 | void initIpv6(const in6_addr& addr); 25 | void init(); 26 | 27 | public: 28 | IpAddr(); 29 | IpAddr(const in_addr& addr); 30 | IpAddr(const in6_addr& addr); 31 | IpAddr(const std::string& addr); 32 | ~IpAddr(); 33 | bool operator==(const IpAddr& addr2); 34 | bool operator==(const UINT32& addr2); 35 | bool operator!=(const IpAddr& addr2); 36 | bool operator<(const IpAddr& addr2); 37 | bool operator<=(const IpAddr& addr2); 38 | bool operator>=(const IpAddr& addr2); 39 | bool operator>(const IpAddr& addr2); 40 | IPFamily get_family(); 41 | std::string to_string(); 42 | in6_addr get_addr(); 43 | in_addr get_ipv4_addr(); 44 | }; 45 | -------------------------------------------------------------------------------- /StreamDivert/StreamDivert.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | "$(SolutionDir)StreamDivert\cfg.txt" -f 5 | WindowsLocalDebugger 6 | 7 | 8 | "$(SolutionDir)StreamDivert\cfg.txt" -f 9 | WindowsLocalDebugger 10 | 11 | 12 | "$(SolutionDir)StreamDivert\cfg.txt" -f 13 | WindowsLocalDebugger 14 | 15 | 16 | "$(SolutionDir)StreamDivert\cfg.txt" -f 17 | WindowsLocalDebugger 18 | 19 | -------------------------------------------------------------------------------- /StreamDivert/OutboundDivertProxy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "BaseProxy.h" 4 | #include "windivert.h" 5 | #include "config.h" 6 | 7 | 8 | class OutboundDivertProxy : public BaseProxy 9 | { 10 | protected: 11 | std::vector relayEntries; 12 | std::map incomingTCPMap; 13 | std::map incomingUDPMap; 14 | std::map incomingICMPMap; 15 | 16 | std::string getStringDesc(); 17 | std::string generateDivertFilterString(); 18 | PacketAction ProcessTCPPacket(unsigned char* packet, UINT& packet_len, PWINDIVERT_ADDRESS addr, PWINDIVERT_IPHDR ip_hdr, PWINDIVERT_IPV6HDR ip6_hdr, PWINDIVERT_TCPHDR tcp_hdr, IpAddr& srcAddr, IpAddr& dstAddr); 19 | PacketAction ProcessICMPPacket(unsigned char * packet, UINT & packet_len, PWINDIVERT_ADDRESS addr, PWINDIVERT_IPHDR ip_hdr, PWINDIVERT_IPV6HDR ip6_hdr, PWINDIVERT_ICMPHDR icmp_hdr, PWINDIVERT_ICMPV6HDR icmp6_hdr, IpAddr & srcAddr, IpAddr & dstAddr); 20 | PacketAction ProcessUDPPacket(unsigned char * packet, UINT & packet_len, PWINDIVERT_ADDRESS addr, PWINDIVERT_IPHDR ip_hdr, PWINDIVERT_IPV6HDR ip6_hdr, PWINDIVERT_UDPHDR udp_header, IpAddr & srcAddr, IpAddr & dstAddr); 21 | 22 | public: 23 | OutboundDivertProxy(bool verbose, std::vector& relayEntries); 24 | ~OutboundDivertProxy(); 25 | virtual bool Stop(); 26 | }; 27 | -------------------------------------------------------------------------------- /StreamDivert.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "StreamDivert", "StreamDivert\StreamDivert.vcxproj", "{D3214282-B88F-44E5-8B5E-57663AD96AD5}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {D3214282-B88F-44E5-8B5E-57663AD96AD5}.Debug|x64.ActiveCfg = Debug|x64 17 | {D3214282-B88F-44E5-8B5E-57663AD96AD5}.Debug|x64.Build.0 = Debug|x64 18 | {D3214282-B88F-44E5-8B5E-57663AD96AD5}.Debug|x86.ActiveCfg = Debug|Win32 19 | {D3214282-B88F-44E5-8B5E-57663AD96AD5}.Debug|x86.Build.0 = Debug|Win32 20 | {D3214282-B88F-44E5-8B5E-57663AD96AD5}.Release|x64.ActiveCfg = Release|x64 21 | {D3214282-B88F-44E5-8B5E-57663AD96AD5}.Release|x64.Build.0 = Release|x64 22 | {D3214282-B88F-44E5-8B5E-57663AD96AD5}.Release|x86.ActiveCfg = Release|Win32 23 | {D3214282-B88F-44E5-8B5E-57663AD96AD5}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /StreamDivert/InboundUDPDivertProxy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "windivert.h" 8 | #include "BaseProxy.h" 9 | #include "config.h" 10 | #include"ipaddr.h" 11 | #include "InboundDivertProxy.h" 12 | 13 | 14 | class InboundUDPDivertProxy : public BaseProxy 15 | { 16 | protected: 17 | std::vector proxyRecords; 18 | std::map connectionMap; 19 | 20 | std::string getStringDesc(); 21 | PacketAction ProcessTCPPacket(unsigned char* packet, UINT& packet_len, PWINDIVERT_ADDRESS addr, PWINDIVERT_IPHDR ip_hdr, PWINDIVERT_IPV6HDR ip6_hdr, PWINDIVERT_TCPHDR tcp_hdr, IpAddr& srcAddr, IpAddr& dstAddr); 22 | PacketAction ProcessICMPPacket(unsigned char * packet, UINT & packet_len, PWINDIVERT_ADDRESS addr, PWINDIVERT_IPHDR ip_hdr, PWINDIVERT_IPV6HDR ip6_hdr, PWINDIVERT_ICMPHDR icmp_hdr, PWINDIVERT_ICMPV6HDR icmp6_hdr, IpAddr & srcAddr, IpAddr & dstAddr); 23 | PacketAction ProcessUDPPacket(unsigned char * packet, UINT & packet_len, PWINDIVERT_ADDRESS addr, PWINDIVERT_IPHDR ip_hdr, PWINDIVERT_IPV6HDR ip6_hdr, PWINDIVERT_UDPHDR udp_header, IpAddr & srcAddr, IpAddr & dstAddr); 24 | std::string generateDivertFilterString(); 25 | public: 26 | InboundUDPDivertProxy(bool verbose, const std::vector& proxyRecords); 27 | ~InboundUDPDivertProxy(); 28 | bool Stop(); 29 | }; 30 | -------------------------------------------------------------------------------- /StreamDivert/InboundICMPDivertProxy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "windivert.h" 8 | #include "BaseProxy.h" 9 | #include "config.h" 10 | #include"ipaddr.h" 11 | #include "InboundDivertProxy.h" 12 | 13 | 14 | class InboundICMPDivertProxy : public BaseProxy 15 | { 16 | protected: 17 | std::vector proxyRecords; 18 | std::map connectionMap; 19 | 20 | std::string getStringDesc(); 21 | PacketAction ProcessTCPPacket(unsigned char* packet, UINT& packet_len, PWINDIVERT_ADDRESS addr, PWINDIVERT_IPHDR ip_hdr, PWINDIVERT_IPV6HDR ip6_hdr, PWINDIVERT_TCPHDR tcp_hdr, IpAddr& srcAddr, IpAddr& dstAddr); 22 | PacketAction ProcessICMPPacket(unsigned char * packet, UINT & packet_len, PWINDIVERT_ADDRESS addr, PWINDIVERT_IPHDR ip_hdr, PWINDIVERT_IPV6HDR ip6_hdr, PWINDIVERT_ICMPHDR icmp_hdr, PWINDIVERT_ICMPV6HDR icmp6_hdr, IpAddr & srcAddr, IpAddr & dstAddr); 23 | PacketAction ProcessUDPPacket(unsigned char * packet, UINT & packet_len, PWINDIVERT_ADDRESS addr, PWINDIVERT_IPHDR ip_hdr, PWINDIVERT_IPV6HDR ip6_hdr, PWINDIVERT_UDPHDR udp_header, IpAddr & srcAddr, IpAddr & dstAddr); 24 | std::string generateDivertFilterString(); 25 | public: 26 | InboundICMPDivertProxy(bool verbose, const std::vector& proxyRecords); 27 | ~InboundICMPDivertProxy(); 28 | bool Stop(); 29 | }; 30 | 31 | -------------------------------------------------------------------------------- /StreamDivert/InboundTCPDivertProxy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "windivert.h" 8 | #include "BaseProxy.h" 9 | #include "config.h" 10 | #include"ipaddr.h" 11 | #include "InboundDivertProxy.h" 12 | #include "SocksProxyServer.h" 13 | 14 | 15 | class InboundTCPDivertProxy : public BaseProxy 16 | { 17 | protected: 18 | SOCKET proxySock; 19 | std::thread proxyThread; 20 | 21 | UINT16 localPort; 22 | UINT16 localProxyPort; 23 | std::vector proxyRecords; 24 | SocksProxyServer socksServer; 25 | bool containsSocksRecords; 26 | 27 | std::string getStringDesc(); 28 | PacketAction ProcessTCPPacket(unsigned char* packet, UINT& packet_len, PWINDIVERT_ADDRESS addr, PWINDIVERT_IPHDR ip_hdr, PWINDIVERT_IPV6HDR ip6_hdr, PWINDIVERT_TCPHDR tcp_hdr, IpAddr& srcAddr, IpAddr& dstAddr); 29 | PacketAction ProcessICMPPacket(unsigned char * packet, UINT & packet_len, PWINDIVERT_ADDRESS addr, PWINDIVERT_IPHDR ip_hdr, PWINDIVERT_IPV6HDR ip6_hdr, PWINDIVERT_ICMPHDR icmp_hdr, PWINDIVERT_ICMPV6HDR icmp6_hdr, IpAddr & srcAddr, IpAddr & dstAddr); 30 | PacketAction ProcessUDPPacket(unsigned char * packet, UINT & packet_len, PWINDIVERT_ADDRESS addr, PWINDIVERT_IPHDR ip_hdr, PWINDIVERT_IPV6HDR ip6_hdr, PWINDIVERT_UDPHDR udp_header, IpAddr & srcAddr, IpAddr & dstAddr); 31 | void ProxyWorker(); 32 | void ProxyConnectionWorker(ProxyConnectionWorkerData* proxyConnectionWorkerData); 33 | std::string generateDivertFilterString(); 34 | bool findProxyRecordBySrcAddr(IpAddr& srcIp, InboundRelayEntry& proxyRecord); 35 | public: 36 | InboundTCPDivertProxy(bool verbose, const UINT16 localPort, const std::vector& proxyRecords); 37 | ~InboundTCPDivertProxy(); 38 | bool Start(); 39 | bool Stop(); 40 | }; 41 | -------------------------------------------------------------------------------- /StreamDivert/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "utils.h" 3 | #include 4 | 5 | HANDLE msgLock = CreateMutex(NULL, FALSE, NULL); 6 | 7 | void message(const char *msg, va_list args) 8 | { 9 | WaitForSingleObject(msgLock, INFINITE); 10 | vfprintf(stderr, msg, args); 11 | putc('\n', stderr); 12 | ReleaseMutex(msgLock); 13 | } 14 | 15 | void verror(std::string msg, va_list args) 16 | { 17 | message(("[-] " + msg).c_str(), args); 18 | } 19 | 20 | void vwarning(std::string msg, va_list args) 21 | { 22 | message(("[!] " + msg).c_str(), args); 23 | } 24 | 25 | void vinfo(std::string msg, va_list args) 26 | { 27 | message(("[*] " + msg).c_str(), args); 28 | } 29 | 30 | void vdebug(std::string msg, va_list args) 31 | { 32 | message(("[*] " + msg).c_str(), args); 33 | } 34 | 35 | void error(std::string msg, ...) 36 | { 37 | va_list args; 38 | va_start(args, msg); 39 | verror(msg, args); 40 | va_end(args); 41 | } 42 | 43 | void warning(std::string msg, ...) 44 | { 45 | va_list args; 46 | va_start(args, msg); 47 | vwarning(msg, args); 48 | va_end(args); 49 | } 50 | 51 | void info(std::string msg, ...) 52 | { 53 | va_list args; 54 | va_start(args, msg); 55 | vinfo(msg, args); 56 | va_end(args); 57 | } 58 | 59 | void debug(std::string msg, ...) 60 | { 61 | va_list args; 62 | va_start(args, msg); 63 | vinfo(msg, args); 64 | va_end(args); 65 | } 66 | 67 | void joinStr(const std::vector& v, std::string& c, std::string& s) 68 | { 69 | for (std::vector::const_iterator p = v.begin(); 70 | p != v.end(); ++p) { 71 | s += *p; 72 | if (p != v.end() - 1) 73 | s += c; 74 | } 75 | } 76 | 77 | void joinStr(const std::set& v, std::string& c, std::string& s) 78 | { 79 | std::vector output(v.begin(), v.end()); 80 | return joinStr(output, c, s); 81 | } 82 | 83 | std::string GetApplicationExecutablePath() 84 | { 85 | char buffer[MAX_PATH]; 86 | DWORD stat = GetModuleFileNameA(NULL, &buffer[0], sizeof(buffer)); 87 | return std::string(&buffer[0]); 88 | } 89 | 90 | char* basename(char* filepath) 91 | { 92 | char* pfile; 93 | pfile = filepath + strlen(filepath); 94 | for (; pfile > filepath; pfile--) 95 | { 96 | if ((*pfile == '\\') || (*pfile == '/')) 97 | { 98 | pfile++; 99 | break; 100 | } 101 | } 102 | return pfile; 103 | } 104 | -------------------------------------------------------------------------------- /StreamDivert/BaseProxy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include "windivert.h" 6 | #include"ipaddr.h" 7 | 8 | static IpAddr anyIpAddr = IpAddr("0.0.0.0"); 9 | static IpAddr anyIp6Addr = IpAddr("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); 10 | static void cleanup(HANDLE ioport, OVERLAPPED *ignore); 11 | 12 | struct EndpointKey 13 | { 14 | in6_addr addr; 15 | UINT16 port; 16 | 17 | bool operator<(const EndpointKey& rhs) const { return memcmp(this, &rhs, sizeof(EndpointKey)) < 0; } 18 | bool operator==(const EndpointKey& rhs) const { return memcmp(this, &rhs, sizeof(EndpointKey)) == 0; } 19 | }; 20 | 21 | struct Endpoint 22 | { 23 | IpAddr addr; 24 | UINT16 port; 25 | UINT32 ifIfx; 26 | }; 27 | 28 | enum PacketAction 29 | { 30 | STATUS_UNKOWN, 31 | STATUS_PROCEED, 32 | STATUS_DROP 33 | }; 34 | 35 | class BaseProxy 36 | { 37 | protected: 38 | bool running; 39 | HANDLE hDivert; 40 | HANDLE ioPort; 41 | HANDLE event; 42 | std::thread divertThread; 43 | INT16 priority; 44 | std::string filterStr; 45 | std::string selfDescStr; 46 | std::recursive_mutex resourceLock; 47 | bool verbose; 48 | 49 | void logDebug(const char* msg, ...); 50 | void logInfo(const char* msg, ...); 51 | void logWarning(const char* msg, ...); 52 | void logError(const char* msg, ...); 53 | std::string getIpAddrIpStr(IpAddr& addr); 54 | virtual std::string getStringDesc(); 55 | virtual std::string generateDivertFilterString(); 56 | void SwapIPHeaderSrcToDst(PWINDIVERT_IPHDR ip_hdr, PWINDIVERT_IPV6HDR ip6_hdr); 57 | void SwapIPHeaderDstToSrc(PWINDIVERT_IPHDR ip_hdr, PWINDIVERT_IPV6HDR ip6_hdr); 58 | void OverrideIPHeaderSrc(PWINDIVERT_IPHDR ip_hdr, PWINDIVERT_IPV6HDR ip6_hdr, IpAddr& addr); 59 | void OverrideIPHeaderDst(PWINDIVERT_IPHDR ip_hdr, PWINDIVERT_IPV6HDR ip6_hdr, IpAddr& addr); 60 | virtual void DivertWorker(); 61 | virtual PacketAction ProcessTCPPacket(unsigned char* packet, UINT& packet_len, PWINDIVERT_ADDRESS addr, PWINDIVERT_IPHDR ip_hdr, PWINDIVERT_IPV6HDR ip6_hdr, PWINDIVERT_TCPHDR tcp_hdr, IpAddr& srcAddr, IpAddr& dstAddr) = 0; 62 | virtual PacketAction ProcessICMPPacket(unsigned char* packet, UINT& packet_len, PWINDIVERT_ADDRESS addr, PWINDIVERT_IPHDR ip_hdr, PWINDIVERT_IPV6HDR ip6_hdr, PWINDIVERT_ICMPHDR icmp_hdr, PWINDIVERT_ICMPV6HDR icmp6_hdr, IpAddr& srcAddr, IpAddr& dstAddr) = 0; 63 | virtual PacketAction ProcessUDPPacket(unsigned char* packet, UINT& packet_len, PWINDIVERT_ADDRESS addr, PWINDIVERT_IPHDR ip_hdr, PWINDIVERT_IPV6HDR ip6_hdr, PWINDIVERT_UDPHDR udp_header, IpAddr& srcAddr, IpAddr& dstAddr) = 0; 64 | 65 | public: 66 | BaseProxy(bool verbose); 67 | ~BaseProxy(); 68 | virtual bool Start(); 69 | virtual bool Stop(); 70 | }; 71 | 72 | -------------------------------------------------------------------------------- /StreamDivert/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | WIN32 APPLICATION : StreamDivert Project Overview 3 | ======================================================================== 4 | 5 | AppWizard has created this StreamDivert application for you. 6 | 7 | This file contains a summary of what you will find in each of the files that 8 | make up your StreamDivert application. 9 | 10 | 11 | StreamDivert.vcxproj 12 | This is the main project file for VC++ projects generated using an Application Wizard. 13 | It contains information about the version of Visual C++ that generated the file, and 14 | information about the platforms, configurations, and project features selected with the 15 | Application Wizard. 16 | 17 | StreamDivert.vcxproj.filters 18 | This is the filters file for VC++ projects generated using an Application Wizard. 19 | It contains information about the association between the files in your project 20 | and the filters. This association is used in the IDE to show grouping of files with 21 | similar extensions under a specific node (for e.g. ".cpp" files are associated with the 22 | "Source Files" filter). 23 | 24 | StreamDivert.cpp 25 | This is the main application source file. 26 | 27 | ///////////////////////////////////////////////////////////////////////////// 28 | AppWizard has created the following resources: 29 | 30 | StreamDivert.rc 31 | This is a listing of all of the Microsoft Windows resources that the 32 | program uses. It includes the icons, bitmaps, and cursors that are stored 33 | in the RES subdirectory. This file can be directly edited in Microsoft 34 | Visual C++. 35 | 36 | Resource.h 37 | This is the standard header file, which defines new resource IDs. 38 | Microsoft Visual C++ reads and updates this file. 39 | 40 | StreamDivert.ico 41 | This is an icon file, which is used as the application's icon (32x32). 42 | This icon is included by the main resource file StreamDivert.rc. 43 | 44 | small.ico 45 | This is an icon file, which contains a smaller version (16x16) 46 | of the application's icon. This icon is included by the main resource 47 | file StreamDivert.rc. 48 | 49 | ///////////////////////////////////////////////////////////////////////////// 50 | Other standard files: 51 | 52 | StdAfx.h, StdAfx.cpp 53 | These files are used to build a precompiled header (PCH) file 54 | named StreamDivert.pch and a precompiled types file named StdAfx.obj. 55 | 56 | ///////////////////////////////////////////////////////////////////////////// 57 | Other notes: 58 | 59 | AppWizard uses "TODO:" comments to indicate parts of the source code you 60 | should add to or customize. 61 | 62 | ///////////////////////////////////////////////////////////////////////////// 63 | -------------------------------------------------------------------------------- /StreamDivert/SocksProxyServer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include "ipaddr.h" 6 | 7 | struct SocksServerConnectionData 8 | { 9 | SOCKET clientSocket; 10 | sockaddr_in6 clientAddr; 11 | }; 12 | 13 | enum SocksVersion 14 | { 15 | SocksVerNone = 0x0, 16 | Socks4 = 0x04, 17 | Socks5 = 0x05, 18 | }; 19 | 20 | 21 | 22 | enum Socks4aClientResponse : char 23 | { 24 | RequestGranted = 90, 25 | RequestRejectedOrFailed = 91, 26 | RequestRejectedIdentd = 92, 27 | RequestRejectedUserid = 93 28 | }; 29 | 30 | enum Socks5ClientResponse : char 31 | { 32 | succeeded = 0, 33 | GeneralServerFailure = 1, 34 | ConnectionNotAllowed = 2, 35 | NetworkUnreachable = 3, 36 | HostUnreachable = 4, 37 | ConnectionRefused = 5, 38 | TTLExpired = 6, 39 | CommandNotSupported = 7, 40 | AddressTypeNotSupported = 8 41 | }; 42 | 43 | enum Socks5AuthMethods { 44 | NOAUTH = 0x00, 45 | USERPASS = 0x02, 46 | NOMETHOD = 0xff 47 | }; 48 | 49 | enum Socks5UserPassAuth 50 | { 51 | AuthOk = 0, 52 | AuthFail = 0xff 53 | }; 54 | 55 | enum Socks5AddressType 56 | { 57 | AddrTypeNone = 0, 58 | AddrTypeIPv4 = 1, 59 | AddrTypeDomainName = 3, 60 | AddrTypeIPv6 = 4 61 | }; 62 | 63 | #define CMD_CONNECT 0x1 64 | #define AUTH_VERSION 0x1 65 | 66 | class SocksProxyServer 67 | { 68 | protected: 69 | int port; 70 | SOCKET serverSock; 71 | std::thread serverThread; 72 | std::string selfDescStr; 73 | std::recursive_mutex resourceLock; 74 | bool running; 75 | Socks5AuthMethods socks5AuthType; 76 | std::string username; 77 | std::string password; 78 | bool enableSocks4; 79 | bool enableSocks5; 80 | 81 | std::string getSelfDescription(); 82 | void ProxyServerWorker(); 83 | void ProxyConnectionWorker(SocksServerConnectionData* data); 84 | SocksVersion recvSocksVersion(SOCKET sock); 85 | SOCKET ProcessSocks4Connection(SOCKET sock); 86 | bool socks4aIsInvalidIpv4(int ip); 87 | bool socks4aSendClientResponse(SOCKET sock, Socks4aClientResponse response); 88 | SOCKET ProcessSocks5Connection(SOCKET sock); 89 | bool socks5Auth(SOCKET sock, int methods); 90 | void socks5SendAuthNotSupported(SOCKET sock); 91 | void socks5SendNoAth(SOCKET sock); 92 | bool socks5UserPassAuthentication(SOCKET sock); 93 | bool socks5GetUserPassStr(SOCKET sock, std::string& user); 94 | bool socks5SendClientResponse(SOCKET sock, Socks5ClientResponse reply, Socks5AddressType addrType, IpAddr* ipAddr, std::string* domain, unsigned short int port); 95 | SOCKET socksConnect(IpAddr& ip, int port); 96 | SOCKET socksConnect(std::string domain, int port); 97 | public: 98 | SocksProxyServer(int port, bool enableSocks4, bool enableSocks5); 99 | SocksProxyServer(int port); 100 | 101 | ~SocksProxyServer(); 102 | void SetAuthType(Socks5AuthMethods method); 103 | void SetAuthUsername(std::string& username); 104 | void SetAuthPassword(std::string& password); 105 | int GetPort(); 106 | bool IsRunning(); 107 | bool Start(); 108 | bool Stop(); 109 | }; 110 | 111 | -------------------------------------------------------------------------------- /StreamDivert/sockutils.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "sockutils.h" 3 | #include 4 | #include "utils.h" 5 | 6 | 7 | int recvall(SOCKET sock, char* buffer, int len) 8 | { 9 | char* dataPtr = buffer; 10 | int totalRead = 0; 11 | while (totalRead < len) 12 | { 13 | int read = recv(sock, dataPtr, len - totalRead, 0); 14 | if(read == 0 || read == SOCKET_ERROR) 15 | { 16 | break; 17 | } 18 | totalRead += read; 19 | dataPtr += read; 20 | } 21 | return totalRead; 22 | } 23 | 24 | bool recvallb(SOCKET sock, char* buffer, int len) 25 | { 26 | return recvall(sock, buffer, len) == len; 27 | } 28 | 29 | int sendall(SOCKET sock, const char* buffer, int len) 30 | { 31 | const char* dataPtr = buffer; 32 | int totalSent = 0; 33 | while (totalSent < len) 34 | { 35 | int sent = send(sock, dataPtr, len - totalSent, 0); 36 | if (sent == SOCKET_ERROR) 37 | { 38 | break; 39 | } 40 | totalSent += sent; 41 | dataPtr += sent; 42 | } 43 | return totalSent; 44 | } 45 | 46 | bool sendallb(SOCKET sock, const char* buffer, int len) 47 | { 48 | return sendall(sock, buffer, len) == len; 49 | } 50 | 51 | bool recvstr(SOCKET sock, char* buf, int* len) 52 | { 53 | int totalRead = 0; 54 | int read = 0; 55 | while (totalRead < *len) 56 | { 57 | read = recv(sock, buf + totalRead, 1, 0); 58 | if (read == 0 || read == SOCKET_ERROR) 59 | { 60 | return false; 61 | } 62 | if (*(buf + totalRead) == 0) 63 | { 64 | return true; 65 | } 66 | } 67 | return false; 68 | } 69 | 70 | void ProxyTunnelWorker(ProxyTunnelWorkerData* proxyTunnelWorkerData, std::string& logDesc) 71 | { 72 | SOCKET sockA = proxyTunnelWorkerData->sockA; 73 | std::string sockAAddrStr = proxyTunnelWorkerData->sockAAddr.to_string(); 74 | UINT16 sockAPort = proxyTunnelWorkerData->sockAPort; 75 | SOCKET sockB = proxyTunnelWorkerData->sockB; 76 | std::string sockBAddrStr = proxyTunnelWorkerData->sockBAddr.to_string(); 77 | UINT16 sockBPort = proxyTunnelWorkerData->sockBPort; 78 | delete proxyTunnelWorkerData; 79 | char buf[8192]; 80 | int recvLen; 81 | 82 | info("Tunneling %s:%d -> %s:%d", sockAAddrStr.c_str(), sockAPort, sockBAddrStr.c_str(), sockBPort); 83 | 84 | while (true) 85 | { 86 | recvLen = recv(sockA, buf, sizeof(buf), 0); 87 | if (recvLen == SOCKET_ERROR) 88 | { 89 | warning("%s: failed to recv from socket A(%s:%hu): %d", logDesc.c_str(), sockAAddrStr.c_str(), sockAPort, WSAGetLastError()); 90 | goto failure; 91 | } 92 | if (recvLen == 0) 93 | { 94 | shutdown(sockA, SD_RECEIVE); 95 | shutdown(sockB, SD_SEND); 96 | goto end; //return 97 | } 98 | 99 | for (int i = 0; i < recvLen; ) 100 | { 101 | int sendLen = send(sockB, buf + i, recvLen - i, 0); 102 | if (sendLen == SOCKET_ERROR) 103 | { 104 | warning("%s: failed to send to socket B(%s:%hu): %d", logDesc.c_str(), sockBAddrStr.c_str(), sockBPort, WSAGetLastError()); 105 | goto failure; //return 106 | } 107 | i += sendLen; 108 | } 109 | } 110 | 111 | failure: 112 | shutdown(sockA, SD_BOTH); 113 | shutdown(sockB, SD_BOTH); 114 | end: 115 | info("%s: ProxyTunnelWorker(%s:%hu -> %s:%hu) exiting", logDesc.c_str(), sockAAddrStr.c_str(), sockAPort, sockBAddrStr.c_str(), sockBPort); 116 | } -------------------------------------------------------------------------------- /StreamDivert/ipaddr.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "ipaddr.h" 3 | #include 4 | #include 5 | #include "utils.h" 6 | 7 | 8 | void IpAddr::initIpv4(const in_addr & addr) 9 | { 10 | memcpy(&this->m_addr.s6_addr[0], ipv4_mapped_prefix, sizeof(ipv4_mapped_prefix)); 11 | memcpy(&this->m_addr.s6_addr[12], &addr.s_addr, sizeof(addr)); 12 | this->init(); 13 | } 14 | 15 | void IpAddr::initIpv6(const in6_addr & addr) 16 | { 17 | this->m_addr = addr; 18 | this->init(); 19 | } 20 | 21 | void IpAddr::init() 22 | { 23 | #if _DEBUG 24 | this->addrStr = this->to_string(); 25 | #endif 26 | } 27 | 28 | IpAddr::IpAddr() 29 | { 30 | memset(&this->m_addr, 0, sizeof(in6_addr)); 31 | } 32 | 33 | IpAddr::IpAddr(const in_addr& addr) 34 | { 35 | this->initIpv4(addr); 36 | } 37 | 38 | IpAddr::IpAddr(const in6_addr& addr) 39 | { 40 | this->initIpv6(addr); 41 | } 42 | 43 | IpAddr::IpAddr(const std::string & addrstr) 44 | { 45 | struct in_addr addr; 46 | bool isipv4 = inet_pton(AF_INET, addrstr.c_str(), &addr) != 0; 47 | if (isipv4) 48 | { 49 | this->initIpv4(addr); 50 | } 51 | struct in6_addr addr6; 52 | bool isipv6 = inet_pton(AF_INET6, addrstr.c_str(), &addr6) != 0; 53 | if (isipv6) 54 | { 55 | this->initIpv6(addr6); 56 | } 57 | } 58 | 59 | IpAddr::~IpAddr() 60 | { 61 | } 62 | 63 | IPFamily IpAddr::get_family() 64 | { 65 | if(memcmp(&this->m_addr.s6_addr[0], ipv4_mapped_prefix, sizeof(ipv4_mapped_prefix)) == 0) 66 | { 67 | return IPFamily::IPv4; 68 | } 69 | else 70 | { 71 | return IPFamily::IPv6; 72 | } 73 | } 74 | 75 | std::string IpAddr::to_string() 76 | { 77 | std::string result; 78 | 79 | IPFamily ipfamily = this->get_family(); 80 | if(ipfamily == IPFamily::IPv4) 81 | { 82 | result.resize(INET_ADDRSTRLEN); 83 | const char* r = inet_ntop(AF_INET, &this->m_addr.s6_addr[12], &result[0], INET_ADDRSTRLEN); 84 | if (r == NULL) 85 | { 86 | error("Failed to convert ip to ipv4 address string!"); 87 | } 88 | } 89 | else if(ipfamily == IPFamily::IPv6) 90 | { 91 | result.resize(INET6_ADDRSTRLEN); 92 | const char* r = inet_ntop(AF_INET6, &this->m_addr, &result[0], INET6_ADDRSTRLEN); 93 | if (r == NULL) 94 | { 95 | error("Failed to convert ip to ipv6 address string!"); 96 | } 97 | } 98 | result.resize(strlen(result.c_str())); 99 | return result; 100 | } 101 | 102 | in6_addr IpAddr::get_addr() 103 | { 104 | return this->m_addr; 105 | } 106 | 107 | in_addr IpAddr::get_ipv4_addr() 108 | { 109 | return *(in_addr*)&this->m_addr.s6_addr[12]; 110 | } 111 | 112 | bool IpAddr::operator==(const IpAddr& addr2) 113 | { 114 | return memcmp(&this->m_addr, &addr2.m_addr, sizeof(in6_addr)) == 0; 115 | } 116 | 117 | bool IpAddr::operator==(const UINT32 & addr2) 118 | { 119 | if (this->get_family() != IPFamily::IPv4) 120 | { 121 | return false; 122 | } 123 | return memcmp(&this->m_addr.s6_addr[12], &addr2, sizeof(in_addr)) == 0; 124 | } 125 | 126 | bool IpAddr::operator!=(const IpAddr& addr2) 127 | { 128 | return ! (*this == addr2); 129 | } 130 | 131 | bool IpAddr::operator<(const IpAddr& addr2) 132 | { 133 | return memcmp(&this->m_addr, &addr2.m_addr, sizeof(in6_addr)) < 0; 134 | } 135 | 136 | bool IpAddr::operator<=(const IpAddr& addr2) 137 | { 138 | return *this < addr2 || *this == addr2; 139 | } 140 | 141 | bool IpAddr::operator>=(const IpAddr& addr2) 142 | { 143 | return ! ( *this < addr2 ); 144 | } 145 | 146 | bool IpAddr::operator>(const IpAddr& addr2) 147 | { 148 | return ! ( *this <= addr2 ); 149 | } -------------------------------------------------------------------------------- /StreamDivert/config.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "config.h" 3 | #include "utils.h" 4 | #include 5 | #include 6 | 7 | 8 | bool LoadConfig(std::string path, RelayConfig& result) 9 | { 10 | std::ifstream ifs((path)); 11 | std::string line; 12 | 13 | if (!ifs) { 14 | return false; 15 | } 16 | while (std::getline(ifs, line)) 17 | { 18 | char proto[200] = { 0 }; 19 | UINT16 localPort = 0; 20 | char srcAddr[200] = { 0 }; 21 | char dstAddr[200] = { 0 }; 22 | UINT16 dstPort = 0; 23 | char forwardAddr[200] = { 0 }; 24 | UINT16 forwardPort = 0; 25 | UINT32 interfaceIdx = -1; 26 | 27 | if (sscanf_s(line.c_str(), "%[a-z] < %hu %s -> %s %hu", &proto[0], _countof(proto), &localPort, &srcAddr[0], _countof(srcAddr), &forwardAddr[0], _countof(forwardAddr), &forwardPort) == 5) 28 | { 29 | InboundRelayEntry entry; 30 | entry.type = InboundRelayEntryType::Divert; 31 | entry.protocol = std::string(proto); 32 | entry.localPort = localPort; 33 | entry.srcAddr = IpAddr(srcAddr); 34 | entry.forwardAddr = IpAddr(forwardAddr); 35 | entry.forwardPort = forwardPort; 36 | result.inboundRelayEntries.push_back(entry); 37 | } 38 | else if (sscanf_s(line.c_str(), "%[a-z] < %hu %s -> socks", &proto[0], _countof(proto), &localPort, &srcAddr[0], _countof(srcAddr)) == 3) 39 | { 40 | InboundRelayEntry entry; 41 | entry.type = InboundRelayEntryType::Socks; 42 | entry.protocol = std::string(proto); 43 | entry.localPort = localPort; 44 | entry.srcAddr = IpAddr(srcAddr); 45 | result.inboundRelayEntries.push_back(entry); 46 | } 47 | else if (sscanf_s(line.c_str(), "%[a-z] > %s %hu -> %s %hu force interface %u", &proto[0], _countof(proto), &dstAddr[0], _countof(dstAddr), &dstPort, &forwardAddr[0], _countof(forwardAddr), &forwardPort, &interfaceIdx) == 6) 48 | { 49 | OutboundRelayEntry entry; 50 | entry.protocol = std::string(proto); 51 | entry.dstAddr = IpAddr(dstAddr); 52 | entry.dstPort = dstPort; 53 | entry.forwardAddr = IpAddr(forwardAddr); 54 | entry.forwardPort = forwardPort; 55 | entry.interfaceIdx = interfaceIdx; 56 | entry.forceInterfaceIdx = true; 57 | result.outboundRelayEntries.push_back(entry); 58 | } 59 | else if (sscanf_s(line.c_str(), "%[a-z] > %s %hu -> %s %hu interface %u", &proto[0], _countof(proto), &dstAddr[0], _countof(dstAddr), &dstPort, &forwardAddr[0], _countof(forwardAddr), &forwardPort, &interfaceIdx) == 6) 60 | { 61 | OutboundRelayEntry entry; 62 | entry.protocol = std::string(proto); 63 | entry.dstAddr = IpAddr(dstAddr); 64 | entry.dstPort = dstPort; 65 | entry.forwardAddr = IpAddr(forwardAddr); 66 | entry.forwardPort = forwardPort; 67 | entry.interfaceIdx = interfaceIdx; 68 | entry.forceInterfaceIdx = false; 69 | result.outboundRelayEntries.push_back(entry); 70 | } 71 | else if(sscanf_s(line.c_str(), "%[a-z] > %s %hu -> %s %hu", &proto[0], _countof(proto), &dstAddr[0], _countof(dstAddr), &dstPort, &forwardAddr[0], _countof(forwardAddr), &forwardPort) == 5) 72 | { 73 | OutboundRelayEntry entry; 74 | entry.protocol = std::string(proto); 75 | entry.dstAddr = IpAddr(dstAddr); 76 | entry.dstPort = dstPort; 77 | entry.forwardAddr = IpAddr(forwardAddr); 78 | entry.forwardPort = forwardPort; 79 | entry.interfaceIdx = interfaceIdx; 80 | result.outboundRelayEntries.push_back(entry); 81 | } 82 | else if (sscanf_s(line.c_str(), "icmp < %s -> %s", &srcAddr[0], _countof(srcAddr), &forwardAddr[0], _countof(forwardAddr)) == 2) 83 | { 84 | InboundRelayEntry entry; 85 | entry.protocol = "icmp"; 86 | entry.localPort = 0; 87 | entry.srcAddr = IpAddr(srcAddr); 88 | entry.forwardAddr = IpAddr(forwardAddr); 89 | entry.forwardPort = 0; 90 | result.inboundRelayEntries.push_back(entry); 91 | } 92 | else if (sscanf_s(line.c_str(), "icmp > %s -> %s", &dstAddr[0], _countof(dstAddr), &forwardAddr[0], _countof(forwardAddr)) == 2) 93 | { 94 | OutboundRelayEntry entry; 95 | entry.protocol = "icmp"; 96 | entry.dstAddr = IpAddr(dstAddr); 97 | entry.dstPort = 0; 98 | entry.forwardAddr = IpAddr(forwardAddr); 99 | entry.forwardPort = 0; 100 | result.outboundRelayEntries.push_back(entry); 101 | } 102 | } 103 | return true; 104 | } 105 | -------------------------------------------------------------------------------- /StreamDivert/StreamDivert.cpp: -------------------------------------------------------------------------------- 1 | // StreamDivert.cpp : Defines the entry point for the application. 2 | // 3 | 4 | #include "stdafx.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "StreamDivert.h" 15 | #include "InboundTCPDivertProxy.h" 16 | #include "InboundUDPDivertProxy.h" 17 | #include "InboundICMPDivertProxy.h" 18 | #include "OutboundDivertProxy.h" 19 | #include "utils.h" 20 | #include "config.h" 21 | #include "WindowsFirewall.h" 22 | #include "SocksProxyServer.h" 23 | #include "interfaces.h" 24 | #include "utils.h" 25 | 26 | // Global Variables: 27 | HINSTANCE hInst; // current instance 28 | const char* version = "1.1.0"; 29 | 30 | 31 | int __cdecl main(int argc, char **argv) 32 | { 33 | bool modifyFW = false; 34 | bool verbose = false; 35 | if (argc < 2) 36 | { 37 | char* filename = basename(argv[0]); 38 | fprintf(stderr, "StreamDivert %s - Redirect network traffic\n", version); 39 | fprintf(stderr, "%s cfg_file [-v] [-f]\n", filename); 40 | fprintf(stderr, "%s interfaces\n", filename); 41 | fprintf(stderr, "-f\tModify windows firewall to allow redirecting incomming TCP streams\n"); 42 | fprintf(stderr, "-v\tPrint modified packets to stderr\n"); 43 | fprintf(stderr, "interfaces\tPrint information regarding the network interfaces\n"); 44 | 45 | exit(EXIT_SUCCESS); 46 | } 47 | if (argc == 2 && std::string(argv[1]) == "interfaces") 48 | { 49 | PrintInterfaceInfo(); 50 | exit(EXIT_SUCCESS); 51 | } 52 | 53 | for (int i = 2; i < argc; i++) 54 | { 55 | std::string argval = argv[i]; 56 | if (argval == "-f") 57 | { 58 | modifyFW = true; 59 | } 60 | else if (argval == "-v") 61 | { 62 | verbose = true; 63 | } 64 | } 65 | std::string cfgPath = argv[1]; 66 | 67 | if (modifyFW) 68 | { 69 | info("Modifying firewall.."); 70 | WindowsFirewall fw; 71 | if (fw.Initialize()) 72 | { 73 | std::string path = GetApplicationExecutablePath(); 74 | fw.AddApplication(path, "StreamDivert"); 75 | } 76 | else 77 | { 78 | error("Failed to initialize FW object"); 79 | } 80 | } 81 | 82 | info("Parsing config file..."); 83 | RelayConfig cfg; 84 | bool cfgLoadResult = LoadConfig(cfgPath, cfg); 85 | if (!cfgLoadResult) 86 | { 87 | error("Failed to load config file!"); 88 | exit(EXIT_FAILURE); 89 | } 90 | info("Parsed %d inbound and %d outbound relay entries.", cfg.inboundRelayEntries.size(), cfg.outboundRelayEntries.size()); 91 | 92 | info("Starting packet diverters..."); 93 | std::vector proxies; 94 | std::map> mappedInboundTCPRelayEntries; 95 | std::vector inboundUDPRelayEntries; 96 | std::vector inboundICMPRelayEntries; 97 | for (auto entry : cfg.inboundRelayEntries) 98 | { 99 | if (entry.protocol == "tcp") 100 | { 101 | std::vector& entries = mappedInboundTCPRelayEntries[entry.localPort]; 102 | entries.push_back(entry); 103 | } 104 | else if (entry.protocol == "udp") 105 | { 106 | inboundUDPRelayEntries.push_back(entry); 107 | } 108 | else if (entry.protocol == "icmp") 109 | { 110 | inboundICMPRelayEntries.push_back(entry); 111 | } 112 | } 113 | 114 | for (auto mapping : mappedInboundTCPRelayEntries) 115 | { 116 | InboundTCPDivertProxy* proxy = new InboundTCPDivertProxy(verbose, mapping.first, mapping.second); 117 | proxy->Start(); 118 | proxies.push_back(proxy); 119 | //proxy->Stop(); 120 | } 121 | 122 | InboundUDPDivertProxy* inboundUDPProxy = new InboundUDPDivertProxy(verbose, inboundUDPRelayEntries); 123 | inboundUDPProxy->Start(); 124 | proxies.push_back(inboundUDPProxy); 125 | 126 | InboundICMPDivertProxy* inboundICMPProxy = new InboundICMPDivertProxy(verbose, inboundICMPRelayEntries); 127 | inboundICMPProxy->Start(); 128 | proxies.push_back(inboundICMPProxy); 129 | 130 | OutboundDivertProxy* outboundProxy = new OutboundDivertProxy(verbose, cfg.outboundRelayEntries); 131 | outboundProxy->Start(); 132 | proxies.push_back(outboundProxy); 133 | 134 | //Wait indefinitely 135 | std::promise p; 136 | p.get_future().wait(); 137 | } 138 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # StreamDivert 2 | StreamDivert is a tool to man-in-the-middle or relay in and outgoing network connections on a system. It has the ability to, for example, relay all incoming SMB connections to port 445 to another server, or only relay specific incoming SMB connections from a specific set of source IP's to another server. Summed up, StreamDivert is able to: 3 | 4 | 5 | * Relay all incoming connections to a specific port to another destination. 6 | * Relay incoming connections from a specific source IP to a port to another destination. 7 | * Relay incoming connections to a SOCKS(4/5) server. 8 | * Relay all outgoing connections to a specific port to another destination. 9 | * Relay outgoing connections to a specific IP and port to another destination. 10 | * Handle TCP, UDP and ICMP traffic over IPv4 and IPv6. 11 | * Force redirected packets over a specific network interface. 12 | 13 | ## Download Binaries 14 | Pre-compiled binaries for StreamDivert can be downloaded [here](https://github.com/jellever/StreamDivert/releases). 15 | 16 | ## Usage 17 | How do you use StreamDivert? Run the the tool with administrative privileges: 18 | 19 | ```console 20 | streamdivert.exe config_file [-f] [-v] 21 | ``` 22 | 23 | The config file contains entries for streams you want to have diverted. En example config file: 24 | ```conf 25 | //Divert all inbound TCP connections to port 445 (SMB) coming from 10.0.1.50 to 10.0.1.49 port 445 26 | tcp < 445 10.0.1.50 -> 10.0.1.49 445 27 | 28 | //Divert all inbound TCP connections to port 445 (SMB) coming from 10.0.1.51 to a local SOCKS server 29 | tcp < 445 10.0.1.51 -> socks 30 | 31 | //Divert all inbound TCP connections to port 445 (SMB) coming from fe80::f477:846a:775d:d37 to fe80::20c:29ff:fe6f:88ff port 445 32 | tcp < 445 fe80::f477:846a:775d:d37 -> fe80::20c:29ff:fe6f:88ff 445 33 | 34 | //Divert all inbound TCP connections to port 445 (SMB) to 10.0.1.48 port 445 35 | tcp < 445 0.0.0.0 -> 10.0.1.48 445 36 | 37 | //Divert all inbound UDP connections to to port 53 (DNS) to 10.0.1.49 port 53 38 | udp < 53 0.0.0.0 -> 10.0.1.49 53 39 | 40 | //Divert all inbound ICMP packets coming from 10.0.1.50 to 10.0.1.49 41 | icmp < 10.0.1.50 -> 10.0.1.49 42 | 43 | //Divert all outbound TCP connections to 10.0.1.50, port 80 to 10.0.1.49 port 8080 44 | tcp > 10.0.1.50 80 -> 10.0.1.49 8080 45 | 46 | //Send all packets going to 10.0.1.50 port 80 and prefer interface 9 to send them. If the interface does not exist or is not up, the packets are send from the default interface. 47 | tcp > 10.0.1.50 80 -> 10.0.1.50 80 interface 9 48 | 49 | //Force all packets going to 10.0.1.50 port 80 over interface 9, or drop the packets if the interface does not exist or is not up. 50 | tcp > 10.0.1.50 80 -> 10.0.1.50 80 force interface 9 51 | 52 | //Divert all outbound UDP connection to port 53 (DNS) to 10.0.1.49 port 53 53 | udp > 0.0.0.0 53 -> 10.0.1.49 53 54 | ``` 55 | 56 | The [-f] flag, when present, will modify the Windows Firewall to add an exception for the application to properly redirect incoming traffic to another port. 57 | The [-v] flag control the logging verbosity. When provided, StreamDivert will log details about redirected packets and streams. 58 | 59 | ## Some Use Cases 60 | * Diverting outbound C&C traffic to a local socket for dynamic malware analysis. 61 | * Diverting inbound SMB connections of a compromised host to Responder/ ntlmrelayx (usefull in penetration tests). 62 | * Routing traffic over reserved ports. Usefull when a network firewall is in between. For example... 63 | * Routing a meterpreter shell over port 445. 64 | * Running a SOCKS server on port 3389. 65 | * ... 66 | 67 | ## Help! My packets/ connections are not correctly diverted! 68 | One thing to keep in mind when configuring diverted connections is that you don't have conflicting diverted streams. Given the following example config file: 69 | ```conf 70 | icmp < 0.0.0.0 -> 10.0.1.50 71 | icmp > 10.0.1.49 -> 10.0.1.48 72 | ``` 73 | Those two diverted streams will conflict with eachother, as packets for the first diverted stream will also be picked up by the second packet 'diverter'. Generally you will only run into these issues with UDP and ICMP and using wildcards. 74 | 75 | Also note that diverting an IPv4 to an IPv6 address and vice versa is not supported for UDP and ICMP traffic. 76 | ## Contributing to StreamDivert 77 | Features wanted: 78 | * IP range support 79 | * ... 80 | -------------------------------------------------------------------------------- /StreamDivert/InboundICMPDivertProxy.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "InboundICMPDivertProxy.h" 3 | #include "utils.h" 4 | #include "windivert.h" 5 | #include 6 | 7 | InboundICMPDivertProxy::InboundICMPDivertProxy(bool verbose, const std::vector& proxyRecords) 8 | : BaseProxy(verbose) 9 | { 10 | this->proxyRecords = proxyRecords; 11 | this->selfDescStr = this->getStringDesc(); 12 | } 13 | 14 | 15 | InboundICMPDivertProxy::~InboundICMPDivertProxy() 16 | { 17 | } 18 | 19 | bool InboundICMPDivertProxy::Stop() 20 | { 21 | this->connectionMap.clear(); 22 | return BaseProxy::Stop(); 23 | } 24 | 25 | 26 | std::string InboundICMPDivertProxy::getStringDesc() 27 | { 28 | return std::string("InboundICMPDivertProxy()"); 29 | } 30 | 31 | PacketAction InboundICMPDivertProxy::ProcessTCPPacket(unsigned char * packet, UINT & packet_len, PWINDIVERT_ADDRESS addr, PWINDIVERT_IPHDR ip_hdr, PWINDIVERT_IPV6HDR ip6_hdr, PWINDIVERT_TCPHDR tcp_hdr, IpAddr & srcAddr, IpAddr & dstAddr) 32 | { 33 | return PacketAction::STATUS_PROCEED; 34 | } 35 | 36 | PacketAction InboundICMPDivertProxy::ProcessICMPPacket(unsigned char * packet, UINT & packet_len, PWINDIVERT_ADDRESS addr, PWINDIVERT_IPHDR ip_hdr, PWINDIVERT_IPV6HDR ip6_hdr, PWINDIVERT_ICMPHDR icmp_hdr, PWINDIVERT_ICMPV6HDR icmp6_hdr, IpAddr & srcAddr, IpAddr & dstAddr) 37 | { 38 | if (!addr->Outbound) 39 | { 40 | for (auto record = this->proxyRecords.begin(); record != this->proxyRecords.end(); ++record) 41 | { 42 | // Inbound packets from a configured source address 43 | if ((srcAddr == record->srcAddr || record->srcAddr == anyIpAddr)) 44 | { 45 | std::string forwardAddrStr = record->forwardAddr.to_string(); 46 | std::string dstAddrStr = dstAddr.to_string(); 47 | this->logDebug("Modify packet src -> %s", dstAddrStr.c_str()); 48 | this->logDebug("Modify packet dst -> %s", forwardAddrStr.c_str()); 49 | 50 | EndpointKey key; 51 | key.addr = record->forwardAddr.get_addr(); 52 | key.port = 0; 53 | this->connectionMap[key] = { srcAddr, 0 }; 54 | 55 | this->SwapIPHeaderDstToSrc(ip_hdr, ip6_hdr); 56 | this->OverrideIPHeaderDst(ip_hdr, ip6_hdr, record->forwardAddr); 57 | addr->Outbound = 1; 58 | break; 59 | } 60 | // Inbound packets from a forward address 61 | else if ((srcAddr == record->forwardAddr || record->srcAddr == anyIpAddr)) 62 | { 63 | EndpointKey key; 64 | key.addr = srcAddr.get_addr(); 65 | key.port = 0; 66 | std::map::iterator it = this->connectionMap.find(key); 67 | if (it != this->connectionMap.end()) 68 | { 69 | IpAddr& lookupAddr = it->second.addr; 70 | this->logDebug("Modify packet src -> %s", dstAddr.to_string().c_str()); 71 | this->logDebug("Modify packet dst -> %s", lookupAddr.to_string().c_str()); 72 | 73 | this->SwapIPHeaderDstToSrc(ip_hdr, ip6_hdr); 74 | this->OverrideIPHeaderDst(ip_hdr, ip6_hdr, lookupAddr); 75 | addr->Outbound = 1; 76 | break; 77 | } 78 | } 79 | } 80 | } 81 | return PacketAction::STATUS_PROCEED; 82 | } 83 | 84 | PacketAction InboundICMPDivertProxy::ProcessUDPPacket(unsigned char * packet, UINT & packet_len, PWINDIVERT_ADDRESS addr, PWINDIVERT_IPHDR ip_hdr, PWINDIVERT_IPV6HDR ip6_hdr, PWINDIVERT_UDPHDR udp_header, IpAddr & srcAddr, IpAddr & dstAddr) 85 | { 86 | return PacketAction::STATUS_PROCEED; 87 | } 88 | 89 | std::string InboundICMPDivertProxy::generateDivertFilterString() 90 | { 91 | std::string result = "(icmp or icmpv6)"; 92 | std::set orExpressions; 93 | 94 | if (this->proxyRecords.size() == 0) 95 | { 96 | return "false"; 97 | } 98 | 99 | //check for wildcard address 100 | bool containsWildcard = false; 101 | for (auto record = this->proxyRecords.begin(); record != this->proxyRecords.end(); ++record) 102 | { 103 | if (record->srcAddr == anyIpAddr) 104 | { 105 | containsWildcard = true; 106 | } 107 | } 108 | 109 | if (!containsWildcard) 110 | { 111 | for (auto record = this->proxyRecords.begin(); record != this->proxyRecords.end(); ++record) 112 | { 113 | std::string srcAddrIpStr = this->getIpAddrIpStr(record->srcAddr); 114 | std::string forwardAddrIpStr = this->getIpAddrIpStr(record->forwardAddr); 115 | std::string recordFilterStr; 116 | 117 | recordFilterStr = "(" + forwardAddrIpStr + ".SrcAddr == " + record->forwardAddr.to_string() + ")"; 118 | orExpressions.insert(recordFilterStr); 119 | 120 | recordFilterStr = "(" + srcAddrIpStr + ".SrcAddr == " + record->srcAddr.to_string() + ")"; 121 | orExpressions.insert(recordFilterStr); 122 | } 123 | } 124 | 125 | if (orExpressions.size() > 0) 126 | { 127 | result += " and ("; 128 | joinStr(orExpressions, std::string(" or "), result); 129 | result += ")"; 130 | } 131 | return result; 132 | } 133 | -------------------------------------------------------------------------------- /StreamDivert/StreamDivert.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | 23 | 24 | Header Files 25 | 26 | 27 | Header Files 28 | 29 | 30 | Header Files 31 | 32 | 33 | Header Files 34 | 35 | 36 | Header Files 37 | 38 | 39 | Header Files 40 | 41 | 42 | Header Files 43 | 44 | 45 | Header Files 46 | 47 | 48 | Header Files 49 | 50 | 51 | Header Files 52 | 53 | 54 | Header Files 55 | 56 | 57 | Header Files 58 | 59 | 60 | Header Files 61 | 62 | 63 | Header Files 64 | 65 | 66 | Header Files 67 | 68 | 69 | Header Files 70 | 71 | 72 | Header Files 73 | 74 | 75 | Header Files 76 | 77 | 78 | 79 | 80 | Source Files 81 | 82 | 83 | Source Files 84 | 85 | 86 | Source Files 87 | 88 | 89 | Source Files 90 | 91 | 92 | Source Files 93 | 94 | 95 | Source Files 96 | 97 | 98 | Source Files 99 | 100 | 101 | Source Files 102 | 103 | 104 | Source Files 105 | 106 | 107 | Source Files 108 | 109 | 110 | Source Files 111 | 112 | 113 | Source Files 114 | 115 | 116 | Source Files 117 | 118 | 119 | Source Files 120 | 121 | 122 | 123 | 124 | Resource Files 125 | 126 | 127 | 128 | 129 | Resource Files 130 | 131 | 132 | Resource Files 133 | 134 | 135 | -------------------------------------------------------------------------------- /StreamDivert/InboundUDPDivertProxy.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "InboundUDPDivertProxy.h" 3 | #include "utils.h" 4 | #include "windivert.h" 5 | #include 6 | 7 | 8 | InboundUDPDivertProxy::InboundUDPDivertProxy(bool verbose, const std::vector& proxyRecords) 9 | : BaseProxy(verbose) 10 | { 11 | this->proxyRecords = proxyRecords; 12 | this->selfDescStr = this->getStringDesc(); 13 | } 14 | 15 | InboundUDPDivertProxy::~InboundUDPDivertProxy() 16 | { 17 | } 18 | 19 | bool InboundUDPDivertProxy::Stop() 20 | { 21 | this->connectionMap.clear(); 22 | return BaseProxy::Stop(); 23 | } 24 | 25 | std::string InboundUDPDivertProxy::getStringDesc() 26 | { 27 | std::string result = std::string("InboundUDPDivertProxy()"); 28 | return result; 29 | } 30 | 31 | PacketAction InboundUDPDivertProxy::ProcessTCPPacket(unsigned char* packet, UINT& packet_len, PWINDIVERT_ADDRESS addr, PWINDIVERT_IPHDR ip_hdr, PWINDIVERT_IPV6HDR ip6_hdr, PWINDIVERT_TCPHDR tcp_hdr, IpAddr& srcAddr, IpAddr& dstAddr) 32 | { 33 | return PacketAction::STATUS_PROCEED; 34 | } 35 | 36 | PacketAction InboundUDPDivertProxy::ProcessICMPPacket(unsigned char* packet, UINT& packet_len, PWINDIVERT_ADDRESS addr, PWINDIVERT_IPHDR ip_hdr, PWINDIVERT_IPV6HDR ip6_hdr, PWINDIVERT_ICMPHDR icmp_hdr, PWINDIVERT_ICMPV6HDR icmp6_hdr, IpAddr& srcAddr, IpAddr& dstAddr) 37 | { 38 | return PacketAction::STATUS_PROCEED; 39 | } 40 | 41 | PacketAction InboundUDPDivertProxy::ProcessUDPPacket(unsigned char* packet, UINT& packet_len, PWINDIVERT_ADDRESS addr, PWINDIVERT_IPHDR ip_hdr, PWINDIVERT_IPV6HDR ip6_hdr, PWINDIVERT_UDPHDR udp_header, IpAddr& srcAddr, IpAddr& dstAddr) 42 | { 43 | if (!addr->Outbound) 44 | { 45 | for (auto record = this->proxyRecords.begin(); record != this->proxyRecords.end(); ++record) 46 | { 47 | // Inbound packets from a configured source address 48 | if ((srcAddr == record->srcAddr || record->srcAddr == anyIpAddr) && 49 | udp_header->DstPort == htons(record->localPort)) 50 | { 51 | std::string forwardAddrStr = record->forwardAddr.to_string(); 52 | std::string dstAddrStr = dstAddr.to_string(); 53 | this->logDebug("Modify packet src -> %s:%hu", dstAddrStr.c_str(), ntohs(udp_header->SrcPort)); 54 | this->logDebug("Modify packet dst -> %s:%hu", forwardAddrStr.c_str(), record->forwardPort); 55 | 56 | EndpointKey key; 57 | key.addr = record->forwardAddr.get_addr(); 58 | key.port = udp_header->SrcPort; 59 | this->connectionMap[key] = { srcAddr, udp_header->DstPort }; 60 | 61 | this->SwapIPHeaderDstToSrc(ip_hdr, ip6_hdr); 62 | this->OverrideIPHeaderDst(ip_hdr, ip6_hdr, record->forwardAddr); 63 | udp_header->DstPort = htons(record->forwardPort); 64 | addr->Outbound = 1; 65 | break; 66 | } 67 | // Inbound packets from a forward address 68 | else if ((srcAddr == record->forwardAddr || record->srcAddr == anyIpAddr) && 69 | udp_header->SrcPort == htons(record->forwardPort)) 70 | { 71 | EndpointKey key; 72 | key.addr = srcAddr.get_addr(); 73 | key.port = udp_header->DstPort; 74 | std::map::iterator it = this->connectionMap.find(key); 75 | if (it != this->connectionMap.end()) 76 | { 77 | IpAddr& lookupAddr = it->second.addr; 78 | this->logDebug("Modify packet src -> %s:%hu", dstAddr.to_string().c_str(), ntohs(it->second.port)); 79 | this->logDebug("Modify packet dst -> %s:%hu", lookupAddr.to_string().c_str(), ntohs(udp_header->DstPort)); 80 | 81 | this->SwapIPHeaderDstToSrc(ip_hdr, ip6_hdr); 82 | this->OverrideIPHeaderDst(ip_hdr, ip6_hdr, lookupAddr); 83 | udp_header->SrcPort = it->second.port; 84 | addr->Outbound = 1; 85 | break; 86 | } 87 | } 88 | } 89 | } 90 | return PacketAction::STATUS_PROCEED; 91 | } 92 | 93 | std::string InboundUDPDivertProxy::generateDivertFilterString() 94 | { 95 | std::string result = "udp"; 96 | std::set orExpressions; 97 | 98 | //check for wildcard address 99 | bool containsWildcard = false; 100 | for (auto record = this->proxyRecords.begin(); record != this->proxyRecords.end(); ++record) 101 | { 102 | if (record->srcAddr == anyIpAddr) 103 | { 104 | std::string forwardAddrIpStr = this->getIpAddrIpStr(record->forwardAddr); 105 | std::string recordFilterStr; 106 | 107 | recordFilterStr = "(udp.DstPort == " + std::to_string(record->localPort) + ")"; 108 | orExpressions.insert(recordFilterStr); 109 | containsWildcard = true; 110 | } 111 | } 112 | 113 | for (auto record = this->proxyRecords.begin(); record != this->proxyRecords.end(); ++record) 114 | { 115 | std::string srcAddrIpStr = this->getIpAddrIpStr(record->srcAddr); 116 | std::string forwardAddrIpStr = this->getIpAddrIpStr(record->forwardAddr); 117 | std::string recordFilterStr; 118 | 119 | if (!containsWildcard) 120 | { 121 | recordFilterStr = "(udp.DstPort == " + std::to_string(record->localPort) + " and " + srcAddrIpStr + ".SrcAddr == " + record->srcAddr.to_string() + ")"; 122 | orExpressions.insert(recordFilterStr); 123 | } 124 | recordFilterStr = "(udp.SrcPort == " + std::to_string(record->forwardPort) + " and " + forwardAddrIpStr + ".SrcAddr == " + record->forwardAddr.to_string() + ")"; 125 | orExpressions.insert(recordFilterStr); 126 | } 127 | 128 | result += " and ("; 129 | joinStr(orExpressions, std::string(" or "), result); 130 | result += ")"; 131 | return result; 132 | } 133 | -------------------------------------------------------------------------------- /StreamDivert/interfaces.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "interfaces.h" 3 | 4 | 5 | // Link with Iphlpapi.lib 6 | #pragma comment(lib, "IPHLPAPI.lib") 7 | 8 | 9 | std::string InterfaceTypeToFriendName(int ifType) 10 | { 11 | switch (ifType) 12 | { 13 | case 1: 14 | return "Other"; 15 | case 6: 16 | return "Ethernet"; 17 | case 9: 18 | return "Token ring"; 19 | case 23: 20 | return "PPP"; 21 | case 24: 22 | return "Software loopback"; 23 | case 37: 24 | return "ATM"; 25 | case 71: 26 | return "Wiress"; 27 | case 131: 28 | return "Tunnel"; 29 | case 144: 30 | return "IEEE 1394 serial bus"; 31 | } 32 | return "Unknown"; 33 | } 34 | 35 | void PrintInterfaceInfo() 36 | { 37 | DWORD dwSize = 0; 38 | DWORD dwRetVal = 0; 39 | 40 | unsigned int i = 0; 41 | 42 | // Set the flags to pass to GetAdaptersAddresses 43 | ULONG flags = GAA_FLAG_INCLUDE_PREFIX; 44 | 45 | // default to unspecified address family (both) 46 | ULONG family = AF_UNSPEC; 47 | 48 | LPVOID lpMsgBuf = NULL; 49 | 50 | PIP_ADAPTER_ADDRESSES pAddresses = NULL; 51 | ULONG outBufLen = 0; 52 | ULONG Iterations = 0; 53 | 54 | PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL; 55 | PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL; 56 | PIP_ADAPTER_ANYCAST_ADDRESS pAnycast = NULL; 57 | PIP_ADAPTER_MULTICAST_ADDRESS pMulticast = NULL; 58 | IP_ADAPTER_DNS_SERVER_ADDRESS* pDnServer = NULL; 59 | IP_ADAPTER_PREFIX* pPrefix = NULL; 60 | 61 | // Allocate a 15 KB buffer to start with. 62 | outBufLen = WORKING_BUFFER_SIZE; 63 | 64 | do { 65 | 66 | pAddresses = (IP_ADAPTER_ADDRESSES*)malloc(outBufLen); 67 | if (pAddresses == NULL) { 68 | printf 69 | ("Memory allocation failed for IP_ADAPTER_ADDRESSES struct\n"); 70 | exit(1); 71 | } 72 | 73 | dwRetVal = GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen); 74 | 75 | if (dwRetVal == ERROR_BUFFER_OVERFLOW) { 76 | free(pAddresses); 77 | pAddresses = NULL; 78 | } 79 | else { 80 | break; 81 | } 82 | 83 | Iterations++; 84 | 85 | } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (Iterations < MAX_TRIES)); 86 | 87 | if (dwRetVal == NO_ERROR) { 88 | // If successful, output some information from the data we received 89 | pCurrAddresses = pAddresses; 90 | while (pCurrAddresses) { 91 | //printf("\tLength of the IP_ADAPTER_ADDRESS struct: %ld\n", pCurrAddresses->Length); 92 | printf("\tIfIndex (IPv4 interface): %u\n", pCurrAddresses->IfIndex); 93 | //printf("\tAdapter name: %s\n", pCurrAddresses->AdapterName); 94 | 95 | pUnicast = pCurrAddresses->FirstUnicastAddress; 96 | if (pUnicast != NULL) { 97 | for (i = 0; pUnicast != NULL; i++) 98 | pUnicast = pUnicast->Next; 99 | // printf("\tNumber of Unicast Addresses: %d\n", i); 100 | } 101 | // else 102 | // printf("\tNo Unicast Addresses\n"); 103 | 104 | pAnycast = pCurrAddresses->FirstAnycastAddress; 105 | if (pAnycast) { 106 | for (i = 0; pAnycast != NULL; i++) 107 | pAnycast = pAnycast->Next; 108 | //printf("\tNumber of Anycast Addresses: %d\n", i); 109 | } 110 | //else 111 | //printf("\tNo Anycast Addresses\n"); 112 | 113 | pMulticast = pCurrAddresses->FirstMulticastAddress; 114 | if (pMulticast) { 115 | for (i = 0; pMulticast != NULL; i++) 116 | pMulticast = pMulticast->Next; 117 | // printf("\tNumber of Multicast Addresses: %d\n", i); 118 | } 119 | //else 120 | // printf("\tNo Multicast Addresses\n"); 121 | 122 | pDnServer = pCurrAddresses->FirstDnsServerAddress; 123 | if (pDnServer) { 124 | for (i = 0; pDnServer != NULL; i++) 125 | pDnServer = pDnServer->Next; 126 | //printf("\tNumber of DNS Server Addresses: %d\n", i); 127 | } 128 | else 129 | printf("\tNo DNS Server Addresses\n"); 130 | 131 | printf("\tDNS Suffix: %wS\n", pCurrAddresses->DnsSuffix); 132 | printf("\tDescription: %wS\n", pCurrAddresses->Description); 133 | printf("\tFriendly name: %wS\n", pCurrAddresses->FriendlyName); 134 | 135 | if (pCurrAddresses->PhysicalAddressLength != 0) { 136 | printf("\tPhysical address: "); 137 | for (i = 0; i < (int)pCurrAddresses->PhysicalAddressLength; 138 | i++) { 139 | if (i == (pCurrAddresses->PhysicalAddressLength - 1)) 140 | printf("%.2X\n", 141 | (int)pCurrAddresses->PhysicalAddress[i]); 142 | else 143 | printf("%.2X-", 144 | (int)pCurrAddresses->PhysicalAddress[i]); 145 | } 146 | } 147 | //printf("\tFlags: %ld\n", pCurrAddresses->Flags); 148 | printf("\tMtu: %lu\n", pCurrAddresses->Mtu); 149 | printf("\tIfType: %s\n", InterfaceTypeToFriendName(pCurrAddresses->IfType).c_str()); 150 | printf("\tOperStatus: %ld\n", pCurrAddresses->OperStatus); 151 | printf("\tIpv6IfIndex (IPv6 interface): %u\n", 152 | pCurrAddresses->Ipv6IfIndex); 153 | //printf("\tZoneIndices (hex): "); 154 | //for (i = 0; i < 16; i++) 155 | // printf("%lx ", pCurrAddresses->ZoneIndices[i]); 156 | printf("\n"); 157 | 158 | //printf("\tTransmit link speed: %I64u\n", pCurrAddresses->TransmitLinkSpeed); 159 | //printf("\tReceive link speed: %I64u\n", pCurrAddresses->ReceiveLinkSpeed); 160 | 161 | pPrefix = pCurrAddresses->FirstPrefix; 162 | if (pPrefix) { 163 | for (i = 0; pPrefix != NULL; i++) 164 | pPrefix = pPrefix->Next; 165 | // printf("\tNumber of IP Adapter Prefix entries: %d\n", i); 166 | } 167 | //else 168 | //printf("\tNumber of IP Adapter Prefix entries: 0\n"); 169 | 170 | 171 | 172 | pCurrAddresses = pCurrAddresses->Next; 173 | } 174 | } 175 | else { 176 | printf("Call to GetAdaptersAddresses failed with error: %d\n", 177 | dwRetVal); 178 | if (dwRetVal == ERROR_NO_DATA) 179 | printf("\tNo addresses were found for the requested parameters\n"); 180 | else { 181 | 182 | if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 183 | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 184 | NULL, dwRetVal, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 185 | // Default language 186 | (LPTSTR)&lpMsgBuf, 0, NULL)) { 187 | printf("\tError: %s", lpMsgBuf); 188 | LocalFree(lpMsgBuf); 189 | if (pAddresses) 190 | free(pAddresses); 191 | exit(1); 192 | } 193 | } 194 | } 195 | 196 | if (pAddresses) { 197 | free(pAddresses); 198 | } 199 | } 200 | 201 | 202 | bool GetInterfaceAddressByIdx(UINT16 ifIdx, IpAddr& addr, IPFamily family, bool onlyEnabled) 203 | { 204 | DWORD flags = GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_MULTICAST; 205 | ULONG wantedFamily = AF_UNSPEC; 206 | PIP_ADAPTER_ADDRESSES pAddresses = NULL; 207 | ULONG outBufLen = 0; 208 | ULONG iterations = 0; 209 | PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL; 210 | PIP_ADAPTER_ANYCAST_ADDRESS pAnycast = NULL; 211 | PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL; 212 | DWORD dwRetVal = 0; 213 | DWORD dwSize = 0; 214 | unsigned int i = 0; 215 | bool result = false; 216 | 217 | outBufLen = WORKING_BUFFER_SIZE; 218 | do { 219 | pAddresses = (IP_ADAPTER_ADDRESSES*)malloc(outBufLen); 220 | if (pAddresses == NULL) { 221 | return false; 222 | } 223 | 224 | dwRetVal = GetAdaptersAddresses(wantedFamily, flags, NULL, pAddresses, &outBufLen); 225 | 226 | if (dwRetVal == ERROR_BUFFER_OVERFLOW) { 227 | free(pAddresses); 228 | pAddresses = NULL; 229 | } 230 | else { 231 | break; 232 | } 233 | iterations++; 234 | 235 | } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (iterations < MAX_TRIES)); 236 | 237 | if (dwRetVal == NO_ERROR) { 238 | // If successful, output some information from the data we received 239 | pCurrAddresses = pAddresses; 240 | while (pCurrAddresses) { 241 | if (pCurrAddresses->IfIndex == ifIdx && (onlyEnabled && pCurrAddresses->OperStatus == IfOperStatusUp)) 242 | { 243 | //pCurrAddresses-> 244 | pUnicast = pCurrAddresses->FirstUnicastAddress; 245 | if (pUnicast) 246 | { 247 | for (i = 0; pUnicast != NULL; i++) 248 | { 249 | if (pUnicast->Address.lpSockaddr->sa_family == AF_INET6 && (family == IPFamily::IPv6 || family == IPFamily::Unknown)) 250 | { 251 | addr = IpAddr(((sockaddr_in6*)pUnicast->Address.lpSockaddr)->sin6_addr); 252 | result = true; 253 | goto CLEANUP; 254 | } 255 | if (pUnicast->Address.lpSockaddr->sa_family == AF_INET && (family == IPFamily::IPv4 || family == IPFamily::Unknown)) 256 | { 257 | addr = IpAddr(((sockaddr_in*)pUnicast->Address.lpSockaddr)->sin_addr); 258 | result = true; 259 | goto CLEANUP; 260 | } 261 | pUnicast = pUnicast->Next; 262 | } 263 | } 264 | } 265 | 266 | pCurrAddresses = pCurrAddresses->Next; 267 | } 268 | } 269 | 270 | CLEANUP: 271 | if (pAddresses) { 272 | free(pAddresses); 273 | } 274 | return result; 275 | } -------------------------------------------------------------------------------- /StreamDivert/OutboundDivertProxy.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "OutboundDivertProxy.h" 3 | #include "utils.h" 4 | #include 5 | #include 6 | #include "interfaces.h" 7 | 8 | 9 | std::string OutboundDivertProxy::getStringDesc() 10 | { 11 | return std::string("OutboundDivertProxy()"); 12 | } 13 | 14 | std::string OutboundDivertProxy::generateDivertFilterString() 15 | { 16 | std::string result = ""; 17 | std::set protocols; 18 | std::vector orExpressions; 19 | std::string recordFilterStr; 20 | 21 | for (auto record = this->relayEntries.begin(); record != this->relayEntries.end(); ++record) 22 | { 23 | if (record->protocol == "tcp" || record->protocol == "icmp" || record->protocol == "udp") 24 | { 25 | if (record->protocol == "icmp") 26 | { 27 | protocols.insert("icmpv6"); 28 | } 29 | protocols.insert(record->protocol); 30 | } 31 | if (record->protocol == "tcp" || record->protocol == "udp") 32 | { 33 | if (record->dstAddr == anyIpAddr) 34 | { 35 | recordFilterStr = "(" + record->protocol + ".DstPort == " + std::to_string(record->dstPort) + ")"; 36 | orExpressions.push_back(recordFilterStr); 37 | recordFilterStr = "(" + record->protocol + ".SrcPort == " + std::to_string(record->dstPort) + ")"; 38 | orExpressions.push_back(recordFilterStr); 39 | } 40 | else 41 | { 42 | std::string dstAddrIpStr = this->getIpAddrIpStr(record->dstAddr); 43 | std::string forwardAddrIpStr = this->getIpAddrIpStr(record->forwardAddr); 44 | 45 | recordFilterStr = "(" + dstAddrIpStr + ".DstAddr == " + record->dstAddr.to_string() + " and " + record->protocol + ".DstPort == " + std::to_string(record->dstPort) + ")"; 46 | orExpressions.push_back(recordFilterStr); 47 | 48 | recordFilterStr = "(" + forwardAddrIpStr + ".SrcAddr == " + record->forwardAddr.to_string() + " and " + record->protocol + ".SrcPort == " + std::to_string(record->forwardPort) + ")"; 49 | orExpressions.push_back(recordFilterStr); 50 | } 51 | } 52 | } 53 | result = "("; 54 | joinStr(protocols, std::string(" or "), result); 55 | result += ")"; 56 | 57 | if (orExpressions.size() > 0) 58 | { 59 | result += " and ("; 60 | joinStr(orExpressions, std::string(" or "), result); 61 | result += ")"; 62 | } 63 | return result; 64 | } 65 | 66 | 67 | 68 | PacketAction OutboundDivertProxy::ProcessTCPPacket(unsigned char * packet, UINT & packet_len, PWINDIVERT_ADDRESS addr, PWINDIVERT_IPHDR ip_hdr, PWINDIVERT_IPV6HDR ip6_hdr, PWINDIVERT_TCPHDR tcp_hdr, IpAddr & srcAddr, IpAddr & dstAddr) 69 | { 70 | if (true) 71 | { 72 | if (addr->Outbound) 73 | { 74 | for (auto record = this->relayEntries.begin(); record != this->relayEntries.end(); ++record) 75 | { 76 | if (record->protocol == "tcp" && (dstAddr == record->dstAddr || record->dstAddr == anyIpAddr) && tcp_hdr->DstPort == htons(record->dstPort)) 77 | { 78 | UINT32 ifIfx = addr->Network.IfIdx; 79 | EndpointKey key; 80 | key.addr = srcAddr.get_addr(); 81 | key.port = tcp_hdr->SrcPort; 82 | if (record->interfaceIdx != -1) 83 | { 84 | IpAddr newSrc; 85 | bool ifAddrLookupSuc = GetInterfaceAddressByIdx(record->interfaceIdx, newSrc, srcAddr.get_family(), true); 86 | if (ifAddrLookupSuc) 87 | { 88 | this->logDebug("Modify packet src -> %s:%hu", newSrc.to_string().c_str(), tcp_hdr->SrcPort); 89 | key.addr = newSrc.get_addr(); 90 | this->OverrideIPHeaderSrc(ip_hdr, ip6_hdr, newSrc); 91 | addr->Network.IfIdx = record->interfaceIdx; 92 | if (ip_hdr) 93 | { 94 | WINDIVERT_IPHDR_SET_DF(ip_hdr, 0); 95 | } 96 | } 97 | else if (record->forceInterfaceIdx) 98 | { 99 | return PacketAction::STATUS_DROP; 100 | } 101 | } 102 | this->logDebug("Modify packet dst -> %s:%hu", record->forwardAddr.to_string().c_str(), record->forwardPort); 103 | this->OverrideIPHeaderDst(ip_hdr, ip6_hdr, record->forwardAddr); 104 | tcp_hdr->DstPort = htons(record->forwardPort); 105 | this->incomingTCPMap[key] = { dstAddr, tcp_hdr->DstPort, ifIfx }; 106 | break; 107 | } 108 | } 109 | } 110 | else 111 | { 112 | for (auto record = this->relayEntries.begin(); record != this->relayEntries.end(); ++record) 113 | { 114 | if (record->protocol == "tcp" && (srcAddr == record->forwardAddr || record->dstAddr == anyIpAddr) && tcp_hdr->SrcPort == htons(record->forwardPort)) 115 | { 116 | EndpointKey key; 117 | key.addr = dstAddr.get_addr(); 118 | key.port = tcp_hdr->DstPort; 119 | std::map::iterator it = this->incomingTCPMap.find(key); 120 | if (it != this->incomingTCPMap.end()) 121 | { 122 | if (record->interfaceIdx != -1) 123 | { 124 | IpAddr newDst; 125 | bool ifAddrLookupSuc = GetInterfaceAddressByIdx(it->second.ifIfx, newDst, dstAddr.get_family(), true); 126 | if (ifAddrLookupSuc) 127 | { 128 | this->logDebug("Modify packet dst -> %s:%hu", newDst.to_string().c_str(), tcp_hdr->DstPort); 129 | this->OverrideIPHeaderDst(ip_hdr, ip6_hdr, newDst); 130 | addr->Network.IfIdx = it->second.ifIfx; 131 | if (ip_hdr) 132 | { 133 | WINDIVERT_IPHDR_SET_DF(ip_hdr, 0); 134 | } 135 | } 136 | else if (record->forceInterfaceIdx) 137 | { 138 | return PacketAction::STATUS_DROP; 139 | } 140 | } 141 | IpAddr& lookupAddr = it->second.addr; 142 | this->logDebug("Modify packet src -> %s:%hu", lookupAddr.to_string().c_str(), ntohs(it->second.port)); 143 | this->OverrideIPHeaderSrc(ip_hdr, ip6_hdr, lookupAddr); 144 | tcp_hdr->SrcPort = it->second.port; 145 | 146 | break; 147 | } 148 | } 149 | } 150 | } 151 | } 152 | return PacketAction::STATUS_PROCEED; 153 | } 154 | 155 | 156 | PacketAction OutboundDivertProxy::ProcessICMPPacket(unsigned char * packet, UINT & packet_len, PWINDIVERT_ADDRESS addr, PWINDIVERT_IPHDR ip_hdr, PWINDIVERT_IPV6HDR ip6_hdr, PWINDIVERT_ICMPHDR icmp_hdr, PWINDIVERT_ICMPV6HDR icmp6_hdr, IpAddr & srcAddr, IpAddr & dstAddr) 157 | { 158 | if (addr->Outbound) 159 | { 160 | for (auto record = this->relayEntries.begin(); record != this->relayEntries.end(); ++record) 161 | { 162 | if (record->protocol == "icmp" && (dstAddr == record->dstAddr || record->dstAddr == anyIpAddr)) 163 | { 164 | this->logDebug("Modify packet dst -> %s", record->forwardAddr.to_string().c_str()); 165 | if (record->dstAddr == anyIpAddr) 166 | { 167 | EndpointKey key; 168 | key.addr = srcAddr.get_addr(); 169 | key.port = 0; 170 | this->incomingICMPMap[key] = { dstAddr, 0}; 171 | } 172 | this->OverrideIPHeaderDst(ip_hdr, ip6_hdr, record->forwardAddr); 173 | break; 174 | } 175 | } 176 | } 177 | else 178 | { 179 | for (auto record = this->relayEntries.begin(); record != this->relayEntries.end(); ++record) 180 | { 181 | if (record->protocol == "icmp" && (srcAddr == record->forwardAddr || record->dstAddr == anyIpAddr)) 182 | { 183 | if (record->dstAddr == anyIpAddr) 184 | { 185 | EndpointKey key; 186 | key.addr = dstAddr.get_addr(); 187 | key.port = 0; 188 | std::map::iterator it = this->incomingICMPMap.find(key); 189 | if (it != this->incomingICMPMap.end()) 190 | { 191 | IpAddr& lookupAddr = it->second.addr; 192 | this->OverrideIPHeaderSrc(ip_hdr, ip6_hdr, lookupAddr); 193 | this->logDebug("Modify packet src -> %s", lookupAddr.to_string().c_str()); 194 | break; 195 | } 196 | } 197 | else 198 | { 199 | this->OverrideIPHeaderSrc(ip_hdr, ip6_hdr, record->dstAddr); 200 | this->logDebug("Modify packet src -> %s", record->dstAddr.to_string().c_str()); 201 | break; 202 | } 203 | } 204 | } 205 | } 206 | return PacketAction::STATUS_PROCEED; 207 | } 208 | 209 | PacketAction OutboundDivertProxy::ProcessUDPPacket(unsigned char * packet, UINT & packet_len, PWINDIVERT_ADDRESS addr, PWINDIVERT_IPHDR ip_hdr, PWINDIVERT_IPV6HDR ip6_hdr, PWINDIVERT_UDPHDR udp_header, IpAddr & srcAddr, IpAddr & dstAddr) 210 | { 211 | if (addr->Outbound) 212 | { 213 | for (auto record = this->relayEntries.begin(); record != this->relayEntries.end(); ++record) 214 | { 215 | if (record->protocol == "udp" && (dstAddr == record->dstAddr || record->dstAddr == anyIpAddr) && udp_header->DstPort == htons(record->dstPort)) 216 | { 217 | this->logDebug("Modify packet dst -> %s:%hu", record->forwardAddr.to_string().c_str(), record->forwardPort); 218 | if (record->dstAddr == anyIpAddr) 219 | { 220 | EndpointKey key; 221 | key.addr = srcAddr.get_addr(); 222 | key.port = udp_header->SrcPort; 223 | this->incomingUDPMap[key] = { dstAddr, udp_header->DstPort }; 224 | } 225 | this->OverrideIPHeaderDst(ip_hdr, ip6_hdr, record->forwardAddr); 226 | udp_header->DstPort = htons(record->forwardPort); 227 | break; 228 | } 229 | } 230 | } 231 | else 232 | { 233 | for (auto record = this->relayEntries.begin(); record != this->relayEntries.end(); ++record) 234 | { 235 | if (record->protocol == "udp" && (srcAddr == record->forwardAddr || record->dstAddr == anyIpAddr) && udp_header->SrcPort == htons(record->forwardPort)) 236 | { 237 | if (record->dstAddr == anyIpAddr) 238 | { 239 | EndpointKey key; 240 | key.addr = dstAddr.get_addr(); 241 | key.port = udp_header->DstPort; 242 | std::map::iterator it = this->incomingUDPMap.find(key); 243 | if (it != this->incomingUDPMap.end()) 244 | { 245 | IpAddr& addr = it->second.addr; 246 | this->OverrideIPHeaderSrc(ip_hdr, ip6_hdr, addr); 247 | udp_header->SrcPort = it->second.port; 248 | this->logDebug("Modify packet src -> %s:%hu", addr.to_string().c_str(), ntohs(it->second.port)); 249 | break; 250 | } 251 | } 252 | else 253 | { 254 | this->OverrideIPHeaderSrc(ip_hdr, ip6_hdr, record->dstAddr); 255 | udp_header->SrcPort = htons(record->dstPort); 256 | this->logDebug("Modify packet src -> %s:%hu", record->dstAddr.to_string().c_str(), record->dstPort); 257 | break; 258 | } 259 | } 260 | } 261 | } 262 | return PacketAction::STATUS_PROCEED; 263 | } 264 | 265 | OutboundDivertProxy::OutboundDivertProxy(bool verbose, std::vector& relayEntries) 266 | : BaseProxy(verbose) 267 | { 268 | this->relayEntries = relayEntries; 269 | this->selfDescStr = this->getStringDesc(); 270 | } 271 | 272 | OutboundDivertProxy::~OutboundDivertProxy() 273 | { 274 | } 275 | 276 | bool OutboundDivertProxy::Stop() 277 | { 278 | this->incomingTCPMap.clear(); 279 | this->incomingUDPMap.clear(); 280 | this->incomingICMPMap.clear(); 281 | return BaseProxy::Stop(); 282 | } 283 | -------------------------------------------------------------------------------- /StreamDivert/BaseProxy.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "BaseProxy.h" 3 | #include"utils.h" 4 | #include "windivert.h" 5 | #include "ipaddr.h" 6 | 7 | 8 | /* 9 | * Cleanup completed I/O requests. 10 | */ 11 | static void cleanup(HANDLE ioport, OVERLAPPED* ignore) 12 | { 13 | OVERLAPPED* overlapped; 14 | DWORD iolen; 15 | ULONG_PTR iokey = 0; 16 | 17 | while (GetQueuedCompletionStatus(ioport, &iolen, &iokey, &overlapped, 0)) 18 | { 19 | if (overlapped != ignore) 20 | { 21 | free(overlapped); 22 | } 23 | } 24 | } 25 | 26 | 27 | void BaseProxy::logDebug(const char* msg, ...) 28 | { 29 | va_list args; 30 | va_start(args, msg); 31 | if (this->verbose) 32 | { 33 | std::string selfDesc = this->selfDescStr; 34 | std::string msgStr = selfDesc + " " + msg; 35 | vdebug(msgStr.c_str(), args); 36 | 37 | } 38 | va_end(args); 39 | } 40 | 41 | void BaseProxy::logInfo(const char* msg, ...) 42 | { 43 | va_list args; 44 | va_start(args, msg); 45 | std::string selfDesc = this->selfDescStr; 46 | std::string msgStr = selfDesc + " " + msg; 47 | vinfo(msgStr.c_str(), args); 48 | va_end(args); 49 | } 50 | 51 | void BaseProxy::logWarning(const char* msg, ...) 52 | { 53 | va_list args; 54 | va_start(args, msg); 55 | std::string selfDesc = this->selfDescStr; 56 | std::string msgStr = selfDesc + " " + msg; 57 | vwarning(msgStr.c_str(), args); 58 | va_end(args); 59 | } 60 | 61 | void BaseProxy::logError(const char* msg, ...) 62 | { 63 | va_list args; 64 | va_start(args, msg); 65 | std::string selfDesc = this->selfDescStr; 66 | std::string msgStr = selfDesc + " " + msg; 67 | verror(msgStr.c_str(), args); 68 | va_end(args); 69 | } 70 | 71 | std::string BaseProxy::getIpAddrIpStr(IpAddr& addr) 72 | { 73 | if (addr.get_family() == IPFamily::IPv4) 74 | { 75 | return "ip"; 76 | } 77 | else if (addr.get_family() == IPFamily::IPv6) 78 | { 79 | return "ipv6"; 80 | } 81 | return "Unknown"; 82 | } 83 | 84 | std::string BaseProxy::getStringDesc() 85 | { 86 | std::string result = std::string("BaseProxy()"); 87 | return result; 88 | } 89 | 90 | std::string BaseProxy::generateDivertFilterString() 91 | { 92 | return std::string("tcp"); 93 | } 94 | 95 | void BaseProxy::SwapIPHeaderSrcToDst(PWINDIVERT_IPHDR ip_hdr, PWINDIVERT_IPV6HDR ip6_hdr) 96 | { 97 | if (ip_hdr) 98 | { 99 | ip_hdr->DstAddr = ip_hdr->SrcAddr; 100 | } 101 | else if (ip6_hdr) 102 | { 103 | *(in6_addr*)&ip6_hdr->DstAddr[0] = *(in6_addr*)&ip6_hdr->SrcAddr[0]; 104 | } 105 | } 106 | 107 | void BaseProxy::SwapIPHeaderDstToSrc(PWINDIVERT_IPHDR ip_hdr, PWINDIVERT_IPV6HDR ip6_hdr) 108 | { 109 | if (ip_hdr) 110 | { 111 | ip_hdr->SrcAddr = ip_hdr->DstAddr; 112 | } 113 | else if (ip6_hdr) 114 | { 115 | *(in6_addr*)&ip6_hdr->SrcAddr[0] = *(in6_addr*)&ip6_hdr->DstAddr[0]; 116 | } 117 | } 118 | 119 | void BaseProxy::OverrideIPHeaderSrc(PWINDIVERT_IPHDR ip_hdr, PWINDIVERT_IPV6HDR ip6_hdr, IpAddr& addr) 120 | { 121 | if (ip_hdr) 122 | { 123 | ip_hdr->SrcAddr = addr.get_ipv4_addr().S_un.S_addr; 124 | } 125 | else if (ip6_hdr) 126 | { 127 | *(in6_addr*)&ip6_hdr->SrcAddr[0] = addr.get_addr(); 128 | } 129 | } 130 | 131 | void BaseProxy::OverrideIPHeaderDst(PWINDIVERT_IPHDR ip_hdr, PWINDIVERT_IPV6HDR ip6_hdr, IpAddr& addr) 132 | { 133 | if (ip_hdr) 134 | { 135 | ip_hdr->DstAddr = addr.get_ipv4_addr().S_un.S_addr; 136 | } 137 | else if (ip6_hdr) 138 | { 139 | *(in6_addr*)&ip6_hdr->DstAddr[0] = addr.get_addr(); 140 | } 141 | } 142 | 143 | void BaseProxy::DivertWorker() 144 | { 145 | OVERLAPPED overlapped; 146 | OVERLAPPED* poverlapped; 147 | unsigned char packet[WINDIVERT_MTU_MAX]; 148 | UINT packet_len = sizeof(packet); 149 | WINDIVERT_ADDRESS addr; 150 | PWINDIVERT_IPHDR ip_header; 151 | PWINDIVERT_IPV6HDR ip6_header; 152 | PWINDIVERT_TCPHDR tcp_header; 153 | PWINDIVERT_ICMPHDR icmp_header; 154 | PWINDIVERT_ICMPV6HDR icmp6_header; 155 | PWINDIVERT_UDPHDR udp_header; 156 | IpAddr srcIp; 157 | IpAddr dstIp; 158 | UINT addr_len = sizeof(WINDIVERT_ADDRESS); 159 | UINT recv_packet_len = 0; 160 | UINT recv_len = 0; 161 | DWORD len; 162 | UINT8 protocol; 163 | std::string selfDesc = this->getStringDesc(); 164 | PacketAction action = PacketAction::STATUS_PROCEED; 165 | 166 | while (TRUE) 167 | { 168 | memset(&overlapped, 0, sizeof(overlapped)); 169 | ResetEvent(this->event); 170 | overlapped.hEvent = this->event; 171 | if (!WinDivertRecvEx(this->hDivert, &packet[0], packet_len, &recv_len, 0, &addr, &addr_len, &overlapped)) 172 | { 173 | DWORD lastErr = GetLastError(); 174 | if (lastErr == ERROR_INVALID_HANDLE || lastErr == ERROR_OPERATION_ABORTED) 175 | { 176 | //error("%s: WinDivertRecvEx failed: (%d)", selfDesc.c_str(), lastErr); 177 | goto END; 178 | } 179 | else if (lastErr != ERROR_IO_PENDING) 180 | { 181 | read_failed: 182 | this->logWarning("failed to read packet (%d)", lastErr); 183 | continue; 184 | } 185 | 186 | // Timeout = 1s 187 | while (WaitForSingleObject(event, 1000) == WAIT_TIMEOUT) 188 | { 189 | cleanup(this->ioPort, &overlapped); 190 | } 191 | if (!GetOverlappedResult(this->hDivert, &overlapped, &len, FALSE)) 192 | { 193 | goto read_failed; 194 | } 195 | recv_packet_len = len; 196 | } 197 | cleanup(this->ioPort, &overlapped); 198 | 199 | if (WinDivertHelperParsePacket(&packet[0], recv_packet_len, &ip_header, &ip6_header, &protocol, &icmp_header, &icmp6_header, &tcp_header, &udp_header, NULL, NULL, NULL, NULL)) 200 | { 201 | bool packet_contains_iphdr = true; 202 | if (ip_header != NULL) 203 | { 204 | in_addr temp_addr; 205 | temp_addr.S_un.S_addr = ip_header->SrcAddr; 206 | srcIp = IpAddr(temp_addr); 207 | temp_addr.S_un.S_addr = ip_header->DstAddr; 208 | dstIp = IpAddr(temp_addr); 209 | } 210 | else if (ip6_header != NULL) 211 | { 212 | in6_addr temp_addr; 213 | memcpy(&temp_addr.u.Byte[0], ip6_header->SrcAddr, sizeof(in6_addr)); 214 | srcIp = IpAddr(temp_addr); 215 | memcpy(&temp_addr.u.Byte[0], ip6_header->DstAddr, sizeof(in6_addr)); 216 | dstIp = IpAddr(temp_addr); 217 | } 218 | else 219 | { 220 | packet_contains_iphdr = false; 221 | this->logError("No IP header in packet!?"); 222 | } 223 | 224 | if (packet_contains_iphdr) 225 | { 226 | std::string srcIpStr = srcIp.to_string(); 227 | std::string dstIpStr = dstIp.to_string(); 228 | std::string direction_str = addr.Outbound == 1 ? "OUT" : "IN"; 229 | 230 | if (protocol == IPPROTO_TCP) 231 | { 232 | UINT16 srcPort = ntohs(tcp_header->SrcPort); 233 | UINT16 dstPort = ntohs(tcp_header->DstPort); 234 | this->logDebug("TCP Packet %s:%hu %s:%hu %s", srcIpStr.c_str(), srcPort, dstIpStr.c_str(), dstPort, direction_str.c_str()); 235 | action = this->ProcessTCPPacket(&packet[0], recv_packet_len, &addr, ip_header, ip6_header, tcp_header, srcIp, dstIp); 236 | } 237 | else if (protocol == IPPROTO_ICMP || protocol == IPPROTO_ICMPV6) 238 | { 239 | this->logDebug("ICMP Packet %s %s %s", srcIpStr.c_str(), dstIpStr.c_str(), direction_str.c_str()); 240 | action = this->ProcessICMPPacket(&packet[0], recv_packet_len, &addr, ip_header, ip6_header, icmp_header, icmp6_header, srcIp, dstIp); 241 | } 242 | else if (protocol == IPPROTO_UDP) 243 | { 244 | UINT16 srcPort = ntohs(udp_header->SrcPort); 245 | UINT16 dstPort = ntohs(udp_header->DstPort); 246 | this->logDebug("UDP Packet %s:%hu %s:%hu %s", srcIpStr.c_str(), srcPort, dstIpStr.c_str(), dstPort, direction_str.c_str()); 247 | action = this->ProcessUDPPacket(&packet[0], recv_packet_len, &addr, ip_header, ip6_header, udp_header, srcIp, dstIp); 248 | } 249 | } 250 | } 251 | else 252 | { 253 | this->logWarning("failed to parse packet (%d)", GetLastError()); 254 | } 255 | 256 | if (action == PacketAction::STATUS_PROCEED) 257 | { 258 | if (!WinDivertHelperCalcChecksums(&packet[0], recv_packet_len, &addr, 0)) 259 | { 260 | this->logError("failed to recalc packet checksum: (%d)", GetLastError()); 261 | } 262 | poverlapped = (OVERLAPPED*)malloc(sizeof(OVERLAPPED)); 263 | if (poverlapped == NULL) 264 | { 265 | error("%s: failed to allocate poverlapped memory", selfDesc.c_str()); 266 | } 267 | memset(poverlapped, 0, sizeof(OVERLAPPED)); 268 | if (WinDivertSendEx(this->hDivert, &packet[0], recv_packet_len, NULL, 0, &addr, addr_len, poverlapped)) 269 | { 270 | continue; 271 | } 272 | if (GetLastError() != ERROR_IO_PENDING) 273 | { 274 | this->logWarning("failed to send packet (%d)", GetLastError()); 275 | continue; 276 | } 277 | } 278 | else 279 | { 280 | this->logDebug("Dropping packet"); 281 | } 282 | } 283 | END: 284 | this->logInfo("DivertWorker exiting"); 285 | return; 286 | } 287 | 288 | BaseProxy::BaseProxy(bool verbose) 289 | { 290 | this->running = false; 291 | this->priority = 0; 292 | this->selfDescStr = this->getStringDesc(); 293 | this->verbose = verbose; 294 | } 295 | 296 | 297 | BaseProxy::~BaseProxy() 298 | { 299 | if (this->running) 300 | { 301 | this->Stop(); 302 | } 303 | } 304 | 305 | bool BaseProxy::Start() 306 | { 307 | //lock scope 308 | { 309 | std::lock_guard lock(this->resourceLock); 310 | this->logInfo("Start"); 311 | 312 | this->ioPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); 313 | if (this->ioPort == NULL) 314 | { 315 | this->logError("failed to create I/O completion port (%d)", GetLastError()); 316 | goto failure; 317 | } 318 | 319 | this->event = CreateEvent(NULL, FALSE, FALSE, NULL); 320 | if (event == NULL) 321 | { 322 | this->logError("failed to create event (%d)", GetLastError()); 323 | goto failure; 324 | } 325 | 326 | this->filterStr = this->generateDivertFilterString(); 327 | this->logInfo("%s", this->filterStr.c_str()); 328 | this->hDivert = WinDivertOpen(this->filterStr.c_str(), WINDIVERT_LAYER_NETWORK, this->priority, 0); 329 | if (this->hDivert == INVALID_HANDLE_VALUE) 330 | { 331 | this->logError("failed to open the WinDivert device (%d)", GetLastError()); 332 | goto failure; 333 | } 334 | if (CreateIoCompletionPort(this->hDivert, this->ioPort, 0, 0) == NULL) 335 | { 336 | this->logError("failed to associate I/O completion port (%d)", GetLastError()); 337 | goto failure; 338 | } 339 | }//lock scope 340 | 341 | this->running = true; 342 | this->divertThread = std::thread(&BaseProxy::DivertWorker, this); 343 | return true; 344 | 345 | failure: 346 | this->Stop(); 347 | return false; 348 | } 349 | 350 | bool BaseProxy::Stop() 351 | { 352 | this->logInfo("Stop"); 353 | {//lock scope 354 | std::lock_guard lock(this->resourceLock); 355 | this->running = false; 356 | if (this->hDivert != NULL) 357 | { 358 | WinDivertClose(this->hDivert); 359 | this->hDivert = NULL; 360 | } 361 | if (this->ioPort != NULL) 362 | { 363 | CloseHandle(this->ioPort); 364 | this->ioPort = NULL; 365 | } 366 | if (this->event != NULL) 367 | { 368 | CloseHandle(this->event); 369 | this->event = NULL; 370 | } 371 | }//lock scope 372 | 373 | if (this->divertThread.joinable()) 374 | { 375 | this->divertThread.join(); 376 | } 377 | return true; 378 | } 379 | -------------------------------------------------------------------------------- /StreamDivert/StreamDivert.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {D3214282-B88F-44E5-8B5E-57663AD96AD5} 23 | Win32Proj 24 | StreamDivert 25 | 10.0 26 | StreamDivert 27 | 28 | 29 | 30 | Application 31 | true 32 | v142 33 | MultiByte 34 | 35 | 36 | Application 37 | false 38 | v142 39 | true 40 | MultiByte 41 | 42 | 43 | Application 44 | true 45 | v142 46 | MultiByte 47 | 48 | 49 | Application 50 | false 51 | v142 52 | true 53 | MultiByte 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | true 78 | 79 | 80 | false 81 | 82 | 83 | false 84 | 85 | 86 | 87 | Use 88 | Level3 89 | Disabled 90 | WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) 91 | true 92 | MultiThreadedDebug 93 | 94 | 95 | Console 96 | true 97 | $(SolutionDir)WinDivert\x86;%(AdditionalLibraryDirectories) 98 | WinDivert.lib;Ws2_32.lib;%(AdditionalDependencies) 99 | 100 | 101 | xcopy "$(SolutionDir)\WinDivert\$(PlatformTargetAsMSBuildArchitecture)\WinDivert.dll" "$(OutDir)" /y /d 102 | xcopy "$(SolutionDir)\WinDivert\$(PlatformTargetAsMSBuildArchitecture)\WinDivert32.sys" "$(OutDir)" /y /d 103 | xcopy "$(SolutionDir)\WinDivert\$(PlatformTargetAsMSBuildArchitecture)\WinDivert64.sys" "$(OutDir)" /y /d 104 | 105 | 106 | 107 | 108 | Use 109 | Level3 110 | Disabled 111 | _DEBUG;_WINDOWS;%(PreprocessorDefinitions) 112 | true 113 | MultiThreadedDebug 114 | 115 | 116 | Console 117 | true 118 | $(SolutionDir)WinDivert\x64;%(AdditionalLibraryDirectories) 119 | WinDivert.lib;Ws2_32.lib;%(AdditionalDependencies) 120 | 121 | 122 | xcopy "$(SolutionDir)\WinDivert\$(PlatformTargetAsMSBuildArchitecture)\WinDivert.dll" "$(OutDir)" /y /d 123 | xcopy "$(SolutionDir)\WinDivert\$(PlatformTargetAsMSBuildArchitecture)\WinDivert32.sys" "$(OutDir)" /y /d 124 | xcopy "$(SolutionDir)\WinDivert\$(PlatformTargetAsMSBuildArchitecture)\WinDivert64.sys" "$(OutDir)" /y /d 125 | 126 | 127 | 128 | 129 | Level3 130 | Use 131 | MaxSpeed 132 | true 133 | true 134 | WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 135 | true 136 | MultiThreaded 137 | 138 | 139 | Console 140 | true 141 | true 142 | true 143 | $(SolutionDir)WinDivert\x86;%(AdditionalLibraryDirectories) 144 | WinDivert.lib;Ws2_32.lib;%(AdditionalDependencies) 145 | false 146 | 147 | 148 | xcopy "$(SolutionDir)\WinDivert\$(PlatformTargetAsMSBuildArchitecture)\WinDivert.dll" "$(OutDir)" /y /d 149 | 150 | xcopy "$(SolutionDir)\WinDivert\$(PlatformTargetAsMSBuildArchitecture)\WinDivert32.sys" "$(OutDir)" /y /d 151 | 152 | xcopy "$(SolutionDir)\WinDivert\$(PlatformTargetAsMSBuildArchitecture)\WinDivert64.sys" "$(OutDir)" /y /d 153 | 154 | 155 | 156 | 157 | Level3 158 | Use 159 | MaxSpeed 160 | true 161 | true 162 | NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 163 | true 164 | MultiThreaded 165 | 166 | 167 | Console 168 | true 169 | true 170 | true 171 | $(SolutionDir)WinDivert\x64;%(AdditionalLibraryDirectories) 172 | WinDivert.lib;Ws2_32.lib;%(AdditionalDependencies) 173 | 174 | 175 | xcopy "$(SolutionDir)\WinDivert\$(PlatformTargetAsMSBuildArchitecture)\WinDivert.dll" "$(OutDir)" /y /d 176 | 177 | xcopy "$(SolutionDir)\WinDivert\$(PlatformTargetAsMSBuildArchitecture)\WinDivert32.sys" "$(OutDir)" /y /d 178 | 179 | xcopy "$(SolutionDir)\WinDivert\$(PlatformTargetAsMSBuildArchitecture)\WinDivert64.sys" "$(OutDir)" /y /d 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | Create 218 | Create 219 | Create 220 | Create 221 | 222 | 223 | CppCode 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | -------------------------------------------------------------------------------- /StreamDivert/InboundTCPDivertProxy.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "InboundTCPDivertProxy.h" 3 | #include "utils.h" 4 | #include "windivert.h" 5 | #include 6 | #include "sockutils.h" 7 | 8 | 9 | InboundTCPDivertProxy::InboundTCPDivertProxy(bool verbose, const UINT16 localPort, const std::vector& proxyRecords) 10 | : BaseProxy(verbose), 11 | socksServer(0) 12 | { 13 | this->localPort = localPort; 14 | this->localProxyPort = 0; 15 | this->proxyRecords = proxyRecords; 16 | this->proxySock = NULL; 17 | this->selfDescStr = this->getStringDesc(); 18 | this->containsSocksRecords = false; 19 | } 20 | 21 | InboundTCPDivertProxy::~InboundTCPDivertProxy() 22 | { 23 | } 24 | 25 | bool InboundTCPDivertProxy::Start() 26 | { 27 | WSADATA wsa_data; 28 | WORD wsa_version = MAKEWORD(2, 2); 29 | int on = 1; 30 | int off = 0; 31 | struct sockaddr_in6 addr; 32 | 33 | //lock scope 34 | { 35 | std::lock_guard lock(this->resourceLock); 36 | this->logInfo("Start"); 37 | 38 | if (WSAStartup(wsa_version, &wsa_data) != 0) 39 | { 40 | this->logError("failed to start WSA (%d)", GetLastError()); 41 | goto failure; 42 | } 43 | this->proxySock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); 44 | if (this->proxySock == INVALID_SOCKET) 45 | { 46 | this->logError("failed to create socket (%d)", WSAGetLastError()); 47 | goto failure; 48 | } 49 | if (setsockopt(this->proxySock, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(int)) == SOCKET_ERROR) 50 | { 51 | this->logError("failed to re-use address (%d)", GetLastError()); 52 | goto failure; 53 | } 54 | if (setsockopt(this->proxySock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&off, sizeof(int)) == SOCKET_ERROR) 55 | { 56 | this->logError("failed to set socket dual-stack (%d)", GetLastError()); 57 | goto failure; 58 | } 59 | memset(&addr, 0, sizeof(addr)); 60 | addr.sin6_family = AF_INET6; 61 | addr.sin6_port = htons(0); 62 | addr.sin6_addr = in6addr_any; 63 | //inet_pton(AF_INET6, "::1", &addr.sin6_addr); 64 | if (::bind(this->proxySock, (SOCKADDR *)&addr, sizeof(addr)) == SOCKET_ERROR) 65 | { 66 | this->logError("failed to bind socket (%d)", WSAGetLastError()); 67 | goto failure; 68 | } 69 | 70 | struct sockaddr_in6 bind_addr; 71 | int bind_addr_len = sizeof(bind_addr); 72 | if (getsockname(this->proxySock, (struct sockaddr *)&bind_addr, &bind_addr_len) == -1) 73 | { 74 | this->logError("failed to get bind socket port (%d)", WSAGetLastError()); 75 | } 76 | this->localProxyPort = ntohs(bind_addr.sin6_port); 77 | this->selfDescStr = this->getStringDesc(); 78 | 79 | if (listen(this->proxySock, 16) == SOCKET_ERROR) 80 | { 81 | this->logError("failed to listen socket (%d)", WSAGetLastError()); 82 | goto failure; 83 | } 84 | 85 | for each (auto record in this->proxyRecords) 86 | { 87 | if (record.type == InboundRelayEntryType::Socks) 88 | { 89 | this->socksServer.Start(); 90 | containsSocksRecords = true; 91 | break; 92 | } 93 | } 94 | 95 | BaseProxy::Start(); 96 | }//lock scope 97 | 98 | this->proxyThread = std::thread(&InboundTCPDivertProxy::ProxyWorker, this); 99 | return true; 100 | 101 | failure: 102 | this->Stop(); 103 | return false; 104 | } 105 | 106 | 107 | std::string InboundTCPDivertProxy::getStringDesc() 108 | { 109 | std::string result = std::string("InboundTCPDivertProxy(" + std::to_string(this->localPort) + ":"); 110 | if (this->localProxyPort == 0) 111 | { 112 | result += "?"; 113 | } 114 | else 115 | { 116 | result += std::to_string(this->localProxyPort); 117 | } 118 | result += ")"; 119 | return result; 120 | } 121 | 122 | PacketAction InboundTCPDivertProxy::ProcessTCPPacket(unsigned char* packet, UINT& packet_len, PWINDIVERT_ADDRESS addr, PWINDIVERT_IPHDR ip_hdr, PWINDIVERT_IPV6HDR ip6_hdr, PWINDIVERT_TCPHDR tcp_hdr, IpAddr& srcAddr, IpAddr& dstAddr) 123 | { 124 | if (!addr->Outbound) 125 | { 126 | for (auto record = this->proxyRecords.begin(); record != this->proxyRecords.end(); ++record) 127 | { 128 | if ((srcAddr == record->srcAddr || record->srcAddr == anyIpAddr) && 129 | tcp_hdr->DstPort == htons(this->localPort)) 130 | { 131 | std::string dstAddrStr = dstAddr.to_string(); 132 | if (record->type == InboundRelayEntryType::Divert) 133 | { 134 | this->logDebug("Modify packet dst -> %s:%hu", dstAddrStr.c_str(), this->localProxyPort); 135 | tcp_hdr->DstPort = htons(this->localProxyPort); 136 | break; 137 | } 138 | else if (record->type == InboundRelayEntryType::Socks) 139 | { 140 | int socksPort = this->socksServer.GetPort(); 141 | this->logDebug("Modify packet dst -> %s:%hu", dstAddrStr.c_str(), socksPort); 142 | tcp_hdr->DstPort = htons(socksPort); 143 | break; 144 | } 145 | } 146 | } 147 | } 148 | else 149 | { 150 | for (auto record = this->proxyRecords.begin(); record != this->proxyRecords.end(); ++record) 151 | { 152 | if ((dstAddr == record->srcAddr || record->srcAddr == anyIpAddr)) 153 | { 154 | if ( 155 | (record->type == InboundRelayEntryType::Divert && tcp_hdr->SrcPort == htons(this->localProxyPort) ) || 156 | (record->type == InboundRelayEntryType::Socks && tcp_hdr->SrcPort == htons(this->socksServer.GetPort())) 157 | ) 158 | { 159 | std::string srcAddrStr = srcAddr.to_string(); 160 | this->logDebug("Modify packet src -> %s:%hu", srcAddrStr.c_str(), this->localPort); 161 | tcp_hdr->SrcPort = htons(this->localPort); 162 | break; 163 | } 164 | } 165 | } 166 | } 167 | return PacketAction::STATUS_PROCEED; 168 | } 169 | 170 | void InboundTCPDivertProxy::ProxyWorker() 171 | { 172 | while (true) 173 | { 174 | struct sockaddr_in6 clientSockAddr; 175 | int size = sizeof(clientSockAddr); 176 | SOCKET incommingSock = accept(this->proxySock, (SOCKADDR *)&clientSockAddr, &size); 177 | if (incommingSock == INVALID_SOCKET) 178 | { 179 | std::lock_guard lock(this->resourceLock); 180 | if (this->running == false) 181 | { 182 | goto cleanup; 183 | } 184 | this->logWarning("failed to accept socket (%d)", WSAGetLastError()); 185 | continue; 186 | } 187 | IpAddr clientSockIp = IpAddr(clientSockAddr.sin6_addr); 188 | std::string srcAddr = clientSockIp.to_string(); 189 | this->logInfo("Incoming connection from %s:%hu", srcAddr.c_str(), ntohs(clientSockAddr.sin6_port)); 190 | ProxyConnectionWorkerData* proxyConnectionWorkerData = new ProxyConnectionWorkerData(); 191 | proxyConnectionWorkerData->clientSock = incommingSock; 192 | proxyConnectionWorkerData->clientAddr = clientSockAddr; 193 | std::thread proxyConnectionThread(&InboundTCPDivertProxy::ProxyConnectionWorker, this, proxyConnectionWorkerData); 194 | proxyConnectionThread.detach(); 195 | } 196 | cleanup: 197 | if (this->proxySock != NULL) 198 | { 199 | closesocket(this->proxySock); 200 | this->proxySock = NULL; 201 | } 202 | this->logInfo("ProxyWorker exiting"); 203 | } 204 | 205 | void InboundTCPDivertProxy::ProxyConnectionWorker(ProxyConnectionWorkerData* proxyConnectionWorkerData) 206 | { 207 | int off = 0; 208 | SOCKET destSock = NULL; 209 | SOCKET clientSock = proxyConnectionWorkerData->clientSock; 210 | sockaddr_in6 clientSockAddr = proxyConnectionWorkerData->clientAddr; 211 | IpAddr clientSockIp = IpAddr(clientSockAddr.sin6_addr); 212 | delete proxyConnectionWorkerData; 213 | 214 | std::string selfDesc = this->getStringDesc(); 215 | 216 | InboundRelayEntry proxyRecord; 217 | UINT16 clientSrcPort = ntohs(clientSockAddr.sin6_port); 218 | std::string srcAddr = clientSockIp.to_string(); 219 | bool lookupSuccess = this->findProxyRecordBySrcAddr(clientSockIp, proxyRecord); 220 | if (lookupSuccess) 221 | { 222 | struct sockaddr_in6 destAddr; 223 | ZeroMemory(&destAddr, sizeof(destAddr)); 224 | destAddr.sin6_family = AF_INET6; 225 | destAddr.sin6_addr = proxyRecord.forwardAddr.get_addr(); 226 | destAddr.sin6_port = htons(proxyRecord.forwardPort); 227 | destSock = socket(AF_INET6, SOCK_STREAM, 0); 228 | if (destSock == INVALID_SOCKET) 229 | { 230 | this->logError("failed to create socket (%d)", WSAGetLastError()); 231 | goto cleanup; 232 | } 233 | if (setsockopt(destSock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&off, sizeof(int)) == SOCKET_ERROR) 234 | { 235 | this->logError("failed to set connect socket dual-stack (%d)", GetLastError()); 236 | goto cleanup; 237 | } 238 | std::string forwardAddr = proxyRecord.forwardAddr.to_string(); 239 | this->logInfo("Connecting to forward host %s:%hu", forwardAddr.c_str(), proxyRecord.forwardPort); 240 | if (connect(destSock, (SOCKADDR *)&destAddr, sizeof(destAddr)) == SOCKET_ERROR) 241 | { 242 | this->logError("failed to connect socket (%d)", WSAGetLastError()); 243 | goto cleanup; 244 | } 245 | 246 | this->logInfo("Starting to route %s:%hu -> %s:%hu", srcAddr.c_str(), clientSrcPort, forwardAddr.c_str(), proxyRecord.forwardPort); 247 | ProxyTunnelWorkerData* tunnelDataA = new ProxyTunnelWorkerData(); 248 | ProxyTunnelWorkerData* tunnelDataB = new ProxyTunnelWorkerData(); 249 | tunnelDataA->sockA = clientSock; 250 | tunnelDataA->sockAAddr = clientSockIp; 251 | tunnelDataA->sockAPort = clientSrcPort; 252 | tunnelDataA->sockB = destSock; 253 | tunnelDataA->sockBAddr = proxyRecord.forwardAddr; 254 | tunnelDataA->sockBPort = proxyRecord.forwardPort; 255 | 256 | tunnelDataB->sockA = destSock; 257 | tunnelDataB->sockAAddr = proxyRecord.forwardAddr; 258 | tunnelDataB->sockAPort = proxyRecord.forwardPort; 259 | tunnelDataB->sockB = clientSock; 260 | tunnelDataB->sockBAddr = clientSockIp; 261 | tunnelDataB->sockBPort = clientSrcPort; 262 | std::thread tunnelThread(&ProxyTunnelWorker, tunnelDataA, this->selfDescStr); 263 | ProxyTunnelWorker(tunnelDataB, this->selfDescStr); 264 | tunnelThread.join(); 265 | } 266 | 267 | cleanup: 268 | if (clientSock != NULL) 269 | closesocket(clientSock); 270 | if (destSock != NULL) 271 | closesocket(destSock); 272 | 273 | this->logInfo("ProxyConnectionWorker exiting for client %s:%hu", srcAddr.c_str(), clientSrcPort); 274 | return; 275 | } 276 | 277 | std::string InboundTCPDivertProxy::generateDivertFilterString() 278 | { 279 | std::string result = "tcp"; 280 | std::vector orExpressions; 281 | std::string proxyFilterStr = "(tcp.SrcPort == " + std::to_string(this->localProxyPort) + ")"; 282 | orExpressions.push_back(proxyFilterStr); 283 | 284 | if (this->containsSocksRecords) 285 | { 286 | proxyFilterStr = "(tcp.SrcPort == " + std::to_string(this->socksServer.GetPort()) + ")"; 287 | orExpressions.push_back(proxyFilterStr); 288 | } 289 | 290 | //check for wildcard address 291 | bool containsWildcard = false; 292 | for (auto record = this->proxyRecords.begin(); record != this->proxyRecords.end(); ++record) 293 | { 294 | if (record->srcAddr == anyIpAddr) 295 | { 296 | std::string recordFilterStr = "(tcp.DstPort == " + std::to_string(this->localPort) + ")"; 297 | orExpressions.push_back(recordFilterStr); 298 | containsWildcard = true; 299 | break; 300 | } 301 | } 302 | 303 | if (!containsWildcard) 304 | { 305 | for (auto record = this->proxyRecords.begin(); record != this->proxyRecords.end(); ++record) 306 | { 307 | std::string srcAddrIpStr = this->getIpAddrIpStr(record->srcAddr); 308 | 309 | std::string recordFilterStr = "(tcp.DstPort == " + std::to_string(this->localPort) + " and " + srcAddrIpStr + ".SrcAddr == " + record->srcAddr.to_string() + ")"; 310 | orExpressions.push_back(recordFilterStr); 311 | } 312 | } 313 | 314 | result += " and ("; 315 | joinStr(orExpressions, std::string(" or "), result); 316 | result += ")"; 317 | return result; 318 | } 319 | 320 | bool InboundTCPDivertProxy::findProxyRecordBySrcAddr(IpAddr& srcAddr, InboundRelayEntry& proxyRecord) 321 | { 322 | for (auto record = this->proxyRecords.begin(); record != this->proxyRecords.end(); ++record) 323 | { 324 | if (record->srcAddr == anyIpAddr || record->srcAddr == srcAddr) 325 | { 326 | proxyRecord = *record; 327 | return true; 328 | } 329 | } 330 | return false; 331 | } 332 | 333 | bool InboundTCPDivertProxy::Stop() 334 | { 335 | this->logInfo("Stop"); 336 | {//lock scope 337 | std::lock_guard lock(this->resourceLock); 338 | BaseProxy::Stop(); 339 | if (this->proxySock != NULL) 340 | { 341 | shutdown(this->proxySock, SD_BOTH); 342 | closesocket(this->proxySock); 343 | this->proxySock = NULL; 344 | } 345 | }//lock scope 346 | 347 | if (this->proxyThread.joinable()) 348 | { 349 | this->proxyThread.join(); 350 | } 351 | if (this->socksServer.IsRunning()) 352 | { 353 | return this->socksServer.Stop(); 354 | } 355 | return true; 356 | } 357 | 358 | PacketAction InboundTCPDivertProxy::ProcessICMPPacket(unsigned char * packet, UINT & packet_len, PWINDIVERT_ADDRESS addr, PWINDIVERT_IPHDR ip_hdr, PWINDIVERT_IPV6HDR ip6_hdr, PWINDIVERT_ICMPHDR icmp_hdr, PWINDIVERT_ICMPV6HDR icmp6_hdr, IpAddr & srcAddr, IpAddr & dstAddr) 359 | { 360 | return PacketAction::STATUS_PROCEED; 361 | } 362 | 363 | PacketAction InboundTCPDivertProxy::ProcessUDPPacket(unsigned char * packet, UINT & packet_len, PWINDIVERT_ADDRESS addr, PWINDIVERT_IPHDR ip_hdr, PWINDIVERT_IPV6HDR ip6_hdr, PWINDIVERT_UDPHDR udp_header, IpAddr & srcAddr, IpAddr & dstAddr) 364 | { 365 | return PacketAction::STATUS_PROCEED; 366 | } 367 | 368 | -------------------------------------------------------------------------------- /StreamDivert/WindowsFirewall.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "WindowsFirewall.h" 3 | #include "utils.h" 4 | 5 | WindowsFirewall::WindowsFirewall() 6 | { 7 | this->profile = NULL; 8 | } 9 | 10 | WindowsFirewall::~WindowsFirewall() 11 | { 12 | // Release the firewall profile. 13 | if (this->profile != NULL) 14 | { 15 | this->profile->Release(); 16 | this->profile = NULL; 17 | } 18 | } 19 | 20 | bool WindowsFirewall::Initialize() 21 | { 22 | HRESULT hr = S_OK; 23 | INetFwMgr* fwMgr = NULL; 24 | INetFwPolicy* fwPolicy = NULL; 25 | 26 | CoInitialize(NULL); 27 | 28 | // Create an instance of the firewall settings manager. 29 | hr = CoCreateInstance( 30 | __uuidof(NetFwMgr), 31 | NULL, 32 | CLSCTX_INPROC_SERVER, 33 | __uuidof(INetFwMgr), 34 | (void**)&fwMgr 35 | ); 36 | if (FAILED(hr)) 37 | { 38 | error("CoCreateInstance failed: 0x%08lx\n", hr); 39 | goto error; 40 | } 41 | 42 | 43 | // Retrieve the local firewall policy. 44 | hr = fwMgr->get_LocalPolicy(&fwPolicy); 45 | if (FAILED(hr)) 46 | { 47 | error("get_LocalPolicy failed: 0x%08lx\n", hr); 48 | goto error; 49 | } 50 | 51 | // Retrieve the firewall profile currently in effect. 52 | hr = fwPolicy->get_CurrentProfile(&this->profile); 53 | if (FAILED(hr)) 54 | { 55 | error("get_CurrentProfile failed: 0x%08lx\n", hr); 56 | goto error; 57 | } 58 | 59 | error: 60 | 61 | // Release the local firewall policy. 62 | if (fwPolicy != NULL) 63 | { 64 | fwPolicy->Release(); 65 | } 66 | 67 | // Release the firewall settings manager. 68 | if (fwMgr != NULL) 69 | { 70 | fwMgr->Release(); 71 | } 72 | 73 | return SUCCEEDED(hr); 74 | } 75 | 76 | bool WindowsFirewall::IsFirewallOn(bool& fwOn) 77 | { 78 | HRESULT hr = S_OK; 79 | VARIANT_BOOL fwEnabled; 80 | fwOn = FALSE; 81 | 82 | // Get the current state of the firewall. 83 | hr = this->profile->get_FirewallEnabled(&fwEnabled); 84 | if (FAILED(hr)) 85 | { 86 | error("get_FirewallEnabled failed: 0x%08lx\n", hr); 87 | goto error; 88 | } 89 | 90 | // Check to see if the firewall is on. 91 | if (fwEnabled != VARIANT_FALSE) 92 | { 93 | fwOn = TRUE; 94 | } 95 | 96 | error: 97 | return SUCCEEDED(hr); 98 | } 99 | 100 | bool WindowsFirewall::PortIsConfigured(long port, NET_FW_IP_PROTOCOL proto, bool& isConfigured) 101 | { 102 | HRESULT hr = S_OK; 103 | VARIANT_BOOL fwEnabled; 104 | INetFwOpenPort* fwOpenPort = NULL; 105 | INetFwOpenPorts* fwOpenPorts = NULL; 106 | 107 | isConfigured = FALSE; 108 | 109 | // Retrieve the globally open ports collection. 110 | hr = this->profile->get_GloballyOpenPorts(&fwOpenPorts); 111 | if (FAILED(hr)) 112 | { 113 | error("get_GloballyOpenPorts failed: 0x%08lx\n", hr); 114 | goto error; 115 | } 116 | 117 | // Attempt to retrieve the globally open port. 118 | hr = fwOpenPorts->Item(port, proto, &fwOpenPort); 119 | if (SUCCEEDED(hr)) 120 | { 121 | // Find out if the globally open port is enabled. 122 | hr = fwOpenPort->get_Enabled(&fwEnabled); 123 | if (FAILED(hr)) 124 | { 125 | error("get_Enabled failed: 0x%08lx\n", hr); 126 | goto error; 127 | } 128 | 129 | if (fwEnabled != VARIANT_FALSE) 130 | { 131 | // The globally open port is enabled. 132 | isConfigured = TRUE; 133 | } 134 | } 135 | else 136 | { 137 | // The globally open port was not in the collection. 138 | hr = S_OK; 139 | } 140 | 141 | error: 142 | 143 | // Release the globally open port. 144 | if (fwOpenPort != NULL) 145 | { 146 | fwOpenPort->Release(); 147 | } 148 | 149 | // Release the globally open ports collection. 150 | if (fwOpenPorts != NULL) 151 | { 152 | fwOpenPorts->Release(); 153 | } 154 | 155 | return SUCCEEDED(hr); 156 | } 157 | 158 | bool WindowsFirewall::AddPort(long port, NET_FW_IP_PROTOCOL ipProtocol, std::string& name) 159 | { 160 | HRESULT hr = S_OK; 161 | bool fwPortEnabled; 162 | BSTR fwBstrName = NULL; 163 | INetFwOpenPort* fwOpenPort = NULL; 164 | INetFwOpenPorts* fwOpenPorts = NULL; 165 | 166 | // First check to see if the port is already added. 167 | if(!this->PortIsConfigured(port, ipProtocol, fwPortEnabled)) 168 | { 169 | error("PortIsConfigured failed\n"); 170 | hr = E_FAIL; 171 | goto error; 172 | } 173 | 174 | // Only add the port if it isn't already added. 175 | if (!fwPortEnabled) 176 | { 177 | // Retrieve the collection of globally open ports. 178 | hr = this->profile->get_GloballyOpenPorts(&fwOpenPorts); 179 | if (FAILED(hr)) 180 | { 181 | error("get_GloballyOpenPorts failed: 0x%08lx\n", hr); 182 | goto error; 183 | } 184 | 185 | // Create an instance of an open port. 186 | hr = CoCreateInstance( 187 | __uuidof(NetFwOpenPort), 188 | NULL, 189 | CLSCTX_INPROC_SERVER, 190 | __uuidof(INetFwOpenPort), 191 | (void**)&fwOpenPort 192 | ); 193 | if (FAILED(hr)) 194 | { 195 | printf("CoCreateInstance failed: 0x%08lx\n", hr); 196 | goto error; 197 | } 198 | 199 | // Set the port number. 200 | hr = fwOpenPort->put_Port(port); 201 | if (FAILED(hr)) 202 | { 203 | printf("put_Port failed: 0x%08lx\n", hr); 204 | goto error; 205 | } 206 | 207 | // Set the IP protocol. 208 | hr = fwOpenPort->put_Protocol(ipProtocol); 209 | if (FAILED(hr)) 210 | { 211 | printf("put_Protocol failed: 0x%08lx\n", hr); 212 | goto error; 213 | } 214 | 215 | // Allocate a BSTR for the friendly name of the port. 216 | int wslen = MultiByteToWideChar(CP_ACP, 0, name.c_str(), name.length(), 0, 0); 217 | fwBstrName = SysAllocStringLen(0, wslen); 218 | MultiByteToWideChar(CP_ACP, 0, name.c_str(), name.length(), fwBstrName, wslen); 219 | if (SysStringLen(fwBstrName) == 0) 220 | { 221 | hr = E_OUTOFMEMORY; 222 | error("SysAllocString failed: 0x%08lx\n", hr); 223 | goto error; 224 | } 225 | 226 | // Set the friendly name of the port. 227 | hr = fwOpenPort->put_Name(fwBstrName); 228 | if (FAILED(hr)) 229 | { 230 | error("put_Name failed: 0x%08lx\n", hr); 231 | goto error; 232 | } 233 | 234 | // Opens the port and adds it to the collection. 235 | hr = fwOpenPorts->Add(fwOpenPort); 236 | if (FAILED(hr)) 237 | { 238 | error("Add failed: 0x%08lx\n", hr); 239 | goto error; 240 | } 241 | 242 | info("Port %ld is now open in the firewall.\n", port); 243 | } 244 | 245 | error: 246 | 247 | // Free the BSTR. 248 | SysFreeString(fwBstrName); 249 | 250 | // Release the open port instance. 251 | if (fwOpenPort != NULL) 252 | { 253 | fwOpenPort->Release(); 254 | } 255 | 256 | // Release the globally open ports collection. 257 | if (fwOpenPorts != NULL) 258 | { 259 | fwOpenPorts->Release(); 260 | } 261 | 262 | return SUCCEEDED(hr); 263 | } 264 | 265 | bool WindowsFirewall::RemovePort(long port, NET_FW_IP_PROTOCOL ipProtocol) 266 | { 267 | HRESULT hr = S_OK; 268 | bool fwPortEnabled; 269 | INetFwOpenPorts* fwOpenPorts = NULL; 270 | 271 | // First check to see if the port is already added. 272 | if (!this->PortIsConfigured(port, ipProtocol, fwPortEnabled)) 273 | { 274 | error("PortIsConfigured failed\n"); 275 | hr = E_FAIL; 276 | goto error; 277 | } 278 | 279 | // Only add the port if it isn't already added. 280 | if (fwPortEnabled) 281 | { 282 | // Retrieve the collection of globally open ports. 283 | hr = this->profile->get_GloballyOpenPorts(&fwOpenPorts); 284 | if (FAILED(hr)) 285 | { 286 | error("get_GloballyOpenPorts failed: 0x%08lx\n", hr); 287 | goto error; 288 | } 289 | 290 | hr = fwOpenPorts->Remove(port, ipProtocol); 291 | if (FAILED(hr)) 292 | { 293 | error("Remove failed: 0x%08lx\n", hr); 294 | goto error; 295 | } 296 | } 297 | 298 | error: 299 | 300 | // Release the globally open ports collection. 301 | if (fwOpenPorts != NULL) 302 | { 303 | fwOpenPorts->Release(); 304 | } 305 | 306 | return SUCCEEDED(hr); 307 | } 308 | 309 | bool WindowsFirewall::IsApplicationConfigured(std::string path, bool& configured) 310 | { 311 | HRESULT hr = S_OK; 312 | BSTR fwBstrProcessImageFileName = NULL; 313 | VARIANT_BOOL fwEnabled; 314 | INetFwAuthorizedApplication* fwApp = NULL; 315 | INetFwAuthorizedApplications* fwApps = NULL; 316 | 317 | configured = FALSE; 318 | 319 | // Retrieve the authorized application collection. 320 | hr = this->profile->get_AuthorizedApplications(&fwApps); 321 | if (FAILED(hr)) 322 | { 323 | error("get_AuthorizedApplications failed: 0x%08lx\n", hr); 324 | goto error; 325 | } 326 | 327 | // Allocate a BSTR for the process image file name. 328 | int wslen = MultiByteToWideChar(CP_ACP, 0, path.c_str(), path.length(), 0, 0); 329 | fwBstrProcessImageFileName = SysAllocStringLen(0, wslen); 330 | if (fwBstrProcessImageFileName == NULL) 331 | { 332 | hr = E_OUTOFMEMORY; 333 | error("SysAllocString failed: 0x%08lx\n", hr); 334 | goto error; 335 | } 336 | MultiByteToWideChar(CP_ACP, 0, path.c_str(), path.length(), fwBstrProcessImageFileName, wslen); 337 | 338 | // Attempt to retrieve the authorized application. 339 | hr = fwApps->Item(fwBstrProcessImageFileName, &fwApp); 340 | if (SUCCEEDED(hr)) 341 | { 342 | // Find out if the authorized application is enabled. 343 | hr = fwApp->get_Enabled(&fwEnabled); 344 | if (FAILED(hr)) 345 | { 346 | error("get_Enabled failed: 0x%08lx\n", hr); 347 | goto error; 348 | } 349 | 350 | if (fwEnabled != VARIANT_FALSE) 351 | { 352 | // The authorized application is enabled. 353 | configured = TRUE; 354 | } 355 | } 356 | else 357 | { 358 | // The authorized application was not in the collection. 359 | hr = S_OK; 360 | } 361 | 362 | error: 363 | 364 | // Free the BSTR. 365 | SysFreeString(fwBstrProcessImageFileName); 366 | // Release the authorized application instance. 367 | if (fwApp != NULL) 368 | { 369 | fwApp->Release(); 370 | } 371 | 372 | // Release the authorized application collection. 373 | if (fwApps != NULL) 374 | { 375 | fwApps->Release(); 376 | } 377 | return SUCCEEDED(hr); 378 | } 379 | 380 | bool WindowsFirewall::AddApplication(std::string path, std::string name) 381 | { 382 | HRESULT hr = S_OK; 383 | bool fwAppEnabled; 384 | BSTR fwBstrName = NULL; 385 | BSTR fwBstrProcessImageFileName = NULL; 386 | INetFwAuthorizedApplication* fwApp = NULL; 387 | INetFwAuthorizedApplications* fwApps = NULL; 388 | 389 | // First check to see if the application is already authorized. 390 | if (!IsApplicationConfigured(path, fwAppEnabled)) 391 | { 392 | printf("WindowsFirewallAppIsEnabled failed: 0x%08lx\n", hr); 393 | goto error; 394 | } 395 | 396 | // Only add the application if it isn't already authorized. 397 | if (!fwAppEnabled) 398 | { 399 | // Retrieve the authorized application collection. 400 | hr = this->profile->get_AuthorizedApplications(&fwApps); 401 | if (FAILED(hr)) 402 | { 403 | printf("get_AuthorizedApplications failed: 0x%08lx\n", hr); 404 | goto error; 405 | } 406 | 407 | // Create an instance of an authorized application. 408 | hr = CoCreateInstance( 409 | __uuidof(NetFwAuthorizedApplication), 410 | NULL, 411 | CLSCTX_INPROC_SERVER, 412 | __uuidof(INetFwAuthorizedApplication), 413 | (void**)&fwApp 414 | ); 415 | if (FAILED(hr)) 416 | { 417 | printf("CoCreateInstance failed: 0x%08lx\n", hr); 418 | goto error; 419 | } 420 | 421 | // Allocate a BSTR for the process image file name. 422 | int wslen = MultiByteToWideChar(CP_ACP, 0, path.c_str(), path.length(), 0, 0); 423 | fwBstrProcessImageFileName = SysAllocStringLen(0, wslen); 424 | if (fwBstrProcessImageFileName == NULL) 425 | { 426 | hr = E_OUTOFMEMORY; 427 | printf("SysAllocString failed: 0x%08lx\n", hr); 428 | goto error; 429 | } 430 | MultiByteToWideChar(CP_ACP, 0, path.c_str(), path.length(), fwBstrProcessImageFileName, wslen); 431 | 432 | // Set the process image file name. 433 | hr = fwApp->put_ProcessImageFileName(fwBstrProcessImageFileName); 434 | if (FAILED(hr)) 435 | { 436 | printf("put_ProcessImageFileName failed: 0x%08lx\n", hr); 437 | goto error; 438 | } 439 | 440 | // Allocate a BSTR for the application friendly name. 441 | wslen = MultiByteToWideChar(CP_ACP, 0, name.c_str(), name.length(), 0, 0); 442 | fwBstrName = SysAllocStringLen(0, wslen); 443 | if (SysStringLen(fwBstrName) == 0) 444 | { 445 | hr = E_OUTOFMEMORY; 446 | printf("SysAllocString failed: 0x%08lx\n", hr); 447 | goto error; 448 | } 449 | MultiByteToWideChar(CP_ACP, 0, name.c_str(), name.length(), fwBstrName, wslen); 450 | 451 | // Set the application friendly name. 452 | hr = fwApp->put_Name(fwBstrName); 453 | if (FAILED(hr)) 454 | { 455 | printf("put_Name failed: 0x%08lx\n", hr); 456 | goto error; 457 | } 458 | 459 | // Add the application to the collection. 460 | hr = fwApps->Add(fwApp); 461 | if (FAILED(hr)) 462 | { 463 | printf("Add failed: 0x%08lx\n", hr); 464 | goto error; 465 | } 466 | 467 | info("Authorized application %s is now enabled in the firewall.\n", path.c_str()); 468 | } 469 | else 470 | { 471 | info("Authorized application %s is already enabled in the firewall.\n", path.c_str()); 472 | } 473 | 474 | error: 475 | 476 | // Free the BSTRs. 477 | SysFreeString(fwBstrName); 478 | SysFreeString(fwBstrProcessImageFileName); 479 | 480 | // Release the authorized application instance. 481 | if (fwApp != NULL) 482 | { 483 | fwApp->Release(); 484 | } 485 | 486 | // Release the authorized application collection. 487 | if (fwApps != NULL) 488 | { 489 | fwApps->Release(); 490 | } 491 | 492 | return SUCCEEDED(hr); 493 | } 494 | 495 | bool WindowsFirewall::RemoveApplication(std::string path) 496 | { 497 | HRESULT hr = S_OK; 498 | bool fwAppEnabled; 499 | BSTR fwBstrName = NULL; 500 | BSTR fwBstrProcessImageFileName = NULL; 501 | INetFwAuthorizedApplication* fwApp = NULL; 502 | INetFwAuthorizedApplications* fwApps = NULL; 503 | 504 | // First check to see if the application is already authorized. 505 | if (!IsApplicationConfigured(path, fwAppEnabled)) 506 | { 507 | printf("WindowsFirewallAppIsEnabled failed: 0x%08lx\n", hr); 508 | goto error; 509 | } 510 | 511 | // Only add the application if it isn't already authorized. 512 | if (fwAppEnabled) 513 | { 514 | // Retrieve the authorized application collection. 515 | hr = this->profile->get_AuthorizedApplications(&fwApps); 516 | if (FAILED(hr)) 517 | { 518 | printf("get_AuthorizedApplications failed: 0x%08lx\n", hr); 519 | goto error; 520 | } 521 | 522 | // Allocate a BSTR for the process image file name. 523 | int wslen = MultiByteToWideChar(CP_ACP, 0, path.c_str(), path.length(), 0, 0); 524 | fwBstrProcessImageFileName = SysAllocStringLen(0, wslen); 525 | if (fwBstrProcessImageFileName == NULL) 526 | { 527 | hr = E_OUTOFMEMORY; 528 | printf("SysAllocString failed: 0x%08lx\n", hr); 529 | goto error; 530 | } 531 | MultiByteToWideChar(CP_ACP, 0, path.c_str(), path.length(), fwBstrProcessImageFileName, wslen); 532 | 533 | 534 | hr = fwApps->Remove(fwBstrProcessImageFileName); 535 | if (SUCCEEDED(hr)) 536 | { 537 | info("Authorized application %lS is now removed from the firewall.\n", path.c_str()); 538 | } 539 | } 540 | 541 | error: 542 | // Release the authorized application collection. 543 | if (fwApps != NULL) 544 | { 545 | fwApps->Release(); 546 | } 547 | return SUCCEEDED(hr); 548 | } 549 | -------------------------------------------------------------------------------- /StreamDivert/SocksProxyServer.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "SocksProxyServer.h" 3 | #include "utils.h" 4 | #include 5 | #include 6 | #include "ipaddr.h" 7 | #include "sockutils.h" 8 | 9 | 10 | SocksProxyServer::SocksProxyServer(int port, bool enableSocks4, bool enableSocks5) 11 | { 12 | this->port = port; 13 | this->serverSock = INVALID_SOCKET; 14 | this->selfDescStr = this->getSelfDescription(); 15 | this->running = false; 16 | this->socks5AuthType = Socks5AuthMethods::NOAUTH; 17 | this->username = ""; 18 | this->password = ""; 19 | this->enableSocks4 = enableSocks4; 20 | this->enableSocks5 = enableSocks5; 21 | } 22 | 23 | SocksProxyServer::SocksProxyServer(int port) 24 | : SocksProxyServer(port, true, true) 25 | { 26 | } 27 | 28 | SocksProxyServer::~SocksProxyServer() 29 | { 30 | } 31 | 32 | void SocksProxyServer::SetAuthType(Socks5AuthMethods method) 33 | { 34 | this->socks5AuthType = method; 35 | } 36 | 37 | void SocksProxyServer::SetAuthUsername(std::string& username) 38 | { 39 | this->username = username; 40 | } 41 | 42 | void SocksProxyServer::SetAuthPassword(std::string& password) 43 | { 44 | this->password = password; 45 | } 46 | 47 | int SocksProxyServer::GetPort() 48 | { 49 | return this->port; 50 | } 51 | 52 | bool SocksProxyServer::IsRunning() 53 | { 54 | return this->running; 55 | } 56 | 57 | 58 | std::string SocksProxyServer::getSelfDescription() 59 | { 60 | return "SocksProxyServer(" + std::to_string(this->port) + ")"; 61 | } 62 | 63 | void SocksProxyServer::ProxyServerWorker() 64 | { 65 | while (true) 66 | { 67 | struct sockaddr_in6 clientSockAddr; 68 | int size = sizeof(clientSockAddr); 69 | SOCKET incommingSock = accept(this->serverSock, (SOCKADDR*)&clientSockAddr, &size); 70 | if (incommingSock == INVALID_SOCKET) 71 | { 72 | std::lock_guard lock(this->resourceLock); 73 | if (this->running == false) 74 | { 75 | goto cleanup; 76 | } 77 | warning("%s: failed to accept socket (%d)", this->selfDescStr.c_str(), WSAGetLastError()); 78 | continue; 79 | } 80 | IpAddr clientSockIp = IpAddr(clientSockAddr.sin6_addr); 81 | std::string srcAddr = clientSockIp.to_string(); 82 | info("%s: Incoming connection from %s:%hu", this->selfDescStr.c_str(), srcAddr.c_str(), ntohs(clientSockAddr.sin6_port)); 83 | 84 | int one = 1; 85 | setsockopt(incommingSock, IPPROTO_TCP, TCP_NODELAY, (const char*)&one, sizeof(one)); 86 | 87 | SocksServerConnectionData* proxyConnectionWorkerData = new SocksServerConnectionData(); 88 | proxyConnectionWorkerData->clientSocket = incommingSock; 89 | proxyConnectionWorkerData->clientAddr = clientSockAddr; 90 | std::thread proxyConnectionThread(&SocksProxyServer::ProxyConnectionWorker, this, proxyConnectionWorkerData); 91 | proxyConnectionThread.detach(); 92 | } 93 | cleanup: 94 | if (this->serverSock != NULL) 95 | { 96 | closesocket(this->serverSock); 97 | this->serverSock = NULL; 98 | } 99 | info("%s: ProxyServerWorker exiting", this->selfDescStr.c_str()); 100 | } 101 | 102 | SOCKET SocksProxyServer::ProcessSocks4Connection(SOCKET sock) 103 | { 104 | SOCKET proxySock = INVALID_SOCKET; 105 | char cmd; 106 | int received = 0; 107 | received = recvall(sock, &cmd, 1); 108 | if (cmd == CMD_CONNECT) 109 | { 110 | unsigned short int port; 111 | in_addr ipv4AddrStore; 112 | IpAddr ipv4Addr; 113 | char userid[1024]; 114 | char domain[1024]; 115 | int useridLen, domainLen; 116 | useridLen = sizeof(userid); 117 | domainLen = sizeof(domain); 118 | if (!recvallb(sock, (char*)&port, sizeof(port))) 119 | { 120 | return false; 121 | } 122 | port = ntohs(port); 123 | if (!recvallb(sock, (char*)&ipv4AddrStore.S_un.S_addr, sizeof(ipv4AddrStore.S_un.S_addr))) 124 | { 125 | return false; 126 | } 127 | if (!recvstr(sock, &userid[0], &useridLen)) 128 | { 129 | return false; 130 | } 131 | 132 | if (this->socks4aIsInvalidIpv4(ipv4AddrStore.S_un.S_addr)) 133 | { 134 | if (!recvstr(sock, &domain[0], &domainLen)) 135 | { 136 | return false; 137 | } 138 | proxySock = SocksProxyServer::socksConnect(std::string(&domain[0]), port); 139 | } 140 | else 141 | { 142 | ipv4Addr = IpAddr(ipv4AddrStore); 143 | proxySock = SocksProxyServer::socksConnect(ipv4Addr, port); 144 | } 145 | if (proxySock != INVALID_SOCKET) 146 | { 147 | this->socks4aSendClientResponse(sock, Socks4aClientResponse::RequestGranted); 148 | } 149 | else 150 | { 151 | this->socks4aSendClientResponse(sock, Socks4aClientResponse::RequestRejectedOrFailed); 152 | } 153 | } 154 | else 155 | { 156 | error("Unsupported socks4 cmd: %hhi", cmd); 157 | } 158 | return proxySock; 159 | } 160 | 161 | SOCKET SocksProxyServer::ProcessSocks5Connection(SOCKET sock) 162 | { 163 | SOCKET proxySock = INVALID_SOCKET; 164 | char methods; 165 | char buffer[4]; 166 | IpAddr ipAddr; 167 | std::string domain; 168 | unsigned short int port; 169 | Socks5AddressType addrType; 170 | 171 | if (!recvallb(sock, &methods, 1)) 172 | { 173 | goto failure; 174 | } 175 | if (!this->socks5Auth(sock, methods)) 176 | { 177 | goto failure; 178 | } 179 | 180 | /* 181 | +----+-----+-------+------+----------+----------+ 182 | |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | 183 | +----+-----+-------+------+----------+----------+ 184 | | 1 | 1 | X'00' | 1 | Variable | 2 | 185 | +----+-----+-------+------+----------+----------+ 186 | */ 187 | 188 | if (!recvallb(sock, &buffer[0], sizeof(buffer))) 189 | { 190 | goto failure; 191 | } 192 | if (buffer[0] != SocksVersion::Socks5) 193 | { 194 | goto failure; 195 | } 196 | if (buffer[1] != CMD_CONNECT) //Others not supported 197 | { 198 | goto failure; 199 | } 200 | 201 | addrType = (Socks5AddressType)buffer[3]; 202 | if (addrType == Socks5AddressType::AddrTypeIPv4) 203 | { 204 | in_addr addr; 205 | if (!recvallb(sock, (char*)&addr.S_un.S_addr, sizeof(addr))) 206 | { 207 | goto failure; 208 | } 209 | if (!recvallb(sock, (char*)&port, sizeof(port))) 210 | { 211 | goto failure; 212 | } 213 | port = ntohs(port); 214 | ipAddr = IpAddr(addr); 215 | proxySock = this->socksConnect(ipAddr, port); 216 | } 217 | else if (addrType == Socks5AddressType::AddrTypeIPv6) 218 | { 219 | in6_addr addr; 220 | if (!recvallb(sock, (char*)&addr.u.Byte, sizeof(addr))) 221 | { 222 | goto failure; 223 | } 224 | if (!recvallb(sock, (char*)&port, sizeof(port))) 225 | { 226 | goto failure; 227 | } 228 | port = ntohs(port); 229 | ipAddr = IpAddr(addr); 230 | proxySock = this->socksConnect(ipAddr, port); 231 | } 232 | else if (addrType == Socks5AddressType::AddrTypeDomainName) 233 | { 234 | unsigned char domainLen; 235 | char domainBuf[1024]; 236 | if (!recvallb(sock, (char*)&domainLen, sizeof(domainLen))) 237 | { 238 | goto failure; 239 | } 240 | if (!recvallb(sock, (char*)&domainBuf[0], domainLen)) 241 | { 242 | goto failure; 243 | } 244 | if (!recvallb(sock, (char*)&port, sizeof(port))) 245 | { 246 | goto failure; 247 | } 248 | port = ntohs(port); 249 | domainBuf[domainLen] = 0; 250 | domain = std::string(domainBuf); 251 | proxySock = this->socksConnect(domain, port); 252 | } 253 | 254 | if (proxySock != INVALID_SOCKET) 255 | { 256 | if (this->socks5SendClientResponse(sock, Socks5ClientResponse::succeeded, addrType, &ipAddr, &domain, port)) 257 | { 258 | return proxySock; 259 | } 260 | } 261 | 262 | failure: 263 | closesocket(proxySock); 264 | return INVALID_SOCKET; 265 | } 266 | 267 | bool SocksProxyServer::socks5Auth(SOCKET sock, int methods) 268 | { 269 | bool supported = false; 270 | for (int i = 0; i < methods; i++) { 271 | char type; 272 | recvallb(sock, (char*)&type, 1); 273 | if (type == this->socks5AuthType) { 274 | supported = true; 275 | } 276 | } 277 | if (!supported) { 278 | this->socks5SendAuthNotSupported(sock); 279 | return false; 280 | } 281 | switch (this->socks5AuthType) { 282 | case Socks5AuthMethods::NOAUTH: 283 | this->socks5SendNoAth(sock); 284 | return true; 285 | break; 286 | case Socks5AuthMethods::USERPASS: 287 | return this->socks5UserPassAuthentication(sock); 288 | break; 289 | } 290 | return false; 291 | } 292 | 293 | void SocksProxyServer::socks5SendAuthNotSupported(SOCKET sock) 294 | { 295 | char answer[2] = { (char)SocksVersion::Socks5 , Socks5AuthMethods::NOMETHOD }; 296 | sendallb(sock, answer, sizeof(answer)); 297 | } 298 | 299 | void SocksProxyServer::socks5SendNoAth(SOCKET sock) 300 | { 301 | char answer[2] = { (char)SocksVersion::Socks5, Socks5AuthMethods::NOAUTH }; 302 | sendallb(sock, answer, sizeof(answer)); 303 | } 304 | 305 | bool SocksProxyServer::socks5UserPassAuthentication(SOCKET sock) 306 | { 307 | char answer[2] = { (char)SocksVersion::Socks5, Socks5AuthMethods::USERPASS }; 308 | if (!sendallb(sock, answer, sizeof(answer))) { 309 | return false; 310 | } 311 | 312 | /* 313 | +----+------+----------+------+----------+ 314 | |VER | ULEN | UNAME | PLEN | PASSWD | 315 | +----+------+----------+------+----------+ 316 | | 1 | 1 | 1 to 255 | 1 | 1 to 255 | 317 | +----+------+----------+------+----------+ 318 | */ 319 | char ver; 320 | if (!recvallb(sock, &ver, sizeof(ver))) 321 | { 322 | return false; 323 | } 324 | if (ver != AUTH_VERSION) 325 | { 326 | return false; 327 | } 328 | std::string username; 329 | std::string password; 330 | if (!this->socks5GetUserPassStr(sock, username)) 331 | { 332 | return false; 333 | } 334 | if (!this->socks5GetUserPassStr(sock, password)) 335 | { 336 | return false; 337 | } 338 | if (username == this->username && password == this->password) 339 | { 340 | char authokResp[2] = { AUTH_VERSION, Socks5UserPassAuth::AuthOk }; 341 | return sendallb(sock, authokResp, sizeof(authokResp)); 342 | } 343 | char authFailResp[2] = { AUTH_VERSION, Socks5UserPassAuth::AuthFail }; 344 | sendallb(sock, authFailResp, sizeof(authFailResp)); 345 | return false; 346 | } 347 | 348 | bool SocksProxyServer::socks5GetUserPassStr(SOCKET sock, std::string& value) 349 | { 350 | unsigned char size; 351 | char buf[256] = { 0 }; 352 | if (!recvallb(sock, (char*)&size, sizeof(size))) 353 | { 354 | return false; 355 | } 356 | if (!recvallb(sock, &buf[0], size)) 357 | { 358 | return false; 359 | } 360 | value = std::string(buf); 361 | return true; 362 | } 363 | 364 | bool SocksProxyServer::socks5SendClientResponse(SOCKET sock, Socks5ClientResponse reply, Socks5AddressType addrType, IpAddr* ipAddr, std::string* domain, unsigned short int port) 365 | { 366 | char response[4] = { (char)SocksVersion::Socks5, reply, 0, (char)addrType }; 367 | if (!sendallb(sock, &response[0], sizeof(response))) 368 | { 369 | return false; 370 | } 371 | if (addrType == Socks5AddressType::AddrTypeIPv4) 372 | { 373 | in_addr addr = ipAddr->get_ipv4_addr(); 374 | if (!sendallb(sock, (char*)&addr, sizeof(addr))) 375 | { 376 | return false; 377 | } 378 | } 379 | else if (addrType == Socks5AddressType::AddrTypeIPv6) 380 | { 381 | in6_addr addr = ipAddr->get_addr(); 382 | if (!sendallb(sock, (char*)&addr, sizeof(addr))) 383 | { 384 | return false; 385 | } 386 | } 387 | else if (addrType == Socks5AddressType::AddrTypeDomainName) 388 | { 389 | unsigned char len = domain->length(); 390 | if (!sendallb(sock, (char*)&len, sizeof(len))) 391 | { 392 | return false; 393 | } 394 | if (!sendallb(sock, domain->c_str(), len)) 395 | { 396 | return false; 397 | } 398 | } 399 | 400 | if (!sendallb(sock, (char*)&port, sizeof(port))) 401 | { 402 | return false; 403 | } 404 | return true; 405 | } 406 | 407 | bool SocksProxyServer::socks4aIsInvalidIpv4(int ip) 408 | { 409 | char* rawIp = (char*)&ip; 410 | return (rawIp[0] == 0 && rawIp[1] == 0 && rawIp[2] == 0 && rawIp[3] != 0); 411 | } 412 | 413 | bool SocksProxyServer::socks4aSendClientResponse(SOCKET sock, Socks4aClientResponse status) 414 | { 415 | /* 416 | +----+----+----+----+----+----+----+----+ 417 | | VN | CD | DSTPORT | DSTIP | 418 | +----+----+----+----+----+----+----+----+ 419 | # of bytes: 1 1 2 4 420 | 421 | VN is the version of the reply code and should be 0. CD is the result 422 | code with one of the following values: 423 | 424 | 90: request granted 425 | 91: request rejected or failed 426 | 92: request rejected becasue SOCKS server cannot connect to 427 | identd on the client 428 | 93: request rejected because the client program and identd 429 | report different user-ids 430 | */ 431 | char resp[8] = { 0x00, (char)status, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 432 | return sendallb(sock, resp, sizeof(resp)); 433 | } 434 | 435 | SOCKET SocksProxyServer::socksConnect(IpAddr& ip, int port) 436 | { 437 | int off = 0; 438 | SOCKET sock; 439 | struct sockaddr_in6 destAddr; 440 | ZeroMemory(&destAddr, sizeof(destAddr)); 441 | destAddr.sin6_family = AF_INET6; 442 | destAddr.sin6_addr = ip.get_addr(); 443 | destAddr.sin6_port = htons(port); 444 | 445 | info("%s: Setting up client connection to %s:%d", selfDescStr.c_str(), ip.to_string().c_str(), port); 446 | sock = socket(AF_INET6, SOCK_STREAM, 0); 447 | if (sock == INVALID_SOCKET) 448 | { 449 | error("%s: failed to create socket (%d)", selfDescStr.c_str(), WSAGetLastError()); 450 | goto failure; 451 | } 452 | if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&off, sizeof(int)) == SOCKET_ERROR) 453 | { 454 | error("%s: failed to set connect socket dual-stack (%d)", selfDescStr.c_str(), GetLastError()); 455 | goto failure; 456 | } 457 | if (connect(sock, (struct sockaddr*)&destAddr, sizeof(destAddr)) == SOCKET_ERROR) 458 | { 459 | error("%s: failed to connect socket (%d)", selfDescStr.c_str(), WSAGetLastError()); 460 | } 461 | return sock; 462 | 463 | failure: 464 | closesocket(sock); 465 | return INVALID_SOCKET; 466 | } 467 | 468 | SOCKET SocksProxyServer::socksConnect(std::string domain, int port) 469 | { 470 | SOCKET sock; 471 | char portStr[6]; 472 | struct addrinfo* res = NULL; 473 | IpAddr ipAddr; 474 | 475 | info("%s: Setting up client connection to %s:%d", selfDescStr.c_str(), domain.c_str(), port); 476 | snprintf(portStr, sizeof(portStr), "%d", port); 477 | int ret = getaddrinfo((char*)domain.c_str(), portStr, NULL, &res); 478 | if (ret == EAI_NODATA) 479 | { 480 | return INVALID_SOCKET; 481 | } 482 | else if (ret == 0) 483 | { 484 | struct addrinfo* r; 485 | for (r = res; r != NULL; r = r->ai_next) 486 | { 487 | if (r->ai_family == AF_INET) 488 | { 489 | ipAddr = IpAddr(((sockaddr_in*)r->ai_addr)->sin_addr); 490 | sock = this->socksConnect(ipAddr, port); 491 | } 492 | else if (r->ai_family == AF_INET6) 493 | { 494 | ipAddr = IpAddr(((sockaddr_in6*)r->ai_addr)->sin6_addr); 495 | sock = this->socksConnect(ipAddr, port); 496 | } 497 | 498 | if (sock != INVALID_SOCKET) 499 | { 500 | break; 501 | } 502 | } 503 | } 504 | 505 | if (res != NULL) 506 | { 507 | freeaddrinfo(res); 508 | res = NULL; 509 | } 510 | return sock; 511 | } 512 | 513 | void SocksProxyServer::ProxyConnectionWorker(SocksServerConnectionData* data) 514 | { 515 | SOCKET sock = data->clientSocket; 516 | sockaddr_in6 clientAddr = data->clientAddr; 517 | delete data; 518 | data = NULL; 519 | SOCKET proxySock = INVALID_SOCKET; 520 | 521 | SocksVersion version = this->recvSocksVersion(sock); 522 | info("SOCKS version: %d", version); 523 | switch (version) 524 | { 525 | case SocksVersion::Socks4: 526 | { 527 | if (this->enableSocks4) 528 | { 529 | proxySock = this->ProcessSocks4Connection(sock); 530 | } 531 | else 532 | { 533 | warning("Received unsupported SOCKS connection"); 534 | } 535 | } 536 | break; 537 | case SocksVersion::Socks5: 538 | { 539 | if (this->enableSocks5) 540 | { 541 | proxySock = this->ProcessSocks5Connection(sock); 542 | } 543 | else 544 | { 545 | warning("Received unsupported SOCKS connection"); 546 | } 547 | } 548 | break; 549 | } 550 | if (proxySock != INVALID_SOCKET) 551 | { 552 | sockaddr_in6 proxySockAddr; 553 | int proxySockAddrLen = sizeof(proxySockAddr); 554 | if (getsockname(proxySock, (struct sockaddr*)&proxySockAddr, &proxySockAddrLen) == -1) 555 | { 556 | error("%s: failed to get bind socket port (%d)", this->selfDescStr.c_str(), WSAGetLastError()); 557 | goto failure; 558 | } 559 | 560 | 561 | ProxyTunnelWorkerData* tunnelDataA = new ProxyTunnelWorkerData(); 562 | ProxyTunnelWorkerData* tunnelDataB = new ProxyTunnelWorkerData(); 563 | tunnelDataA->sockA = sock; 564 | tunnelDataA->sockAAddr = IpAddr(clientAddr.sin6_addr); 565 | tunnelDataA->sockAPort = ntohs(clientAddr.sin6_port); 566 | tunnelDataA->sockB = proxySock; 567 | tunnelDataA->sockBAddr = IpAddr(proxySockAddr.sin6_addr); 568 | tunnelDataA->sockBPort = ntohs(proxySockAddr.sin6_port); 569 | 570 | tunnelDataB->sockA = proxySock; 571 | tunnelDataB->sockAAddr = tunnelDataA->sockBAddr; 572 | tunnelDataB->sockAPort = tunnelDataA->sockBPort; 573 | tunnelDataB->sockB = sock; 574 | tunnelDataB->sockBAddr = tunnelDataA->sockAAddr; 575 | tunnelDataB->sockBPort = tunnelDataA->sockAPort; 576 | std::thread tunnelThread(&ProxyTunnelWorker, tunnelDataA, this->selfDescStr); 577 | ProxyTunnelWorker(tunnelDataB, this->selfDescStr); 578 | tunnelThread.join(); 579 | } 580 | 581 | failure: 582 | closesocket(sock); 583 | closesocket(proxySock); 584 | } 585 | 586 | SocksVersion SocksProxyServer::recvSocksVersion(SOCKET sock) 587 | { 588 | char buf; 589 | int bufLen = sizeof(buf); 590 | recvall(sock, (char*)&buf, bufLen); 591 | return (SocksVersion)buf; 592 | } 593 | 594 | bool SocksProxyServer::Start() 595 | { 596 | int on = 1; 597 | int off = 0; 598 | WSADATA wsa_data; 599 | WORD wsa_version = MAKEWORD(2, 2); 600 | struct sockaddr_in6 addr; 601 | info("%s: Start", this->selfDescStr.c_str()); 602 | 603 | if (WSAStartup(wsa_version, &wsa_data) != 0) 604 | { 605 | error("%s: failed to start WSA (%d)", this->selfDescStr.c_str(), GetLastError()); 606 | goto failure; 607 | } 608 | this->serverSock = socket(AF_INET6, SOCK_STREAM, 0); 609 | if (this->serverSock == INVALID_SOCKET) 610 | { 611 | error("%s: failed to create socket (%d)", this->selfDescStr.c_str(), WSAGetLastError()); 612 | goto failure; 613 | } 614 | if (WSAStartup(wsa_version, &wsa_data) != 0) 615 | { 616 | error("%s: failed to start WSA (%d)", this->selfDescStr.c_str(), GetLastError()); 617 | goto failure; 618 | } 619 | if (setsockopt(this->serverSock, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(int)) == SOCKET_ERROR) 620 | { 621 | error("%s: failed to re-use address (%d)", this->selfDescStr.c_str(), GetLastError()); 622 | goto failure; 623 | } 624 | if (setsockopt(this->serverSock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&off, sizeof(int)) == SOCKET_ERROR) 625 | { 626 | error("%s: failed to set socket dual-stack (%d)", this->selfDescStr.c_str(), GetLastError()); 627 | goto failure; 628 | } 629 | memset(&addr, 0, sizeof(addr)); 630 | addr.sin6_family = AF_INET6; 631 | addr.sin6_port = htons(this->port); 632 | addr.sin6_addr = in6addr_any; 633 | 634 | if (::bind(this->serverSock, (SOCKADDR*)&addr, sizeof(addr)) == SOCKET_ERROR) 635 | { 636 | error("%s: failed to bind socket (%d)", this->selfDescStr.c_str(), WSAGetLastError()); 637 | goto failure; 638 | } 639 | 640 | if (this->port == 0) 641 | { 642 | struct sockaddr_in6 bind_addr; 643 | int bind_addr_len = sizeof(bind_addr); 644 | if (getsockname(this->serverSock, (struct sockaddr*)&bind_addr, &bind_addr_len) == -1) 645 | { 646 | error("%s: failed to get bind socket port (%d)", this->selfDescStr.c_str(), WSAGetLastError()); 647 | } 648 | this->port = ntohs(bind_addr.sin6_port); 649 | } 650 | 651 | if (listen(this->serverSock, 25) == SOCKET_ERROR) 652 | { 653 | error("%s: failed to listen socket (%d)", this->selfDescStr.c_str(), WSAGetLastError()); 654 | goto failure; 655 | } 656 | 657 | this->selfDescStr = this->getSelfDescription(); 658 | this->serverThread = std::thread(&SocksProxyServer::ProxyServerWorker, this); 659 | this->running = true; 660 | info("%s: Start completed", this->selfDescStr.c_str()); 661 | return true; 662 | 663 | failure: 664 | error("%s: Start failed", this->selfDescStr.c_str()); 665 | this->Stop(); 666 | return false; 667 | } 668 | 669 | bool SocksProxyServer::Stop() 670 | { 671 | info("%s: Stop", this->selfDescStr.c_str()); 672 | {//lock scope 673 | std::lock_guard lock(this->resourceLock); 674 | this->running = false; 675 | if (this->serverSock != NULL) 676 | { 677 | shutdown(this->serverSock, SD_BOTH); 678 | closesocket(this->serverSock); 679 | this->serverSock = NULL; 680 | } 681 | } 682 | if (this->serverThread.joinable()) 683 | { 684 | this->serverThread.join(); 685 | } 686 | 687 | return true; 688 | } 689 | -------------------------------------------------------------------------------- /StreamDivert/windivert.h: -------------------------------------------------------------------------------- 1 | /* 2 | * windivert.h 3 | * (C) 2019, all rights reserved, 4 | * 5 | * This file is part of WinDivert. 6 | * 7 | * WinDivert is free software: you can redistribute it and/or modify it under 8 | * the terms of the GNU Lesser General Public License as published by the 9 | * Free Software Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with this program. If not, see . 19 | * 20 | * WinDivert is free software; you can redistribute it and/or modify it under 21 | * the terms of the GNU General Public License as published by the Free 22 | * Software Foundation; either version 2 of the License, or (at your option) 23 | * any later version. 24 | * 25 | * This program is distributed in the hope that it will be useful, but 26 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 27 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 28 | * for more details. 29 | * 30 | * You should have received a copy of the GNU General Public License along 31 | * with this program; if not, write to the Free Software Foundation, Inc., 51 32 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 33 | */ 34 | 35 | #ifndef __WINDIVERT_H 36 | #define __WINDIVERT_H 37 | 38 | #ifndef WINDIVERT_KERNEL 39 | #include 40 | #endif /* WINDIVERT_KERNEL */ 41 | 42 | #ifndef WINDIVERTEXPORT 43 | #define WINDIVERTEXPORT extern __declspec(dllimport) 44 | #endif /* WINDIVERTEXPORT */ 45 | 46 | #ifdef __MINGW32__ 47 | #define __in 48 | #define __in_opt 49 | #define __out 50 | #define __out_opt 51 | #define __inout 52 | #define __inout_opt 53 | #include 54 | #define INT8 int8_t 55 | #define UINT8 uint8_t 56 | #define INT16 int16_t 57 | #define UINT16 uint16_t 58 | #define INT32 int32_t 59 | #define UINT32 uint32_t 60 | #define INT64 int64_t 61 | #define UINT64 uint64_t 62 | #endif /* __MINGW32__ */ 63 | 64 | #ifdef __cplusplus 65 | extern "C" { 66 | #endif 67 | 68 | /****************************************************************************/ 69 | /* WINDIVERT API */ 70 | /****************************************************************************/ 71 | 72 | /* 73 | * WinDivert layers. 74 | */ 75 | typedef enum 76 | { 77 | WINDIVERT_LAYER_NETWORK = 0, /* Network layer. */ 78 | WINDIVERT_LAYER_NETWORK_FORWARD = 1,/* Network layer (forwarded packets) */ 79 | WINDIVERT_LAYER_FLOW = 2, /* Flow layer. */ 80 | WINDIVERT_LAYER_SOCKET = 3, /* Socket layer. */ 81 | WINDIVERT_LAYER_REFLECT = 4, /* Reflect layer. */ 82 | } WINDIVERT_LAYER, *PWINDIVERT_LAYER; 83 | 84 | /* 85 | * WinDivert NETWORK and NETWORK_FORWARD layer data. 86 | */ 87 | typedef struct 88 | { 89 | UINT32 IfIdx; /* Packet's interface index. */ 90 | UINT32 SubIfIdx; /* Packet's sub-interface index. */ 91 | } WINDIVERT_DATA_NETWORK, *PWINDIVERT_DATA_NETWORK; 92 | 93 | /* 94 | * WinDivert FLOW layer data. 95 | */ 96 | typedef struct 97 | { 98 | UINT64 EndpointId; /* Endpoint ID. */ 99 | UINT64 ParentEndpointId; /* Parent endpoint ID. */ 100 | UINT32 ProcessId; /* Process ID. */ 101 | UINT32 LocalAddr[4]; /* Local address. */ 102 | UINT32 RemoteAddr[4]; /* Remote address. */ 103 | UINT16 LocalPort; /* Local port. */ 104 | UINT16 RemotePort; /* Remote port. */ 105 | UINT8 Protocol; /* Protocol. */ 106 | } WINDIVERT_DATA_FLOW, *PWINDIVERT_DATA_FLOW; 107 | 108 | /* 109 | * WinDivert SOCKET layer data. 110 | */ 111 | typedef struct 112 | { 113 | UINT64 EndpointId; /* Endpoint ID. */ 114 | UINT64 ParentEndpointId; /* Parent Endpoint ID. */ 115 | UINT32 ProcessId; /* Process ID. */ 116 | UINT32 LocalAddr[4]; /* Local address. */ 117 | UINT32 RemoteAddr[4]; /* Remote address. */ 118 | UINT16 LocalPort; /* Local port. */ 119 | UINT16 RemotePort; /* Remote port. */ 120 | UINT8 Protocol; /* Protocol. */ 121 | } WINDIVERT_DATA_SOCKET, *PWINDIVERT_DATA_SOCKET; 122 | 123 | /* 124 | * WinDivert REFLECTION layer data. 125 | */ 126 | typedef struct 127 | { 128 | INT64 Timestamp; /* Handle open time. */ 129 | UINT32 ProcessId; /* Handle process ID. */ 130 | WINDIVERT_LAYER Layer; /* Handle layer. */ 131 | UINT64 Flags; /* Handle flags. */ 132 | INT16 Priority; /* Handle priority. */ 133 | } WINDIVERT_DATA_REFLECT, *PWINDIVERT_DATA_REFLECT; 134 | 135 | /* 136 | * WinDivert address. 137 | */ 138 | #ifdef _MSC_VER 139 | #pragma warning(push) 140 | #pragma warning(disable: 4201) 141 | #endif 142 | typedef struct 143 | { 144 | INT64 Timestamp; /* Packet's timestamp. */ 145 | UINT32 Layer:8; /* Packet's layer. */ 146 | UINT32 Event:8; /* Packet event. */ 147 | UINT32 Sniffed:1; /* Packet was sniffed? */ 148 | UINT32 Outbound:1; /* Packet is outound? */ 149 | UINT32 Loopback:1; /* Packet is loopback? */ 150 | UINT32 Impostor:1; /* Packet is impostor? */ 151 | UINT32 IPv6:1; /* Packet is IPv6? */ 152 | UINT32 IPChecksum:1; /* Packet has valid IPv4 checksum? */ 153 | UINT32 TCPChecksum:1; /* Packet has valid TCP checksum? */ 154 | UINT32 UDPChecksum:1; /* Packet has valid UDP checksum? */ 155 | UINT32 Reserved1:8; 156 | UINT32 Reserved2; 157 | union 158 | { 159 | WINDIVERT_DATA_NETWORK Network; /* Network layer data. */ 160 | WINDIVERT_DATA_FLOW Flow; /* Flow layer data. */ 161 | WINDIVERT_DATA_SOCKET Socket; /* Socket layer data. */ 162 | WINDIVERT_DATA_REFLECT Reflect; /* Reflect layer data. */ 163 | UINT8 Reserved3[64]; 164 | }; 165 | } WINDIVERT_ADDRESS, *PWINDIVERT_ADDRESS; 166 | #ifdef _MSC_VER 167 | #pragma warning(pop) 168 | #endif 169 | 170 | /* 171 | * WinDivert events. 172 | */ 173 | typedef enum 174 | { 175 | WINDIVERT_EVENT_NETWORK_PACKET = 0, /* Network packet. */ 176 | WINDIVERT_EVENT_FLOW_ESTABLISHED = 1, 177 | /* Flow established. */ 178 | WINDIVERT_EVENT_FLOW_DELETED = 2, /* Flow deleted. */ 179 | WINDIVERT_EVENT_SOCKET_BIND = 3, /* Socket bind. */ 180 | WINDIVERT_EVENT_SOCKET_CONNECT = 4, /* Socket connect. */ 181 | WINDIVERT_EVENT_SOCKET_LISTEN = 5, /* Socket listen. */ 182 | WINDIVERT_EVENT_SOCKET_ACCEPT = 6, /* Socket accept. */ 183 | WINDIVERT_EVENT_SOCKET_CLOSE = 7, /* Socket close. */ 184 | WINDIVERT_EVENT_REFLECT_OPEN = 8, /* WinDivert handle opened. */ 185 | WINDIVERT_EVENT_REFLECT_CLOSE = 9, /* WinDivert handle closed. */ 186 | } WINDIVERT_EVENT, *PWINDIVERT_EVENT; 187 | 188 | /* 189 | * WinDivert flags. 190 | */ 191 | #define WINDIVERT_FLAG_SNIFF 0x0001 192 | #define WINDIVERT_FLAG_DROP 0x0002 193 | #define WINDIVERT_FLAG_RECV_ONLY 0x0004 194 | #define WINDIVERT_FLAG_READ_ONLY WINDIVERT_FLAG_RECV_ONLY 195 | #define WINDIVERT_FLAG_SEND_ONLY 0x0008 196 | #define WINDIVERT_FLAG_WRITE_ONLY WINDIVERT_FLAG_SEND_ONLY 197 | #define WINDIVERT_FLAG_NO_INSTALL 0x0010 198 | #define WINDIVERT_FLAG_FRAGMENTS 0x0020 199 | 200 | /* 201 | * WinDivert parameters. 202 | */ 203 | typedef enum 204 | { 205 | WINDIVERT_PARAM_QUEUE_LENGTH = 0, /* Packet queue length. */ 206 | WINDIVERT_PARAM_QUEUE_TIME = 1, /* Packet queue time. */ 207 | WINDIVERT_PARAM_QUEUE_SIZE = 2, /* Packet queue size. */ 208 | WINDIVERT_PARAM_VERSION_MAJOR = 3, /* Driver version (major). */ 209 | WINDIVERT_PARAM_VERSION_MINOR = 4, /* Driver version (minor). */ 210 | } WINDIVERT_PARAM, *PWINDIVERT_PARAM; 211 | #define WINDIVERT_PARAM_MAX WINDIVERT_PARAM_VERSION_MINOR 212 | 213 | /* 214 | * WinDivert shutdown parameter. 215 | */ 216 | typedef enum 217 | { 218 | WINDIVERT_SHUTDOWN_RECV = 0x1, /* Shutdown recv. */ 219 | WINDIVERT_SHUTDOWN_SEND = 0x2, /* Shutdown send. */ 220 | WINDIVERT_SHUTDOWN_BOTH = 0x3, /* Shutdown recv and send. */ 221 | } WINDIVERT_SHUTDOWN, *PWINDIVERT_SHUTDOWN; 222 | #define WINDIVERT_SHUTDOWN_MAX WINDIVERT_SHUTDOWN_BOTH 223 | 224 | #ifndef WINDIVERT_KERNEL 225 | 226 | /* 227 | * Open a WinDivert handle. 228 | */ 229 | WINDIVERTEXPORT HANDLE WinDivertOpen( 230 | __in const char *filter, 231 | __in WINDIVERT_LAYER layer, 232 | __in INT16 priority, 233 | __in UINT64 flags); 234 | 235 | /* 236 | * Receive (read) a packet from a WinDivert handle. 237 | */ 238 | WINDIVERTEXPORT BOOL WinDivertRecv( 239 | __in HANDLE handle, 240 | __out_opt VOID *pPacket, 241 | __in UINT packetLen, 242 | __out_opt UINT *pRecvLen, 243 | __out_opt WINDIVERT_ADDRESS *pAddr); 244 | 245 | /* 246 | * Receive (read) a packet from a WinDivert handle. 247 | */ 248 | WINDIVERTEXPORT BOOL WinDivertRecvEx( 249 | __in HANDLE handle, 250 | __out_opt VOID *pPacket, 251 | __in UINT packetLen, 252 | __out_opt UINT *pRecvLen, 253 | __in UINT64 flags, 254 | __out WINDIVERT_ADDRESS *pAddr, 255 | __inout_opt UINT *pAddrLen, 256 | __inout_opt LPOVERLAPPED lpOverlapped); 257 | 258 | /* 259 | * Send (write/inject) a packet to a WinDivert handle. 260 | */ 261 | WINDIVERTEXPORT BOOL WinDivertSend( 262 | __in HANDLE handle, 263 | __in const VOID *pPacket, 264 | __in UINT packetLen, 265 | __out_opt UINT *pSendLen, 266 | __in const WINDIVERT_ADDRESS *pAddr); 267 | 268 | /* 269 | * Send (write/inject) a packet to a WinDivert handle. 270 | */ 271 | WINDIVERTEXPORT BOOL WinDivertSendEx( 272 | __in HANDLE handle, 273 | __in const VOID *pPacket, 274 | __in UINT packetLen, 275 | __out_opt UINT *pSendLen, 276 | __in UINT64 flags, 277 | __in const WINDIVERT_ADDRESS *pAddr, 278 | __in UINT addrLen, 279 | __inout_opt LPOVERLAPPED lpOverlapped); 280 | 281 | /* 282 | * Shutdown a WinDivert handle. 283 | */ 284 | WINDIVERTEXPORT BOOL WinDivertShutdown( 285 | __in HANDLE handle, 286 | __in WINDIVERT_SHUTDOWN how); 287 | 288 | /* 289 | * Close a WinDivert handle. 290 | */ 291 | WINDIVERTEXPORT BOOL WinDivertClose( 292 | __in HANDLE handle); 293 | 294 | /* 295 | * Set a WinDivert handle parameter. 296 | */ 297 | WINDIVERTEXPORT BOOL WinDivertSetParam( 298 | __in HANDLE handle, 299 | __in WINDIVERT_PARAM param, 300 | __in UINT64 value); 301 | 302 | /* 303 | * Get a WinDivert handle parameter. 304 | */ 305 | WINDIVERTEXPORT BOOL WinDivertGetParam( 306 | __in HANDLE handle, 307 | __in WINDIVERT_PARAM param, 308 | __out UINT64 *pValue); 309 | 310 | #endif /* WINDIVERT_KERNEL */ 311 | 312 | /* 313 | * WinDivert constants. 314 | */ 315 | #define WINDIVERT_PRIORITY_HIGHEST 30000 316 | #define WINDIVERT_PRIORITY_LOWEST (-WINDIVERT_PRIORITY_HIGHEST) 317 | #define WINDIVERT_PARAM_QUEUE_LENGTH_DEFAULT 4096 318 | #define WINDIVERT_PARAM_QUEUE_LENGTH_MIN 32 319 | #define WINDIVERT_PARAM_QUEUE_LENGTH_MAX 16384 320 | #define WINDIVERT_PARAM_QUEUE_TIME_DEFAULT 2000 /* 2s */ 321 | #define WINDIVERT_PARAM_QUEUE_TIME_MIN 100 /* 100ms */ 322 | #define WINDIVERT_PARAM_QUEUE_TIME_MAX 16000 /* 16s */ 323 | #define WINDIVERT_PARAM_QUEUE_SIZE_DEFAULT 4194304 /* 4MB */ 324 | #define WINDIVERT_PARAM_QUEUE_SIZE_MIN 65535 /* 64KB */ 325 | #define WINDIVERT_PARAM_QUEUE_SIZE_MAX 33554432 /* 32MB */ 326 | #define WINDIVERT_BATCH_MAX 0xFF /* 255 */ 327 | #define WINDIVERT_MTU_MAX (40 + 0xFFFF) 328 | 329 | /****************************************************************************/ 330 | /* WINDIVERT HELPER API */ 331 | /****************************************************************************/ 332 | 333 | #ifdef _MSC_VER 334 | #pragma warning(push) 335 | #pragma warning(disable: 4214) 336 | #endif 337 | 338 | /* 339 | * IPv4/IPv6/ICMP/ICMPv6/TCP/UDP header definitions. 340 | */ 341 | typedef struct 342 | { 343 | UINT8 HdrLength:4; 344 | UINT8 Version:4; 345 | UINT8 TOS; 346 | UINT16 Length; 347 | UINT16 Id; 348 | UINT16 FragOff0; 349 | UINT8 TTL; 350 | UINT8 Protocol; 351 | UINT16 Checksum; 352 | UINT32 SrcAddr; 353 | UINT32 DstAddr; 354 | } WINDIVERT_IPHDR, *PWINDIVERT_IPHDR; 355 | 356 | #define WINDIVERT_IPHDR_GET_FRAGOFF(hdr) \ 357 | (((hdr)->FragOff0) & 0xFF1F) 358 | #define WINDIVERT_IPHDR_GET_MF(hdr) \ 359 | ((((hdr)->FragOff0) & 0x0020) != 0) 360 | #define WINDIVERT_IPHDR_GET_DF(hdr) \ 361 | ((((hdr)->FragOff0) & 0x0040) != 0) 362 | #define WINDIVERT_IPHDR_GET_RESERVED(hdr) \ 363 | ((((hdr)->FragOff0) & 0x0080) != 0) 364 | 365 | #define WINDIVERT_IPHDR_SET_FRAGOFF(hdr, val) \ 366 | do \ 367 | { \ 368 | (hdr)->FragOff0 = (((hdr)->FragOff0) & 0x00E0) | \ 369 | ((val) & 0xFF1F); \ 370 | } \ 371 | while (FALSE) 372 | #define WINDIVERT_IPHDR_SET_MF(hdr, val) \ 373 | do \ 374 | { \ 375 | (hdr)->FragOff0 = (((hdr)->FragOff0) & 0xFFDF) | \ 376 | (((val) & 0x0001) << 5); \ 377 | } \ 378 | while (FALSE) 379 | #define WINDIVERT_IPHDR_SET_DF(hdr, val) \ 380 | do \ 381 | { \ 382 | (hdr)->FragOff0 = (((hdr)->FragOff0) & 0xFFBF) | \ 383 | (((val) & 0x0001) << 6); \ 384 | } \ 385 | while (FALSE) 386 | #define WINDIVERT_IPHDR_SET_RESERVED(hdr, val) \ 387 | do \ 388 | { \ 389 | (hdr)->FragOff0 = (((hdr)->FragOff0) & 0xFF7F) | \ 390 | (((val) & 0x0001) << 7); \ 391 | } \ 392 | while (FALSE) 393 | 394 | typedef struct 395 | { 396 | UINT8 TrafficClass0:4; 397 | UINT8 Version:4; 398 | UINT8 FlowLabel0:4; 399 | UINT8 TrafficClass1:4; 400 | UINT16 FlowLabel1; 401 | UINT16 Length; 402 | UINT8 NextHdr; 403 | UINT8 HopLimit; 404 | UINT32 SrcAddr[4]; 405 | UINT32 DstAddr[4]; 406 | } WINDIVERT_IPV6HDR, *PWINDIVERT_IPV6HDR; 407 | 408 | #define WINDIVERT_IPV6HDR_GET_TRAFFICCLASS(hdr) \ 409 | ((((hdr)->TrafficClass0) << 4) | ((hdr)->TrafficClass1)) 410 | #define WINDIVERT_IPV6HDR_GET_FLOWLABEL(hdr) \ 411 | ((((UINT32)(hdr)->FlowLabel0) << 16) | ((UINT32)(hdr)->FlowLabel1)) 412 | 413 | #define WINDIVERT_IPV6HDR_SET_TRAFFICCLASS(hdr, val) \ 414 | do \ 415 | { \ 416 | (hdr)->TrafficClass0 = ((UINT8)(val) >> 4); \ 417 | (hdr)->TrafficClass1 = (UINT8)(val); \ 418 | } \ 419 | while (FALSE) 420 | #define WINDIVERT_IPV6HDR_SET_FLOWLABEL(hdr, val) \ 421 | do \ 422 | { \ 423 | (hdr)->FlowLabel0 = (UINT8)((val) >> 16); \ 424 | (hdr)->FlowLabel1 = (UINT16)(val); \ 425 | } \ 426 | while (FALSE) 427 | 428 | typedef struct 429 | { 430 | UINT8 Type; 431 | UINT8 Code; 432 | UINT16 Checksum; 433 | UINT32 Body; 434 | } WINDIVERT_ICMPHDR, *PWINDIVERT_ICMPHDR; 435 | 436 | typedef struct 437 | { 438 | UINT8 Type; 439 | UINT8 Code; 440 | UINT16 Checksum; 441 | UINT32 Body; 442 | } WINDIVERT_ICMPV6HDR, *PWINDIVERT_ICMPV6HDR; 443 | 444 | typedef struct 445 | { 446 | UINT16 SrcPort; 447 | UINT16 DstPort; 448 | UINT32 SeqNum; 449 | UINT32 AckNum; 450 | UINT16 Reserved1:4; 451 | UINT16 HdrLength:4; 452 | UINT16 Fin:1; 453 | UINT16 Syn:1; 454 | UINT16 Rst:1; 455 | UINT16 Psh:1; 456 | UINT16 Ack:1; 457 | UINT16 Urg:1; 458 | UINT16 Reserved2:2; 459 | UINT16 Window; 460 | UINT16 Checksum; 461 | UINT16 UrgPtr; 462 | } WINDIVERT_TCPHDR, *PWINDIVERT_TCPHDR; 463 | 464 | typedef struct 465 | { 466 | UINT16 SrcPort; 467 | UINT16 DstPort; 468 | UINT16 Length; 469 | UINT16 Checksum; 470 | } WINDIVERT_UDPHDR, *PWINDIVERT_UDPHDR; 471 | 472 | #ifdef _MSC_VER 473 | #pragma warning(pop) 474 | #endif 475 | 476 | /* 477 | * Flags for WinDivertHelperCalcChecksums() 478 | */ 479 | #define WINDIVERT_HELPER_NO_IP_CHECKSUM 1 480 | #define WINDIVERT_HELPER_NO_ICMP_CHECKSUM 2 481 | #define WINDIVERT_HELPER_NO_ICMPV6_CHECKSUM 4 482 | #define WINDIVERT_HELPER_NO_TCP_CHECKSUM 8 483 | #define WINDIVERT_HELPER_NO_UDP_CHECKSUM 16 484 | 485 | #ifndef WINDIVERT_KERNEL 486 | 487 | /* 488 | * Hash a packet. 489 | */ 490 | WINDIVERTEXPORT UINT64 WinDivertHelperHashPacket( 491 | __in const VOID *pPacket, 492 | __in UINT packetLen, 493 | __in UINT64 seed 494 | #ifdef __cplusplus 495 | = 0 496 | #endif 497 | ); 498 | 499 | /* 500 | * Parse IPv4/IPv6/ICMP/ICMPv6/TCP/UDP headers from a raw packet. 501 | */ 502 | WINDIVERTEXPORT BOOL WinDivertHelperParsePacket( 503 | __in const VOID *pPacket, 504 | __in UINT packetLen, 505 | __out_opt PWINDIVERT_IPHDR *ppIpHdr, 506 | __out_opt PWINDIVERT_IPV6HDR *ppIpv6Hdr, 507 | __out_opt UINT8 *pProtocol, 508 | __out_opt PWINDIVERT_ICMPHDR *ppIcmpHdr, 509 | __out_opt PWINDIVERT_ICMPV6HDR *ppIcmpv6Hdr, 510 | __out_opt PWINDIVERT_TCPHDR *ppTcpHdr, 511 | __out_opt PWINDIVERT_UDPHDR *ppUdpHdr, 512 | __out_opt PVOID *ppData, 513 | __out_opt UINT *pDataLen, 514 | __out_opt PVOID *ppNext, 515 | __out_opt UINT *pNextLen); 516 | 517 | /* 518 | * Parse an IPv4 address. 519 | */ 520 | WINDIVERTEXPORT BOOL WinDivertHelperParseIPv4Address( 521 | __in const char *addrStr, 522 | __out_opt UINT32 *pAddr); 523 | 524 | /* 525 | * Parse an IPv6 address. 526 | */ 527 | WINDIVERTEXPORT BOOL WinDivertHelperParseIPv6Address( 528 | __in const char *addrStr, 529 | __out_opt UINT32 *pAddr); 530 | 531 | /* 532 | * Format an IPv4 address. 533 | */ 534 | WINDIVERTEXPORT BOOL WinDivertHelperFormatIPv4Address( 535 | __in UINT32 addr, 536 | __out char *buffer, 537 | __in UINT bufLen); 538 | 539 | /* 540 | * Format an IPv6 address. 541 | */ 542 | WINDIVERTEXPORT BOOL WinDivertHelperFormatIPv6Address( 543 | __in const UINT32 *pAddr, 544 | __out char *buffer, 545 | __in UINT bufLen); 546 | 547 | /* 548 | * Calculate IPv4/IPv6/ICMP/ICMPv6/TCP/UDP checksums. 549 | */ 550 | WINDIVERTEXPORT BOOL WinDivertHelperCalcChecksums( 551 | __inout VOID *pPacket, 552 | __in UINT packetLen, 553 | __out_opt WINDIVERT_ADDRESS *pAddr, 554 | __in UINT64 flags); 555 | 556 | /* 557 | * Decrement the TTL/HopLimit. 558 | */ 559 | WINDIVERTEXPORT BOOL WinDivertHelperDecrementTTL( 560 | __inout VOID *pPacket, 561 | __in UINT packetLen); 562 | 563 | /* 564 | * Compile the given filter string. 565 | */ 566 | WINDIVERTEXPORT BOOL WinDivertHelperCompileFilter( 567 | __in const char *filter, 568 | __in WINDIVERT_LAYER layer, 569 | __out_opt char *object, 570 | __in UINT objLen, 571 | __out_opt const char **errorStr, 572 | __out_opt UINT *errorPos); 573 | 574 | /* 575 | * Evaluate the given filter string. 576 | */ 577 | WINDIVERTEXPORT BOOL WinDivertHelperEvalFilter( 578 | __in const char *filter, 579 | __in const VOID *pPacket, 580 | __in UINT packetLen, 581 | __in const WINDIVERT_ADDRESS *pAddr); 582 | 583 | /* 584 | * Format the given filter string. 585 | */ 586 | WINDIVERTEXPORT BOOL WinDivertHelperFormatFilter( 587 | __in const char *filter, 588 | __in WINDIVERT_LAYER layer, 589 | __out char *buffer, 590 | __in UINT bufLen); 591 | 592 | /* 593 | * Byte ordering. 594 | */ 595 | WINDIVERTEXPORT UINT16 WinDivertHelperNtohs( 596 | __in UINT16 x); 597 | WINDIVERTEXPORT UINT16 WinDivertHelperHtons( 598 | __in UINT16 x); 599 | WINDIVERTEXPORT UINT32 WinDivertHelperNtohl( 600 | __in UINT32 x); 601 | WINDIVERTEXPORT UINT32 WinDivertHelperHtonl( 602 | __in UINT32 x); 603 | WINDIVERTEXPORT UINT64 WinDivertHelperNtohll( 604 | __in UINT64 x); 605 | WINDIVERTEXPORT UINT64 WinDivertHelperHtonll( 606 | __in UINT64 x); 607 | WINDIVERTEXPORT void WinDivertHelperNtohIPv6Address( 608 | __in const UINT *inAddr, 609 | __out UINT *outAddr); 610 | WINDIVERTEXPORT void WinDivertHelperHtonIPv6Address( 611 | __in const UINT *inAddr, 612 | __out UINT *outAddr); 613 | 614 | /* 615 | * Old names to be removed in the next version. 616 | */ 617 | WINDIVERTEXPORT void WinDivertHelperNtohIpv6Address( 618 | __in const UINT *inAddr, 619 | __out UINT *outAddr); 620 | WINDIVERTEXPORT void WinDivertHelperHtonIpv6Address( 621 | __in const UINT *inAddr, 622 | __out UINT *outAddr); 623 | 624 | #endif /* WINDIVERT_KERNEL */ 625 | 626 | #ifdef __cplusplus 627 | } 628 | #endif 629 | 630 | #endif /* __WINDIVERT_H */ 631 | --------------------------------------------------------------------------------