├── .clang-format ├── .github └── workflows │ ├── build.yml │ └── hashfile.yml ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── NetfilterPlugin.cpp ├── NetfilterPlugin.hpp ├── README.md ├── assets └── qv2ray.png ├── core ├── EventHandler.cpp ├── EventHandler.hpp └── Settings.hpp ├── netfilter ├── NFEventHandler.cpp ├── NFEventHandler.hpp ├── SOCKS.h ├── SocksRedirector.cpp ├── SocksRedirector.hpp ├── UDPContext.hpp ├── UDPProxy.cpp ├── UTF-8.h ├── UdpProxy.h ├── base.h ├── bin │ ├── driver │ │ ├── driver_versions.txt │ │ └── wfp │ │ │ └── amd64 │ │ │ └── netfilter2.sys │ ├── install_wfp_driver.bat │ ├── install_wfp_driver_x64.bat │ ├── release │ │ └── nfapi.dll │ └── uninstall_driver.bat ├── include │ ├── nfapi.h │ ├── nfapi_linux.h │ ├── nfapi_macos.h │ ├── nfdriver.h │ ├── nfevents.h │ └── nfext_macos.h ├── iocp.h ├── lib │ ├── Debug │ │ ├── nfapi.exp │ │ └── nfapi.lib │ └── Release │ │ ├── nfapi.exp │ │ └── nfapi.lib ├── linkedlist.h ├── sync.h └── threadpool.h ├── resx.qrc └── ui ├── Interface.hpp ├── PluginMainWindowWidget.cpp ├── PluginMainWindowWidget.hpp ├── PluginMainWindowWidget.ui ├── PluginSettingsWidget.cpp ├── PluginSettingsWidget.hpp └── PluginSettingsWidget.ui /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: Microsoft 3 | AccessModifierOffset: -2 4 | AlignAfterOpenBracket: Align 5 | AllowAllArgumentsOnNextLine: false 6 | AllowAllConstructorInitializersOnNextLine: false 7 | AllowAllParametersOfDeclarationOnNextLine: false 8 | AllowShortBlocksOnASingleLine: Never 9 | AllowShortCaseLabelsOnASingleLine: true 10 | AllowShortFunctionsOnASingleLine: None 11 | AllowShortIfStatementsOnASingleLine: Never 12 | AllowShortLambdasOnASingleLine: All 13 | AllowShortLoopsOnASingleLine: false 14 | AlwaysBreakAfterDefinitionReturnType: None 15 | AlwaysBreakAfterReturnType: None 16 | AlwaysBreakBeforeMultilineStrings: false 17 | AlwaysBreakTemplateDeclarations: Yes 18 | BinPackArguments: true 19 | BinPackParameters: true 20 | BreakBeforeBraces: Allman 21 | BreakBeforeTernaryOperators: false 22 | BreakInheritanceList: BeforeComma 23 | BreakStringLiterals: false 24 | ColumnLimit: 150 25 | CompactNamespaces: false 26 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 27 | Cpp11BracedListStyle: false 28 | ExperimentalAutoDetectBinPacking: false 29 | FixNamespaceComments: true 30 | IncludeBlocks: Regroup 31 | IndentCaseLabels: true 32 | IndentPPDirectives: None 33 | IndentWidth: 4 34 | Language: Cpp 35 | MaxEmptyLinesToKeep: 1 36 | NamespaceIndentation: All 37 | ReflowComments: true 38 | SortIncludes: true 39 | SortUsingDeclarations: true 40 | SpaceAfterCStyleCast: true 41 | SpaceAfterTemplateKeyword: false 42 | SpaceBeforeParens: ControlStatements 43 | SpaceBeforeRangeBasedForLoopColon: true 44 | SpacesInParentheses: false 45 | Standard: c++17 46 | StatementMacros: [ Q_UNUSED LOG DEBUG ] 47 | TabWidth: 4 48 | UseTab: Never 49 | 50 | ... 51 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: QvPlugin Build Action Qt6 2 | 3 | on: 4 | push: 5 | release: 6 | types: [prereleased] 7 | 8 | jobs: 9 | build: 10 | runs-on: windows-latest 11 | steps: 12 | - name: Get the version 13 | id: get_version 14 | shell: bash 15 | run: echo ::set-output name=VERSION::$(echo $GITHUB_REF | cut -d / -f 3) 16 | 17 | - name: Get Plugin Name 18 | id: get_name 19 | shell: bash 20 | run: echo ::set-output name=NAME::QvPlugin-WinNetFilter 21 | 22 | - name: Checking out sources 23 | uses: actions/checkout@master 24 | with: 25 | submodules: recursive 26 | 27 | - name: Install Python 3.7 version 28 | uses: actions/setup-python@v1 29 | with: 30 | python-version: '3.7' 31 | 32 | - name: Install MSVC compiler 33 | uses: ilammy/msvc-dev-cmd@v1 34 | with: 35 | toolset: 14.2 36 | arch: x64 37 | 38 | - name: Install Qt 39 | uses: jurplel/install-qt-action@v2 40 | with: 41 | version: 6.2.0 42 | arch: win64_msvc2019_64 43 | aqtversion: ==1.2.2 44 | 45 | - name: Install Vulkan SDK 46 | uses: humbletim/setup-vulkan-sdk@v1.0.2 47 | 48 | - name: Build 49 | shell: bash 50 | env: 51 | CC: cl.exe 52 | CXX: cl.exe 53 | run: | 54 | mkdir build 55 | cd build 56 | cmake .. -DCMAKE_BUILD_TYPE=Release -A x64 57 | cmake --build . --parallel $(nproc) --config Release 58 | 59 | - name: Uploading artifact 60 | uses: actions/upload-artifact@master 61 | with: 62 | name: ${{ steps.get_name.outputs.NAME }}-${{ github.sha }}.Windows.dll 63 | path: build/Release/${{ steps.get_name.outputs.NAME }}.dll 64 | 65 | - name: Upload binaries to release 66 | uses: svenstaro/upload-release-action@v1-release 67 | if: github.event_name == 'release' 68 | with: 69 | repo_token: ${{ secrets.GITHUB_TOKEN }} 70 | file: build/Release/${{ steps.get_name.outputs.NAME }}.dll 71 | asset_name: ${{ steps.get_name.outputs.NAME }}.${{ steps.get_version.outputs.VERSION }}.Windows.Qt6.dll 72 | tag: ${{ github.ref }} 73 | overwrite: true 74 | -------------------------------------------------------------------------------- /.github/workflows/hashfile.yml: -------------------------------------------------------------------------------- 1 | name: Update release files hash 2 | 3 | on: 4 | release: 5 | types: [edited] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | env: 11 | ACTIONS_ALLOW_UNSECURE_COMMANDS: true 12 | steps: 13 | - run: echo ::set-env name=VERSION::$(echo $GITHUB_REF | cut -d / -f 3) 14 | shell: bash 15 | - run: echo ::set-env name=REPOSITORY_NAME::$(echo "$GITHUB_REPOSITORY" | awk -F / '{print $2}') 16 | shell: bash 17 | - name: Checking out sources 18 | uses: actions/checkout@master 19 | - name: Hash File 20 | shell: bash 21 | run: | 22 | wget -O release.info https://api.github.com/repos/Qv2ray/${REPOSITORY_NAME}/releases/tags/${VERSION} 23 | cat ./release.info | jq -r ".assets | .[] | .browser_download_url" > download.list 24 | cat ./release.info | jq -r ".assets | .[] | { uploader_id: .uploader.login, asset_name: .name }" > assets.info.json 25 | mkdir files 26 | cd files 27 | for x in $(cat ../download.list); do 28 | wget "$x"; 29 | done; 30 | rm assets.info.json || true 31 | rm sha256.list || true 32 | sha256sum ./* > ../sha256.list 33 | - name: Upload metadata to release 34 | uses: svenstaro/upload-release-action@v1-release 35 | with: 36 | repo_token: ${{ secrets.GITHUB_TOKEN }} 37 | file: assets.info.json 38 | asset_name: assets.info.json 39 | tag: ${{ github.ref }} 40 | overwrite: true 41 | - name: Upload metadata to release 42 | uses: svenstaro/upload-release-action@v1-release 43 | with: 44 | repo_token: ${{ secrets.GITHUB_TOKEN }} 45 | file: sha256.list 46 | asset_name: sha256.list 47 | tag: ${{ github.ref }} 48 | overwrite: true 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | CMakeSettings.json 2 | .vs/ 3 | out/ 4 | *.user 5 | build/ 6 | 7 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "interface"] 2 | path = interface 3 | url = https://github.com/Shadowsocks-NET/Qv2rayBase-PluginInterface.git 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1.0) 2 | cmake_policy(SET CMP0048 NEW) 3 | cmake_policy(SET CMP0003 NEW) 4 | cmake_policy(SET CMP0012 NEW) 5 | cmake_policy(SET CMP0100 NEW) 6 | cmake_policy(SET CMP0071 NEW) 7 | 8 | project(NetFilterPlugin LANGUAGES CXX VERSION 1.0.0) 9 | 10 | set(CMAKE_CXX_STANDARD 17) 11 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 12 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 13 | 14 | set(CMAKE_AUTOMOC ON) 15 | set(CMAKE_AUTOUIC ON) 16 | set(CMAKE_AUTORCC ON) 17 | 18 | find_package(Qt6 COMPONENTS Core Widgets Gui Network REQUIRED) 19 | set(CMAKE_POSITION_INDEPENDENT_CODE ON) 20 | 21 | add_subdirectory(interface) 22 | 23 | add_definitions(-DUNICODE -D_UNICODE -D_WIN32_WINNT=0x0A000000 -DWIN32_LEAN_AND_MEAN) 24 | 25 | set(SOURCES 26 | ${CMAKE_CURRENT_LIST_DIR}/NetfilterPlugin.hpp 27 | ${CMAKE_CURRENT_LIST_DIR}/NetfilterPlugin.cpp 28 | ${CMAKE_CURRENT_LIST_DIR}/core/Settings.hpp 29 | ${CMAKE_CURRENT_LIST_DIR}/core/EventHandler.cpp 30 | ${CMAKE_CURRENT_LIST_DIR}/core/EventHandler.hpp 31 | ${CMAKE_CURRENT_LIST_DIR}/ui/Interface.hpp 32 | ${CMAKE_CURRENT_LIST_DIR}/ui/PluginMainWindowWidget.cpp 33 | ${CMAKE_CURRENT_LIST_DIR}/ui/PluginMainWindowWidget.hpp 34 | ${CMAKE_CURRENT_LIST_DIR}/ui/PluginMainWindowWidget.ui 35 | ${CMAKE_CURRENT_LIST_DIR}/ui/PluginSettingsWidget.cpp 36 | ${CMAKE_CURRENT_LIST_DIR}/ui/PluginSettingsWidget.hpp 37 | ${CMAKE_CURRENT_LIST_DIR}/ui/PluginSettingsWidget.ui 38 | ${CMAKE_CURRENT_LIST_DIR}/resx.qrc 39 | # 40 | ${CMAKE_CURRENT_LIST_DIR}/netfilter/UDPContext.hpp 41 | ${CMAKE_CURRENT_LIST_DIR}/netfilter/iocp.h 42 | ${CMAKE_CURRENT_LIST_DIR}/netfilter/linkedlist.h 43 | ${CMAKE_CURRENT_LIST_DIR}/netfilter/SOCKS.h 44 | ${CMAKE_CURRENT_LIST_DIR}/netfilter/SocksRedirector.cpp 45 | ${CMAKE_CURRENT_LIST_DIR}/netfilter/SocksRedirector.hpp 46 | ${CMAKE_CURRENT_LIST_DIR}/netfilter/NFEventHandler.cpp 47 | ${CMAKE_CURRENT_LIST_DIR}/netfilter/NFEventHandler.hpp 48 | ${CMAKE_CURRENT_LIST_DIR}/netfilter/sync.h 49 | ${CMAKE_CURRENT_LIST_DIR}/netfilter/base.h 50 | ${CMAKE_CURRENT_LIST_DIR}/netfilter/UDPProxy.h 51 | ${CMAKE_CURRENT_LIST_DIR}/netfilter/UDPProxy.cpp 52 | ${CMAKE_CURRENT_LIST_DIR}/netfilter/UTF-8.h) 53 | 54 | qv2ray_add_plugin(NetFilterPlugin Widgets 55 | EXTRA_DEPENDENCY_DIRS_WINDOWS "${CMAKE_CURRENT_LIST_DIR}/netfilter/bin/release") 56 | 57 | target_include_directories(NetFilterPlugin PRIVATE ${CMAKE_CURRENT_LIST_DIR}/netfilter/include) 58 | 59 | target_sources(NetFilterPlugin PRIVATE ${SOURCES}) 60 | 61 | target_link_libraries(NetFilterPlugin PRIVATE ws2_32 wininet ${CMAKE_CURRENT_LIST_DIR}/netfilter/lib/${CMAKE_BUILD_TYPE}/nfapi.lib) 62 | target_link_libraries(NetFilterPlugin PRIVATE Qt::Network) 63 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Shadowsocks.NET 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /NetfilterPlugin.cpp: -------------------------------------------------------------------------------- 1 | #include "NetfilterPlugin.hpp" 2 | 3 | #include "core/EventHandler.hpp" 4 | #include "ui/Interface.hpp" 5 | 6 | bool NetfilterPlugin::InitializePlugin() 7 | { 8 | options.loadJson(m_Settings); 9 | m_EventHandler = std::make_shared(); 10 | m_GUIInterface = new SimpleGUIInterface(); 11 | return true; 12 | } 13 | -------------------------------------------------------------------------------- /NetfilterPlugin.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "QvPlugin/PluginInterface.hpp" 4 | #include "core/Settings.hpp" 5 | 6 | #include 7 | #include 8 | 9 | using namespace Qv2rayPlugin; 10 | 11 | class NetfilterPlugin 12 | : public QObject 13 | , public Qv2rayInterface 14 | { 15 | Q_OBJECT 16 | QV2RAY_PLUGIN(NetfilterPlugin) 17 | friend class NetfilterPluginEventHandler; 18 | 19 | public: 20 | const QvPluginMetadata GetMetadata() const override 21 | { 22 | return QvPluginMetadata{ 23 | "NetFilter Transparent Proxy", 24 | "Community", 25 | PluginId{ "netfilter" }, 26 | "A transparent proxy plugin for Qv2ray, uses NetfilterSDK", 27 | QUrl{}, 28 | { Qv2rayPlugin::COMPONENT_EVENT_HANDLER, Qv2rayPlugin::COMPONENT_GUI }, 29 | }; 30 | } 31 | 32 | bool InitializePlugin() override; 33 | void SettingsUpdated() override{}; 34 | 35 | private: 36 | PluginOptions options; 37 | }; 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Qv2ray Windows Netfilter SDK Transparent Proxy Plugin 2 | 3 | Qv2ray Plugin which enables transparent proxy on Windows 4 | -------------------------------------------------------------------------------- /assets/qv2ray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shadowsocks-NET/QvPlugin-Netfilter/c0617220093cf73185427f091b91e8cdb1aafe03/assets/qv2ray.png -------------------------------------------------------------------------------- /core/EventHandler.cpp: -------------------------------------------------------------------------------- 1 | #include "EventHandler.hpp" 2 | 3 | #include "NetfilterPlugin.hpp" 4 | 5 | #include 6 | 7 | NetfilterPluginEventHandler::NetfilterPluginEventHandler() : QObject(), Qv2rayPlugin::IEventHandler() 8 | { 9 | connect(&core, &NetFilterCore::OnLogMessageReady, this, &NetfilterPluginEventHandler::OnLog); 10 | } 11 | 12 | void NetfilterPluginEventHandler::ProcessEvent(const Connectivity::EventObject &o) 13 | { 14 | switch (o.Type) 15 | { 16 | case Connectivity::EventType::Connected: 17 | { 18 | int socksPort = [&] { 19 | for (auto it = o.InboundData.constKeyValueBegin(); it != o.InboundData.constKeyValueEnd(); it++) 20 | { 21 | const auto &[protocol, address, port] = it->second; 22 | if (protocol == "socks") 23 | return port.from; 24 | } 25 | return 0; 26 | }(); 27 | core.Start(NetfilterPlugin::PluginInstance->options.rules, "127.0.0.1", socksPort); 28 | break; 29 | } 30 | case Connectivity::EventType::Disconnecting: 31 | { 32 | core.Stop(); 33 | break; 34 | } 35 | default: break; 36 | } 37 | } 38 | 39 | void NetfilterPluginEventHandler::OnLog(size_t cid, QString protocol, bool isOpen, QString local, QString remote, int pid, QString path) 40 | { 41 | // plugin_instance->PluginLog("Connection: " + QString::number(cid) + ":" + protocol + ":" + (isOpen ? "opening" : "closing") + " " + local + 42 | // " -> " + remote + " :: " + path); 43 | } 44 | -------------------------------------------------------------------------------- /core/EventHandler.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "QvPlugin/Handlers/EventHandler.hpp" 3 | #include "netfilter/SocksRedirector.hpp" 4 | 5 | using namespace Qv2rayPlugin::Event; 6 | 7 | class NetfilterPluginEventHandler 8 | : public QObject 9 | , public Qv2rayPlugin::Event::IEventHandler 10 | { 11 | Q_OBJECT 12 | public: 13 | NetfilterPluginEventHandler(); 14 | void ProcessEvent(const Connectivity::EventObject &) override; 15 | 16 | private slots: 17 | void OnLog(size_t cid, QString protocol, bool isOpen, QString local, QString remote, int pid, QString path); 18 | 19 | private: 20 | NetFilterCore core; 21 | }; 22 | -------------------------------------------------------------------------------- /core/Settings.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "QvPlugin/Utils/BindableProps.hpp" 4 | #include "QvPlugin/Utils/JsonConversion.hpp" 5 | 6 | #include 7 | 8 | enum NetworkType 9 | { 10 | NETWORK_UNSPECIFIED, 11 | NETWORK_TCP = 6, 12 | NETWORK_UDP = 17 13 | }; 14 | 15 | struct FilterRule 16 | { 17 | QJS_JSON(F(portFrom, portTo, networkType, processName)) 18 | Bindable portFrom{ 0 }; 19 | Bindable portTo{ 0 }; 20 | Bindable networkType{ NETWORK_UNSPECIFIED }; 21 | Bindable processName{ "" }; 22 | explicit FilterRule(int f = 0, int t = 0, NetworkType n = NETWORK_UNSPECIFIED, QString proc = "") 23 | { 24 | portFrom = f; 25 | portTo = t; 26 | networkType = n; 27 | processName = proc; 28 | } 29 | }; 30 | 31 | typedef QList FilterRules; 32 | static const inline FilterRules DefaultRules = QList() // 33 | << FilterRule{ 0, 0, NETWORK_UNSPECIFIED, "qv2ray.exe" } // Qv2ray 34 | << FilterRule{ 0, 0, NETWORK_UNSPECIFIED, "v2ray.exe" } // V2Ray 35 | << FilterRule{ 67, 0, NETWORK_UDP } // DHCP 36 | << FilterRule{ 123, 0, NETWORK_UDP }; // NTP 37 | 38 | struct PluginOptions 39 | { 40 | QJS_JSON(F(rules, autoStart)) 41 | Bindable rules{ DefaultRules }; 42 | Bindable autoStart{ false }; 43 | }; 44 | -------------------------------------------------------------------------------- /netfilter/NFEventHandler.cpp: -------------------------------------------------------------------------------- 1 | #include "NFEventHandler.hpp" 2 | 3 | #include "UdpProxy.h" 4 | 5 | EventHandler::EventHandler(logfunc func) 6 | { 7 | doLog = func; 8 | // m_tcpProxy = new TcpProxy::TCPProxy; 9 | m_udpProxy = new UdpProxy::UDPProxy; 10 | } 11 | EventHandler::~EventHandler() 12 | { 13 | delete m_udpProxy; 14 | } 15 | 16 | void EventHandler::tcpCanReceive(nfapi::ENDPOINT_ID){}; 17 | void EventHandler::tcpCanSend(nfapi::ENDPOINT_ID){}; 18 | void EventHandler::udpConnectRequest(nfapi::ENDPOINT_ID, nfapi::PNF_UDP_CONN_REQUEST){}; 19 | void EventHandler::udpCanReceive(nfapi::ENDPOINT_ID){}; 20 | void EventHandler::udpCanSend(nfapi::ENDPOINT_ID){}; 21 | 22 | bool EventHandler::init(std::wstring address, std::string username, std::string password) 23 | { 24 | memset(g_proxyAddress, 0, NF_MAX_ADDRESS_LENGTH); 25 | 26 | auto addrLen = NF_MAX_ADDRESS_LENGTH; 27 | auto err = WSAStringToAddress(address.data(), AF_INET, NULL, (LPSOCKADDR) &g_proxyAddress, &addrLen); 28 | if (err < 0) 29 | { 30 | addrLen = sizeof(g_proxyAddress); 31 | err = WSAStringToAddress(address.data(), AF_INET6, NULL, (LPSOCKADDR) &g_proxyAddress, &addrLen); 32 | if (err < 0) 33 | { 34 | printf("WSAStringToAddress failed, err=%d", WSAGetLastError()); 35 | return false; 36 | } 37 | } 38 | 39 | const int size = (((sockaddr *) g_proxyAddress)->sa_family == AF_INET6) ? sizeof(sockaddr_in6) : sizeof(sockaddr_in); 40 | if (!m_udpProxy->init(this, (char *) g_proxyAddress, size, username, password)) 41 | { 42 | printf("Unable to start UDP proxy"); 43 | free(); 44 | return false; 45 | } 46 | return true; 47 | } 48 | 49 | void EventHandler::free() 50 | { 51 | m_udpProxy->free(); 52 | std::lock_guard guard(lock); 53 | for (auto &&[k, v] : m_udpCtxMap) 54 | delete v; 55 | m_udpCtxMap.clear(); 56 | } 57 | 58 | void EventHandler::onUdpReceiveComplete(unsigned long long id, char *buf, int len, char *remoteAddress, int remoteAddressLen) 59 | { 60 | (void) remoteAddressLen; 61 | std::lock_guard guard(lock); 62 | 63 | auto it = m_udpCtxMap.find(id); 64 | if (it == m_udpCtxMap.end()) 65 | return; 66 | 67 | nf_udpPostReceive(id, (const unsigned char *) remoteAddress, buf, len, it->second->m_options); 68 | } 69 | 70 | void EventHandler::tcpConnectRequest(nfapi::ENDPOINT_ID id, nfapi::PNF_TCP_CONN_INFO pConnInfo) 71 | { 72 | 73 | ORIGINAL_CONN_INFO oci; 74 | memcpy(oci.remoteAddress, pConnInfo->remoteAddress, sizeof(oci.remoteAddress)); 75 | // Save the original remote address 76 | m_connInfoMap[id] = oci; 77 | 78 | sockaddr *pAddr = (sockaddr *) pConnInfo->remoteAddress; 79 | int addrLen = (pAddr->sa_family == AF_INET6) ? sizeof(sockaddr_in6) : sizeof(sockaddr_in); 80 | 81 | // if (pAddr->sa_family == AF_INET) 82 | // { 83 | // Redirect the connection if it is not already redirected 84 | if (memcmp(pAddr, &g_proxyAddress, addrLen) != 0) 85 | { 86 | // Change the remote address 87 | memcpy(pConnInfo->remoteAddress, &g_proxyAddress, sizeof(pConnInfo->remoteAddress)); 88 | pConnInfo->filteringFlag |= nfapi::NF_FILTER; 89 | } 90 | // } 91 | 92 | // if (pAddr->sa_family == AF_INET6) 93 | // { 94 | // sockaddr_in6 addrV6; 95 | // memset(&addrV6, 0, sizeof(addrV6)); 96 | // addrV6.sin6_family = AF_INET6; 97 | // inet_pton(AF_INET6, "::1", &addrV6.sin6_addr); 98 | // addrV6.sin6_port = htons(socksPort); 99 | // // Redirect the connection if it is not already redirected 100 | // if (memcmp(pAddr, &addrV6, addrLen) != 0) 101 | // { 102 | // // Change the remote address 103 | // memcpy(pConnInfo->remoteAddress, &addrV6, sizeof(pConnInfo->remoteAddress)); 104 | // pConnInfo->filteringFlag |= nfapi::NF_FILTER; 105 | // } 106 | // } 107 | } 108 | 109 | void EventHandler::tcpConnected(nfapi::ENDPOINT_ID id, nfapi::PNF_TCP_CONN_INFO pConnInfo) 110 | { 111 | LogTCP(true, id, pConnInfo); 112 | fflush(stdout); 113 | } 114 | 115 | void EventHandler::tcpClosed(nfapi::ENDPOINT_ID id, nfapi::PNF_TCP_CONN_INFO pConnInfo) 116 | { 117 | LogTCP(false, id, pConnInfo); 118 | m_connInfoMap.erase(id); 119 | fflush(stdout); 120 | } 121 | 122 | void EventHandler::tcpReceive(nfapi::ENDPOINT_ID id, const char *buf, int len) 123 | { 124 | auto it = m_connInfoMap.find(id); 125 | if (it != m_connInfoMap.end()) 126 | { 127 | if (!it->second.pendedSends.empty()) 128 | { 129 | nfapi::nf_tcpPostSend(id, &it->second.pendedSends[0], (int) it->second.pendedSends.size()); 130 | } 131 | 132 | m_connInfoMap.erase(id); 133 | return; 134 | } 135 | 136 | // Send the packet to application 137 | nfapi::nf_tcpPostReceive(id, buf, len); 138 | 139 | // Don't filter the subsequent packets (optimization) 140 | nfapi::nf_tcpDisableFiltering(id); 141 | } 142 | 143 | void EventHandler::tcpSend(nfapi::ENDPOINT_ID id, const char *buf, int len) 144 | { 145 | auto it = m_connInfoMap.find(id); 146 | 147 | if (it != m_connInfoMap.end()) 148 | { 149 | SOCKS4_REQUEST request; 150 | sockaddr_in *pAddr; 151 | auto it = m_connInfoMap.find(id); 152 | if (it == m_connInfoMap.end()) 153 | return; 154 | 155 | pAddr = (sockaddr_in *) &it->second.remoteAddress; 156 | if (pAddr->sin_family == AF_INET6) 157 | { 158 | return; 159 | } 160 | 161 | request.version = SOCKS_4; 162 | request.command = S4C_CONNECT; 163 | request.ip = pAddr->sin_addr.S_un.S_addr; 164 | request.port = pAddr->sin_port; 165 | request.userid[0] = '\0'; 166 | 167 | // Send the request first 168 | nfapi::nf_tcpPostSend(id, (char *) &request, (int) sizeof(request)); 169 | 170 | it->second.pendedSends.insert(it->second.pendedSends.end(), buf, buf + len); 171 | 172 | return; 173 | } 174 | 175 | // Send the packet to server 176 | nfapi::nf_tcpPostSend(id, buf, len); 177 | } 178 | 179 | void EventHandler::udpCreated(nfapi::ENDPOINT_ID id, nfapi::PNF_UDP_CONN_INFO pConnInfo) 180 | { 181 | std::lock_guard guard(lock); 182 | LogUDP(true, id, pConnInfo); 183 | } 184 | 185 | void EventHandler::udpClosed(nfapi::ENDPOINT_ID id, nfapi::PNF_UDP_CONN_INFO pConnInfo) 186 | { 187 | LogUDP(false, id, pConnInfo); 188 | 189 | m_udpProxy->deleteProxyConnection(id); 190 | 191 | std::lock_guard guard(lock); 192 | if (m_udpCtxMap.find(id) != m_udpCtxMap.end()) 193 | { 194 | delete m_udpCtxMap[id]; 195 | m_udpCtxMap.erase(id); 196 | } 197 | } 198 | 199 | void EventHandler::udpReceive(nfapi::ENDPOINT_ID id, const unsigned char *remoteAddress, const char *buf, int len, nfapi::PNF_UDP_OPTIONS options) 200 | { 201 | // Send the packet to application 202 | nfapi::nf_udpPostReceive(id, remoteAddress, buf, len, options); 203 | } 204 | 205 | void EventHandler::udpSend(nfapi::ENDPOINT_ID id, const unsigned char *remoteAddress, const char *buf, int len, nfapi::PNF_UDP_OPTIONS options) 206 | { 207 | { 208 | std::lock_guard guard(lock); 209 | if (m_udpCtxMap.find(id) == m_udpCtxMap.end()) 210 | { 211 | if (!m_udpProxy->createProxyConnection(id)) 212 | return; 213 | m_udpCtxMap[id] = new UDPContext(options); 214 | } 215 | } 216 | 217 | int addrLen = (((sockaddr *) remoteAddress)->sa_family == AF_INET) ? sizeof(sockaddr_in) : sizeof(sockaddr_in6); 218 | if (!m_udpProxy->udpSend(id, (char *) buf, len, (char *) remoteAddress, addrLen)) 219 | { 220 | nf_udpPostSend(id, remoteAddress, buf, len, options); 221 | } 222 | } 223 | 224 | void EventHandler::LogTCP(bool connected, nfapi::ENDPOINT_ID id, nfapi::PNF_TCP_CONN_INFO pConnInfo) 225 | { 226 | TCHAR localAddr[MAX_PATH] = L""; 227 | TCHAR remoteAddr[MAX_PATH] = L""; 228 | DWORD dwLen; 229 | sockaddr *pAddr; 230 | TCHAR processName[MAX_PATH] = L""; 231 | 232 | pAddr = (sockaddr *) pConnInfo->localAddress; 233 | dwLen = sizeof(localAddr); 234 | 235 | WSAAddressToString((LPSOCKADDR) pAddr, (pAddr->sa_family == AF_INET6) ? sizeof(sockaddr_in6) : sizeof(sockaddr_in), NULL, localAddr, &dwLen); 236 | 237 | pAddr = (sockaddr *) pConnInfo->remoteAddress; 238 | dwLen = sizeof(remoteAddr); 239 | 240 | WSAAddressToString((LPSOCKADDR) pAddr, (pAddr->sa_family == AF_INET6) ? sizeof(sockaddr_in6) : sizeof(sockaddr_in), NULL, remoteAddr, &dwLen); 241 | 242 | if (!nfapi::nf_getProcessNameFromKernel(pConnInfo->processId, processName, sizeof(processName) / sizeof(processName[0]))) 243 | processName[0] = '\0'; 244 | 245 | doLog(id, PROTOCOL::TCP, connected, localAddr, remoteAddr, pConnInfo->processId, processName); 246 | } 247 | 248 | void EventHandler::LogUDP(bool created, nfapi::ENDPOINT_ID id, nfapi::PNF_UDP_CONN_INFO pConnInfo) 249 | { 250 | TCHAR localAddr[MAX_PATH] = L""; 251 | sockaddr *pAddr; 252 | DWORD dwLen; 253 | TCHAR processName[MAX_PATH] = L""; 254 | 255 | pAddr = (sockaddr *) pConnInfo->localAddress; 256 | dwLen = sizeof(localAddr); 257 | 258 | WSAAddressToString((LPSOCKADDR) pAddr, (pAddr->sa_family == AF_INET6) ? sizeof(sockaddr_in6) : sizeof(sockaddr_in), NULL, localAddr, &dwLen); 259 | 260 | if (nfapi::nf_getProcessNameFromKernel(pConnInfo->processId, processName, sizeof(processName) / sizeof(processName[0]))) 261 | processName[0] = '\0'; 262 | doLog(id, PROTOCOL::UDP, created, localAddr, L"", pConnInfo->processId, processName); 263 | } 264 | -------------------------------------------------------------------------------- /netfilter/NFEventHandler.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "UDPContext.hpp" 4 | #include "base.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace TcpProxy 13 | { 14 | class TCPProxy; 15 | } 16 | 17 | namespace UdpProxy 18 | { 19 | class UDPProxy; 20 | } 21 | 22 | enum class PROTOCOL 23 | { 24 | TCP, 25 | UDP 26 | }; 27 | 28 | class EventHandler 29 | : public nfapi::NF_EventHandler 30 | , public UDPProxyHandler 31 | { 32 | struct ORIGINAL_CONN_INFO 33 | { 34 | unsigned char remoteAddress[NF_MAX_ADDRESS_LENGTH]; 35 | std::vector pendedSends; 36 | }; 37 | 38 | std::map m_connInfoMap; 39 | 40 | public: 41 | // cid, protocol, isOpening, local, remote, pid, fullpath 42 | typedef std::function logfunc; 43 | 44 | EventHandler(logfunc func); 45 | virtual ~EventHandler(); 46 | bool init(std::wstring address, std::string username, std::string password); 47 | void free(); 48 | 49 | // from UDPProxyHandler 50 | virtual void onUdpReceiveComplete(unsigned __int64 id, char *buf, int len, char *remoteAddress, int remoteAddressLen) override; 51 | 52 | virtual void threadStart() override{}; 53 | virtual void threadEnd() override{}; 54 | 55 | // 56 | // TCP events 57 | // 58 | virtual void tcpConnectRequest(nfapi::ENDPOINT_ID id, nfapi::PNF_TCP_CONN_INFO pConnInfo) override; 59 | virtual void tcpConnected(nfapi::ENDPOINT_ID id, nfapi::PNF_TCP_CONN_INFO pConnInfo) override; 60 | virtual void tcpClosed(nfapi::ENDPOINT_ID id, nfapi::PNF_TCP_CONN_INFO pConnInfo) override; 61 | virtual void tcpReceive(nfapi::ENDPOINT_ID id, const char *buf, int len) override; 62 | virtual void tcpSend(nfapi::ENDPOINT_ID id, const char *buf, int len) override; 63 | virtual void tcpCanReceive(nfapi::ENDPOINT_ID id) override; 64 | virtual void tcpCanSend(nfapi::ENDPOINT_ID id) override; 65 | 66 | // 67 | // UDP events 68 | // 69 | virtual void udpCreated(nfapi::ENDPOINT_ID id, nfapi::PNF_UDP_CONN_INFO pConnInfo) override; 70 | virtual void udpConnectRequest(nfapi::ENDPOINT_ID id, nfapi::PNF_UDP_CONN_REQUEST pConnReq) override; 71 | virtual void udpClosed(nfapi::ENDPOINT_ID id, nfapi::PNF_UDP_CONN_INFO pConnInfo) override; 72 | virtual void udpReceive(nfapi::ENDPOINT_ID id, const unsigned char *remoteAddr, const char *buf, int len, nfapi::PNF_UDP_OPTIONS opt) override; 73 | virtual void udpSend(nfapi::ENDPOINT_ID id, const unsigned char *remoteAddr, const char *buf, int len, nfapi::PNF_UDP_OPTIONS opt) override; 74 | virtual void udpCanReceive(nfapi::ENDPOINT_ID id) override; 75 | virtual void udpCanSend(nfapi::ENDPOINT_ID id) override; 76 | 77 | void LogTCP(bool connected, nfapi::ENDPOINT_ID id, nfapi::PNF_TCP_CONN_INFO pConnInfo); 78 | void LogUDP(bool created, nfapi::ENDPOINT_ID id, nfapi::PNF_UDP_CONN_INFO pConnInfo); 79 | 80 | private: 81 | logfunc doLog; 82 | 83 | private: 84 | // TcpProxy::TCPProxy *m_tcpProxy; 85 | UdpProxy::UDPProxy *m_udpProxy; 86 | std::map m_udpCtxMap; 87 | 88 | std::mutex lock; 89 | 90 | private: 91 | unsigned char g_proxyAddress[NF_MAX_ADDRESS_LENGTH]; 92 | std::string m_username; 93 | std::string m_password; 94 | }; 95 | -------------------------------------------------------------------------------- /netfilter/SOCKS.h: -------------------------------------------------------------------------------- 1 | // 2 | // NetFilterSDK 3 | // Copyright (C) Vitaly Sidorov 4 | // All rights reserved. 5 | // 6 | // This file is a part of the NetFilter SDK. 7 | // The code and information is provided "as-is" without 8 | // warranty of any kind, either expressed or implied. 9 | // 10 | 11 | #pragma once 12 | 13 | #pragma pack(push, 1) 14 | 15 | enum eSOCKS_VERSION 16 | { 17 | SOCKS_4 = 4, 18 | SOCKS_5 = 5 19 | }; 20 | 21 | enum eSOCKS4_COMMAND 22 | { 23 | S4C_CONNECT = 1, 24 | S4C_BIND = 2 25 | }; 26 | 27 | struct SOCKS4_REQUEST 28 | { 29 | char version; 30 | char command; 31 | unsigned short port; 32 | unsigned int ip; 33 | char userid[1]; 34 | }; 35 | 36 | enum eSOCKS4_RESCODE 37 | { 38 | S4RC_SUCCESS = 0x5a 39 | }; 40 | 41 | struct SOCKS4_RESPONSE 42 | { 43 | char reserved; 44 | char res_code; 45 | unsigned short port; 46 | unsigned int ip; 47 | }; 48 | 49 | enum eSOCKS5_COMMAND 50 | { 51 | S5C_AUTH = -1, 52 | S5C_CONNECT = 1, 53 | S5C_BIND = 2, 54 | S5C_UDP_ASSOCIATE = 3 55 | }; 56 | 57 | struct SOCKS5_AUTH_REQUEST 58 | { 59 | char version; 60 | unsigned char nmethods; 61 | unsigned char methods[1]; 62 | }; 63 | 64 | enum eSOCKS5_AUTH_METHOD 65 | { 66 | S5AM_NONE = 0, 67 | S5AM_GSSAPI = 1, 68 | S5AM_UNPW = 2 69 | }; 70 | 71 | struct SOCK5_AUTH_RESPONSE 72 | { 73 | char version; 74 | unsigned char method; 75 | }; 76 | 77 | enum eSOCKS5_ADDRESS_TYPE 78 | { 79 | SOCKS5_ADDR_IPV4 = 1, 80 | SOCKS5_ADDR_DOMAIN = 3, 81 | SOCKS5_ADDR_IPV6 = 4 82 | }; 83 | 84 | struct SOCKS5_REQUEST 85 | { 86 | char version; 87 | char command; 88 | char reserved; 89 | char address_type; 90 | char address[1]; 91 | }; 92 | 93 | struct SOCKS5_REQUEST_IPv4 94 | { 95 | char version; 96 | char command; 97 | char reserved; 98 | char address_type; 99 | unsigned int address; 100 | unsigned short port; 101 | }; 102 | 103 | struct SOCKS5_REQUEST_IPv6 104 | { 105 | char version; 106 | char command; 107 | char reserved; 108 | char address_type; 109 | char address[16]; 110 | unsigned short port; 111 | }; 112 | 113 | struct SOCKS5_RESPONSE 114 | { 115 | char version; 116 | char res_code; 117 | char reserved; 118 | char address_type; 119 | char address[1]; 120 | }; 121 | 122 | struct SOCKS5_RESPONSE_IPv4 123 | { 124 | char version; 125 | char res_code; 126 | char reserved; 127 | char address_type; 128 | unsigned int address; 129 | unsigned short port; 130 | }; 131 | 132 | struct SOCKS5_RESPONSE_IPv6 133 | { 134 | char version; 135 | char res_code; 136 | char reserved; 137 | char address_type; 138 | char address[16]; 139 | unsigned short port; 140 | }; 141 | 142 | struct SOCKS5_UDP_REQUEST 143 | { 144 | unsigned short reserved; 145 | char frag; 146 | char address_type; 147 | }; 148 | 149 | struct SOCKS5_UDP_REQUEST_IPv4 150 | { 151 | unsigned short reserved; 152 | char frag; 153 | char address_type; 154 | unsigned int address; 155 | unsigned short port; 156 | }; 157 | 158 | struct SOCKS5_UDP_REQUEST_IPv6 159 | { 160 | unsigned short reserved; 161 | char frag; 162 | char address_type; 163 | char address[16]; 164 | unsigned short port; 165 | }; 166 | 167 | union SOCKS45_REQUEST 168 | { 169 | SOCKS4_REQUEST socks4_req; 170 | SOCKS5_AUTH_REQUEST socks5_auth_req; 171 | SOCKS5_REQUEST socks5_req; 172 | }; 173 | 174 | #pragma pack(pop) 175 | -------------------------------------------------------------------------------- /netfilter/SocksRedirector.cpp: -------------------------------------------------------------------------------- 1 | #include "SocksRedirector.hpp" 2 | 3 | #include "NFEventHandler.hpp" 4 | 5 | // Change this string after renaming and registering the driver under different name 6 | #define NFDRIVER_NAME "netfilter2" 7 | 8 | NetFilterCore::NetFilterCore() 9 | { 10 | eh = new EventHandler(std::function{ [this](size_t c, PROTOCOL p, bool o, std::wstring l, std::wstring r, int pid, std::wstring path) { 11 | QString protocol; 12 | switch (p) 13 | { 14 | case PROTOCOL::TCP: protocol = "TCP"; break; 15 | case PROTOCOL::UDP: protocol = "UDP"; break; 16 | default: break; 17 | } 18 | emit OnLogMessageReady(c, protocol, o, QString::fromStdWString(l), QString::fromStdWString(r), pid, QString::fromStdWString(path)); 19 | } }); 20 | wsaData = new WSADATA; 21 | WSAStartup(MAKEWORD(2, 2), wsaData); 22 | } 23 | 24 | NetFilterCore::~NetFilterCore() 25 | { 26 | WSACleanup(); 27 | delete eh; 28 | } 29 | 30 | void NetFilterCore::Stop() 31 | { 32 | eh->free(); 33 | nfapi::nf_free(); 34 | } 35 | 36 | bool NetFilterCore::Start(const FilterRules &rules, const QString &address, int port, const QString &username, const QString &password) 37 | { 38 | const auto fullAddr = address + ":" + QString::number(port); 39 | 40 | if (!eh->init(fullAddr.toStdWString(), username.toStdString(), password.toStdString())) 41 | { 42 | printf("Failed to initialize the event handler"); 43 | return false; 44 | } 45 | 46 | // Initialize the library and start filtering thread 47 | if (nf_init(NFDRIVER_NAME, eh) != NF_STATUS_SUCCESS) 48 | { 49 | printf("Failed to connect to driver"); 50 | return false; 51 | } 52 | 53 | #define ADD_PRIVATE_IPV4_ADDRESS(addr, mask) \ 54 | { \ 55 | nfapi::NF_RULE rule; \ 56 | memset(&rule, 0, sizeof(rule)); \ 57 | rule.filteringFlag = nfapi::NF_ALLOW; \ 58 | rule.ip_family = AF_INET; \ 59 | inet_pton(AF_INET, addr, &rule.remoteIpAddress); \ 60 | inet_pton(AF_INET, mask, &rule.remoteIpAddressMask); \ 61 | nf_addRule(&rule, FALSE); \ 62 | } 63 | 64 | ADD_PRIVATE_IPV4_ADDRESS("10.0.0.1", "255.0.0.0") 65 | ADD_PRIVATE_IPV4_ADDRESS("127.0.0.1", "255.0.0.0") 66 | ADD_PRIVATE_IPV4_ADDRESS("172.16.0.1", "255.240.0.0") 67 | ADD_PRIVATE_IPV4_ADDRESS("192.168.0.1", "255.255.0.0") 68 | ADD_PRIVATE_IPV4_ADDRESS("224.0.0.1", "240.0.0.0") 69 | 70 | { 71 | nfapi::NF_RULE rule; 72 | memset(&rule, 0, sizeof(rule)); 73 | rule.filteringFlag = nfapi::NF_ALLOW; 74 | rule.ip_family = AF_INET6; 75 | rule.remoteIpAddress[15] = 1; 76 | nf_addRule(&rule, FALSE); 77 | } 78 | 79 | { 80 | nfapi::NF_RULE rule; 81 | memset(&rule, 0, sizeof(rule)); 82 | rule.filteringFlag = nfapi::NF_ALLOW; 83 | rule.ip_family = AF_INET6; 84 | inet_pton(AF_INET, "::ffff:127.0.0.1", &rule.remoteIpAddress); 85 | nf_addRule(&rule, FALSE); 86 | } 87 | 88 | for (const auto &rule : rules) 89 | { 90 | nfapi::NF_RULE_EX ruleEx; 91 | memset(&ruleEx, 0, sizeof(ruleEx)); 92 | ruleEx.filteringFlag = nfapi::NF_ALLOW; 93 | 94 | if (rule.portTo != 0) 95 | { 96 | ruleEx.remotePortRange.valueLow = rule.portFrom; 97 | ruleEx.remotePortRange.valueHigh = rule.portTo; 98 | } 99 | else if (rule.portFrom != 0) 100 | { 101 | ruleEx.remotePort = rule.portFrom; 102 | } 103 | 104 | if (rule.networkType != NETWORK_UNSPECIFIED) 105 | ruleEx.protocol = rule.networkType; 106 | 107 | if (!rule.processName->isEmpty()) 108 | wcsncpy((wchar_t *) ruleEx.processName, rule.processName->toStdWString().c_str(), MAX_PATH); 109 | 110 | nf_addRuleEx(&ruleEx, TRUE); 111 | } 112 | 113 | // Proxy All 114 | { 115 | nfapi::NF_RULE_EX ruleEx; 116 | memset(&ruleEx, 0, sizeof(ruleEx)); 117 | ruleEx.protocol = IPPROTO_TCP; 118 | ruleEx.filteringFlag = nfapi::NF_INDICATE_CONNECT_REQUESTS; 119 | nf_addRuleEx(&ruleEx, FALSE); 120 | 121 | // Filter UDP packets 122 | memset(&ruleEx, 0, sizeof(ruleEx)); 123 | ruleEx.protocol = IPPROTO_UDP; 124 | ruleEx.filteringFlag = nfapi::NF_FILTER; 125 | nf_addRuleEx(&ruleEx, FALSE); 126 | } 127 | return true; 128 | } 129 | -------------------------------------------------------------------------------- /netfilter/SocksRedirector.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "core/Settings.hpp" 4 | 5 | #include 6 | 7 | class EventHandler; 8 | struct WSAData; 9 | 10 | class NetFilterCore : public QObject 11 | { 12 | Q_OBJECT 13 | public: 14 | NetFilterCore(); 15 | bool Start(const FilterRules &rules, const QString &address, int port, const QString &username = "", const QString &password = ""); 16 | void Stop(); 17 | virtual ~NetFilterCore(); 18 | 19 | signals: 20 | void OnLogMessageReady(size_t cid, QString protocol, bool isOpen, QString local, QString remote, int pid, QString path); 21 | 22 | private: 23 | EventHandler *eh; 24 | WSAData *wsaData; 25 | }; 26 | -------------------------------------------------------------------------------- /netfilter/UDPContext.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "base.h" 3 | 4 | struct UDPContext 5 | { 6 | UDPContext(nfapi::PNF_UDP_OPTIONS options) 7 | { 8 | if (options) 9 | { 10 | m_options = (nfapi::PNF_UDP_OPTIONS) new char[sizeof(nfapi::NF_UDP_OPTIONS) + options->optionsLength]; 11 | memcpy(m_options, options, sizeof(nfapi::NF_UDP_OPTIONS) + options->optionsLength - 1); 12 | } 13 | else 14 | { 15 | m_options = NULL; 16 | } 17 | } 18 | ~UDPContext() 19 | { 20 | if (m_options) 21 | { 22 | delete[] m_options; 23 | m_options = NULL; 24 | } 25 | } 26 | 27 | nfapi::PNF_UDP_OPTIONS m_options; 28 | }; 29 | 30 | class UDPProxyHandler 31 | { 32 | public: 33 | virtual void onUdpReceiveComplete(unsigned __int64 id, char *buf, int len, char *remoteAddress, int remoteAddressLen) = 0; 34 | }; 35 | -------------------------------------------------------------------------------- /netfilter/UDPProxy.cpp: -------------------------------------------------------------------------------- 1 | #include "UdpProxy.h" 2 | 3 | using namespace UdpProxy; 4 | 5 | void UDPProxy::onComplete(SOCKET socket, DWORD dwTransferred, OVERLAPPED *pOverlapped, int error) 6 | { 7 | OV_DATA *pov = (OV_DATA *) pOverlapped; 8 | 9 | switch (pov->type) 10 | { 11 | case OVT_UDP_SEND: onUdpSendComplete(socket, dwTransferred, pov, error); break; 12 | case OVT_UDP_RECEIVE: onUdpReceiveComplete(socket, dwTransferred, pov, error); break; 13 | case OVT_CONNECT: onConnectComplete(socket, dwTransferred, pov, error); break; 14 | case OVT_TCP_SEND: onTcpSendComplete(socket, dwTransferred, pov, error); break; 15 | case OVT_TCP_RECEIVE: onTcpReceiveComplete(socket, dwTransferred, pov, error); break; 16 | } 17 | } 18 | 19 | void UDPProxy::onTcpReceiveComplete(SOCKET socket, DWORD dwTransferred, OV_DATA *pov, int error) 20 | { 21 | // DbgPrint("UDPProxy::onTcpReceiveComplete %I64u bytes=%d, err=%d", pov->id, dwTransferred, error); 22 | 23 | if (dwTransferred == 0) 24 | { 25 | deleteOV_DATA(pov); 26 | return; 27 | } 28 | 29 | { 30 | AutoLock lock(m_cs); 31 | 32 | auto it = m_socketMap.find(pov->id); 33 | if (it != m_socketMap.end()) 34 | { 35 | switch (it->second->proxyState) 36 | { 37 | case PS_NONE: break; 38 | 39 | case PS_AUTH: 40 | { 41 | if (dwTransferred < sizeof(SOCK5_AUTH_RESPONSE)) 42 | break; 43 | 44 | SOCK5_AUTH_RESPONSE *pr = (SOCK5_AUTH_RESPONSE *) &pov->buffer[0]; 45 | 46 | if (pr->version != SOCKS_5) 47 | { 48 | break; 49 | } 50 | 51 | if (pr->method == S5AM_UNPW && !it->second->userName.empty()) 52 | { 53 | std::vector authReq; 54 | 55 | authReq.push_back(1); 56 | authReq.push_back((char) it->second->userName.length()); 57 | authReq.insert(authReq.end(), it->second->userName.begin(), it->second->userName.end()); 58 | authReq.push_back((char) it->second->userPassword.length()); 59 | 60 | if (!it->second->userPassword.empty()) 61 | authReq.insert(authReq.end(), it->second->userPassword.begin(), it->second->userPassword.end()); 62 | 63 | if (startTcpSend(it->second->tcpSocket, (char *) &authReq[0], (int) authReq.size(), pov->id)) 64 | { 65 | it->second->proxyState = PS_AUTH_NEGOTIATION; 66 | } 67 | 68 | break; 69 | } 70 | 71 | SOCKS5_REQUEST_IPv4 req; 72 | 73 | req.version = SOCKS_5; 74 | req.command = S5C_UDP_ASSOCIATE; 75 | req.reserved = 0; 76 | req.address_type = SOCKS5_ADDR_IPV4; 77 | req.address = 0; 78 | req.port = 0; 79 | 80 | if (startTcpSend(it->second->tcpSocket, (char *) &req, sizeof(req), pov->id)) 81 | { 82 | it->second->proxyState = PS_UDP_ASSOC; 83 | } 84 | } 85 | break; 86 | 87 | case PS_AUTH_NEGOTIATION: 88 | { 89 | if (dwTransferred < sizeof(SOCK5_AUTH_RESPONSE)) 90 | break; 91 | 92 | SOCK5_AUTH_RESPONSE *pr = (SOCK5_AUTH_RESPONSE *) &pov->buffer[0]; 93 | 94 | if (pr->version != 0x01 || pr->method != 0x00) 95 | { 96 | break; 97 | } 98 | 99 | SOCKS5_REQUEST_IPv4 req; 100 | 101 | req.version = SOCKS_5; 102 | req.command = S5C_UDP_ASSOCIATE; 103 | req.reserved = 0; 104 | req.address_type = SOCKS5_ADDR_IPV4; 105 | req.address = 0; 106 | req.port = 0; 107 | 108 | if (startTcpSend(it->second->tcpSocket, (char *) &req, sizeof(req), pov->id)) 109 | { 110 | it->second->proxyState = PS_UDP_ASSOC; 111 | } 112 | } 113 | break; 114 | 115 | case PS_UDP_ASSOC: 116 | { 117 | if (dwTransferred < sizeof(SOCKS5_RESPONSE)) 118 | break; 119 | 120 | SOCKS5_RESPONSE *pr = (SOCKS5_RESPONSE *) &pov->buffer[0]; 121 | 122 | if (pr->version != SOCKS_5 || pr->res_code != 0) 123 | break; 124 | 125 | if (pr->address_type == SOCKS5_ADDR_IPV4) 126 | { 127 | SOCKS5_RESPONSE_IPv4 *prIPv4 = (SOCKS5_RESPONSE_IPv4 *) &pov->buffer[0]; 128 | sockaddr_in addr; 129 | memset(&addr, 0, sizeof(addr)); 130 | addr.sin_family = AF_INET; 131 | addr.sin_addr.S_un.S_addr = ((sockaddr_in *) m_proxyAddress)->sin_addr.S_un.S_addr; 132 | addr.sin_port = prIPv4->port; 133 | 134 | memcpy(it->second->remoteAddress, &addr, sizeof(addr)); 135 | it->second->remoteAddressLen = sizeof(addr); 136 | } 137 | else if (pr->address_type == SOCKS5_ADDR_IPV6) 138 | { 139 | SOCKS5_RESPONSE_IPv6 *prIPv6 = (SOCKS5_RESPONSE_IPv6 *) &pov->buffer[0]; 140 | sockaddr_in6 addr; 141 | memset(&addr, 0, sizeof(addr)); 142 | addr.sin6_family = AF_INET6; 143 | memcpy(&addr.sin6_addr, &((sockaddr_in6 *) m_proxyAddress)->sin6_addr, 16); 144 | addr.sin6_port = prIPv6->port; 145 | 146 | memcpy(it->second->remoteAddress, &addr, sizeof(addr)); 147 | it->second->remoteAddressLen = sizeof(addr); 148 | } 149 | else 150 | { 151 | break; 152 | } 153 | 154 | it->second->proxyState = PS_CONNECTED; 155 | 156 | while (!it->second->udpSendPackets.empty()) 157 | { 158 | tPacketList::iterator itp = it->second->udpSendPackets.begin(); 159 | 160 | udpSend(pov->id, &(*itp)->buffer[0], (int) (*itp)->buffer.size(), (*itp)->remoteAddress, (*itp)->remoteAddressLen); 161 | 162 | delete (*itp); 163 | it->second->udpSendPackets.erase(itp); 164 | } 165 | } 166 | break; 167 | 168 | default: break; 169 | } 170 | } 171 | } 172 | 173 | memset(&pov->ol, 0, sizeof(pov->ol)); 174 | startTcpReceive(socket, pov->id, pov); 175 | } 176 | 177 | void UDPProxy::onTcpSendComplete(SOCKET socket, DWORD dwTransferred, OV_DATA *pov, int error) 178 | { 179 | deleteOV_DATA(pov); 180 | } 181 | 182 | void UDPProxy::onConnectComplete(SOCKET socket, DWORD dwTransferred, OV_DATA *pov, int error) 183 | { 184 | if (error != 0) 185 | { 186 | deleteProxyConnection(pov->id); 187 | deleteOV_DATA(pov); 188 | return; 189 | } 190 | 191 | AutoLock lock(m_cs); 192 | 193 | auto it = m_socketMap.find(pov->id); 194 | if (it != m_socketMap.end()) 195 | { 196 | BOOL val = 1; 197 | setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char *) &val, sizeof(val)); 198 | setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, (char *) &val, sizeof(val)); 199 | 200 | SOCKS5_AUTH_REQUEST authReq; 201 | authReq.version = SOCKS_5; 202 | authReq.nmethods = 1; 203 | authReq.methods[0] = it->second->userName.empty() ? S5AM_NONE : S5AM_UNPW; 204 | 205 | if (startTcpSend(it->second->tcpSocket, (char *) &authReq, sizeof(authReq), pov->id)) 206 | { 207 | it->second->proxyState = PS_AUTH; 208 | } 209 | 210 | startTcpReceive(it->second->tcpSocket, pov->id, NULL); 211 | } 212 | 213 | deleteOV_DATA(pov); 214 | } 215 | 216 | void UDPProxy::onUdpReceiveComplete(SOCKET socket, DWORD dwTransferred, OV_DATA *pov, int error) 217 | { 218 | // DbgPrint("UDPProxy::onUdpReceiveComplete %I64u bytes=%d, err=%d", pov->id, dwTransferred, error); 219 | 220 | if (dwTransferred == 0) 221 | { 222 | deleteOV_DATA(pov); 223 | return; 224 | } 225 | 226 | if (dwTransferred > sizeof(SOCKS5_UDP_REQUEST)) 227 | { 228 | SOCKS5_UDP_REQUEST *pReq = (SOCKS5_UDP_REQUEST *) &pov->buffer[0]; 229 | if (pReq->address_type == SOCKS5_ADDR_IPV4) 230 | { 231 | const auto pReqIPv4 = (SOCKS5_UDP_REQUEST_IPv4 *) &pov->buffer[0]; 232 | 233 | sockaddr_in addr; 234 | memset(&addr, 0, sizeof(addr)); 235 | addr.sin_family = AF_INET; 236 | addr.sin_addr.S_un.S_addr = pReqIPv4->address; 237 | addr.sin_port = pReqIPv4->port; 238 | 239 | constexpr auto size = sizeof(SOCKS5_UDP_REQUEST_IPv4); 240 | m_pProxyHandler->onUdpReceiveComplete(pov->id, &pov->buffer[size], dwTransferred - size, (char *) &addr, sizeof(addr)); 241 | } 242 | else if (pReq->address_type == SOCKS5_ADDR_IPV6) 243 | { 244 | const auto pReqIPv6 = (SOCKS5_UDP_REQUEST_IPv6 *) &pov->buffer[0]; 245 | 246 | sockaddr_in6 addr; 247 | memset(&addr, 0, sizeof(addr)); 248 | addr.sin6_family = AF_INET6; 249 | memcpy(&addr.sin6_addr, pReqIPv6->address, 16); 250 | addr.sin6_port = pReqIPv6->port; 251 | 252 | constexpr auto size = sizeof(SOCKS5_UDP_REQUEST_IPv6); 253 | m_pProxyHandler->onUdpReceiveComplete(pov->id, &pov->buffer[size], dwTransferred - size, (char *) &addr, sizeof(addr)); 254 | } 255 | } 256 | 257 | memset(&pov->ol, 0, sizeof(pov->ol)); 258 | startUdpReceive(socket, pov->id, pov); 259 | } 260 | 261 | void *UDPProxy::getExtensionFunction(SOCKET s, const GUID *which_fn) 262 | { 263 | void *ptr = NULL; 264 | DWORD bytes = 0; 265 | WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, (GUID *) which_fn, sizeof(*which_fn), &ptr, sizeof(ptr), &bytes, NULL, NULL); 266 | return ptr; 267 | } 268 | 269 | bool UDPProxy::initExtensions() 270 | { 271 | const GUID connectex = WSAID_CONNECTEX; 272 | 273 | SOCKET s = socket(AF_INET, SOCK_STREAM, 0); 274 | if (s == INVALID_SOCKET) 275 | return false; 276 | 277 | m_pConnectEx = (LPFN_CONNECTEX) getExtensionFunction(s, &connectex); 278 | 279 | closesocket(s); 280 | 281 | return m_pConnectEx != NULL; 282 | } 283 | 284 | bool UDPProxy::init(UDPProxyHandler *pProxyHandler, const char *proxyAddress, int proxyAddressLen, const std::string &user, const std::string &pass) 285 | { 286 | if (!initExtensions()) 287 | return false; 288 | 289 | if (!m_service.init(this)) 290 | return false; 291 | 292 | m_pProxyHandler = pProxyHandler; 293 | memcpy(m_proxyAddress, proxyAddress, proxyAddressLen); 294 | m_proxyAddressLen = proxyAddressLen; 295 | m_userName = user; 296 | m_userPassword = pass; 297 | 298 | return true; 299 | } 300 | 301 | void UDPProxy::free() 302 | { 303 | m_service.free(); 304 | while (!m_ovDataSet.empty()) 305 | { 306 | auto it = m_ovDataSet.begin(); 307 | delete (*it); 308 | m_ovDataSet.erase(it); 309 | } 310 | while (!m_socketMap.empty()) 311 | { 312 | auto it = m_socketMap.begin(); 313 | delete it->second; 314 | m_socketMap.erase(it); 315 | } 316 | } 317 | 318 | bool UDPProxy::createProxyConnection(unsigned long long id) 319 | { 320 | bool result = false; 321 | 322 | // DbgPrint("UDPProxy::createProxyConnection %I64u", id); 323 | 324 | for (;;) 325 | { 326 | SOCKET tcpSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); 327 | if (tcpSocket == INVALID_SOCKET) 328 | return false; 329 | 330 | SOCKET udpSocket = WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, WSA_FLAG_OVERLAPPED); 331 | if (udpSocket == INVALID_SOCKET) 332 | { 333 | closesocket(tcpSocket); 334 | return false; 335 | } 336 | 337 | { 338 | AutoLock lock(m_cs); 339 | PROXY_DATA *pd = new PROXY_DATA(); 340 | pd->tcpSocket = tcpSocket; 341 | pd->udpSocket = udpSocket; 342 | pd->userName = m_userName; 343 | pd->userPassword = m_userPassword; 344 | m_socketMap[id] = pd; 345 | } 346 | 347 | if (!m_service.registerSocket(tcpSocket)) 348 | break; 349 | 350 | if (!m_service.registerSocket(udpSocket)) 351 | break; 352 | 353 | if (!startConnect(tcpSocket, (sockaddr *) m_proxyAddress, m_proxyAddressLen, id)) 354 | break; 355 | 356 | result = true; 357 | 358 | break; 359 | } 360 | 361 | if (!result) 362 | { 363 | AutoLock lock(m_cs); 364 | 365 | auto it = m_socketMap.find(id); 366 | if (it != m_socketMap.end()) 367 | { 368 | delete it->second; 369 | m_socketMap.erase(it); 370 | } 371 | } 372 | 373 | return result; 374 | } 375 | 376 | void UDPProxy::deleteProxyConnection(unsigned long long id) 377 | { 378 | // DbgPrint("UDPProxy::deleteProxyConnection %I64u", id); 379 | 380 | AutoLock lock(m_cs); 381 | auto it = m_socketMap.find(id); 382 | if (it != m_socketMap.end()) 383 | { 384 | delete it->second; 385 | m_socketMap.erase(it); 386 | } 387 | } 388 | 389 | bool UDPProxy::udpSend(unsigned long long id, char *buf, int len, char *remoteAddress, int remoteAddressLen) 390 | { 391 | SOCKET s; 392 | 393 | // DbgPrint("udpSend %I64u", id); 394 | 395 | { 396 | AutoLock lock(m_cs); 397 | 398 | auto it = m_socketMap.find(id); 399 | if (it == m_socketMap.end()) 400 | { 401 | return false; 402 | } 403 | 404 | if (it->second->proxyState != PS_CONNECTED) 405 | { 406 | if (len > 0) 407 | { 408 | UDP_PACKET *p = new UDP_PACKET(); 409 | memcpy(p->remoteAddress, remoteAddress, remoteAddressLen); 410 | p->remoteAddressLen = remoteAddressLen; 411 | p->buffer.resize(len); 412 | memcpy(&p->buffer[0], buf, len); 413 | it->second->udpSendPackets.push_back(p); 414 | } 415 | return true; 416 | } 417 | 418 | s = it->second->udpSocket; 419 | 420 | OV_DATA *pov = newOV_DATA(); 421 | DWORD dwBytes; 422 | 423 | pov->type = OVT_UDP_SEND; 424 | pov->id = id; 425 | 426 | if (len > 0) 427 | { 428 | if (((sockaddr *) remoteAddress)->sa_family == AF_INET) 429 | { 430 | pov->buffer.resize(len + sizeof(SOCKS5_UDP_REQUEST_IPv4)); 431 | 432 | SOCKS5_UDP_REQUEST_IPv4 *pReq = (SOCKS5_UDP_REQUEST_IPv4 *) &pov->buffer[0]; 433 | pReq->reserved = 0; 434 | pReq->frag = 0; 435 | pReq->address_type = SOCKS5_ADDR_IPV4; 436 | pReq->address = ((sockaddr_in *) remoteAddress)->sin_addr.S_un.S_addr; 437 | pReq->port = ((sockaddr_in *) remoteAddress)->sin_port; 438 | 439 | memcpy(&pov->buffer[sizeof(SOCKS5_UDP_REQUEST_IPv4)], buf, len); 440 | } 441 | else 442 | { 443 | pov->buffer.resize(len + sizeof(SOCKS5_UDP_REQUEST_IPv6)); 444 | 445 | SOCKS5_UDP_REQUEST_IPv6 *pReq = (SOCKS5_UDP_REQUEST_IPv6 *) &pov->buffer[0]; 446 | pReq->reserved = 0; 447 | pReq->frag = 0; 448 | pReq->address_type = SOCKS5_ADDR_IPV6; 449 | memcpy(pReq->address, &((sockaddr_in6 *) remoteAddress)->sin6_addr, 16); 450 | pReq->port = ((sockaddr_in6 *) remoteAddress)->sin6_port; 451 | 452 | memcpy(&pov->buffer[sizeof(SOCKS5_UDP_REQUEST_IPv6)], buf, len); 453 | } 454 | } 455 | 456 | WSABUF bufs; 457 | 458 | bufs.buf = &pov->buffer[0]; 459 | bufs.len = (u_long) pov->buffer.size(); 460 | 461 | if (WSASendTo(s, &bufs, 1, &dwBytes, 0, (sockaddr *) it->second->remoteAddress, it->second->remoteAddressLen, &pov->ol, NULL) != 0) 462 | { 463 | int err = WSAGetLastError(); 464 | if (err != ERROR_IO_PENDING) 465 | { 466 | pov->type = OVT_UDP_RECEIVE; 467 | pov->buffer.clear(); 468 | if (!m_service.postCompletion(s, 0, &pov->ol)) 469 | deleteOV_DATA(pov); 470 | return false; 471 | } 472 | } 473 | 474 | if (!it->second->udpRecvStarted) 475 | { 476 | it->second->udpRecvStarted = true; 477 | startUdpReceive(s, id, NULL); 478 | } 479 | } 480 | 481 | return true; 482 | } 483 | 484 | OV_DATA *UDPProxy::newOV_DATA() 485 | { 486 | OV_DATA *pov = new OV_DATA(); 487 | AutoLock lock(m_cs); 488 | m_ovDataSet.insert(pov); 489 | return pov; 490 | } 491 | 492 | void UDPProxy::deleteOV_DATA(OV_DATA *pov) 493 | { 494 | AutoLock lock(m_cs); 495 | auto it = m_ovDataSet.find(pov); 496 | if (it == m_ovDataSet.end()) 497 | return; 498 | m_ovDataSet.erase(it); 499 | delete pov; 500 | } 501 | 502 | bool UDPProxy::startConnect(SOCKET socket, sockaddr *pAddr, int addrLen, unsigned long long id) 503 | { 504 | OV_DATA *pov = newOV_DATA(); 505 | pov->type = OVT_CONNECT; 506 | pov->id = id; 507 | 508 | // DbgPrint("UDPProxy::startConnect %I64u, socket=%d", id, socket); 509 | 510 | { 511 | struct sockaddr_in addr; 512 | ZeroMemory(&addr, sizeof(addr)); 513 | addr.sin_family = AF_INET; 514 | addr.sin_addr.s_addr = INADDR_ANY; 515 | addr.sin_port = 0; 516 | 517 | bind(socket, (SOCKADDR *) &addr, sizeof(addr)); 518 | } 519 | 520 | if (!m_pConnectEx(socket, pAddr, addrLen, NULL, 0, NULL, &pov->ol)) 521 | { 522 | int err = WSAGetLastError(); 523 | if (err != ERROR_IO_PENDING) 524 | { 525 | // DbgPrint("UDPProxy::startConnect %I64u failed, err=%d", id, err); 526 | deleteOV_DATA(pov); 527 | return false; 528 | } 529 | } 530 | 531 | return true; 532 | } 533 | 534 | bool UDPProxy::startUdpReceive(SOCKET socket, unsigned long long id, OV_DATA *pov) 535 | { 536 | DWORD dwBytes, dwFlags; 537 | WSABUF bufs; 538 | 539 | if (pov == NULL) 540 | { 541 | pov = newOV_DATA(); 542 | pov->type = OVT_UDP_RECEIVE; 543 | pov->id = id; 544 | pov->buffer.resize(PACKET_SIZE); 545 | } 546 | 547 | bufs.buf = &pov->buffer[0]; 548 | bufs.len = (u_long) pov->buffer.size(); 549 | 550 | dwFlags = 0; 551 | 552 | pov->remoteAddressLen = sizeof(pov->remoteAddress); 553 | 554 | if (WSARecvFrom(socket, &bufs, 1, &dwBytes, &dwFlags, (sockaddr *) pov->remoteAddress, &pov->remoteAddressLen, &pov->ol, NULL) != 0) 555 | if (WSAGetLastError() != ERROR_IO_PENDING) 556 | if (!m_service.postCompletion(socket, 0, &pov->ol)) 557 | deleteOV_DATA(pov); 558 | 559 | return true; 560 | } 561 | 562 | bool UDPProxy::startTcpReceive(SOCKET socket, unsigned long long id, OV_DATA *pov) 563 | { 564 | if (pov == nullptr) 565 | { 566 | pov = newOV_DATA(); 567 | pov->type = OVT_TCP_RECEIVE; 568 | pov->id = id; 569 | pov->buffer.resize(PACKET_SIZE); 570 | } 571 | 572 | WSABUF bufs; 573 | bufs.buf = &pov->buffer[0]; 574 | bufs.len = (u_long) pov->buffer.size(); 575 | 576 | DWORD dwBytes = 0, dwFlags = 0; 577 | if (WSARecv(socket, &bufs, 1, &dwBytes, &dwFlags, &pov->ol, NULL) != 0) 578 | if (WSAGetLastError() != ERROR_IO_PENDING) 579 | if (!m_service.postCompletion(socket, 0, &pov->ol)) 580 | deleteOV_DATA(pov); 581 | 582 | return true; 583 | } 584 | 585 | bool UDPProxy::startTcpSend(SOCKET socket, char *buf, int len, unsigned long long id) 586 | { 587 | OV_DATA *pov = newOV_DATA(); 588 | DWORD dwBytes; 589 | 590 | pov->id = id; 591 | pov->type = OVT_TCP_SEND; 592 | 593 | if (len > 0) 594 | { 595 | pov->buffer.resize(len); 596 | memcpy(&pov->buffer[0], buf, len); 597 | } 598 | 599 | WSABUF bufs; 600 | 601 | bufs.buf = &pov->buffer[0]; 602 | bufs.len = (u_long) pov->buffer.size(); 603 | 604 | if (WSASend(socket, &bufs, 1, &dwBytes, 0, &pov->ol, NULL) != 0) 605 | { 606 | int err = WSAGetLastError(); 607 | if (err != ERROR_IO_PENDING) 608 | { 609 | // DbgPrint("UDPProxy::startTcpSend %I64u failed, err=%d", id, err); 610 | pov->type = OVT_TCP_RECEIVE; 611 | pov->buffer.clear(); 612 | if (!m_service.postCompletion(socket, 0, &pov->ol)) 613 | { 614 | deleteOV_DATA(pov); 615 | } 616 | return false; 617 | } 618 | } 619 | 620 | return true; 621 | } 622 | 623 | void UDPProxy::onUdpSendComplete(SOCKET socket, DWORD dwTransferred, OV_DATA *pov, int error) 624 | { 625 | deleteOV_DATA(pov); 626 | } 627 | -------------------------------------------------------------------------------- /netfilter/UTF-8.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | inline void encodeUTF8Char(std::string &str, wchar_t character) 5 | { 6 | unsigned int c = (unsigned int) character; 7 | 8 | // check for invalid chars 9 | if ((c >= 0xD800 && c <= 0xDFFF) || c == 0xFFFF || c == 0xFFFE || c >= 0x80000000) 10 | { 11 | // check for invalid sequence 12 | // NOTE 3 - Values of x in the range 0000 D800 .. 0000 DFFF 13 | // are reserved for the UTF-16 form and do not occur in UCS-4. 14 | // The values 0000 FFFE and 0000 FFFF also do not occur (see clause 8). 15 | // The mappings of these code positions in UTF-8 are undefined. 16 | c = 0xFFFD; 17 | } 18 | 19 | if (c < 0x80) 20 | { 21 | // x = 0000 0000 .. 0000 007F; x; 22 | str += (char) c; 23 | } 24 | else if (c < 0x800) 25 | { 26 | // x = 0000 0080 .. 0000 07FF; C0 + x/2**6; 27 | // 80 + x%2**6; 28 | str += (char) (0xC0 + (c >> 6)); 29 | str += (char) (0x80 + (c & 0x3F)); 30 | } 31 | // catch 16bit wchar_t here 32 | // anything after this is 32bit wchar_t 33 | else if (sizeof(wchar_t) == 2 || c < 0x10000) 34 | { 35 | // x = 0000 0800 .. 0000 FFFF; E0 + x/2**12; 36 | // 80 + x/2**6%2**6; 37 | // 80 + x%2**6; 38 | str += (char) (0xE0 + (c >> 12)); 39 | str += (char) (0x80 + ((c >> 6) & 0x3F)); 40 | str += (char) (0x80 + (c & 0x3F)); 41 | } 42 | else if (c < 0x200000) 43 | { 44 | // x = 0001 0000 .. 001F FFFF; F0 + x/2**18; 45 | // 80 + x/2**12%2**6; 46 | // 80 + x/2**6%2**6; 47 | // 80 + x%2**6; 48 | str += (char) (0xF0 + (c >> 18)); 49 | str += (char) (0x80 + ((c >> 12) & 0x3F)); 50 | str += (char) (0x80 + ((c >> 6) & 0x3F)); 51 | str += (char) (0x80 + (c & 0x3F)); 52 | } 53 | else if (c < 0x4000000) 54 | { 55 | // x = 0020 0000 .. 03FF FFFF; F8 + x/2**24; 56 | // 80 + x/2**18%2**6; 57 | // 80 + x/2**12%2**6; 58 | // 80 + x/2**6%2**6; 59 | // 80 + x%2**6; 60 | str += (char) (0xF8 + (c >> 24)); 61 | str += (char) (0x80 + ((c >> 18) & 0x3F)); 62 | str += (char) (0x80 + ((c >> 12) & 0x3F)); 63 | str += (char) (0x80 + ((c >> 6) & 0x3F)); 64 | str += (char) (0x80 + (c & 0x3F)); 65 | } 66 | else // if (c<0x80000000) 67 | { 68 | // x = 0400 0000 .. 7FFF FFFF; FC + x/2**30; 69 | // 80 + x/2**24%2**6; 70 | // 80 + x/2**18%2**6; 71 | // 80 + x/2**12%2**6; 72 | // 80 + x/2**6%2**6; 73 | // 80 + x%2**6; 74 | str += (char) (0xFC + (c >> 30)); 75 | str += (char) (0x80 + ((c >> 24) & 0x3F)); 76 | str += (char) (0x80 + ((c >> 18) & 0x3F)); 77 | str += (char) (0x80 + ((c >> 12) & 0x3F)); 78 | str += (char) (0x80 + ((c >> 6) & 0x3F)); 79 | str += (char) (0x80 + (c & 0x3F)); 80 | } 81 | } 82 | 83 | inline std::string encodeUTF8(const std::wstring &source) 84 | { 85 | std::string result; 86 | result.reserve(source.size() * 4 / 3); // optimization 87 | 88 | for (std::wstring::const_iterator it = source.begin(); it != source.end(); ++it) 89 | { 90 | encodeUTF8Char(result, (unsigned int) *it); 91 | } 92 | 93 | return result; 94 | } 95 | 96 | constexpr auto REPLACEMENT_CHAR = 0xFFFD; 97 | 98 | inline std::wstring decodeUTF8(const std::string &source) 99 | { 100 | unsigned int start = 0; 101 | 102 | std::wstring result; 103 | result.reserve(source.size()); 104 | 105 | for (unsigned int i = start; i < source.length(); i++) 106 | { 107 | unsigned char c = source[i]; 108 | 109 | wchar_t n; 110 | 111 | if (c != 0xFF && c != 0xFE) 112 | { 113 | int remainingBytes = (int) source.length() - i; 114 | int extraBytesForChar = -1; 115 | 116 | // check that character isn't a continuation byte 117 | if ((c >> 6) != 2) 118 | { 119 | // work out how many bytes the sequence is. 120 | // Bytes in sequence is equal to the number 121 | // 1 bits before the first 0. 122 | // e.g. 11100101 -> [1110] -> 3 123 | // 11110101 -> [11110] -> 4 124 | unsigned char d = c; 125 | 126 | // LHS contains sequence length. 127 | // RHS contains data. 128 | // dataMask is used to extract data. 129 | int dataMask = 0x7F; 130 | 131 | // Find sequence length 132 | while ((d & 0x80) != 0) 133 | { 134 | dataMask >>= 1; 135 | extraBytesForChar++; 136 | d <<= 1; 137 | } 138 | 139 | n = c & dataMask; 140 | 141 | // if there aren't enough bytes in the encoded sequence. 142 | if (extraBytesForChar > remainingBytes) 143 | { 144 | n = REPLACEMENT_CHAR; 145 | } 146 | else 147 | // decode sequence. 148 | for (int j = 0; j < extraBytesForChar; j++) 149 | { 150 | // update index & get continuation byte. 151 | c = source[++i]; 152 | 153 | if (c == 0xFF || c == 0xFE) 154 | { 155 | n = REPLACEMENT_CHAR; 156 | break; 157 | } 158 | 159 | // Make sure the continuation byte matchs 10xxxxxx. 160 | if ((c >> 6) == 2) 161 | { 162 | n = (n << 6) + (c & 0x3F); 163 | } 164 | else 165 | { 166 | // revert index as this bytes wasn't a continuation, 167 | // so it might have been a start character. 168 | i--; 169 | n = REPLACEMENT_CHAR; 170 | break; 171 | } 172 | } 173 | } 174 | else 175 | { 176 | n = REPLACEMENT_CHAR; 177 | } 178 | 179 | // If the number of extra bytes in sequence is > 2 then it is a utf32 char. 180 | if (sizeof(wchar_t) == 2 && extraBytesForChar > 2) 181 | { 182 | n = REPLACEMENT_CHAR; 183 | } 184 | else if (sizeof(wchar_t) == 4 && extraBytesForChar > 5) 185 | { 186 | n = REPLACEMENT_CHAR; 187 | } 188 | } 189 | else 190 | { 191 | n = REPLACEMENT_CHAR; 192 | } 193 | 194 | // append the decoded character. 195 | result.append(1, n); 196 | } 197 | 198 | return result; 199 | } 200 | -------------------------------------------------------------------------------- /netfilter/UdpProxy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "SOCKS.h" 4 | #include "UDPContext.hpp" 5 | #include "iocp.h" 6 | #include "nfapi.h" 7 | #include "sync.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define PACKET_SIZE 65536 16 | 17 | namespace UdpProxy 18 | { 19 | 20 | enum OV_TYPE 21 | { 22 | OVT_CONNECT, 23 | OVT_TCP_SEND, 24 | OVT_TCP_RECEIVE, 25 | OVT_UDP_SEND, 26 | OVT_UDP_RECEIVE 27 | }; 28 | 29 | struct OV_DATA 30 | { 31 | OV_DATA() 32 | { 33 | memset(&ol, 0, sizeof(ol)); 34 | } 35 | 36 | OVERLAPPED ol; 37 | unsigned __int64 id; 38 | OV_TYPE type; 39 | char remoteAddress[NF_MAX_ADDRESS_LENGTH]; 40 | int remoteAddressLen; 41 | std::vector buffer; 42 | }; 43 | 44 | enum PROXY_STATE 45 | { 46 | PS_NONE, 47 | PS_AUTH, 48 | PS_AUTH_NEGOTIATION, 49 | PS_UDP_ASSOC, 50 | PS_CONNECTED, 51 | PS_CLOSED 52 | }; 53 | 54 | struct UDP_PACKET 55 | { 56 | char remoteAddress[NF_MAX_ADDRESS_LENGTH]; 57 | int remoteAddressLen; 58 | std::vector buffer; 59 | }; 60 | 61 | typedef std::list tPacketList; 62 | 63 | struct PROXY_DATA 64 | { 65 | PROXY_DATA() 66 | { 67 | tcpSocket = INVALID_SOCKET; 68 | udpSocket = INVALID_SOCKET; 69 | proxyState = PS_NONE; 70 | memset(remoteAddress, 0, sizeof(remoteAddress)); 71 | remoteAddressLen = 0; 72 | udpRecvStarted = false; 73 | } 74 | ~PROXY_DATA() 75 | { 76 | if (tcpSocket != INVALID_SOCKET) 77 | { 78 | shutdown(tcpSocket, SD_BOTH); 79 | closesocket(tcpSocket); 80 | } 81 | if (udpSocket != INVALID_SOCKET) 82 | { 83 | closesocket(udpSocket); 84 | } 85 | while (!udpSendPackets.empty()) 86 | { 87 | tPacketList::iterator it = udpSendPackets.begin(); 88 | delete (*it); 89 | udpSendPackets.erase(it); 90 | } 91 | } 92 | 93 | SOCKET tcpSocket; 94 | SOCKET udpSocket; 95 | 96 | PROXY_STATE proxyState; 97 | 98 | char remoteAddress[NF_MAX_ADDRESS_LENGTH]; 99 | int remoteAddressLen; 100 | 101 | std::string userName; 102 | std::string userPassword; 103 | 104 | tPacketList udpSendPackets; 105 | 106 | bool udpRecvStarted; 107 | }; 108 | 109 | class UDPProxy : public IOCPHandler 110 | { 111 | public: 112 | UDPProxy() = default; 113 | virtual ~UDPProxy() = default; 114 | 115 | void *getExtensionFunction(SOCKET s, const GUID *which_fn); 116 | bool initExtensions(); 117 | 118 | bool init(UDPProxyHandler *hander, const char *addr, int addrlen, const std::string &user, const std::string &pass); 119 | void free(); 120 | 121 | bool createProxyConnection(unsigned __int64 id); 122 | void deleteProxyConnection(unsigned __int64 id); 123 | 124 | bool udpSend(unsigned __int64 id, char *buf, int len, char *remoteAddress, int remoteAddressLen); 125 | 126 | OV_DATA *newOV_DATA(); 127 | void deleteOV_DATA(OV_DATA *pov); 128 | 129 | bool startConnect(SOCKET socket, sockaddr *pAddr, int addrLen, unsigned __int64 id); 130 | bool startUdpReceive(SOCKET socket, unsigned __int64 id, OV_DATA *pov); 131 | bool startTcpReceive(SOCKET socket, unsigned __int64 id, OV_DATA *pov); 132 | bool startTcpSend(SOCKET socket, char *buf, int len, unsigned __int64 id); 133 | 134 | void onUdpSendComplete(SOCKET socket, DWORD dwTransferred, OV_DATA *pov, int error); 135 | void onUdpReceiveComplete(SOCKET socket, DWORD dwTransferred, OV_DATA *pov, int error); 136 | 137 | void onConnectComplete(SOCKET socket, DWORD dwTransferred, OV_DATA *pov, int error); 138 | void onTcpSendComplete(SOCKET socket, DWORD dwTransferred, OV_DATA *pov, int error); 139 | void onTcpReceiveComplete(SOCKET socket, DWORD dwTransferred, OV_DATA *pov, int error); 140 | 141 | virtual void onComplete(SOCKET socket, DWORD dwTransferred, OVERLAPPED *pOverlapped, int error); 142 | 143 | private: 144 | IOCPService m_service; 145 | UDPProxyHandler *m_pProxyHandler = nullptr; 146 | 147 | std::set m_ovDataSet; 148 | std::map m_socketMap; 149 | 150 | LPFN_CONNECTEX m_pConnectEx; 151 | 152 | char m_proxyAddress[NF_MAX_ADDRESS_LENGTH]; 153 | int m_proxyAddressLen; 154 | 155 | std::string m_userName; 156 | std::string m_userPassword; 157 | 158 | CriticalSection m_cs; 159 | }; 160 | } // namespace UdpProxy 161 | -------------------------------------------------------------------------------- /netfilter/base.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | // 6 | #include 7 | // 8 | #include "nfapi.h" 9 | -------------------------------------------------------------------------------- /netfilter/bin/driver/driver_versions.txt: -------------------------------------------------------------------------------- 1 | Differences between driver versions. 2 | ================================================================ 3 | 4 | - TDI driver works on Windows XP, Windows Vista and Windows 7. 5 | 6 | - WFP driver works on Windows 7 and higher. It is required on Windows 8 and higher to filter Metro applications and other processes in AppContainers, because Microsoft has disabled TDI interface for this kind of applications. 7 | -------------------------------------------------------------------------------- /netfilter/bin/driver/wfp/amd64/netfilter2.sys: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shadowsocks-NET/QvPlugin-Netfilter/c0617220093cf73185427f091b91e8cdb1aafe03/netfilter/bin/driver/wfp/amd64/netfilter2.sys -------------------------------------------------------------------------------- /netfilter/bin/install_wfp_driver.bat: -------------------------------------------------------------------------------- 1 | cd /d %~dp0 2 | 3 | rem Installing the network hooking driver build for 32-bit systems 4 | 5 | rem Copy the driver to system folder 6 | copy driver\wfp\i386\netfilter2.sys %windir%\system32\drivers 7 | 8 | rem Register the driver 9 | release\win32\nfregdrv.exe netfilter2 10 | 11 | pause -------------------------------------------------------------------------------- /netfilter/bin/install_wfp_driver_x64.bat: -------------------------------------------------------------------------------- 1 | cd /d %~dp0 2 | 3 | rem Installing the network hooking driver build for 64-bit systems 4 | 5 | rem Copy the driver to system folder 6 | copy driver\wfp\amd64\netfilter2.sys %windir%\system32\drivers 7 | 8 | rem Register the driver 9 | release\win32\nfregdrv.exe netfilter2 10 | 11 | pause -------------------------------------------------------------------------------- /netfilter/bin/release/nfapi.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shadowsocks-NET/QvPlugin-Netfilter/c0617220093cf73185427f091b91e8cdb1aafe03/netfilter/bin/release/nfapi.dll -------------------------------------------------------------------------------- /netfilter/bin/uninstall_driver.bat: -------------------------------------------------------------------------------- 1 | cd /d %~dp0 2 | 3 | rem Uninstall the network hooking driver 4 | 5 | rem Try to unload the driver 6 | sc stop netfilter2 7 | 8 | rem Unregister the driver 9 | release\win32\nfregdrv.exe -u netfilter2 10 | 11 | rem Delete driver file 12 | del %windir%\system32\drivers\netfilter2.sys 13 | 14 | 15 | pause -------------------------------------------------------------------------------- /netfilter/include/nfapi.h: -------------------------------------------------------------------------------- 1 | // 2 | // NetFilterSDK 3 | // Copyright (C) Vitaly Sidorov 4 | // All rights reserved. 5 | // 6 | // This file is a part of the NetFilter SDK. 7 | // The code and information is provided "as-is" without 8 | // warranty of any kind, either expressed or implied. 9 | // 10 | 11 | 12 | #ifndef _NFAPI_H 13 | #define _NFAPI_H 14 | 15 | #include "nfevents.h" 16 | 17 | #ifdef _NFAPI_STATIC_LIB 18 | #define NFAPI_API 19 | #else 20 | #ifdef NFAPI_EXPORTS 21 | #define NFAPI_API __declspec(dllexport) 22 | #else 23 | #define NFAPI_API __declspec(dllimport) 24 | #endif 25 | #endif 26 | 27 | // Flags for NF_UDP_OPTIONS.flags 28 | 29 | #define TDI_RECEIVE_BROADCAST 0x00000004 // received TSDU was broadcast. 30 | #define TDI_RECEIVE_MULTICAST 0x00000008 // received TSDU was multicast. 31 | #define TDI_RECEIVE_PARTIAL 0x00000010 // received TSDU is not fully presented. 32 | #define TDI_RECEIVE_NORMAL 0x00000020 // received TSDU is normal data 33 | #define TDI_RECEIVE_EXPEDITED 0x00000040 // received TSDU is expedited data 34 | #define TDI_RECEIVE_PEEK 0x00000080 // received TSDU is not released 35 | #define TDI_RECEIVE_NO_RESPONSE_EXP 0x00000100 // HINT: no back-traffic expected 36 | #define TDI_RECEIVE_COPY_LOOKAHEAD 0x00000200 // for kernel-mode indications 37 | #define TDI_RECEIVE_ENTIRE_MESSAGE 0x00000400 // opposite of RECEIVE_PARTIAL 38 | // (for kernel-mode indications) 39 | #define TDI_RECEIVE_AT_DISPATCH_LEVEL 0x00000800 // receive indication called 40 | // at dispatch level 41 | #define TDI_RECEIVE_CONTROL_INFO 0x00001000 // Control info is being passed up. 42 | #define TDI_RECEIVE_FORCE_INDICATION 0x00002000 // reindicate rejected data. 43 | #define TDI_RECEIVE_NO_PUSH 0x00004000 // complete only when full. 44 | 45 | typedef enum _NF_FLAGS 46 | { 47 | NFF_NONE = 0, 48 | NFF_DONT_DISABLE_TEREDO = 1, 49 | NFF_DONT_DISABLE_TCP_OFFLOADING = 2, 50 | NFF_DISABLE_AUTO_REGISTER = 4, 51 | NFF_DISABLE_AUTO_START = 8, 52 | } NF_FLAGS; 53 | 54 | #ifndef _C_API 55 | namespace nfapi 56 | { 57 | #define NFAPI_NS nfapi:: 58 | #define NFAPI_CC 59 | #else // _C_API 60 | #define NFAPI_CC __cdecl 61 | #define NFAPI_NS 62 | #ifdef __cplusplus 63 | extern "C" 64 | { 65 | #endif 66 | #endif // _C_API 67 | 68 | /** 69 | * Initializes the internal data structures and starts the filtering thread. 70 | * @param driverName The name of hooking driver, without ".sys" extension. 71 | * @param pHandler Pointer to event handling object 72 | **/ 73 | NFAPI_API NF_STATUS NFAPI_CC 74 | nf_init(const char * driverName, NF_EventHandler * pHandler); 75 | 76 | /** 77 | * Stops the filtering thread, breaks all filtered connections and closes 78 | * a connection with the hooking driver. 79 | **/ 80 | NFAPI_API void NFAPI_CC 81 | nf_free(); 82 | 83 | /** 84 | * Registers and starts a driver with specified name (without ".sys" extension) 85 | * @param driverName 86 | **/ 87 | NFAPI_API NF_STATUS NFAPI_CC 88 | nf_registerDriver(const char * driverName); 89 | 90 | /** 91 | * Registers and starts a driver with specified name (without ".sys" extension) and path to driver folder 92 | * @param driverName 93 | * @param driverPath 94 | **/ 95 | NFAPI_API NF_STATUS NFAPI_CC 96 | nf_registerDriverEx(const char * driverName, const char * driverPath); 97 | 98 | /** 99 | * Unregisters a driver with specified name (without ".sys" extension) 100 | * @param driverName 101 | **/ 102 | NFAPI_API NF_STATUS NFAPI_CC 103 | nf_unRegisterDriver(const char * driverName); 104 | 105 | 106 | // 107 | // TCP control routines 108 | // 109 | 110 | /** 111 | * Suspends or resumes indicating of sends and receives for specified connection. 112 | * @param id Connection identifier 113 | * @param suspended TRUE(1) for suspend, FALSE(0) for resume 114 | **/ 115 | NFAPI_API NF_STATUS NFAPI_CC 116 | nf_tcpSetConnectionState(ENDPOINT_ID id, int suspended); 117 | 118 | /** 119 | * Sends the buffer to remote server via specified connection. 120 | * @param id Connection identifier 121 | * @param buf Pointer to data buffer 122 | * @param len Buffer length 123 | **/ 124 | NFAPI_API NF_STATUS NFAPI_CC 125 | nf_tcpPostSend(ENDPOINT_ID id, const char * buf, int len); 126 | 127 | /** 128 | * Indicates the buffer to local process via specified connection. 129 | * @param id Unique connection identifier 130 | * @param buf Pointer to data buffer 131 | * @param len Buffer length 132 | **/ 133 | NFAPI_API NF_STATUS NFAPI_CC 134 | nf_tcpPostReceive(ENDPOINT_ID id, const char * buf, int len); 135 | 136 | /** 137 | * Breaks the connection with given id. 138 | * @param id Connection identifier 139 | **/ 140 | NFAPI_API NF_STATUS NFAPI_CC 141 | nf_tcpClose(ENDPOINT_ID id); 142 | 143 | /** 144 | * Sets the timeout for TCP connections and returns old timeout. 145 | * @param timeout Timeout value in milliseconds. Specify zero value to disable timeouts. 146 | */ 147 | NFAPI_API unsigned long NFAPI_CC 148 | nf_setTCPTimeout(unsigned long timeout); 149 | 150 | /** 151 | * Disables indicating TCP packets to user mode for the specified endpoint 152 | * @param id Socket identifier 153 | */ 154 | NFAPI_API NF_STATUS NFAPI_CC 155 | nf_tcpDisableFiltering(ENDPOINT_ID id); 156 | 157 | 158 | // 159 | // UDP control routines 160 | // 161 | 162 | /** 163 | * Suspends or resumes indicating of sends and receives for specified socket. 164 | * @param id Socket identifier 165 | * @param suspended TRUE(1) for suspend, FALSE(0) for resume 166 | **/ 167 | NFAPI_API NF_STATUS NFAPI_CC 168 | nf_udpSetConnectionState(ENDPOINT_ID id, int suspended); 169 | 170 | /** 171 | * Sends the buffer to remote server via specified socket. 172 | * @param id Socket identifier 173 | * @param options UDP options 174 | * @param remoteAddress Destination address 175 | * @param buf Pointer to data buffer 176 | * @param len Buffer length 177 | **/ 178 | NFAPI_API NF_STATUS NFAPI_CC 179 | nf_udpPostSend(ENDPOINT_ID id, const unsigned char * remoteAddress, const char * buf, int len, PNF_UDP_OPTIONS options); 180 | 181 | /** 182 | * Indicates the buffer to local process via specified socket. 183 | * @param id Unique connection identifier 184 | * @param options UDP options 185 | * @param remoteAddress Source address 186 | * @param buf Pointer to data buffer 187 | * @param len Buffer length 188 | **/ 189 | NFAPI_API NF_STATUS NFAPI_CC 190 | nf_udpPostReceive(ENDPOINT_ID id, const unsigned char * remoteAddress, const char * buf, int len, PNF_UDP_OPTIONS options); 191 | 192 | /** 193 | * Disables indicating UDP packets to user mode for the specified endpoint 194 | * @param id Socket identifier 195 | */ 196 | NFAPI_API NF_STATUS NFAPI_CC 197 | nf_udpDisableFiltering(ENDPOINT_ID id); 198 | 199 | 200 | /** 201 | * Sends a packet to remote IP 202 | * @param buf Pointer to IP packet 203 | * @param len Buffer length 204 | * @param options IP options 205 | **/ 206 | NFAPI_API NF_STATUS NFAPI_CC 207 | nf_ipPostSend(const char * buf, int len, PNF_IP_PACKET_OPTIONS options); 208 | 209 | /** 210 | * Indicates a packet to TCP/IP stack 211 | * @param buf Pointer to IP packet 212 | * @param len Buffer length 213 | * @param options IP options 214 | **/ 215 | NFAPI_API NF_STATUS NFAPI_CC 216 | nf_ipPostReceive(const char * buf, int len, PNF_IP_PACKET_OPTIONS options); 217 | 218 | // 219 | // Filtering rules 220 | // 221 | 222 | /** 223 | * Add a rule to the head of rules list in driver. 224 | * @param pRule See NF_RULE 225 | * @param toHead TRUE (1) - add rule to list head, FALSE (0) - add rule to tail 226 | **/ 227 | NFAPI_API NF_STATUS NFAPI_CC 228 | nf_addRule(PNF_RULE pRule, int toHead); 229 | 230 | /** 231 | * Removes all rules from driver. 232 | **/ 233 | NFAPI_API NF_STATUS NFAPI_CC 234 | nf_deleteRules(); 235 | 236 | /** 237 | * Replace the rules in driver with the specified array. 238 | * @param pRules Array of NF_RULE structures 239 | * @param count Number of items in array 240 | **/ 241 | NFAPI_API NF_STATUS NFAPI_CC 242 | nf_setRules(PNF_RULE pRules, int count); 243 | 244 | /** 245 | * Add a rule to the head of rules list in driver. 246 | * @param pRule See NF_RULE_EX 247 | * @param toHead TRUE (1) - add rule to list head, FALSE (0) - add rule to tail 248 | **/ 249 | NFAPI_API NF_STATUS NFAPI_CC 250 | nf_addRuleEx(PNF_RULE_EX pRule, int toHead); 251 | 252 | /** 253 | * Replace the rules in driver with the specified array. 254 | * @param pRules Array of NF_RULE_EX structures 255 | * @param count Number of items in array 256 | **/ 257 | NFAPI_API NF_STATUS NFAPI_CC 258 | nf_setRulesEx(PNF_RULE_EX pRules, int count); 259 | 260 | // 261 | // Debug routine 262 | // 263 | 264 | NFAPI_API unsigned long NFAPI_CC 265 | nf_getConnCount(); 266 | 267 | NFAPI_API NF_STATUS NFAPI_CC 268 | nf_tcpSetSockOpt(ENDPOINT_ID id, int optname, const char* optval, int optlen); 269 | 270 | /** 271 | * Returns the process name for given process id 272 | * @param processId Process identifier 273 | * @param buf Buffer 274 | * @param len Buffer length 275 | **/ 276 | NFAPI_API BOOL NFAPI_CC 277 | nf_getProcessNameA(DWORD processId, char * buf, DWORD len); 278 | 279 | NFAPI_API BOOL NFAPI_CC 280 | nf_getProcessNameW(DWORD processId, wchar_t * buf, DWORD len); 281 | 282 | #ifdef UNICODE 283 | #define nf_getProcessName nf_getProcessNameW 284 | #else 285 | #define nf_getProcessName nf_getProcessNameA 286 | #endif 287 | 288 | NFAPI_API BOOL NFAPI_CC 289 | nf_getProcessNameFromKernel(DWORD processId, wchar_t * buf, DWORD len); 290 | 291 | /** 292 | * Allows the current process to see the names of all processes in system 293 | **/ 294 | NFAPI_API void NFAPI_CC 295 | nf_adjustProcessPriviledges(); 296 | 297 | /** 298 | * Returns TRUE if the specified process acts as a local proxy, accepting the redirected TCP connections. 299 | **/ 300 | NFAPI_API BOOL NFAPI_CC 301 | nf_tcpIsProxy(DWORD processId); 302 | 303 | /** 304 | * Set the number of worker threads and initialization flags. 305 | * The function should be called before nf_init. 306 | * By default nThreads = 1 and flags = 0 307 | * @param nThreads Number of worker threads for NF_EventHandler events 308 | * @param flags A combination of flags from NF_FLAGS 309 | **/ 310 | NFAPI_API void NFAPI_CC 311 | nf_setOptions(DWORD nThreads, DWORD flags); 312 | 313 | /** 314 | * Complete TCP connect request pended using flag NF_PEND_CONNECT_REQUEST. 315 | **/ 316 | NFAPI_API NF_STATUS NFAPI_CC 317 | nf_completeTCPConnectRequest(ENDPOINT_ID id, PNF_TCP_CONN_INFO pConnInfo); 318 | 319 | /** 320 | * Complete UDP connect request pended using flag NF_PEND_CONNECT_REQUEST. 321 | **/ 322 | NFAPI_API NF_STATUS NFAPI_CC 323 | nf_completeUDPConnectRequest(ENDPOINT_ID id, PNF_UDP_CONN_REQUEST pConnInfo); 324 | 325 | /** 326 | * Returns in pConnInfo the properties of TCP connection with specified id. 327 | **/ 328 | NFAPI_API NF_STATUS NFAPI_CC 329 | nf_getTCPConnInfo(ENDPOINT_ID id, PNF_TCP_CONN_INFO pConnInfo); 330 | 331 | /** 332 | * Returns in pConnInfo the properties of UDP socket with specified id. 333 | **/ 334 | NFAPI_API NF_STATUS NFAPI_CC 335 | nf_getUDPConnInfo(ENDPOINT_ID id, PNF_UDP_CONN_INFO pConnInfo); 336 | 337 | /** 338 | * Set the event handler for IP filtering events 339 | */ 340 | NFAPI_API void NFAPI_CC 341 | nf_setIPEventHandler(NF_IPEventHandler * pHandler); 342 | 343 | /** 344 | * Add flow control context 345 | */ 346 | NFAPI_API NF_STATUS NFAPI_CC 347 | nf_addFlowCtl(PNF_FLOWCTL_DATA pData, unsigned int * pFcHandle); 348 | 349 | /** 350 | * Delete flow control context 351 | */ 352 | NFAPI_API NF_STATUS NFAPI_CC 353 | nf_deleteFlowCtl(unsigned int fcHandle); 354 | 355 | /** 356 | * Associate flow control context with TCP connection 357 | */ 358 | NFAPI_API NF_STATUS NFAPI_CC 359 | nf_setTCPFlowCtl(ENDPOINT_ID id, unsigned int fcHandle); 360 | 361 | /** 362 | * Associate flow control context with UDP socket 363 | */ 364 | NFAPI_API NF_STATUS NFAPI_CC 365 | nf_setUDPFlowCtl(ENDPOINT_ID id, unsigned int fcHandle); 366 | 367 | /** 368 | * Modify flow control context limits 369 | */ 370 | NFAPI_API NF_STATUS NFAPI_CC 371 | nf_modifyFlowCtl(unsigned int fcHandle, PNF_FLOWCTL_DATA pData); 372 | 373 | /** 374 | * Get flow control context statistics as the numbers of in/out bytes 375 | */ 376 | NFAPI_API NF_STATUS NFAPI_CC 377 | nf_getFlowCtlStat(unsigned int fcHandle, PNF_FLOWCTL_STAT pStat); 378 | 379 | /** 380 | * Get TCP connection statistics as the numbers of in/out bytes. 381 | * The function can be called only from tcpClosed handler! 382 | */ 383 | NFAPI_API NF_STATUS NFAPI_CC 384 | nf_getTCPStat(ENDPOINT_ID id, PNF_FLOWCTL_STAT pStat); 385 | 386 | /** 387 | * Get UDP socket statistics as the numbers of in/out bytes. 388 | * The function can be called only from udpClosed handler! 389 | */ 390 | NFAPI_API NF_STATUS NFAPI_CC 391 | nf_getUDPStat(ENDPOINT_ID id, PNF_FLOWCTL_STAT pStat); 392 | 393 | /** 394 | * Add binding rule to driver 395 | */ 396 | NFAPI_API NF_STATUS NFAPI_CC 397 | nf_addBindingRule(PNF_BINDING_RULE pRule, int toHead); 398 | 399 | /** 400 | * Delete all binding rules from driver 401 | */ 402 | NFAPI_API NF_STATUS NFAPI_CC 403 | nf_deleteBindingRules(); 404 | 405 | /** 406 | * Returns the type of attached driver (DT_WFP, DT_TDI or DT_UNKNOWN) 407 | */ 408 | NFAPI_API unsigned long NFAPI_CC 409 | nf_getDriverType(); 410 | 411 | #ifdef __cplusplus 412 | } 413 | #endif 414 | 415 | #endif -------------------------------------------------------------------------------- /netfilter/include/nfapi_linux.h: -------------------------------------------------------------------------------- 1 | // 2 | // NetFilterSDK 3 | // Copyright (C) Vitaly Sidorov 4 | // All rights reserved. 5 | // 6 | // This file is a part of the NetFilter SDK. 7 | // The code and information is provided "as-is" without 8 | // warranty of any kind, either expressed or implied. 9 | // 10 | 11 | #ifndef _NFEXTAPI 12 | #define _NFEXTAPI 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #define UNALIGNED 20 | #define _MAX_PATH 260 21 | #define MAX_PATH 260 22 | #define __int64 long long 23 | #define _snprintf snprintf 24 | #define _vsnprintf vsnprintf 25 | 26 | #include "nfevents.h" 27 | 28 | #define NFAPI_API 29 | 30 | #define NFEXT_MAX_IP_ADDRESS_LENGTH 16 31 | #define NFEXT_MAX_PATH 256 32 | 33 | #pragma pack(push,1) 34 | 35 | // Port range [from:to] for rules. Port numbers must be in host format! 36 | typedef struct _NFEXT_PORT_RANGE 37 | { 38 | unsigned short from; 39 | unsigned short to; 40 | } NFEXT_PORT_RANGE, *PNFEXT_PORT_RANGE; 41 | 42 | typedef enum _NFEXT_FILTERING_FLAG 43 | { 44 | NFEXT_BYPASS = 0, // Bypass connection/packet 45 | NFEXT_REDIRECT = 1, // Redirect connection 46 | NFEXT_BLOCK = 2, // Block connection/packet 47 | } NFEXT_FILTERING_FLAG; 48 | 49 | typedef enum _NFEXT_RULE_FIELDS 50 | { 51 | NFEXT_USE_DST_IP = 1, // Use dstIp 52 | NFEXT_USE_DST_PORTS = 2, // Use dstPorts 53 | NFEXT_USE_SRC_IP = 4, // Use srcIp 54 | NFEXT_USE_SRC_PORTS = 8, // Use srcPorts 55 | NFEXT_USE_UID = 16, // Use uid 56 | NFEXT_USE_GID = 32, // Use gid 57 | } NFEXT_RULE_FIELDS; 58 | 59 | typedef enum _NFEXT_RULE_TYPE 60 | { 61 | NFEXT_NAT_RULE = 0, // Redirection and access control on NAT level 62 | NFEXT_PACKET_RULE = 1, // Access control on packet level 63 | } NFEXT_RULE_TYPE; 64 | 65 | typedef struct _NFEXT_RULE 66 | { 67 | // See NFEXT_RULE_TYPE 68 | int ruleType; 69 | // Protocol (IPPROTO_TCP, IPPROTO_UDP) 70 | int protocol; 71 | // Direction (NF_D_IN, NF_D_OUT, NF_D_BOTH or zero) 72 | int direction; 73 | // AF_INET for IPv4 and AF_INET6 for IPv6 74 | unsigned short ip_family; 75 | // See NFEXT_RULE_FIELDS 76 | unsigned int fieldsMask; 77 | 78 | // Destination IP or network 79 | char dstIp[NFEXT_MAX_IP_ADDRESS_LENGTH]; 80 | // Destination IP mask 81 | unsigned char dstIpMask; 82 | // Destination ports 83 | NFEXT_PORT_RANGE dstPorts; 84 | 85 | // Source IP or network 86 | char srcIp[NFEXT_MAX_IP_ADDRESS_LENGTH]; 87 | // Source IP mask 88 | unsigned char srcIpMask; 89 | // Source ports 90 | NFEXT_PORT_RANGE srcPorts; 91 | 92 | // User id 93 | pid_t uid; 94 | 95 | // Group id 96 | pid_t gid; 97 | 98 | // See NFEXT_FILTERING_FLAG 99 | unsigned long filteringFlag; 100 | } NFEXT_RULE, *PNFEXT_RULE; 101 | 102 | #pragma pack(pop) 103 | 104 | 105 | #ifndef _C_API 106 | namespace nfapi 107 | { 108 | #define NFAPI_NS nfapi:: 109 | #define NFAPI_CC 110 | #else // _C_API 111 | #ifdef WIN32 112 | #define NFAPI_CC __cdecl 113 | #else 114 | #define NFAPI_CC 115 | #endif 116 | #define NFAPI_NS 117 | #ifdef __cplusplus 118 | namespace nfapi 119 | { 120 | } 121 | extern "C" 122 | { 123 | #endif 124 | #endif // _C_API 125 | 126 | /** 127 | * Initializes the internal data structures and starts the filtering thread. 128 | * @param pHandler Pointer to event handling object 129 | **/ 130 | NFAPI_API NF_STATUS NFAPI_CC nf_init(const char * driverName, NF_EventHandler * pHandler); 131 | 132 | /** 133 | * Stops the filtering thread, breaks all filtered connections and closes 134 | * a connection with the hooking driver. 135 | **/ 136 | NFAPI_API void NFAPI_CC 137 | nf_free(); 138 | 139 | /** 140 | * Set the number of worker threads. 141 | * The function should be called before nf_init. 142 | * By default nThreads = 1 and flags = 0 143 | * @param nThreads Number of worker threads for NF_EventHandler events 144 | * @param flags must be zero. 145 | **/ 146 | NFAPI_API void NFAPI_CC 147 | nf_setOptions(int nThreads, int flags); 148 | 149 | 150 | // 151 | // TCP control routines 152 | // 153 | 154 | /** 155 | * Suspends or resumes indicating of sends and receives for specified connection. 156 | * @param id Connection identifier 157 | * @param suspended TRUE(1) for suspend, FALSE(0) for resume 158 | **/ 159 | NFAPI_API NF_STATUS NFAPI_CC 160 | nf_tcpSetConnectionState(ENDPOINT_ID id, int suspended); 161 | 162 | /** 163 | * Sends the buffer to remote server via specified connection. 164 | * @param id Connection identifier 165 | * @param buf Pointer to data buffer 166 | * @param len Buffer length 167 | **/ 168 | NFAPI_API NF_STATUS NFAPI_CC 169 | nf_tcpPostSend(ENDPOINT_ID id, const char * buf, int len); 170 | 171 | /** 172 | * Indicates the buffer to local process via specified connection. 173 | * @param id Unique connection identifier 174 | * @param buf Pointer to data buffer 175 | * @param len Buffer length 176 | **/ 177 | NFAPI_API NF_STATUS NFAPI_CC 178 | nf_tcpPostReceive(ENDPOINT_ID id, const char * buf, int len); 179 | 180 | /** 181 | * Breaks the connection with given id. 182 | * @param id Connection identifier 183 | **/ 184 | NFAPI_API NF_STATUS NFAPI_CC 185 | nf_tcpClose(ENDPOINT_ID id); 186 | 187 | /** 188 | * Sets the timeout for TCP connections and returns old timeout. 189 | * @param timeout Timeout value in milliseconds. Specify zero value to disable timeouts. 190 | */ 191 | NFAPI_API unsigned long NFAPI_CC 192 | nf_setTCPTimeout(unsigned long timeout); 193 | 194 | /** 195 | * Disables indicating TCP packets to user mode for the specified endpoint 196 | * @param id Socket identifier 197 | */ 198 | NFAPI_API NF_STATUS NFAPI_CC 199 | nf_tcpDisableFiltering(ENDPOINT_ID id); 200 | 201 | 202 | // 203 | // UDP control routines 204 | // 205 | 206 | /** 207 | * Suspends or resumes indicating of sends and receives for specified socket. 208 | * @param id Socket identifier 209 | * @param suspended TRUE(1) for suspend, FALSE(0) for resume 210 | **/ 211 | NFAPI_API NF_STATUS NFAPI_CC 212 | nf_udpSetConnectionState(ENDPOINT_ID id, int suspended); 213 | 214 | /** 215 | * Sends the buffer to remote server via specified socket. 216 | * @param id Socket identifier 217 | * @param options UDP options 218 | * @param remoteAddress Destination address 219 | * @param buf Pointer to data buffer 220 | * @param len Buffer length 221 | **/ 222 | NFAPI_API NF_STATUS NFAPI_CC 223 | nf_udpPostSend(ENDPOINT_ID id, const unsigned char * remoteAddress, const char * buf, int len, PNF_UDP_OPTIONS options); 224 | 225 | /** 226 | * Indicates the buffer to local process via specified socket. 227 | * @param id Unique connection identifier 228 | * @param options UDP options 229 | * @param remoteAddress Source address 230 | * @param buf Pointer to data buffer 231 | * @param len Buffer length 232 | **/ 233 | NFAPI_API NF_STATUS NFAPI_CC 234 | nf_udpPostReceive(ENDPOINT_ID id, const unsigned char * remoteAddress, const char * buf, int len, PNF_UDP_OPTIONS options); 235 | 236 | /** 237 | * Disables indicating UDP packets to user mode for the specified endpoint 238 | * @param id Socket identifier 239 | */ 240 | NFAPI_API NF_STATUS NFAPI_CC 241 | nf_udpDisableFiltering(ENDPOINT_ID id); 242 | 243 | 244 | // 245 | // Filtering rules 246 | // 247 | 248 | /** 249 | * Replace the rules with the specified array. 250 | * @param pRules Array of NFEXT_RULE structures 251 | * @param count Number of items in array 252 | **/ 253 | NFAPI_API NF_STATUS NFAPI_CC 254 | nf_setRules(PNFEXT_RULE pRules, int count); 255 | 256 | 257 | /** 258 | * Removes all rules 259 | **/ 260 | NFAPI_API NF_STATUS NFAPI_CC 261 | nf_deleteRules(); 262 | 263 | /** 264 | * Returns in pConnInfo the properties of TCP connection with specified id. 265 | **/ 266 | NFAPI_API NF_STATUS NFAPI_CC 267 | nf_getTCPConnInfo(ENDPOINT_ID id, PNF_TCP_CONN_INFO pConnInfo); 268 | 269 | /** 270 | * Returns a port used by local proxy. 271 | **/ 272 | NFAPI_API unsigned short NFAPI_CC 273 | nf_getProxyPort(); 274 | 275 | /** 276 | * Returns owner of the specified connection as user id. 277 | **/ 278 | NFAPI_API NF_STATUS NFAPI_CC 279 | nf_getUid(ENDPOINT_ID id, unsigned int * pUid); 280 | 281 | /** 282 | * Returns user name for user id. 283 | **/ 284 | NFAPI_API NF_STATUS NFAPI_CC 285 | nf_getUserName(unsigned int uid, char * buf, int len); 286 | 287 | /** 288 | * Returns process name for process id. 289 | **/ 290 | NFAPI_API NF_STATUS NFAPI_CC 291 | nf_getProcessName(unsigned int pid, char * buf, int len); 292 | 293 | /** 294 | * Raises the limit on the number of files to at least the specified value. 295 | **/ 296 | NFAPI_API NF_STATUS NFAPI_CC 297 | nf_requireFileLimit(int file_limit); 298 | 299 | /** 300 | * Returns number of active TCP connections. 301 | **/ 302 | NFAPI_API unsigned long NFAPI_CC 303 | nf_getConnCount(); 304 | 305 | #ifdef __cplusplus 306 | } 307 | #endif 308 | 309 | 310 | 311 | #endif -------------------------------------------------------------------------------- /netfilter/include/nfapi_macos.h: -------------------------------------------------------------------------------- 1 | // 2 | // NetFilterSDK 3 | // Copyright (C) Vitaly Sidorov 4 | // All rights reserved. 5 | // 6 | // This file is a part of the NetFilter SDK. 7 | // The code and information is provided "as-is" without 8 | // warranty of any kind, either expressed or implied. 9 | // 10 | 11 | #ifndef _NFAPI_MACOS 12 | #define _NFAPI_MACOS 13 | 14 | #include "nfext_macos.h" 15 | 16 | #define UNALIGNED 17 | #define _MAX_PATH 260 18 | #define MAX_PATH 260 19 | #define __int64 long long 20 | #define _snprintf snprintf 21 | #define _vsnprintf vsnprintf 22 | 23 | #include "nfevents.h" 24 | 25 | #define NFAPI_API 26 | 27 | 28 | 29 | #ifndef _C_API 30 | namespace nfapi 31 | { 32 | #define NFAPI_NS nfapi:: 33 | #define NFAPI_CC 34 | #else // _C_API 35 | #ifdef WIN32 36 | #define NFAPI_CC __cdecl 37 | #else 38 | #define NFAPI_CC 39 | #endif 40 | #define NFAPI_NS 41 | #ifdef __cplusplus 42 | namespace nfapi 43 | { 44 | } 45 | extern "C" 46 | { 47 | #endif 48 | #endif // _C_API 49 | 50 | 51 | /** 52 | * Initializes the internal data structures and starts the filtering thread. 53 | * @param driverName The name of TDI hooking driver, without ".sys" extension. 54 | * @param pHandler Pointer to event handling object 55 | **/ 56 | NFAPI_API NF_STATUS NFAPI_CC nf_init(const char * driverName, NF_EventHandler * pHandler); 57 | 58 | /** 59 | * Stops the filtering thread, breaks all filtered connections and closes 60 | * a connection with the hooking driver. 61 | **/ 62 | NFAPI_API void NFAPI_CC 63 | nf_free(); 64 | 65 | /** 66 | * Set the number of worker threads. 67 | * The function should be called before nf_init. 68 | * By default nThreads = 1 and flags = 0 69 | * @param nThreads Number of worker threads for NF_EventHandler events 70 | * @param flags must be zero. 71 | **/ 72 | NFAPI_API void NFAPI_CC 73 | nf_setOptions(int nThreads, int flags); 74 | 75 | 76 | /** 77 | * Registers and starts a driver with specified name (without ".sys" extension) 78 | * @param driverName 79 | **/ 80 | NFAPI_API NF_STATUS NFAPI_CC 81 | nf_registerDriver(const char * driverName); 82 | 83 | /** 84 | * Unregisters a driver with specified name (without ".sys" extension) 85 | * @param driverName 86 | **/ 87 | NFAPI_API NF_STATUS NFAPI_CC 88 | nf_unRegisterDriver(const char * driverName); 89 | 90 | 91 | // 92 | // TCP control routines 93 | // 94 | 95 | /** 96 | * Suspends or resumes indicating of sends and receives for specified connection. 97 | * @param id Connection identifier 98 | * @param suspended TRUE(1) for suspend, FALSE(0) for resume 99 | **/ 100 | NFAPI_API NF_STATUS NFAPI_CC 101 | nf_tcpSetConnectionState(ENDPOINT_ID id, int suspended); 102 | 103 | /** 104 | * Sends the buffer to remote server via specified connection. 105 | * @param id Connection identifier 106 | * @param buf Pointer to data buffer 107 | * @param len Buffer length 108 | **/ 109 | NFAPI_API NF_STATUS NFAPI_CC 110 | nf_tcpPostSend(ENDPOINT_ID id, const char * buf, int len); 111 | 112 | /** 113 | * Indicates the buffer to local process via specified connection. 114 | * @param id Unique connection identifier 115 | * @param buf Pointer to data buffer 116 | * @param len Buffer length 117 | **/ 118 | NFAPI_API NF_STATUS NFAPI_CC 119 | nf_tcpPostReceive(ENDPOINT_ID id, const char * buf, int len); 120 | 121 | /** 122 | * Breaks the connection with given id. 123 | * @param id Connection identifier 124 | **/ 125 | NFAPI_API NF_STATUS NFAPI_CC 126 | nf_tcpClose(ENDPOINT_ID id); 127 | 128 | /** 129 | * Sets the timeout for TCP connections and returns old timeout. 130 | * @param timeout Timeout value in milliseconds. Specify zero value to disable timeouts. 131 | */ 132 | NFAPI_API unsigned long NFAPI_CC 133 | nf_setTCPTimeout(unsigned long timeout); 134 | 135 | /** 136 | * Disables indicating TCP packets to user mode for the specified endpoint 137 | * @param id Socket identifier 138 | */ 139 | NFAPI_API NF_STATUS NFAPI_CC 140 | nf_tcpDisableFiltering(ENDPOINT_ID id); 141 | 142 | // 143 | // UDP control routines 144 | // 145 | 146 | /** 147 | * Suspends or resumes indicating of sends and receives for specified socket. 148 | * @param id Socket identifier 149 | * @param suspended TRUE(1) for suspend, FALSE(0) for resume 150 | **/ 151 | NFAPI_API NF_STATUS NFAPI_CC 152 | nf_udpSetConnectionState(ENDPOINT_ID id, int suspended); 153 | 154 | /** 155 | * Sends the buffer to remote server via specified socket. 156 | * @param id Socket identifier 157 | * @param options UDP options 158 | * @param remoteAddress Destination address 159 | * @param buf Pointer to data buffer 160 | * @param len Buffer length 161 | **/ 162 | NFAPI_API NF_STATUS NFAPI_CC 163 | nf_udpPostSend(ENDPOINT_ID id, const unsigned char * remoteAddress, const char * buf, int len, PNF_UDP_OPTIONS options); 164 | 165 | /** 166 | * Indicates the buffer to local process via specified socket. 167 | * @param id Unique connection identifier 168 | * @param options UDP options 169 | * @param remoteAddress Source address 170 | * @param buf Pointer to data buffer 171 | * @param len Buffer length 172 | **/ 173 | NFAPI_API NF_STATUS NFAPI_CC 174 | nf_udpPostReceive(ENDPOINT_ID id, const unsigned char * remoteAddress, const char * buf, int len, PNF_UDP_OPTIONS options); 175 | 176 | /** 177 | * Disables indicating UDP packets to user mode for the specified endpoint 178 | * @param id Socket identifier 179 | */ 180 | NFAPI_API NF_STATUS NFAPI_CC 181 | nf_udpDisableFiltering(ENDPOINT_ID id); 182 | 183 | // 184 | // Filtering rules 185 | // 186 | 187 | /** 188 | * Add a rule to the head of rules list in driver. 189 | * @param pRule See NFEXT_RULE 190 | **/ 191 | NFAPI_API NF_STATUS NFAPI_CC 192 | nf_addRule(PNFEXT_RULE pRule); 193 | 194 | NFAPI_API NF_STATUS NFAPI_CC 195 | nf_addUdpRule(PNFEXT_RULE pRule); 196 | 197 | /** 198 | * Removes all rules from driver. 199 | **/ 200 | NFAPI_API NF_STATUS NFAPI_CC 201 | nf_deleteRules(); 202 | 203 | /** 204 | * Detaches from filtered TCP/UDP sockets 205 | **/ 206 | NFAPI_API NF_STATUS NFAPI_CC 207 | nf_disableFiltering(); 208 | 209 | /** 210 | * Returns in pConnInfo the properties of TCP connection with specified id. 211 | **/ 212 | NFAPI_API NF_STATUS NFAPI_CC 213 | nf_getTCPConnInfo(ENDPOINT_ID id, PNF_TCP_CONN_INFO pConnInfo); 214 | 215 | /** 216 | * Returns a port used by local proxy. 217 | **/ 218 | NFAPI_API unsigned short NFAPI_CC 219 | nf_getProxyPort(); 220 | 221 | /** 222 | * Returns owner of the specified connection as user id. 223 | **/ 224 | NFAPI_API NF_STATUS NFAPI_CC 225 | nf_getUid(ENDPOINT_ID id, unsigned int * pUid); 226 | 227 | /** 228 | * Returns user name for user id. 229 | **/ 230 | NFAPI_API NF_STATUS NFAPI_CC 231 | nf_getUserName(unsigned int uid, char * buf, int len); 232 | 233 | /** 234 | * Returns process name for process id. 235 | **/ 236 | NFAPI_API NF_STATUS NFAPI_CC 237 | nf_getProcessName(unsigned int pid, char * buf, int len); 238 | 239 | /** 240 | * Raises the limit on the number of files to at least the specified value. 241 | **/ 242 | NFAPI_API NF_STATUS NFAPI_CC 243 | nf_requireFileLimit(int file_limit); 244 | 245 | /** 246 | * Returns number of active TCP connections. 247 | **/ 248 | NFAPI_API unsigned long NFAPI_CC 249 | nf_getConnCount(); 250 | 251 | #ifdef __cplusplus 252 | } 253 | #endif 254 | 255 | 256 | #endif -------------------------------------------------------------------------------- /netfilter/include/nfdriver.h: -------------------------------------------------------------------------------- 1 | // 2 | // NetFilterSDK 3 | // Copyright (C) Vitaly Sidorov 4 | // All rights reserved. 5 | // 6 | // This file is a part of the NetFilter SDK. 7 | // The code and information is provided "as-is" without 8 | // warranty of any kind, either expressed or implied. 9 | // 10 | 11 | 12 | #ifndef _NFDRIVER_H 13 | #define _NFDRIVER_H 14 | 15 | #define NF_TCP_PACKET_BUF_SIZE 8192 16 | #define NF_UDP_PACKET_BUF_SIZE 2 * 65536 17 | 18 | /** 19 | * IO data codes 20 | **/ 21 | typedef enum _NF_DATA_CODE 22 | { 23 | NF_TCP_CONNECTED, // TCP connection established 24 | NF_TCP_CLOSED, // TCP connection closed 25 | NF_TCP_RECEIVE, // TCP data packet received 26 | NF_TCP_SEND, // TCP data packet sent 27 | NF_TCP_CAN_RECEIVE, // The buffer for TCP receives is empty 28 | NF_TCP_CAN_SEND, // The buffer for TCP sends is empty 29 | NF_TCP_REQ_SUSPEND, // Requests suspending TCP connection 30 | NF_TCP_REQ_RESUME, // Requests resuming TCP connection 31 | 32 | NF_UDP_CREATED, // UDP socket created 33 | NF_UDP_CLOSED, // UDP socket closed 34 | NF_UDP_RECEIVE, // UDP data packet received 35 | NF_UDP_SEND, // UDP data packet sent 36 | NF_UDP_CAN_RECEIVE, // The buffer for UDP receives is empty 37 | NF_UDP_CAN_SEND, // The buffer for UDP sends is empty 38 | NF_UDP_REQ_SUSPEND, // Requests suspending UDP address 39 | NF_UDP_REQ_RESUME, // Requests resuming UDP address 40 | 41 | NF_REQ_ADD_HEAD_RULE, // Add a rule to list head 42 | NF_REQ_ADD_TAIL_RULE, // Add a rule to list tail 43 | NF_REQ_DELETE_RULES, // Remove all rules 44 | 45 | NF_TCP_CONNECT_REQUEST, // Outgoing TCP connect request 46 | NF_UDP_CONNECT_REQUEST, // Outgoing UDP connect request 47 | 48 | NF_TCP_DISABLE_USER_MODE_FILTERING, // Disable indicating TCP packets to user mode for a connection 49 | NF_UDP_DISABLE_USER_MODE_FILTERING, // Disable indicating UDP packets to user mode for a socket 50 | 51 | NF_REQ_SET_TCP_OPT, // Set TCP socket options 52 | NF_REQ_IS_PROXY, // Check if process with specified id is local proxy 53 | 54 | NF_TCP_REINJECT, // Reinject pended packets 55 | NF_TCP_REMOVE_CLOSED, // Delete TCP context for the closed connection 56 | NF_TCP_DEFERRED_DISCONNECT, // Delete TCP context for the closed connection 57 | 58 | NF_IP_RECEIVE, // IP data packet received 59 | NF_IP_SEND, // IP data packet sent 60 | NF_TCP_RECEIVE_PUSH, // Push all TCP data packets 61 | } NF_DATA_CODE; 62 | 63 | typedef enum _NF_DIRECTION 64 | { 65 | NF_D_IN = 1, // Incoming TCP connection or UDP packet 66 | NF_D_OUT = 2, // Outgoing TCP connection or UDP packet 67 | NF_D_BOTH = 3 // Any direction 68 | } NF_DIRECTION; 69 | 70 | typedef enum _NF_FILTERING_FLAG 71 | { 72 | NF_ALLOW = 0, // Allow the activity without filtering transmitted packets 73 | NF_BLOCK = 1, // Block the activity 74 | NF_FILTER = 2, // Filter the transmitted packets 75 | NF_SUSPENDED = 4, // Suspend receives from server and sends from client 76 | NF_OFFLINE = 8, // Emulate establishing a TCP connection with remote server 77 | NF_INDICATE_CONNECT_REQUESTS = 16, // Indicate outgoing connect requests to API 78 | NF_DISABLE_REDIRECT_PROTECTION = 32, // Disable blocking indicating connect requests for outgoing connections of local proxies 79 | NF_PEND_CONNECT_REQUEST = 64, // Pend outgoing connect request to complete it later using nf_complete(TCP|UDP)ConnectRequest 80 | NF_FILTER_AS_IP_PACKETS = 128, // Indicate the traffic as IP packets via ipSend/ipReceive 81 | NF_READONLY = 256, // Don't block the IP packets and indicate them to ipSend/ipReceive only for monitoring 82 | NF_CONTROL_FLOW = 512, // Use the flow limit rules even without NF_FILTER flag 83 | NF_REDIRECT = 1024, // Redirect the outgoing TCP connections to address specified in redirectTo 84 | } NF_FILTERING_FLAG; 85 | 86 | #pragma pack(push, 1) 87 | 88 | #define NF_MAX_ADDRESS_LENGTH 28 89 | #define NF_MAX_IP_ADDRESS_LENGTH 16 90 | 91 | #ifndef AF_INET 92 | #define AF_INET 2 /* internetwork: UDP, TCP, etc. */ 93 | #endif 94 | 95 | #ifndef AF_INET6 96 | #define AF_INET6 23 /* Internetwork Version 6 */ 97 | #endif 98 | 99 | // Protocols 100 | 101 | #ifndef IPPROTO_TCP 102 | #define IPPROTO_TCP 6 103 | #endif 104 | 105 | #ifndef IPPROTO_UDP 106 | #define IPPROTO_UDP 17 107 | #endif 108 | 109 | #define TCP_SOCKET_NODELAY 1 110 | #define TCP_SOCKET_KEEPALIVE 2 111 | #define TCP_SOCKET_OOBINLINE 3 112 | #define TCP_SOCKET_BSDURGENT 4 113 | #define TCP_SOCKET_ATMARK 5 114 | #define TCP_SOCKET_WINDOW 6 115 | 116 | /** 117 | * Filtering rule 118 | **/ 119 | typedef UNALIGNED struct _NF_RULE 120 | { 121 | int protocol; // IPPROTO_TCP or IPPROTO_UDP 122 | unsigned long processId; // Process identifier 123 | unsigned char direction; // See NF_DIRECTION 124 | unsigned short localPort; // Local port 125 | unsigned short remotePort; // Remote port 126 | unsigned short ip_family; // AF_INET for IPv4 and AF_INET6 for IPv6 127 | 128 | // Local IP (or network if localIpAddressMask is not zero) 129 | unsigned char localIpAddress[NF_MAX_IP_ADDRESS_LENGTH]; 130 | 131 | // Local IP mask 132 | unsigned char localIpAddressMask[NF_MAX_IP_ADDRESS_LENGTH]; 133 | 134 | // Remote IP (or network if remoteIpAddressMask is not zero) 135 | unsigned char remoteIpAddress[NF_MAX_IP_ADDRESS_LENGTH]; 136 | 137 | // Remote IP mask 138 | unsigned char remoteIpAddressMask[NF_MAX_IP_ADDRESS_LENGTH]; 139 | 140 | unsigned long filteringFlag; // See NF_FILTERING_FLAG 141 | } NF_RULE, *PNF_RULE; 142 | 143 | 144 | typedef struct _NF_PORT_RANGE 145 | { 146 | unsigned short valueLow; 147 | unsigned short valueHigh; 148 | } NF_PORT_RANGE, *PNF_PORT_RANGE; 149 | 150 | 151 | /** 152 | * Filtering rule with additional fields 153 | **/ 154 | typedef UNALIGNED struct _NF_RULE_EX 155 | { 156 | int protocol; // IPPROTO_TCP or IPPROTO_UDP 157 | unsigned long processId; // Process identifier 158 | unsigned char direction; // See NF_DIRECTION 159 | unsigned short localPort; // Local port 160 | unsigned short remotePort; // Remote port 161 | unsigned short ip_family; // AF_INET for IPv4 and AF_INET6 for IPv6 162 | 163 | // Local IP (or network if localIpAddressMask is not zero) 164 | unsigned char localIpAddress[NF_MAX_IP_ADDRESS_LENGTH]; 165 | 166 | // Local IP mask 167 | unsigned char localIpAddressMask[NF_MAX_IP_ADDRESS_LENGTH]; 168 | 169 | // Remote IP (or network if remoteIpAddressMask is not zero) 170 | unsigned char remoteIpAddress[NF_MAX_IP_ADDRESS_LENGTH]; 171 | 172 | // Remote IP mask 173 | unsigned char remoteIpAddressMask[NF_MAX_IP_ADDRESS_LENGTH]; 174 | 175 | unsigned long filteringFlag; // See NF_FILTERING_FLAG 176 | 177 | // Process name tail mask (supports * as 0 or more symbols) 178 | wchar_t processName[MAX_PATH]; 179 | 180 | NF_PORT_RANGE localPortRange; // Local port(s) 181 | NF_PORT_RANGE remotePortRange; // Remote port(s) 182 | 183 | // Remote address for redirection as sockaddr_in for IPv4 and sockaddr_in6 for IPv6 184 | unsigned char redirectTo[NF_MAX_ADDRESS_LENGTH]; 185 | // Process identifier of a local proxy 186 | unsigned long localProxyProcessId; 187 | 188 | } NF_RULE_EX, *PNF_RULE_EX; 189 | 190 | typedef unsigned __int64 ENDPOINT_ID; 191 | 192 | 193 | /** 194 | * TCP connection properties 195 | **/ 196 | typedef UNALIGNED struct _NF_TCP_CONN_INFO 197 | { 198 | unsigned long filteringFlag; // See NF_FILTERING_FLAG 199 | unsigned long processId; // Process identifier 200 | unsigned char direction; // See NF_DIRECTION 201 | unsigned short ip_family; // AF_INET for IPv4 and AF_INET6 for IPv6 202 | 203 | // Local address as sockaddr_in for IPv4 and sockaddr_in6 for IPv6 204 | unsigned char localAddress[NF_MAX_ADDRESS_LENGTH]; 205 | 206 | // Remote address as sockaddr_in for IPv4 and sockaddr_in6 for IPv6 207 | unsigned char remoteAddress[NF_MAX_ADDRESS_LENGTH]; 208 | 209 | } NF_TCP_CONN_INFO, *PNF_TCP_CONN_INFO; 210 | 211 | /** 212 | * UDP endpoint properties 213 | **/ 214 | typedef UNALIGNED struct _NF_UDP_CONN_INFO 215 | { 216 | unsigned long processId; // Process identifier 217 | unsigned short ip_family; // AF_INET for IPv4 and AF_INET6 for IPv6 218 | 219 | // Local address as sockaddr_in for IPv4 and sockaddr_in6 for IPv6 220 | unsigned char localAddress[NF_MAX_ADDRESS_LENGTH]; 221 | 222 | } NF_UDP_CONN_INFO, *PNF_UDP_CONN_INFO; 223 | 224 | /** 225 | * UDP TDI_CONNECT request properties 226 | **/ 227 | typedef UNALIGNED struct _NF_UDP_CONN_REQUEST 228 | { 229 | unsigned long filteringFlag; // See NF_FILTERING_FLAG 230 | unsigned long processId; // Process identifier 231 | unsigned short ip_family; // AF_INET for IPv4 and AF_INET6 for IPv6 232 | 233 | // Local address as sockaddr_in for IPv4 and sockaddr_in6 for IPv6 234 | unsigned char localAddress[NF_MAX_ADDRESS_LENGTH]; 235 | 236 | // Remote address as sockaddr_in for IPv4 and sockaddr_in6 for IPv6 237 | unsigned char remoteAddress[NF_MAX_ADDRESS_LENGTH]; 238 | 239 | } NF_UDP_CONN_REQUEST, *PNF_UDP_CONN_REQUEST; 240 | 241 | /** 242 | * UDP options 243 | **/ 244 | typedef UNALIGNED struct _NF_UDP_OPTIONS 245 | { 246 | unsigned long flags; // Datagram flags 247 | long optionsLength; // Length of options buffer 248 | unsigned char options[1]; // Options of variable size 249 | } NF_UDP_OPTIONS, *PNF_UDP_OPTIONS; 250 | 251 | typedef enum _NF_IP_FLAG 252 | { 253 | NFIF_NONE = 0, // No flags 254 | NFIF_READONLY = 1, // The packet was not blocked and indicated only for monitoring in read-only mode 255 | // (see NF_READ_ONLY flags from NF_FILTERING_FLAG). 256 | } NF_IP_FLAG; 257 | 258 | /** 259 | * IP options 260 | **/ 261 | typedef struct _NF_IP_PACKET_OPTIONS 262 | { 263 | unsigned short ip_family; // AF_INET for IPv4 and AF_INET6 for IPv6 264 | unsigned int ipHeaderSize; // Size in bytes of IP header 265 | unsigned long compartmentId; // Network routing compartment identifier (can be zero) 266 | unsigned long interfaceIndex; // Index of the interface on which the original packet data was received (irrelevant to outgoing packets) 267 | unsigned long subInterfaceIndex; // Index of the subinterface on which the original packet data was received (irrelevant to outgoing packets) 268 | unsigned long flags; // Can be a combination of flags from NF_IP_FLAG enumeration 269 | } NF_IP_PACKET_OPTIONS, *PNF_IP_PACKET_OPTIONS; 270 | 271 | /** 272 | * Internal IO structure 273 | **/ 274 | typedef UNALIGNED struct _NF_DATA 275 | { 276 | int code; 277 | ENDPOINT_ID id; 278 | unsigned long bufferSize; 279 | char buffer[1]; 280 | } NF_DATA, *PNF_DATA; 281 | 282 | typedef UNALIGNED struct _NF_BUFFERS 283 | { 284 | unsigned __int64 inBuf; 285 | unsigned __int64 inBufLen; 286 | unsigned __int64 outBuf; 287 | unsigned __int64 outBufLen; 288 | } NF_BUFFERS, *PNF_BUFFERS; 289 | 290 | typedef UNALIGNED struct _NF_READ_RESULT 291 | { 292 | unsigned __int64 length; 293 | } NF_READ_RESULT, *PNF_READ_RESULT; 294 | 295 | typedef UNALIGNED struct _NF_FLOWCTL_DATA 296 | { 297 | unsigned __int64 inLimit; 298 | unsigned __int64 outLimit; 299 | } NF_FLOWCTL_DATA, *PNF_FLOWCTL_DATA; 300 | 301 | typedef UNALIGNED struct _NF_FLOWCTL_MODIFY_DATA 302 | { 303 | unsigned int fcHandle; 304 | NF_FLOWCTL_DATA data; 305 | } NF_FLOWCTL_MODIFY_DATA, *PNF_FLOWCTL_MODIFY_DATA; 306 | 307 | typedef UNALIGNED struct _NF_FLOWCTL_STAT 308 | { 309 | unsigned __int64 inBytes; 310 | unsigned __int64 outBytes; 311 | } NF_FLOWCTL_STAT, *PNF_FLOWCTL_STAT; 312 | 313 | typedef UNALIGNED struct _NF_FLOWCTL_SET_DATA 314 | { 315 | unsigned __int64 endpointId; 316 | unsigned int fcHandle; 317 | } NF_FLOWCTL_SET_DATA, *PNF_FLOWCTL_SET_DATA; 318 | 319 | 320 | /** 321 | * Binding rule 322 | **/ 323 | typedef UNALIGNED struct _NF_BINDING_RULE 324 | { 325 | int protocol; // IPPROTO_TCP or IPPROTO_UDP 326 | 327 | unsigned long processId; // Process identifier 328 | 329 | // Process name tail mask (supports * as 0 or more symbols) 330 | wchar_t processName[MAX_PATH]; 331 | 332 | unsigned short localPort; // Local port 333 | 334 | unsigned short ip_family; // AF_INET for IPv4 and AF_INET6 for IPv6 335 | 336 | // Local IP (or network if localIpAddressMask is not zero) 337 | unsigned char localIpAddress[NF_MAX_IP_ADDRESS_LENGTH]; 338 | 339 | // Local IP mask 340 | unsigned char localIpAddressMask[NF_MAX_IP_ADDRESS_LENGTH]; 341 | 342 | // Redirect bind request to this IP 343 | unsigned char newLocalIpAddress[NF_MAX_IP_ADDRESS_LENGTH]; 344 | 345 | // Redirect bind request to this port, if it is not zero 346 | unsigned short newLocalPort; 347 | 348 | unsigned long filteringFlag; // See NF_FILTERING_FLAG, NF_ALLOW or NF_FILTER 349 | 350 | } NF_BINDING_RULE, *PNF_BINDING_RULE; 351 | 352 | 353 | #pragma pack(pop) 354 | 355 | #ifdef WIN32 356 | 357 | typedef enum _NF_DRIVER_TYPE 358 | { 359 | DT_UNKNOWN = 0, 360 | DT_TDI = 1, 361 | DT_WFP = 2 362 | } NF_DRIVER_TYPE; 363 | 364 | #ifdef _NF_INTERNALS 365 | 366 | #define NF_REQ_GET_ADDR_INFO \ 367 | CTL_CODE(FILE_DEVICE_UNKNOWN, 101, METHOD_BUFFERED, FILE_ANY_ACCESS) 368 | 369 | #define NF_REQ_GET_PROCESS_NAME \ 370 | CTL_CODE(FILE_DEVICE_UNKNOWN, 102, METHOD_BUFFERED, FILE_ANY_ACCESS) 371 | 372 | #define NF_REQ_GET_DRIVER_TYPE \ 373 | CTL_CODE(FILE_DEVICE_UNKNOWN, 103, METHOD_BUFFERED, FILE_ANY_ACCESS) 374 | 375 | #define NF_REQ_TCP_ABORT \ 376 | CTL_CODE(FILE_DEVICE_UNKNOWN, 104, METHOD_BUFFERED, FILE_ANY_ACCESS) 377 | 378 | #define NF_REQ_ADD_FLOW_CTL \ 379 | CTL_CODE(FILE_DEVICE_UNKNOWN, 105, METHOD_BUFFERED, FILE_ANY_ACCESS) 380 | 381 | #define NF_REQ_DELETE_FLOW_CTL \ 382 | CTL_CODE(FILE_DEVICE_UNKNOWN, 106, METHOD_BUFFERED, FILE_ANY_ACCESS) 383 | 384 | #define NF_REQ_SET_TCP_FLOW_CTL \ 385 | CTL_CODE(FILE_DEVICE_UNKNOWN, 107, METHOD_BUFFERED, FILE_ANY_ACCESS) 386 | 387 | #define NF_REQ_SET_UDP_FLOW_CTL \ 388 | CTL_CODE(FILE_DEVICE_UNKNOWN, 108, METHOD_BUFFERED, FILE_ANY_ACCESS) 389 | 390 | #define NF_REQ_MODIFY_FLOW_CTL \ 391 | CTL_CODE(FILE_DEVICE_UNKNOWN, 109, METHOD_BUFFERED, FILE_ANY_ACCESS) 392 | 393 | #define NF_REQ_GET_FLOW_CTL_STAT \ 394 | CTL_CODE(FILE_DEVICE_UNKNOWN, 110, METHOD_BUFFERED, FILE_ANY_ACCESS) 395 | 396 | #define NF_REQ_CLEAR_TEMP_RULES \ 397 | CTL_CODE(FILE_DEVICE_UNKNOWN, 111, METHOD_BUFFERED, FILE_ANY_ACCESS) 398 | 399 | #define NF_REQ_ADD_TEMP_RULE \ 400 | CTL_CODE(FILE_DEVICE_UNKNOWN, 112, METHOD_BUFFERED, FILE_ANY_ACCESS) 401 | 402 | #define NF_REQ_SET_TEMP_RULES \ 403 | CTL_CODE(FILE_DEVICE_UNKNOWN, 113, METHOD_BUFFERED, FILE_ANY_ACCESS) 404 | 405 | #define NF_REQ_ADD_HEAD_BINDING_RULE \ 406 | CTL_CODE(FILE_DEVICE_UNKNOWN, 114, METHOD_BUFFERED, FILE_ANY_ACCESS) 407 | 408 | #define NF_REQ_ADD_TAIL_BINDING_RULE \ 409 | CTL_CODE(FILE_DEVICE_UNKNOWN, 115, METHOD_BUFFERED, FILE_ANY_ACCESS) 410 | 411 | #define NF_REQ_DELETE_BINDING_RULES \ 412 | CTL_CODE(FILE_DEVICE_UNKNOWN, 116, METHOD_BUFFERED, FILE_ANY_ACCESS) 413 | 414 | #define NF_REQ_ADD_HEAD_RULE_EX \ 415 | CTL_CODE(FILE_DEVICE_UNKNOWN, 117, METHOD_BUFFERED, FILE_ANY_ACCESS) 416 | 417 | #define NF_REQ_ADD_TAIL_RULE_EX \ 418 | CTL_CODE(FILE_DEVICE_UNKNOWN, 118, METHOD_BUFFERED, FILE_ANY_ACCESS) 419 | 420 | #define NF_REQ_ADD_TEMP_RULE_EX \ 421 | CTL_CODE(FILE_DEVICE_UNKNOWN, 119, METHOD_BUFFERED, FILE_ANY_ACCESS) 422 | 423 | #define NF_REQ_GET_UDP_ADDR_INFO \ 424 | CTL_CODE(FILE_DEVICE_UNKNOWN, 120, METHOD_BUFFERED, FILE_ANY_ACCESS) 425 | 426 | #define FSCTL_TCP_BASE FILE_DEVICE_NETWORK 427 | 428 | #define _TCP_CTL_CODE(function, method, access) \ 429 | CTL_CODE(FSCTL_TCP_BASE, function, method, access) 430 | 431 | #define IOCTL_TCP_QUERY_INFORMATION_EX \ 432 | _TCP_CTL_CODE(0, METHOD_NEITHER, FILE_ANY_ACCESS) 433 | 434 | #define IOCTL_TCP_SET_INFORMATION_EX \ 435 | _TCP_CTL_CODE(1, METHOD_BUFFERED, FILE_WRITE_ACCESS) 436 | 437 | #endif 438 | 439 | #define FSCTL_DEVCTRL_BASE FILE_DEVICE_NETWORK 440 | 441 | #define _DEVCTRL_CTL_CODE(_Function, _Method, _Access) \ 442 | CTL_CODE(FSCTL_DEVCTRL_BASE, _Function, _Method, _Access) 443 | 444 | #define IOCTL_DEVCTRL_OPEN \ 445 | _DEVCTRL_CTL_CODE(0x200, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) 446 | 447 | #endif 448 | 449 | #endif // _NFDRIVER_H -------------------------------------------------------------------------------- /netfilter/include/nfevents.h: -------------------------------------------------------------------------------- 1 | // 2 | // NetFilterSDK 3 | // Copyright (C) Vitaly Sidorov 4 | // All rights reserved. 5 | // 6 | // This file is a part of the NetFilter SDK. 7 | // The code and information is provided "as-is" without 8 | // warranty of any kind, either expressed or implied. 9 | // 10 | 11 | 12 | #ifndef _NFEVENTS_H 13 | #define _NFEVENTS_H 14 | 15 | /** 16 | * Return status codes 17 | **/ 18 | typedef enum _NF_STATUS 19 | { 20 | NF_STATUS_SUCCESS = 0, 21 | NF_STATUS_FAIL = -1, 22 | NF_STATUS_INVALID_ENDPOINT_ID = -2, 23 | NF_STATUS_NOT_INITIALIZED = -3, 24 | NF_STATUS_IO_ERROR = -4, 25 | NF_STATUS_REBOOT_REQUIRED = -5 26 | } NF_STATUS; 27 | 28 | #ifndef _C_API 29 | 30 | #define NFAPI_NS nfapi:: 31 | #define NFAPI_CC 32 | 33 | ///////////////////////////////////////////////////////////////////////////////////// 34 | // C++ API 35 | ///////////////////////////////////////////////////////////////////////////////////// 36 | 37 | namespace nfapi 38 | { 39 | #include "nfdriver.h" 40 | 41 | /** 42 | * Filtering events 43 | **/ 44 | class NF_EventHandler 45 | { 46 | public: 47 | 48 | /** 49 | * Called immediately after starting the filtering thread. 50 | * Use this event for thread-specific initialization, e.g. calling 51 | * CoInitialize() etc. 52 | **/ 53 | virtual void threadStart() = 0; 54 | 55 | /** 56 | * Called before stopping the thread. 57 | **/ 58 | virtual void threadEnd() = 0; 59 | 60 | // 61 | // TCP events 62 | // 63 | 64 | /** 65 | * Called before establishing an outgoing TCP connection, 66 | * when NF_INDICATE_CONNECT_REQUESTS flag is specified in an appropriate rule. 67 | * It is possible to change pConnInfo->filteringFlag and pConnInfo->remoteAddress 68 | * in this handler. The changes will be applied to connection. 69 | * @param id Unique connection identifier 70 | * @param pConnInfo Connection parameters, see NF_TCP_CONN_INFO 71 | **/ 72 | virtual void tcpConnectRequest(ENDPOINT_ID id, PNF_TCP_CONN_INFO pConnInfo) = 0; 73 | 74 | /** 75 | * Called after successful establishing the incoming or outgoing TCP connection. 76 | * @param id Unique connection identifier 77 | * @param pConnInfo Connection parameters, see NF_TCP_CONN_INFO 78 | **/ 79 | virtual void tcpConnected(ENDPOINT_ID id, PNF_TCP_CONN_INFO pConnInfo) = 0; 80 | 81 | /** 82 | * Called after closing the connection identified by id. 83 | * @param id Unique connection identifier 84 | * @param pConnInfo Connection parameters, see NF_TCP_CONN_INFO 85 | **/ 86 | virtual void tcpClosed(ENDPOINT_ID id, PNF_TCP_CONN_INFO pConnInfo) = 0; 87 | 88 | /** 89 | * Indicates the buffer received from server. 90 | * @param id Unique connection identifier 91 | * @param buf Pointer to data buffer 92 | * @param len Buffer length 93 | **/ 94 | virtual void tcpReceive(ENDPOINT_ID id, const char * buf, int len) = 0; 95 | 96 | /** 97 | * Indicates the buffer sent from the local socket. 98 | * @param id Unique connection identifier 99 | * @param buf Pointer to data buffer 100 | * @param len Buffer length 101 | **/ 102 | virtual void tcpSend(ENDPOINT_ID id, const char * buf, int len) = 0; 103 | 104 | /** 105 | * Informs that the internal buffer for receives is empty and 106 | * it is possible to call nf_tcpPostReceive for pushing receives 107 | * via specified connection. 108 | * @param id Unique connection identifier 109 | **/ 110 | virtual void tcpCanReceive(ENDPOINT_ID id) = 0; 111 | 112 | /** 113 | * Informs that the internal buffer for sends is empty and 114 | * it is possible to call nf_tcpPostSend for pushing sends 115 | * via specified connection. 116 | * @param id Unique connection identifier 117 | **/ 118 | virtual void tcpCanSend(ENDPOINT_ID id) = 0; 119 | 120 | 121 | // 122 | // UDP events 123 | // 124 | 125 | /** 126 | * Called after creating UDP socket. 127 | * @param id Unique socket identifier 128 | * @param pConnInfo Socket parameters, see NF_UDP_CONN_INFO 129 | **/ 130 | virtual void udpCreated(ENDPOINT_ID id, PNF_UDP_CONN_INFO pConnInfo) = 0; 131 | 132 | /** 133 | * Called before establishing an outgoing UDP connection, 134 | * when NF_INDICATE_CONNECT_REQUESTS flag is specified in an appropriate rule. 135 | * It is possible to change pConnReq->filteringFlag and pConnReq->remoteAddress 136 | * in this handler. The changes will be applied to connection. 137 | * @param id Unique connection identifier 138 | * @param pConnInfo Connection parameters, see NF_UDP_CONN_REQUEST 139 | **/ 140 | virtual void udpConnectRequest(ENDPOINT_ID id, PNF_UDP_CONN_REQUEST pConnReq) = 0; 141 | 142 | /** 143 | * Called after closing UDP socket identified by id. 144 | * @param id Unique socket identifier 145 | * @param pConnInfo Socket parameters, see NF_UDP_CONN_INFO 146 | **/ 147 | virtual void udpClosed(ENDPOINT_ID id, PNF_UDP_CONN_INFO pConnInfo) = 0; 148 | 149 | /** 150 | * Indicates the buffer received from server. 151 | * @param id Unique socket identifier 152 | * @param options UDP options 153 | * @param remoteAddress Source address 154 | * @param buf Pointer to data buffer 155 | * @param len Buffer length 156 | **/ 157 | virtual void udpReceive(ENDPOINT_ID id, const unsigned char * remoteAddress, const char * buf, int len, PNF_UDP_OPTIONS options) = 0; 158 | 159 | /** 160 | * Indicates the buffer sent from the local socket. 161 | * @param id Unique socket identifier 162 | * @param options UDP options 163 | * @param remoteAddress Destination address 164 | * @param buf Pointer to data buffer 165 | * @param len Buffer length 166 | **/ 167 | virtual void udpSend(ENDPOINT_ID id, const unsigned char * remoteAddress, const char * buf, int len, PNF_UDP_OPTIONS options) = 0; 168 | 169 | /** 170 | * Informs that the internal buffer for receives is empty and 171 | * it is possible to call nf_udpPostReceive for pushing receives 172 | * via specified socket. 173 | * @param id Unique socket identifier 174 | **/ 175 | virtual void udpCanReceive(ENDPOINT_ID id) = 0; 176 | 177 | /** 178 | * Informs that the internal buffer for sends is empty and 179 | * it is possible to call nf_udpPostSend for pushing sends 180 | * via specified socket. 181 | * @param id Unique socket identifier 182 | **/ 183 | virtual void udpCanSend(ENDPOINT_ID id) = 0; 184 | }; 185 | 186 | /** 187 | * IP level filtering events 188 | **/ 189 | class NF_IPEventHandler 190 | { 191 | public: 192 | /** 193 | * Indicates a packet received from server. 194 | * @param buf Pointer to data buffer 195 | * @param len Buffer length 196 | * @param options IP options 197 | **/ 198 | virtual void ipReceive(const char * buf, int len, PNF_IP_PACKET_OPTIONS options) = 0; 199 | 200 | /** 201 | * Indicates a packet sent to server. 202 | * @param buf Pointer to data buffer 203 | * @param len Buffer length 204 | * @param options IP options 205 | **/ 206 | virtual void ipSend(const char * buf, int len, PNF_IP_PACKET_OPTIONS options) = 0; 207 | }; 208 | 209 | #else 210 | 211 | #ifdef WIN32 212 | #define NFAPI_CC __cdecl 213 | #else 214 | #define NFAPI_CC 215 | #endif 216 | #define NFAPI_NS 217 | 218 | ///////////////////////////////////////////////////////////////////////////////////// 219 | // C API 220 | ///////////////////////////////////////////////////////////////////////////////////// 221 | 222 | #ifdef __cplusplus 223 | extern "C" 224 | { 225 | #endif 226 | 227 | #include "nfdriver.h" 228 | 229 | #pragma pack(push, 1) 230 | 231 | // C analogue of the class NF_EventHandler (see the definition above) 232 | typedef struct _NF_EventHandler 233 | { 234 | void (NFAPI_CC *threadStart)(); 235 | void (NFAPI_CC *threadEnd)(); 236 | void (NFAPI_CC *tcpConnectRequest)(ENDPOINT_ID id, PNF_TCP_CONN_INFO pConnInfo); 237 | void (NFAPI_CC *tcpConnected)(ENDPOINT_ID id, PNF_TCP_CONN_INFO pConnInfo); 238 | void (NFAPI_CC *tcpClosed)(ENDPOINT_ID id, PNF_TCP_CONN_INFO pConnInfo); 239 | void (NFAPI_CC *tcpReceive)(ENDPOINT_ID id, const char * buf, int len); 240 | void (NFAPI_CC *tcpSend)(ENDPOINT_ID id, const char * buf, int len); 241 | void (NFAPI_CC *tcpCanReceive)(ENDPOINT_ID id); 242 | void (NFAPI_CC *tcpCanSend)(ENDPOINT_ID id); 243 | void (NFAPI_CC *udpCreated)(ENDPOINT_ID id, PNF_UDP_CONN_INFO pConnInfo); 244 | void (NFAPI_CC *udpConnectRequest)(ENDPOINT_ID id, PNF_UDP_CONN_REQUEST pConnReq); 245 | void (NFAPI_CC *udpClosed)(ENDPOINT_ID id, PNF_UDP_CONN_INFO pConnInfo); 246 | void (NFAPI_CC *udpReceive)(ENDPOINT_ID id, const unsigned char * remoteAddress, const char * buf, int len, PNF_UDP_OPTIONS options); 247 | void (NFAPI_CC *udpSend)(ENDPOINT_ID id, const unsigned char * remoteAddress, const char * buf, int len, PNF_UDP_OPTIONS options); 248 | void (NFAPI_CC *udpCanReceive)(ENDPOINT_ID id); 249 | void (NFAPI_CC *udpCanSend)(ENDPOINT_ID id); 250 | } NF_EventHandler, *PNF_EventHandler; 251 | 252 | // C analogue of the class NF_IPEventHandler (see the definition above) 253 | typedef struct _NF_IPEventHandler 254 | { 255 | void (NFAPI_CC *ipReceive)(const char * buf, int len, PNF_IP_PACKET_OPTIONS options); 256 | void (NFAPI_CC *ipSend)(const char * buf, int len, PNF_IP_PACKET_OPTIONS options); 257 | } NF_IPEventHandler, *PNF_IPEventHandler; 258 | 259 | #pragma pack(pop) 260 | 261 | #endif 262 | 263 | 264 | #ifdef __cplusplus 265 | } 266 | #endif 267 | 268 | #endif -------------------------------------------------------------------------------- /netfilter/include/nfext_macos.h: -------------------------------------------------------------------------------- 1 | // 2 | // NetFilterSDK 3 | // Copyright (C) Vitaly Sidorov 4 | // All rights reserved. 5 | // 6 | // This file is a part of the NetFilter SDK. 7 | // The code and information is provided "as-is" without 8 | // warranty of any kind, either expressed or implied. 9 | // 10 | 11 | #ifndef _NFEXTAPI 12 | #define _NFEXTAPI 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #define NFEXT_BUNDLEID "nfext" 20 | 21 | #define NFEXT_MAX_IP_ADDRESS_LENGTH 16 22 | #define NFEXT_MAX_PATH 256 23 | 24 | enum NFEXT_REQUEST 25 | { 26 | NFEXT_ADD_RULE = 1, 27 | NFEXT_DELETE_RULES = 2, 28 | NFEXT_ADD_UDP_RULE = 3, 29 | }; 30 | 31 | #pragma pack(push,1) 32 | 33 | // Port range [from:to] for rules. Port numbers must be in host format! 34 | typedef struct _NFEXT_PORT_RANGE 35 | { 36 | unsigned short from; 37 | unsigned short to; 38 | } NFEXT_PORT_RANGE, *PNFEXT_PORT_RANGE; 39 | 40 | typedef enum _NFEXT_FILTERING_FLAG 41 | { 42 | NFEXT_BYPASS = 0, // Bypass connection/packet 43 | NFEXT_REDIRECT = 1, // Redirect connection 44 | NFEXT_BLOCK = 2, // Block connection/packet 45 | } NFEXT_FILTERING_FLAG; 46 | 47 | typedef enum _NFEXT_RULE_FIELDS 48 | { 49 | NFEXT_USE_REMOTE_IP = 1, // Use remoteIp 50 | NFEXT_USE_REMOTE_IP_MASK = 2, // Use remoteIpMask 51 | NFEXT_USE_REMOTE_PORTS = 4, // Use remotePorts 52 | NFEXT_USE_PID = 8, // Use pid 53 | NFEXT_USE_UID = 16, // Use uid 54 | NFEXT_USE_PROCESS_NAME = 32, // Use processName 55 | } NFEXT_RULE_FIELDS; 56 | 57 | typedef struct _NFEXT_RULE 58 | { 59 | // See NFEXT_RULE_FIELDS 60 | unsigned int fieldsMask; 61 | // AF_INET for IPv4 and AF_INET6 for IPv6 62 | unsigned short ip_family; 63 | // Remote IP or network 64 | char remoteIp[NFEXT_MAX_IP_ADDRESS_LENGTH]; 65 | // Remote IP mask 66 | char remoteIpMask[NFEXT_MAX_IP_ADDRESS_LENGTH]; 67 | // Remote ports 68 | NFEXT_PORT_RANGE remotePorts; 69 | 70 | // Where to redirect the connection 71 | union 72 | { 73 | struct sockaddr_in addr4; // ipv4 remote addr 74 | struct sockaddr_in6 addr6; // ipv6 remote addr 75 | } redirectTo; 76 | 77 | // Process id 78 | pid_t pid; 79 | // User id 80 | pid_t uid; 81 | // Process name mask 82 | char processName[NFEXT_MAX_PATH]; 83 | // See NFEXT_FILTERING_FLAG 84 | unsigned long filteringFlag; 85 | } NFEXT_RULE, *PNFEXT_RULE; 86 | 87 | #define NFEXT_INFO_MAGIC 0xEEBBCCDD 88 | 89 | typedef struct _NFEXT_INFO 90 | { 91 | int magic; // Must be NFEXT_INFO_MAGIC 92 | // Original remote address of redirected connection 93 | union 94 | { 95 | struct sockaddr_in addr4; // ipv4 remote addr 96 | struct sockaddr_in6 addr6; // ipv6 remote addr 97 | } remote_addr; 98 | pid_t pid; // pid that created the socket 99 | pid_t uid; // used id that created the socket 100 | } NFEXT_INFO, *PNFEXT_INFO; 101 | 102 | #pragma pack(pop) 103 | 104 | #endif -------------------------------------------------------------------------------- /netfilter/iocp.h: -------------------------------------------------------------------------------- 1 | // 2 | // NetFilterSDK 3 | // Copyright (C) Vitaly Sidorov 4 | // All rights reserved. 5 | // 6 | // This file is a part of the NetFilter SDK. 7 | // The code and information is provided "as-is" without 8 | // warranty of any kind, either expressed or implied. 9 | // 10 | 11 | #pragma once 12 | 13 | #include "SOCKS.h" 14 | #include "base.h" 15 | #include "sync.h" 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | class IOCPHandler 23 | { 24 | public: 25 | virtual void onComplete(SOCKET socket, DWORD dwTransferred, OVERLAPPED *pOverlapped, int error) = 0; 26 | }; 27 | 28 | class IOCPService 29 | { 30 | public: 31 | IOCPService() : m_hIOCP(INVALID_HANDLE_VALUE), m_pHandler(NULL) 32 | { 33 | } 34 | ~IOCPService() = default; 35 | 36 | bool init(IOCPHandler *pHandler) 37 | { 38 | m_pHandler = pHandler; 39 | 40 | if (m_hIOCP != INVALID_HANDLE_VALUE) 41 | return false; 42 | 43 | m_hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 0); 44 | if (m_hIOCP == INVALID_HANDLE_VALUE) 45 | return false; 46 | 47 | ResetEvent(m_stopEvent); 48 | 49 | HANDLE hThread = (HANDLE) _beginthreadex(0, 0, _workerThread, (LPVOID) this, 0, NULL); 50 | 51 | if (hThread != 0) 52 | { 53 | m_workerThread.Attach(hThread); 54 | } 55 | 56 | return true; 57 | } 58 | 59 | void free() 60 | { 61 | if (m_workerThread == INVALID_HANDLE_VALUE) 62 | return; 63 | 64 | SetEvent(m_stopEvent); 65 | WaitForSingleObject(m_workerThread, INFINITE); 66 | m_workerThread.Close(); 67 | 68 | if (m_hIOCP != INVALID_HANDLE_VALUE) 69 | { 70 | CloseHandle(m_hIOCP); 71 | m_hIOCP = INVALID_HANDLE_VALUE; 72 | } 73 | } 74 | 75 | bool registerSocket(SOCKET s) 76 | { 77 | return CreateIoCompletionPort((HANDLE) s, m_hIOCP, (ULONG_PTR) s, 1); 78 | } 79 | 80 | bool postCompletion(SOCKET s, DWORD dwTransferred, LPOVERLAPPED pol) 81 | { 82 | return PostQueuedCompletionStatus(m_hIOCP, dwTransferred, (ULONG_PTR) s, pol); 83 | } 84 | 85 | protected: 86 | void workerThread() 87 | { 88 | DWORD dwTransferred; 89 | ULONG_PTR cKey; 90 | OVERLAPPED *pOverlapped; 91 | 92 | for (;;) 93 | { 94 | if (GetQueuedCompletionStatus(m_hIOCP, &dwTransferred, &cKey, &pOverlapped, 500)) 95 | { 96 | m_pHandler->onComplete((SOCKET) cKey, dwTransferred, pOverlapped, 0); 97 | } 98 | else 99 | { 100 | DWORD err = GetLastError(); 101 | if (err != WAIT_TIMEOUT) 102 | { 103 | m_pHandler->onComplete((SOCKET) cKey, dwTransferred, pOverlapped, err); 104 | } 105 | } 106 | 107 | if (WaitForSingleObject(m_stopEvent, 0) == WAIT_OBJECT_0) 108 | break; 109 | } 110 | } 111 | 112 | static unsigned int WINAPI _workerThread(void *pThis) 113 | { 114 | ((IOCPService *) pThis)->workerThread(); 115 | return 0; 116 | } 117 | 118 | private: 119 | HANDLE m_hIOCP; 120 | AutoEventHandle m_stopEvent; 121 | AutoHandle m_workerThread; 122 | IOCPHandler *m_pHandler; 123 | }; 124 | -------------------------------------------------------------------------------- /netfilter/lib/Debug/nfapi.exp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shadowsocks-NET/QvPlugin-Netfilter/c0617220093cf73185427f091b91e8cdb1aafe03/netfilter/lib/Debug/nfapi.exp -------------------------------------------------------------------------------- /netfilter/lib/Debug/nfapi.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shadowsocks-NET/QvPlugin-Netfilter/c0617220093cf73185427f091b91e8cdb1aafe03/netfilter/lib/Debug/nfapi.lib -------------------------------------------------------------------------------- /netfilter/lib/Release/nfapi.exp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shadowsocks-NET/QvPlugin-Netfilter/c0617220093cf73185427f091b91e8cdb1aafe03/netfilter/lib/Release/nfapi.exp -------------------------------------------------------------------------------- /netfilter/lib/Release/nfapi.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shadowsocks-NET/QvPlugin-Netfilter/c0617220093cf73185427f091b91e8cdb1aafe03/netfilter/lib/Release/nfapi.lib -------------------------------------------------------------------------------- /netfilter/linkedlist.h: -------------------------------------------------------------------------------- 1 | // 2 | // NetFilterSDK 3 | // Copyright (C) Vitaly Sidorov 4 | // All rights reserved. 5 | // 6 | // This file is a part of the NetFilter SDK. 7 | // The code and information is provided "as-is" without 8 | // warranty of any kind, either expressed or implied. 9 | // 10 | 11 | #ifndef _LINKED_LIST 12 | 13 | // 14 | // Calculate the address of the base of the structure given its type, and an 15 | // address of a field within the structure. 16 | // 17 | #ifndef CONTAINING_RECORD 18 | #define CONTAINING_RECORD(address, type, field) ((type *) ((PCHAR)(address) - (ULONG_PTR)(&((type *) 0)->field))) 19 | #endif 20 | 21 | // 22 | // VOID 23 | // InitializeListHead( 24 | // PLIST_ENTRY ListHead 25 | // ); 26 | // 27 | 28 | #define InitializeListHead(ListHead) ((ListHead)->Flink = (ListHead)->Blink = (ListHead)) 29 | 30 | // 31 | // BOOLEAN 32 | // IsListEmpty( 33 | // PLIST_ENTRY ListHead 34 | // ); 35 | // 36 | 37 | #define IsListEmpty(ListHead) ((ListHead)->Flink == (ListHead)) 38 | 39 | // 40 | // PLIST_ENTRY 41 | // RemoveHeadList( 42 | // PLIST_ENTRY ListHead 43 | // ); 44 | // 45 | 46 | #define RemoveHeadList(ListHead) \ 47 | (ListHead)->Flink; \ 48 | { \ 49 | RemoveEntryList((ListHead)->Flink) \ 50 | } 51 | 52 | // 53 | // PLIST_ENTRY 54 | // RemoveTailList( 55 | // PLIST_ENTRY ListHead 56 | // ); 57 | // 58 | 59 | #define RemoveTailList(ListHead) \ 60 | (ListHead)->Blink; \ 61 | { \ 62 | RemoveEntryList((ListHead)->Blink) \ 63 | } 64 | 65 | // 66 | // VOID 67 | // RemoveEntryList( 68 | // PLIST_ENTRY Entry 69 | // ); 70 | // 71 | 72 | #define RemoveEntryList(Entry) \ 73 | { \ 74 | PLIST_ENTRY _EX_Blink; \ 75 | PLIST_ENTRY _EX_Flink; \ 76 | _EX_Flink = (Entry)->Flink; \ 77 | _EX_Blink = (Entry)->Blink; \ 78 | _EX_Blink->Flink = _EX_Flink; \ 79 | _EX_Flink->Blink = _EX_Blink; \ 80 | } 81 | 82 | // 83 | // VOID 84 | // InsertTailList( 85 | // PLIST_ENTRY ListHead, 86 | // PLIST_ENTRY Entry 87 | // ); 88 | // 89 | 90 | #define InsertTailList(ListHead, Entry) \ 91 | { \ 92 | PLIST_ENTRY _EX_Blink; \ 93 | PLIST_ENTRY _EX_ListHead; \ 94 | _EX_ListHead = (ListHead); \ 95 | _EX_Blink = _EX_ListHead->Blink; \ 96 | (Entry)->Flink = _EX_ListHead; \ 97 | (Entry)->Blink = _EX_Blink; \ 98 | _EX_Blink->Flink = (Entry); \ 99 | _EX_ListHead->Blink = (Entry); \ 100 | } 101 | 102 | // 103 | // VOID 104 | // InsertHeadList( 105 | // PLIST_ENTRY ListHead, 106 | // PLIST_ENTRY Entry 107 | // ); 108 | // 109 | 110 | #define InsertHeadList(ListHead, Entry) \ 111 | { \ 112 | PLIST_ENTRY _EX_Flink; \ 113 | PLIST_ENTRY _EX_ListHead; \ 114 | _EX_ListHead = (ListHead); \ 115 | _EX_Flink = _EX_ListHead->Flink; \ 116 | (Entry)->Flink = _EX_Flink; \ 117 | (Entry)->Blink = _EX_ListHead; \ 118 | _EX_Flink->Blink = (Entry); \ 119 | _EX_ListHead->Flink = (Entry); \ 120 | } 121 | 122 | #endif //_LINKED_LIST 123 | -------------------------------------------------------------------------------- /netfilter/sync.h: -------------------------------------------------------------------------------- 1 | // 2 | // NetFilterSDK 3 | // Copyright (C) Vitaly Sidorov 4 | // All rights reserved. 5 | // 6 | // This file is a part of the NetFilter SDK. 7 | // The code and information is provided "as-is" without 8 | // warranty of any kind, either expressed or implied. 9 | // 10 | 11 | #pragma once 12 | 13 | #include "base.h" 14 | 15 | class CriticalSection 16 | { 17 | public: 18 | CriticalSection() throw() 19 | { 20 | memset(&m_sec, 0, sizeof(CRITICAL_SECTION)); 21 | InitializeCriticalSection(&m_sec); 22 | } 23 | ~CriticalSection() 24 | { 25 | DeleteCriticalSection(&m_sec); 26 | } 27 | HRESULT Lock() throw() 28 | { 29 | EnterCriticalSection(&m_sec); 30 | return S_OK; 31 | } 32 | HRESULT Unlock() throw() 33 | { 34 | LeaveCriticalSection(&m_sec); 35 | return S_OK; 36 | } 37 | 38 | private: 39 | CRITICAL_SECTION m_sec; 40 | }; 41 | 42 | class AutoLock 43 | { 44 | public: 45 | AutoLock(CriticalSection &cs) : m_cs(cs) 46 | { 47 | m_cs.Lock(); 48 | } 49 | 50 | virtual ~AutoLock() 51 | { 52 | m_cs.Unlock(); 53 | } 54 | 55 | private: 56 | CriticalSection &m_cs; 57 | }; 58 | 59 | class AutoHandle 60 | { 61 | public: 62 | AutoHandle() throw() : m_h(INVALID_HANDLE_VALUE) 63 | { 64 | } 65 | AutoHandle(AutoHandle &h) throw() : m_h(INVALID_HANDLE_VALUE) 66 | { 67 | Attach(h.Detach()); 68 | } 69 | explicit AutoHandle(HANDLE h) throw() : m_h(h) 70 | { 71 | } 72 | ~AutoHandle() throw() 73 | { 74 | if (m_h != INVALID_HANDLE_VALUE) 75 | { 76 | Close(); 77 | } 78 | } 79 | 80 | AutoHandle &operator=(AutoHandle &h) throw() 81 | { 82 | if (this != &h) 83 | { 84 | if (m_h != INVALID_HANDLE_VALUE) 85 | { 86 | Close(); 87 | } 88 | Attach(h.Detach()); 89 | } 90 | 91 | return (*this); 92 | } 93 | 94 | operator HANDLE() const throw() 95 | { 96 | return (m_h); 97 | } 98 | 99 | // Attach to an existing handle (takes ownership). 100 | void Attach(HANDLE h) throw() 101 | { 102 | m_h = h; // Take ownership 103 | } 104 | 105 | // Detach the handle from the object (releases ownership). 106 | HANDLE Detach() throw() 107 | { 108 | HANDLE h; 109 | 110 | h = m_h; // Release ownership 111 | m_h = INVALID_HANDLE_VALUE; 112 | 113 | return (h); 114 | } 115 | 116 | // Close the handle. 117 | void Close() throw() 118 | { 119 | if (m_h != INVALID_HANDLE_VALUE) 120 | { 121 | ::CloseHandle(m_h); 122 | m_h = INVALID_HANDLE_VALUE; 123 | } 124 | } 125 | 126 | protected: 127 | HANDLE m_h; 128 | }; 129 | 130 | class AutoEventHandle : public AutoHandle 131 | { 132 | public: 133 | AutoEventHandle() 134 | { 135 | m_h = CreateEvent(NULL, FALSE, FALSE, NULL); 136 | } 137 | ~AutoEventHandle() 138 | { 139 | Close(); 140 | } 141 | }; 142 | -------------------------------------------------------------------------------- /netfilter/threadpool.h: -------------------------------------------------------------------------------- 1 | // 2 | // NetFilterSDK 3 | // Copyright (C) Vitaly Sidorov 4 | // All rights reserved. 5 | // 6 | // This file is a part of the NetFilter SDK. 7 | // The code and information is provided "as-is" without 8 | // warranty of any kind, either expressed or implied. 9 | // 10 | 11 | #pragma once 12 | #include "sync.h" 13 | 14 | #include 15 | 16 | class ThreadJobSource 17 | { 18 | public: 19 | virtual void execute() = 0; 20 | virtual void threadStarted() = 0; 21 | virtual void threadStopped() = 0; 22 | }; 23 | 24 | class ThreadPool 25 | { 26 | public: 27 | ThreadPool() 28 | { 29 | m_stopEvent.Attach(CreateEvent(NULL, TRUE, FALSE, NULL)); 30 | m_pJobSource = NULL; 31 | } 32 | 33 | ~ThreadPool() 34 | { 35 | free(); 36 | } 37 | 38 | bool init(int threadCount, ThreadJobSource *pJobSource) 39 | { 40 | HANDLE hThread; 41 | unsigned threadId; 42 | int i; 43 | 44 | ResetEvent(m_stopEvent); 45 | 46 | m_pJobSource = pJobSource; 47 | 48 | if (threadCount <= 0) 49 | { 50 | SYSTEM_INFO sysinfo; 51 | GetSystemInfo(&sysinfo); 52 | 53 | threadCount = sysinfo.dwNumberOfProcessors; 54 | if (threadCount == 0) 55 | { 56 | threadCount = 1; 57 | } 58 | } 59 | 60 | for (i = 0; i < threadCount; i++) 61 | { 62 | hThread = (HANDLE) _beginthreadex(0, 0, _threadProc, (LPVOID) this, 0, &threadId); 63 | 64 | if (hThread != 0 && hThread != (HANDLE)(-1L)) 65 | { 66 | m_threads.push_back(hThread); 67 | } 68 | } 69 | 70 | return true; 71 | } 72 | 73 | void free() 74 | { 75 | SetEvent(m_stopEvent); 76 | 77 | for (tThreads::iterator it = m_threads.begin(); it != m_threads.end(); it++) 78 | { 79 | WaitForSingleObject(*it, INFINITE); 80 | CloseHandle(*it); 81 | } 82 | 83 | m_threads.clear(); 84 | } 85 | 86 | void jobAvailable() 87 | { 88 | SetEvent(m_jobAvailableEvent); 89 | } 90 | 91 | protected: 92 | void threadProc() 93 | { 94 | HANDLE handles[] = { m_jobAvailableEvent, m_stopEvent }; 95 | 96 | m_pJobSource->threadStarted(); 97 | 98 | for (;;) 99 | { 100 | DWORD res = WaitForMultipleObjects(2, handles, FALSE, INFINITE); 101 | 102 | if (res == (WAIT_OBJECT_0 + 1)) 103 | break; 104 | 105 | m_pJobSource->execute(); 106 | } 107 | 108 | m_pJobSource->threadStopped(); 109 | } 110 | 111 | static unsigned WINAPI _threadProc(void *pData) 112 | { 113 | (reinterpret_cast(pData))->threadProc(); 114 | return 0; 115 | } 116 | 117 | private: 118 | ThreadJobSource *m_pJobSource; 119 | 120 | typedef std::vector tThreads; 121 | tThreads m_threads; 122 | 123 | AutoEventHandle m_jobAvailableEvent; 124 | AutoHandle m_stopEvent; 125 | }; 126 | -------------------------------------------------------------------------------- /resx.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | assets/qv2ray.png 4 | 5 | 6 | -------------------------------------------------------------------------------- /ui/Interface.hpp: -------------------------------------------------------------------------------- 1 | #include "QvPlugin/Gui/QvGUIPluginInterface.hpp" 2 | #include "ui/PluginMainWindowWidget.hpp" 3 | #include "ui/PluginSettingsWidget.hpp" 4 | 5 | using namespace Qv2rayPlugin; 6 | 7 | class SimpleGUIInterface : public Qv2rayPlugin::Gui::Qv2rayGUIInterface 8 | { 9 | public: 10 | explicit SimpleGUIInterface() : Qv2rayPlugin::Gui::Qv2rayGUIInterface(){}; 11 | ~SimpleGUIInterface(){}; 12 | QList GetComponents() const override 13 | { 14 | return { 15 | GUI_COMPONENT_SETTINGS, 16 | GUI_COMPONENT_MAIN_WINDOW_ACTIONS, 17 | }; 18 | } 19 | std::unique_ptr GetSettingsWidget() const override 20 | { 21 | return std::make_unique(); 22 | } 23 | PluginEditorDescriptor GetInboundEditors() const override 24 | { 25 | return {}; 26 | } 27 | PluginEditorDescriptor GetOutboundEditors() const override 28 | { 29 | return {}; 30 | } 31 | std::unique_ptr GetMainWindowWidget() const override 32 | { 33 | return std::make_unique(); 34 | } 35 | QIcon Icon() const override 36 | { 37 | return QIcon(":/assets/qv2ray.png"); 38 | } 39 | }; 40 | -------------------------------------------------------------------------------- /ui/PluginMainWindowWidget.cpp: -------------------------------------------------------------------------------- 1 | #include "PluginMainWindowWidget.hpp" 2 | 3 | SimplePluginMainWindowWidget::SimplePluginMainWindowWidget(QWidget *parent) : Qv2rayPlugin::Gui::PluginMainWindowWidget(parent) 4 | { 5 | setupUi(this); 6 | } 7 | 8 | void SimplePluginMainWindowWidget::changeEvent(QEvent *e) 9 | { 10 | QWidget::changeEvent(e); 11 | switch (e->type()) 12 | { 13 | case QEvent::LanguageChange: retranslateUi(this); break; 14 | default: break; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ui/PluginMainWindowWidget.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "QvPlugin/Gui/QvGUIPluginInterface.hpp" 4 | #include "ui_PluginMainWindowWidget.h" 5 | 6 | class SimplePluginMainWindowWidget 7 | : public Qv2rayPlugin::Gui::PluginMainWindowWidget 8 | , private Ui::PluginMainWindowWidget 9 | { 10 | Q_OBJECT 11 | 12 | public: 13 | explicit SimplePluginMainWindowWidget(QWidget *parent = nullptr); 14 | 15 | protected: 16 | void changeEvent(QEvent *e) override; 17 | }; 18 | -------------------------------------------------------------------------------- /ui/PluginMainWindowWidget.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | PluginMainWindowWidget 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 300 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 10 20 | 20 21 | 121 22 | 16 23 | 24 | 25 | 26 | Transparent Proxy 27 | 28 | 29 | 30 | 31 | 32 | 170 33 | 20 34 | 80 35 | 21 36 | 37 | 38 | 39 | Start 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /ui/PluginSettingsWidget.cpp: -------------------------------------------------------------------------------- 1 | #include "PluginSettingsWidget.hpp" 2 | 3 | SimplePluginSettingsWidget::SimplePluginSettingsWidget(QWidget *parent) : Qv2rayPlugin::Gui::PluginSettingsWidget(parent) 4 | { 5 | setupUi(this); 6 | option.autoStart.ReadWriteBind(autoStartCB, "checked", &QCheckBox::toggled); 7 | } 8 | 9 | void SimplePluginSettingsWidget::changeEvent(QEvent *e) 10 | { 11 | QWidget::changeEvent(e); 12 | switch (e->type()) 13 | { 14 | case QEvent::LanguageChange: retranslateUi(this); break; 15 | default: break; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ui/PluginSettingsWidget.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "QvPlugin/Gui/QvGUIPluginInterface.hpp" 4 | #include "core/Settings.hpp" 5 | #include "ui_PluginSettingsWidget.h" 6 | 7 | class SimplePluginSettingsWidget 8 | : public Qv2rayPlugin::Gui::PluginSettingsWidget 9 | , private Ui::PluginSettingsWidget 10 | { 11 | Q_OBJECT 12 | 13 | public: 14 | explicit SimplePluginSettingsWidget(QWidget *parent = nullptr); 15 | 16 | // PluginSettingsWidget interface 17 | public: 18 | void Load() override 19 | { 20 | option.loadJson(settings); 21 | } 22 | void Store() override 23 | { 24 | settings = option.toJson(); 25 | } 26 | 27 | protected: 28 | void changeEvent(QEvent *e) override; 29 | 30 | private: 31 | PluginOptions option; 32 | }; 33 | -------------------------------------------------------------------------------- /ui/PluginSettingsWidget.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | PluginSettingsWidget 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 300 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | Automatiacally Start 21 | 22 | 23 | 24 | 25 | 26 | 27 | Enabled 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | --------------------------------------------------------------------------------