Skip to content

Commit

Permalink
v2.9.4
Browse files Browse the repository at this point in the history
  • Loading branch information
bernerdad committed Jan 23, 2024
1 parent 3319da7 commit 5bb345d
Show file tree
Hide file tree
Showing 426 changed files with 8,319 additions and 13,725 deletions.
6 changes: 6 additions & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,11 @@ variables:
- curl --silent --show-error --fail -u "${NEXUS_USERNAME}:${NEXUS_PASSWORD}" --cacert tools/cacert.pem
--create-dirs -o ${BUILD_LIBS_FOLDER}/openvpn.zip "${NEXUS_PATH_DEPS}/${OS_IDENTIFIER}/openvpn.zip"

.download_dependency_openvpn_dco:
script:
- curl --silent --show-error --fail -u "${NEXUS_USERNAME}:${NEXUS_PASSWORD}" --cacert tools/cacert.pem
--create-dirs -o ${BUILD_LIBS_FOLDER}/openvpn_dco.zip "${NEXUS_PATH_DEPS}/${OS_IDENTIFIER}/openvpn_dco.zip"

.download_dependency_qt:
script:
- curl --silent --show-error --fail -u "${NEXUS_USERNAME}:${NEXUS_PASSWORD}" --cacert tools/cacert.pem
Expand Down Expand Up @@ -156,6 +161,7 @@ variables:
- !reference [.download_dependency_dga, script]
- !reference [.download_dependency_openssl, script]
- !reference [.download_dependency_openvpn, script]
- !reference [.download_dependency_openvpn_dco, script]
- !reference [.download_dependency_qt, script]
- !reference [.download_dependency_wintun, script]
- !reference [.download_dependency_wireguard, script]
Expand Down
8 changes: 3 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ install_zlib
install_curl
install_boost
install_openvpn
install_openvpn_dco
install_wintun
install_wireguard
install_wstunnel
Expand Down Expand Up @@ -191,13 +192,10 @@ Build process tested on Ubuntu 20.04/ZorinOS 16 (gcc 9.3.0).
- Install build requirements:
```bash
sudo apt-get update
sudo apt-get install build-essential git curl patchelf libpam0g-dev software-properties-common libgl1-mesa-dev fakeroot python3-pip zip unzip libnl-genl-3-dev pkg-config libcap-ng-dev wget autoconf libtool libfontconfig1-dev libfreetype6-dev libx11-dev libx11-xcb-dev libxext-dev libxfixes-dev libxi-dev libxrender-dev libxcb1-dev libxcb-cursor-dev libxcb-glx0-dev libxcb-keysyms1-dev libxcb-image0-dev libxcb-shm0-dev libxcb-icccm4-dev libxcb-sync-dev libxcb-xfixes0-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-render-util0-dev libxcb-util-dev libxcb-xinerama0-dev libxcb-xkb-dev libxkbcommon-dev libxkbcommon-x11-dev libwayland-dev
sudo apt-get install build-essential git curl patchelf libpam0g-dev software-properties-common libgl1-mesa-dev fakeroot python3-pip zip unzip libnl-genl-3-dev pkg-config libcap-ng-dev wget autoconf libtool libfontconfig1-dev libfreetype6-dev libx11-dev libx11-xcb-dev libxext-dev libxfixes-dev libxi-dev libxrender-dev libxcb1-dev libxcb-cursor-dev libxcb-glx0-dev libxcb-keysyms1-dev libxcb-image0-dev libxcb-shm0-dev libxcb-icccm4-dev libxcb-sync-dev libxcb-xfixes0-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-render-util0-dev libxcb-util-dev libxcb-xinerama0-dev libxcb-xkb-dev libxkbcommon-dev libxkbcommon-x11-dev

# install cmake 3.23.x or newer (default for Ubuntu 20.04 is 3.16.3)
wget -qO /etc/apt/trusted.gpg.d/kitware-key.asc https://apt.kitware.com/keys/kitware-archive-latest.asc
echo "deb https://apt.kitware.com/ubuntu/ focal main" | tee /etc/apt/sources.list.d/kitware.list
sudo apt-get -y update
sudo apt-get -y install cmake
sudo snap install cmake --classic
```
- Install golang (minimum version 1.18): follow instructions from `https://go.dev/doc/install`
- Clone the repository.
Expand Down
2 changes: 2 additions & 0 deletions backend/linux/helper/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ set(SOURCES
routes_manager/bound_route.cpp
routes_manager/routes.cpp
routes_manager/routes_manager.cpp
split_tunneling/cgroups.cpp
split_tunneling/process_monitor.cpp
split_tunneling/split_tunneling.cpp
split_tunneling/hostnames_manager/ares_library_init.cpp
split_tunneling/hostnames_manager/dns_resolver.cpp
Expand Down
169 changes: 109 additions & 60 deletions backend/linux/helper/firewallcontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <fstream>
#include <sstream>

#include "split_tunneling/cgroups.h"
#include "logger.h"
#include "utils.h"

Expand All @@ -21,26 +22,26 @@ bool FirewallController::enable(bool ipv6, const std::string &rules)
if (fd < 0) {
Logger::instance().out("Could not open firewall rules for writing");
return 1;
} else {
int bytes = write(fd, rules.c_str(), rules.length());
close(fd);
if (bytes <= 0) {
Logger::instance().out("Could not write rules");
return 1;
} else {
if (ipv6) {
Utils::executeCommand("ip6tables-restore", {"-n", "/etc/windscribe/rules.v6"});
} else {
Utils::executeCommand("iptables-restore", {"-n", "/etc/windscribe/rules.v4"});
}
enabled_ = true;
}

// reapply split tunneling rules if necessary
setSplitTunnelExceptions(splitTunnelIps_);
int bytes = write(fd, rules.c_str(), rules.length());
close(fd);
if (bytes <= 0) {
Logger::instance().out("Could not write rules");
return 1;
}

return 0;
}
if (ipv6) {
Utils::executeCommand("ip6tables-restore", {"-n", "/etc/windscribe/rules.v6"});
} else {
Utils::executeCommand("iptables-restore", {"-n", "/etc/windscribe/rules.v4"});
}

// reapply split tunneling rules if necessary
setSplitTunnelIpExceptions(splitTunnelIps_);
setSplitTunnelAppExceptions();

return 0;
}

