Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: CI

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
build-and-test:
name: Build & Test (Ubuntu)
runs-on: ubuntu-22.04

steps:
- uses: actions/checkout@v4
with:
submodules: recursive

- name: Install dependencies
run: |
sudo apt-get update -y
sudo apt-get install -y \
libxtst-dev \
qtdeclarative5-dev \
libavahi-compat-libdnssd-dev \
libcurl4-openssl-dev \
libssl-dev \
cmake \
make

- name: Configure
run: cmake -B build -DCMAKE_BUILD_TYPE=Debug -DBARRIER_BUILD_TESTS=ON

- name: Build
run: cmake --build build --parallel $(nproc)

- name: Run unit tests
run: ctest --test-dir build --output-on-failure -R unittests
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,9 @@ CMakeCache.txt
# Transient in-project-directory dependencies
/deps/
/out/build/x64-Debug
/build-test

# Beads / Dolt files (added by bd init)
.dolt/
*.db
.beads-credential-key
6 changes: 6 additions & 0 deletions src/gui/src/AppConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ void AppConfig::loadSettings()
m_ElevateMode = static_cast<ElevateMode>(elevateMode.toInt());
m_AutoConfigPrompted = settings().value("autoConfigPrompted", false).toBool();
m_CryptoEnabled = settings().value("cryptoEnabled", true).toBool();
m_TailscaleMode = settings().value("tailscaleMode", false).toBool();
// TODO: set default value of requireClientCertificate to true on Barrier 2.5.0
m_RequireClientCertificate = settings().value("requireClientCertificate", false).toBool();
m_AutoHide = settings().value("autoHide", false).toBool();
Expand All @@ -183,6 +184,7 @@ void AppConfig::saveSettings()
settings().setValue("elevateModeEnum", static_cast<int>(m_ElevateMode));
settings().setValue("autoConfigPrompted", m_AutoConfigPrompted);
settings().setValue("cryptoEnabled", m_CryptoEnabled);
settings().setValue("tailscaleMode", m_TailscaleMode);
settings().setValue("requireClientCertificate", m_RequireClientCertificate);
settings().setValue("autoHide", m_AutoHide);
settings().setValue("autoStart", m_AutoStart);
Expand Down Expand Up @@ -228,6 +230,10 @@ void AppConfig::setCryptoEnabled(bool e) { m_CryptoEnabled = e; }

bool AppConfig::getCryptoEnabled() const { return m_CryptoEnabled; }

void AppConfig::setTailscaleMode(bool e) { m_TailscaleMode = e; }

bool AppConfig::getTailscaleMode() const { return m_TailscaleMode; }

void AppConfig::setRequireClientCertificate(bool e) { m_RequireClientCertificate = e; }

bool AppConfig::getRequireClientCertificate() const { return m_RequireClientCertificate; }
Expand Down
4 changes: 4 additions & 0 deletions src/gui/src/AppConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ class AppConfig: public QObject
void setCryptoEnabled(bool e);
bool getCryptoEnabled() const;

void setTailscaleMode(bool e);
bool getTailscaleMode() const;

void setRequireClientCertificate(bool e);
bool getRequireClientCertificate() const;

Expand Down Expand Up @@ -135,6 +138,7 @@ class AppConfig: public QObject
ElevateMode m_ElevateMode;
bool m_AutoConfigPrompted;
bool m_CryptoEnabled;
bool m_TailscaleMode = false;
bool m_RequireClientCertificate = false;
bool m_AutoHide;
bool m_AutoStart;
Expand Down
4 changes: 3 additions & 1 deletion src/gui/src/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,9 @@ void MainWindow::startBarrier()

#endif

if (!m_AppConfig->getCryptoEnabled()) {
if (m_AppConfig->getTailscaleMode()) {
args << "--tailscale-mode";
} else if (!m_AppConfig->getCryptoEnabled()) {
args << "--disable-crypto";
}

Expand Down
12 changes: 12 additions & 0 deletions src/gui/src/SettingsDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ SettingsDialog::SettingsDialog(QWidget* parent, AppConfig& config) :
m_pCheckBoxMinimizeToTray->setChecked(appConfig().getMinimizeToTray());
m_pCheckBoxEnableCrypto->setChecked(m_appConfig.getCryptoEnabled());
checkbox_require_client_certificate->setChecked(m_appConfig.getRequireClientCertificate());
m_pCheckBoxTailscaleMode->setChecked(m_appConfig.getTailscaleMode());
// Set initial enabled state of SSL controls to match Tailscale checkbox
on_m_pCheckBoxTailscaleMode_stateChanged(m_appConfig.getTailscaleMode() ? 2 : 0);

#if defined(Q_OS_WIN)
m_pComboElevate->setCurrentIndex(static_cast<int>(appConfig().elevateMode()));
Expand All @@ -69,6 +72,7 @@ void SettingsDialog::accept()
m_appConfig.setNetworkInterface(m_pLineEditInterface->text());
m_appConfig.setCryptoEnabled(m_pCheckBoxEnableCrypto->isChecked());
m_appConfig.setRequireClientCertificate(checkbox_require_client_certificate->isChecked());
m_appConfig.setTailscaleMode(m_pCheckBoxTailscaleMode->isChecked());
m_appConfig.setLogLevel(m_pComboLogLevel->currentIndex());
m_appConfig.setLogToFile(m_pCheckBoxLogToFile->isChecked());
m_appConfig.setLogFilename(m_pLineEditLogFilename->text());
Expand Down Expand Up @@ -121,6 +125,14 @@ void SettingsDialog::on_m_pCheckBoxLogToFile_stateChanged(int i)
m_pButtonBrowseLog->setEnabled(checked);
}

