Skip to content

Commit e63010b

Browse files
committed
feat: Add firewall rule automatically for TCP mode
1 parent 2c18933 commit e63010b

File tree

6 files changed

+92
-27
lines changed

6 files changed

+92
-27
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ add_executable(connecttool-qt
116116
steam/steam_vpn_bridge.cpp)
117117

118118
if(WIN32)
119-
target_sources(connecttool-qt PRIVATE tun/tun_windows.cpp)
119+
target_sources(connecttool-qt PRIVATE tun/tun_windows.cpp src/firewall_windows.cpp)
120120
elseif(APPLE)
121121
target_sources(connecttool-qt PRIVATE tun/tun_macos.cpp)
122122
else()

net/tcp_server.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "tcp_server.h"
22
#include "../steam/steam_networking_manager.h"
3+
#include "firewall_windows.h"
34
#include <iostream>
45
#include <algorithm>
56

@@ -15,6 +16,16 @@ bool TCPServer::start() {
1516
acceptor_.bind(endpoint);
1617
acceptor_.listen();
1718

19+
#if defined(_WIN32)
20+
if (!ensureTcpFirewallRule("ConnectTool TCP inbound", port_)) {
21+
std::cerr << "Failed to add firewall rule for TCP port " << port_
22+
<< std::endl;
23+
} else {
24+
std::cout << "Added firewall rule for TCP port " << port_
25+
<< std::endl;
26+
}
27+
#endif
28+
1829
running_ = true;
1930
serverThread_ = std::thread([this]() {
2031
std::cout << "Server thread started" << std::endl;

src/backend.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "../steam/steam_utils.h"
77
#include "../steam/steam_vpn_bridge.h"
88
#include "../steam/steam_vpn_networking_manager.h"
9+
#include "firewall_windows.h"
910

1011
#include <QClipboard>
1112
#include <QCoreApplication>
@@ -224,6 +225,7 @@ QString stripGhProxyPrefix(const QString &url) {
224225
}
225226
return url;
226227
}
228+
227229
} // namespace
228230

229231
Backend::Backend(QObject *parent)
@@ -627,6 +629,15 @@ void Backend::startHosting() {
627629

628630
if (roomManager_ && roomManager_->startHosting()) {
629631
steamManager_->setHostSteamID(SteamUser()->GetSteamID());
632+
#ifdef Q_OS_WIN
633+
if (localPort_ > 0) {
634+
if (!ensureTcpFirewallRule("ConnectTool TCP forward", localPort_)) {
635+
qWarning() << "Failed to add firewall rule for TCP port" << localPort_;
636+
} else {
637+
qInfo() << "Added firewall rule for TCP port" << localPort_;
638+
}
639+
}
640+
#endif
630641
updateStatus();
631642
refreshLobbies();
632643
} else {

src/firewall_windows.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#ifdef _WIN32
2+
3+
#include "firewall_windows.h"
4+
5+
#include <cstdlib>
6+
#include <sstream>
7+
#include <string>
8+
9+
namespace {
10+
std::string escape_ps(const std::string &value) {
11+
std::string escaped;
12+
escaped.reserve(value.size());
13+
for (char c : value) {
14+
if (c == '\'') {
15+
escaped += "''";
16+
} else {
17+
escaped.push_back(c);
18+
}
19+
}
20+
return escaped;
21+
}
22+
} // namespace
23+
24+
bool ensureTcpFirewallRule(const char *ruleName, int port) {
25+
if (port <= 0 || ruleName == nullptr || ruleName[0] == '\0') {
26+
return false;
27+
}
28+
const std::string escapedName = escape_ps(ruleName);
29+
std::ostringstream ps;
30+
ps << "powershell -Command \"$ErrorActionPreference='SilentlyContinue'; "
31+
<< "Remove-NetFirewallRule -DisplayName '" << escapedName
32+
<< "' -ErrorAction SilentlyContinue; "
33+
<< "New-NetFirewallRule -DisplayName '" << escapedName
34+
<< "' -Direction Inbound -Action Allow -Protocol TCP -LocalPort "
35+
<< port << " -Enabled True\"";
36+
return ::system(ps.str().c_str()) == 0;
37+
}
38+
39+
bool ensureTunFirewallRule(const char *ruleName, const char *interfaceAlias) {
40+
if (ruleName == nullptr || ruleName[0] == '\0' || interfaceAlias == nullptr ||
41+
interfaceAlias[0] == '\0') {
42+
return false;
43+
}
44+
const std::string escapedName = escape_ps(ruleName);
45+
const std::string escapedAlias = escape_ps(interfaceAlias);
46+
std::ostringstream ps;
47+
ps << "powershell -Command \"$ErrorActionPreference='SilentlyContinue'; "
48+
<< "Remove-NetFirewallRule -DisplayName '" << escapedName
49+
<< "' -ErrorAction SilentlyContinue; "
50+
<< "New-NetFirewallRule -DisplayName '" << escapedName
51+
<< "' -Direction Inbound -Action Allow -Protocol Any "
52+
<< "-InterfaceAlias '" << escapedAlias << "' -Enabled True\"";
53+
return ::system(ps.str().c_str()) == 0;
54+
}
55+
56+
#endif

src/firewall_windows.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#pragma once
2+
3+
#ifdef _WIN32
4+
bool ensureTcpFirewallRule(const char *ruleName, int port);
5+
bool ensureTunFirewallRule(const char *ruleName, const char *interfaceAlias);
6+
#else
7+
inline bool ensureTcpFirewallRule(const char *, int) { return true; }
8+
inline bool ensureTunFirewallRule(const char *, const char *) { return true; }
9+
#endif

tun/tun_windows.cpp

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#ifdef _WIN32
22

33
#include "tun_interface.h"
4+
#include "firewall_windows.h"
45

56
#ifndef _WIN32_WINNT
67
#define _WIN32_WINNT 0x0601
@@ -381,37 +382,14 @@ class TunWindows : public TunInterface {
381382
}
382383

383384
private:
384-
static std::string escape_ps(const std::string &value) {
385-
std::string escaped;
386-
escaped.reserve(value.size());
387-
for (char c : value) {
388-
if (c == '\'') {
389-
escaped += "''";
390-
} else {
391-
escaped.push_back(c);
392-
}
393-
}
394-
return escaped;
395-
}
396-
397385
void ensureFirewallRule() const {
398386
if (deviceName_.empty()) {
399387
return;
400388
}
401-
const std::string ruleName = "ConnectTool TUN inbound";
402-
const std::string escapedName = escape_ps(ruleName);
403-
const std::string escapedAlias = escape_ps(deviceName_);
404-
std::ostringstream ps;
405-
ps << "powershell -Command \"$ErrorActionPreference='SilentlyContinue'; "
406-
<< "Remove-NetFirewallRule -DisplayName '" << escapedName
407-
<< "' -ErrorAction SilentlyContinue; "
408-
<< "New-NetFirewallRule -DisplayName '" << escapedName
409-
<< "' -Direction Inbound -Action Allow -Protocol Any "
410-
<< "-InterfaceAlias '" << escapedAlias << "' -Enabled True\"";
411-
const int rc = ::system(ps.str().c_str());
412-
if (rc != 0) {
389+
const char *ruleName = "ConnectTool TUN inbound";
390+
if (!ensureTunFirewallRule(ruleName, deviceName_.c_str())) {
413391
std::cerr << "Failed to add firewall rule for " << deviceName_
414-
<< " (rc=" << rc << ")" << std::endl;
392+
<< std::endl;
415393
} else {
416394
std::cout << "Added firewall rule for interface " << deviceName_
417395
<< std::endl;

0 commit comments

Comments
 (0)