void FirewallController::getRules(bool ipv6, std::string *outRules)
Expand Down Expand Up @@ -70,83 +71,131 @@ void FirewallController::disable()
{
Utils::executeCommand("rm", {"-f", "/etc/windscribe/rules.v4"});
Utils::executeCommand("rm", {"-f", "/etc/windscribe/rules.v6"});

enabled_ = false;
}


void FirewallController::setSplitTunnelingEnabled(bool isConnected, bool isEnabled, bool isExclude)
void FirewallController::setSplitTunnelingEnabled(bool isConnected, bool isEnabled, bool isExclude, const std::string &defaultAdapter)
{
connected_ = isConnected;
splitTunnelEnabled_ = isEnabled;
splitTunnelExclude_ = isExclude;
prevAdapter_ = defaultAdapter_;
defaultAdapter_ = defaultAdapter;

// If firewall is on, apply rules immediately
if (enabled_) {
setSplitTunnelExceptions(splitTunnelIps_);
}
setSplitTunnelIpExceptions(splitTunnelIps_);
setSplitTunnelAppExceptions();
}

void FirewallController::removeExclusiveRules()
void FirewallController::removeExclusiveIpRules()
{
for (auto ip : splitTunnelIps_) {
Logger::instance().out("Removing exclude rule for %s", ip.c_str());
Utils::executeCommand("iptables", {"-D", "windscribe_input", "-s", (ip + "/32").c_str(), "-j", "ACCEPT", "-m", "comment", "--comment", "Windscribe client rule"});
Utils::executeCommand("iptables", {"-D", "windscribe_output", "-d", (ip + "/32").c_str(), "-j", "ACCEPT", "-m", "comment", "--comment", "Windscribe client rule"});
Utils::executeCommand("iptables", {"-D", "windscribe_input", "-s", (ip + "/32").c_str(), "-j", "ACCEPT", "-m", "comment", "--comment", kTag});
Utils::executeCommand("iptables", {"-D", "windscribe_output", "-d", (ip + "/32").c_str(), "-j", "ACCEPT", "-m", "comment", "--comment", kTag});
}
}