void SettingsDialog::on_m_pCheckBoxTailscaleMode_stateChanged(int i)
{
// When Tailscale is active it owns encryption; SSL controls have no effect.
bool tailscale = i == 2;
m_pCheckBoxEnableCrypto->setEnabled(!tailscale);
checkbox_require_client_certificate->setEnabled(!tailscale);
}

void SettingsDialog::on_m_pButtonBrowseLog_clicked()
{
QString fileName = QFileDialog::getSaveFileName(
Expand Down
1 change: 1 addition & 0 deletions src/gui/src/SettingsDialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class SettingsDialog : public QDialog, public Ui::SettingsDialogBase
void on_m_pComboLanguage_currentIndexChanged(int index);
void on_m_pCheckBoxLogToFile_stateChanged(int );
void on_m_pButtonBrowseLog_clicked();
void on_m_pCheckBoxTailscaleMode_stateChanged(int );
};

#endif
11 changes: 11 additions & 0 deletions src/gui/src/SettingsDialogBase.ui
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,16 @@
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QCheckBox" name="m_pCheckBoxTailscaleMode">
<property name="text">
<string>Use &amp;Tailscale (disables SSL — Tailscale handles encryption)</string>
</property>
<property name="toolTip">
<string>When checked, Barrier binds to the Tailscale network interface and disables its own TLS. Tailscale provides end-to-end encryption.</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
Expand Down Expand Up @@ -340,6 +350,7 @@
<tabstop>m_pSpinBoxPort</tabstop>
<tabstop>m_pLineEditInterface</tabstop>
<tabstop>m_pCheckBoxEnableCrypto</tabstop>
<tabstop>m_pCheckBoxTailscaleMode</tabstop>
<tabstop>m_pComboLogLevel</tabstop>
<tabstop>m_pCheckBoxLogToFile</tabstop>
<tabstop>m_pLineEditLogFilename</tabstop>
Expand Down
2 changes: 2 additions & 0 deletions src/lib/barrier/App.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ class MinimalApp : public App {
" --enable-drag-drop enable file drag & drop.\n" \
" --enable-crypto enable the crypto (ssl) plugin (default, deprecated).\n" \
" --disable-crypto disable the crypto (ssl) plugin.\n" \
" --tailscale-mode bind to Tailscale interface, disable TLS\n" \
" (Tailscale handles encryption end-to-end).\n" \
" --profile-dir <path> use named profile directory instead.\n" \
" --drop-dir <path> use named drop target directory instead.\n"

Expand Down
5 changes: 5 additions & 0 deletions src/lib/barrier/ArgParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,11 @@ ArgParser::parseGenericArgs(int argc, const char* const* argv, int& i)
else if (isArg(i, argc, argv, NULL, "--disable-crypto")) {
argsBase().m_enableCrypto = false;
}
else if (isArg(i, argc, argv, NULL, "--tailscale-mode")) {
argsBase().m_tailscaleMode = true;
argsBase().m_enableCrypto = false;
LOG((CLOG_INFO "tailscale mode: binding to Tailscale interface, TLS disabled (Tailscale handles encryption)"));
}
else if (isArg(i, argc, argv, NULL, "--profile-dir", 1)) {
argsBase().m_profileDirectory = barrier::fs::u8path(argv[++i]);
}
Expand Down
1 change: 1 addition & 0 deletions src/lib/barrier/ArgsBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ m_dropTarget(""),
m_shouldExit(false),
m_barrierAddress(),
m_enableCrypto(true),
m_tailscaleMode(false),
m_profileDirectory(),
m_pluginDirectory("")
{
Expand Down
1 change: 1 addition & 0 deletions src/lib/barrier/ArgsBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class ArgsBase {
bool m_shouldExit;
String m_barrierAddress;
bool m_enableCrypto;
bool m_tailscaleMode;
barrier::fs::path m_profileDirectory;
barrier::fs::path m_pluginDirectory;
};
10 changes: 10 additions & 0 deletions src/lib/barrier/ClientApp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include "base/EventQueue.h"
#include "base/Log.h"
#include "common/Version.h"
#include "net/TailscaleUtil.h"

#if WINAPI_MSWINDOWS
#include "platform/MSWindowsScreen.h"
Expand Down Expand Up @@ -387,6 +388,15 @@ ClientApp::foregroundStartup(int argc, char** argv)
bool
ClientApp::startClient()
{
if (args().m_tailscaleMode) {
std::string tsAddr = barrier::get_tailscale_address();
if (tsAddr.empty()) {
LOG((CLOG_ERR "tailscale mode is active but no Tailscale interface found -- is Tailscale running?"));
return false;
}
LOG((CLOG_NOTE "tailscale mode active: TLS disabled, expecting server on Tailscale network (%s local)", tsAddr.c_str()));
}

double retryTime;
barrier::Screen* clientScreen = NULL;
try {
Expand Down
11 changes: 11 additions & 0 deletions src/lib/barrier/ServerApp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include "base/Log.h"
#include "base/TMethodEventJob.h"
#include "common/Version.h"
#include "net/TailscaleUtil.h"
#include "common/DataDirectories.h"

#if SYSAPI_WIN32
Expand Down Expand Up @@ -564,6 +565,16 @@ ServerApp::startServer()
ClientListener* listener = NULL;
try {
auto listenAddress = args().m_config->getBarrierAddress();
if (args().m_tailscaleMode) {
std::string tsAddr = barrier::get_tailscale_address();
if (tsAddr.empty()) {
LOG((CLOG_ERR "tailscale mode is active but no Tailscale interface found -- is Tailscale running?"));
return false;
}
LOG((CLOG_NOTE "tailscale mode: binding server to %s", tsAddr.c_str()));
listenAddress = NetworkAddress(tsAddr, listenAddress.getPort());
listenAddress.resolve();
}
auto family = family_string(ARCH->getAddrFamily(listenAddress.getAddress()));
listener = openClientListener(listenAddress);
m_server = openServer(*args().m_config, m_primaryClient);
Expand Down
108 changes: 108 additions & 0 deletions src/lib/net/TailscaleUtil.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2024 Barrier Contributors
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "net/TailscaleUtil.h"

#if SYSAPI_WIN32
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# include <iphlpapi.h>
# pragma comment(lib, "iphlpapi.lib")
#else
# include <ifaddrs.h>
# include <netinet/in.h>
# include <arpa/inet.h>
#endif

#include <cstdint>

namespace barrier {

// Tailscale uses the 100.64.0.0/10 CGNAT block:
// first address: 100.64.0.0 → 0x64400000
// last address: 100.127.255.255 → 0x647FFFFF
namespace detail {
bool is_tailscale_addr(uint32_t addr_host_order)
{
return (addr_host_order >= 0x64400000u) && (addr_host_order <= 0x647FFFFFu);
}
} // namespace detail

std::string get_tailscale_address()
{
#if SYSAPI_WIN32
// Use GetAdaptersAddresses to enumerate IPv4 addresses on Windows.
ULONG bufLen = 15000;
auto buf = std::make_unique<char[]>(bufLen);
IP_ADAPTER_ADDRESSES* adapters = reinterpret_cast<IP_ADAPTER_ADDRESSES*>(buf.get());

ULONG ret = GetAdaptersAddresses(AF_INET,
GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER,
nullptr, adapters, &bufLen);

if (ret == ERROR_BUFFER_OVERFLOW) {
buf = std::make_unique<char[]>(bufLen);
adapters = reinterpret_cast<IP_ADAPTER_ADDRESSES*>(buf.get());
ret = GetAdaptersAddresses(AF_INET,
GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER,
nullptr, adapters, &bufLen);
}

if (ret != NO_ERROR) {
return {};
}

for (auto* a = adapters; a != nullptr; a = a->Next) {
for (auto* ua = a->FirstUnicastAddress; ua != nullptr; ua = ua->Next) {
auto* sin = reinterpret_cast<sockaddr_in*>(ua->Address.lpSockaddr);
uint32_t addr = ntohl(sin->sin_addr.s_addr);
if (detail::is_tailscale_addr(addr)) {
char buf[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &sin->sin_addr, buf, sizeof(buf));
return buf;
}
}
}
return {};

#else
// Use getifaddrs on Unix/macOS.
struct ifaddrs* ifap = nullptr;
if (getifaddrs(&ifap) != 0) {
return {};
}

std::string result;
for (auto* ifa = ifap; ifa != nullptr; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == nullptr || ifa->ifa_addr->sa_family != AF_INET) {
continue;
}
auto* sin = reinterpret_cast<struct sockaddr_in*>(ifa->ifa_addr);
uint32_t addr = ntohl(sin->sin_addr.s_addr);
if (detail::is_tailscale_addr(addr)) {
char buf[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &sin->sin_addr, buf, sizeof(buf));
result = buf;
break;
}
}
freeifaddrs(ifap);
return result;
#endif
}

} // namespace barrier
Loading