void FirewallController::removeInclusiveIpRules()
{
Utils::executeCommand("iptables", {"-D", "windscribe_input", "-j", "ACCEPT", "-m", "comment", "--comment", kTag});
Utils::executeCommand("iptables", {"-D", "windscribe_output", "-j", "ACCEPT", "-m", "comment", "--comment", kTag});
}

void FirewallController::removeExclusiveAppRules()
{
Utils::executeCommand("iptables", {"-D", "OUTPUT", "-t", "mangle", "-m", "cgroup", "--cgroup", CGroups::instance().netClassId(), "-j", "MARK", "--set-mark", CGroups::instance().mark(), "-m", "comment", "--comment", kTag});
if (!prevAdapter_.empty()) {
Utils::executeCommand("iptables", {"-D", "POSTROUTING", "-t", "nat", "-m", "cgroup", "--cgroup", CGroups::instance().netClassId(), "-o", prevAdapter_.c_str(), "-j", "MASQUERADE", "-m", "comment", "--comment", kTag});
}

Utils::executeCommand("iptables", {"-D", "windscribe_input", "-j", "ACCEPT", "-m", "comment", "--comment", kTag});
Utils::executeCommand("iptables", {"-D", "windscribe_output", "-j", "ACCEPT", "-m", "comment", "--comment", kTag});
}

void FirewallController::removeInclusiveRules()
void FirewallController::removeInclusiveAppRules()
{
Utils::executeCommand("iptables", {"-D", "windscribe_input", "-s", "0/0", "-j", "ACCEPT", "-m", "comment", "--comment", "Windscribe client rule"});
Utils::executeCommand("iptables", {"-D", "windscribe_output", "-d", "0/0", "-j", "ACCEPT", "-m", "comment", "--comment", "Windscribe client rule"});
Utils::executeCommand("iptables", {"-D", "OUTPUT", "-t", "mangle", "-m", "cgroup", "!", "--cgroup", CGroups::instance().netClassId(), "-j", "MARK", "--set-mark", CGroups::instance().mark(), "-m", "comment", "--comment", kTag});
if (!prevAdapter_.empty()) {
Utils::executeCommand("iptables", {"-D", "POSTROUTING", "-t", "nat", "-m", "cgroup", "!", "--cgroup", CGroups::instance().netClassId(), "-o", prevAdapter_.c_str(), "-j", "MASQUERADE", "-m", "comment", "--comment", kTag});
}
}

void FirewallController::setSplitTunnelExceptions(const std::vector<std::string> &ips)
void FirewallController::setSplitTunnelAppExceptions()
{
if (!connected_ || !splitTunnelEnabled_) {
removeInclusiveRules();
removeExclusiveRules();
removeExclusiveAppRules();
removeInclusiveAppRules();
return;
}

if (splitTunnelExclude_) {
removeInclusiveAppRules();

addRule({"POSTROUTING", "-t", "nat", "-m", "cgroup", "--cgroup", CGroups::instance().netClassId(), "-o", defaultAdapter_.c_str(), "-j", "MASQUERADE", "-m", "comment", "--comment", kTag});
addRule({"OUTPUT", "-t", "mangle", "-m", "cgroup", "--cgroup", CGroups::instance().netClassId(), "-j", "MARK", "--set-mark", CGroups::instance().mark(), "-m", "comment", "--comment", kTag});

// allow packets from excluded apps, if firewall is on
if (enabled()) {
addRule({"windscribe_input", "-m", "cgroup", "--cgroup", CGroups::instance().netClassId(), "-j", "ACCEPT", "-m", "comment", "--comment", kTag});
addRule({"windscribe_output", "-m", "cgroup", "--cgroup", CGroups::instance().netClassId(), "-j", "ACCEPT", "-m", "comment", "--comment", kTag});
}
} else {
removeExclusiveAppRules();

addRule({"POSTROUTING", "-t", "nat", "-m", "cgroup", "!", "--cgroup", CGroups::instance().netClassId(), "-o", defaultAdapter_.c_str(), "-j", "MASQUERADE", "-m", "comment", "--comment", kTag});
addRule({"OUTPUT", "-t", "mangle", "-m", "cgroup", "!", "--cgroup", CGroups::instance().netClassId(), "-j", "MARK", "--set-mark", CGroups::instance().mark(), "-m", "comment", "--comment", kTag});

// For inclusive, allow all packets
if (enabled()) {
addRule({"windscribe_input", "-j", "ACCEPT", "-m", "comment", "--comment", kTag});
addRule({"windscribe_output", "-j", "ACCEPT", "-m", "comment", "--comment", kTag});
}
}
}

void FirewallController::setSplitTunnelIpExceptions(const std::vector<std::string> &ips)
{
if (!connected_ || !splitTunnelEnabled_ || !enabled()) {
removeInclusiveIpRules();
removeExclusiveIpRules();
splitTunnelIps_ = ips;
return;
}

// Otherwise, split tunneling is still enabled.
if (splitTunnelExclude_) {
removeInclusiveRules();
removeInclusiveIpRules();

// For exclusive, remove rules for addresses no longer in "ips"
for (auto ip : splitTunnelIps_) {
if (std::find(ips.begin(), ips.end(), ip) == ips.end()) {
Logger::instance().out("Removing old exclude rule for %s", ip.c_str());
Utils::executeCommand("iptables", {"-D", "windscribe_input", "-s", (ip + "/32").c_str(), "-j", "ACCEPT", "-m", "comment", "--comment", "Windscribe client rule"});
Utils::executeCommand("iptables", {"-D", "windscribe_output", "-d", (ip + "/32").c_str(), "-j", "ACCEPT", "-m", "comment", "--comment", "Windscribe client rule"});
Utils::executeCommand("iptables", {"-D", "windscribe_input", "-s", (ip + "/32").c_str(), "-j", "ACCEPT", "-m", "comment", "--comment", kTag});
Utils::executeCommand("iptables", {"-D", "windscribe_output", "-d", (ip + "/32").c_str(), "-j", "ACCEPT", "-m", "comment", "--comment", kTag});
}
}

// Add rules for new IPs
for (auto ip : ips) {
Logger::instance().out("Adding exclude rule for %s", ip.c_str());
int ret = Utils::executeCommand("iptables", {"-C", "windscribe_input", "-s", (ip + "/32").c_str(), "-j", "ACCEPT", "-m", "comment", "--comment", "Windscribe client rule"});
if (ret) {
Utils::executeCommand("iptables", {"-I", "windscribe_input", "-s", (ip + "/32").c_str(), "-j", "ACCEPT", "-m", "comment", "--comment", "Windscribe client rule"});
}
ret = Utils::executeCommand("iptables", {"-C", "windscribe_output", "-d", (ip + "/32").c_str(), "-j", "ACCEPT", "-m", "comment", "--comment", "Windscribe client rule"});
if (ret) {
ret = Utils::executeCommand("iptables", {"-I", "windscribe_output", "-d", (ip + "/32").c_str(), "-j", "ACCEPT", "-m", "comment", "--comment", "Windscribe client rule"});
}
addRule({"windscribe_input", "-s", (ip + "/32").c_str(), "-j", "ACCEPT", "-m", "comment", "--comment", kTag});
addRule({"windscribe_output", "-d", (ip + "/32").c_str(), "-j", "ACCEPT", "-m", "comment", "--comment", kTag});
}
} else {
removeExclusiveRules();
// For inclusive, keep the "allow all" rules
int ret = Utils::executeCommand("iptables", {"-C", "windscribe_input", "-s", "0/0", "-j", "ACCEPT", "-m", "comment", "--comment", "Windscribe client rule"});
if (ret) {
Logger::instance().out("Adding inclusive input rule");
Utils::executeCommand("iptables", {"-I", "windscribe_input", "-s", "0/0", "-j", "ACCEPT", "-m", "comment", "--comment", "Windscribe client rule"});
}
ret = Utils::executeCommand("iptables", {"-C", "windscribe_output", "-d", "0/0", "-j", "ACCEPT", "-m", "comment", "--comment", "Windscribe client rule"});
if (ret) {
Logger::instance().out("Adding inclusive output rule");
Utils::executeCommand("iptables", {"-I", "windscribe_output", "-d", "0/0", "-j", "ACCEPT", "-m", "comment", "--comment", "Windscribe client rule"});
}
removeExclusiveIpRules();

// For inclusive, keep the "allow all" rules; these rules only apply to non-included apps
addRule({"windscribe_input", "-j", "ACCEPT", "-m", "comment", "--comment", kTag});
addRule({"windscribe_output", "-j", "ACCEPT", "-m", "comment", "--comment", kTag});
}

splitTunnelIps_ = ips;
}

void FirewallController::addRule(const std::vector<std::string> &args)
{
std::vector<std::string> checkArgs = args;
checkArgs.insert(checkArgs.begin(), "-C");
int ret = Utils::executeCommand("iptables", checkArgs);
if (ret) {
std::vector<std::string> insertArgs = args;
insertArgs.insert(insertArgs.begin(), "-I");
Utils::executeCommand("iptables", insertArgs);
}
}
26 changes: 19 additions & 7 deletions backend/linux/helper/firewallcontroller.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
class FirewallController
{
public:
inline static const std::string kTag = "Windscribe client rule";

static FirewallController & instance()
{
static FirewallController fc;
Expand All @@ -14,22 +16,32 @@ class FirewallController

bool enable(bool ipv6, const std::string &rules);
void disable();
bool enabled(const std::string &tag);
bool enabled(const std::string &tag = kTag);
void getRules(bool ipv6, std::string *outRules);

void setSplitTunnelingEnabled(bool isConnected, bool isEnabled, bool isExclude);
void setSplitTunnelExceptions(const std::vector<std::string> &ips);
void setSplitTunnelingEnabled(
bool isConnected,
bool isEnabled,
bool isExclude,
const std::string &adapter);
void setSplitTunnelIpExceptions(const std::vector<std::string> &ips);

private:
FirewallController() : enabled_(false), connected_(false), splitTunnelEnabled_(false), splitTunnelExclude_(true) {};
FirewallController() : connected_(false), splitTunnelEnabled_(false), splitTunnelExclude_(true) {};
~FirewallController() { disable(); };

bool enabled_;
bool connected_;
bool splitTunnelEnabled_;
bool splitTunnelExclude_;
std::vector<std::string> splitTunnelIps_;
std::string defaultAdapter_;
std::string prevAdapter_;
std::string netclassid_;

void removeExclusiveRules();
void removeInclusiveRules();
void removeExclusiveIpRules();
void removeInclusiveIpRules();
void removeExclusiveAppRules();
void removeInclusiveAppRules();
void setSplitTunnelAppExceptions();
void addRule(const std::vector<std::string> &args);
};
2 changes: 1 addition & 1 deletion backend/linux/helper/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ void handler_sigterm(int signum)
{
UNUSED(signum);
Logger::instance().out("Windscribe helper terminated");
server.stop();
exit(0);
}

int main(int argc, const char *argv[])
Expand Down
12 changes: 8 additions & 4 deletions backend/linux/helper/process_command.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ CMD_ANSWER splitTunnelingSettings(boost::archive::text_iarchive &ia)
CMD_SPLIT_TUNNELING_SETTINGS cmd;
ia >> cmd;

SplitTunneling::instance().setSplitTunnelingParams(cmd.isActive, cmd.isExclude, cmd.files, cmd.ips, cmd.hosts);
SplitTunneling::instance().setSplitTunnelingParams(cmd.isActive, cmd.isExclude, cmd.files, cmd.ips, cmd.hosts, cmd.isAllowLanTraffic);
answer.executed = 1;

return answer;
Expand All @@ -113,8 +113,11 @@ CMD_ANSWER sendConnectStatus(boost::archive::text_iarchive &ia)
CMD_SEND_CONNECT_STATUS cmd;
ia >> cmd;

SplitTunneling::instance().setConnectParams(cmd);
answer.executed = 1;
if (SplitTunneling::instance().setConnectParams(cmd)) {
answer.executed = 0;
} else {
answer.executed = 1;
}

return answer;
}
Expand Down Expand Up @@ -160,7 +163,8 @@ CMD_ANSWER configureWireGuard(boost::archive::text_iarchive &ia)

if (!WireGuardController::instance().configure(cmd.clientPrivateKey,
cmd.peerPublicKey, cmd.peerPresharedKey,
cmd.peerEndpoint, allowed_ips_vector, fwmark)) {
cmd.peerEndpoint, allowed_ips_vector,
fwmark, cmd.listenPort)) {
Logger::instance().out("WireGuard: configure() failed");
break;
}
Expand Down
Loading

0 comments on commit 5bb345d

Please sign in to comment.