diff --git a/client/core/controllers/selfhosted/installController.cpp b/client/core/controllers/selfhosted/installController.cpp
index f87f6dbd2..0a7b8e14a 100644
--- a/client/core/controllers/selfhosted/installController.cpp
+++ b/client/core/controllers/selfhosted/installController.cpp
@@ -835,6 +835,20 @@ ErrorCode InstallController::installDockerWorker(const ServerCredentials &creden
qDebug().noquote() << "InstallController::installDockerWorker" << stdOut;
+ if (container == DockerContainer::MtProxy || container == DockerContainer::Telemt) {
+ QString conntrackOut;
+ auto cbConntrack = [&](const QString &data, libssh::Client &) {
+ conntrackOut += data + "\n";
+ return ErrorCode::NoError;
+ };
+ sshSession.runScript(
+ credentials,
+ sshSession.replaceVars(amnezia::scriptData(SharedScriptType::install_conntrack),
+ amnezia::genBaseVars(credentials, DockerContainer::None, QString(), QString())),
+ cbConntrack, cbConntrack);
+ qDebug().noquote() << "InstallController::installDockerWorker install_conntrack:" << conntrackOut;
+ }
+
if (container == DockerContainer::Awg2) {
QRegularExpression regex(R"(Linux\s+(\d+)\.(\d+)[^\d]*)");
QRegularExpressionMatch match = regex.match(stdOut);
diff --git a/client/core/installers/mtProxyInstaller.cpp b/client/core/installers/mtProxyInstaller.cpp
index 937dab0db..149bac886 100644
--- a/client/core/installers/mtProxyInstaller.cpp
+++ b/client/core/installers/mtProxyInstaller.cpp
@@ -71,48 +71,62 @@ ErrorCode MtProxyInstaller::queryDiagnostics(SshSession &sshSession, const Serve
DockerContainer container, int listenPort,
MtProxyContainerDiagnostics &out)
{
- out = {};
- if (container != DockerContainer::MtProxy && container != DockerContainer::Telemt) {
- return ErrorCode::InternalError;
- }
- const QString containerName = ContainerUtils::containerToString(container);
- const QString script =
- QStringLiteral(
- "PORT_OK=$(sudo docker exec %1 sh -c 'ss -tlnp 2>/dev/null | grep -q :%2 && echo yes || echo no' 2>/dev/null || echo no); "
- "TG_OK=$(curl -s --max-time 5 -o /dev/null -w '%%{http_code}' https://core.telegram.org/getProxySecret 2>/dev/null | grep -q '200' && echo yes || echo no); "
- "CLIENTS=$(sudo docker exec amnezia-mtproxy sh -c 'curl -s --max-time 3 http://localhost:2398/stats 2>/dev/null | grep -o \"total_special_connections:[0-9]*\" | cut -d: -f2' 2>/dev/null); "
- "CONF_TIME=$(sudo docker exec amnezia-mtproxy sh -c 'stat -c \"%%y\" /data/proxy-multi.conf 2>/dev/null | cut -d. -f1' 2>/dev/null || echo unknown); "
- "echo \"PORT_OK=${PORT_OK}\"; "
- "echo \"TG_OK=${TG_OK}\"; "
- "echo \"CLIENTS=${CLIENTS:-0}\"; "
- "echo \"CONF_TIME=${CONF_TIME}\"; "
- "echo \"STATS=http://localhost:2398/stats\";")
- .arg(containerName)
- .arg(listenPort);
+ out = { };
+ if (container == DockerContainer::MtProxy || container == DockerContainer::Telemt) {
+ const QString containerName = ContainerUtils::containerToString(container);
+ const bool isTelemt = container == DockerContainer::Telemt;
- QString stdOut;
- auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
- stdOut += data;
- return ErrorCode::NoError;
- };
- const ErrorCode errorCode = sshSession.runScript(credentials, script, cbReadStdOut);
- if (errorCode != ErrorCode::NoError) {
- return errorCode;
- }
- for (const QString &line : stdOut.split('\n', Qt::SkipEmptyParts)) {
- if (line.startsWith(QLatin1String("PORT_OK="))) {
- out.portReachable = line.mid(8).trimmed() == QLatin1String("yes");
- } else if (line.startsWith(QLatin1String("TG_OK="))) {
- out.upstreamReachable = line.mid(6).trimmed() == QLatin1String("yes");
- } else if (line.startsWith(QLatin1String("CLIENTS="))) {
- out.clientsConnected = line.mid(8).trimmed().toInt();
- } else if (line.startsWith(QLatin1String("CONF_TIME="))) {
- out.lastConfigRefresh = line.mid(10).trimmed();
- } else if (line.startsWith(QLatin1String("STATS="))) {
- out.statsEndpoint = line.mid(6).trimmed();
+ const QString sportFilter = QString::number(listenPort);
+ const QString peersCmd = QStringLiteral("sudo conntrack -L -p tcp --dport ") + sportFilter
+ + QStringLiteral(" 2>/dev/null | grep ESTABLISHED | awk '{for(i=1;i<=NF;i++) if($i ~ /^src=/){print "
+ "substr($i,5); break}}'");
+ const QString publicFilter = QStringLiteral(" | grep -vE "
+ "'^(10\\.|127\\.|169\\.254\\.|192\\.168\\.|172\\.(1[6-9]|2[0-9]|3["
+ "01])\\.|::1$|fe80:|f[cd][0-9a-f][0-9a-f]:)'");
+ const QString clientsCmd =
+ QStringLiteral("CLIENTS=$(") + peersCmd + publicFilter + QStringLiteral(" | sort -u | grep -c .); ");
+ const QString confFile =
+ isTelemt ? QStringLiteral("/data/config.toml") : QStringLiteral("/data/proxy-multi.conf");
+ const QString statsUrl = QString();
+
+ const QString script = QStringLiteral("CN=") + containerName + QStringLiteral("; ")
+ + QStringLiteral("PORT_OK=$(sudo ss -tlnp 2>/dev/null | grep -q :") + QString::number(listenPort)
+ + QStringLiteral(" && echo yes || echo no); ")
+ + QStringLiteral("TG_OK=$(curl -s --max-time 5 -o /dev/null -w '%{http_code}' "
+ "https://core.telegram.org/getProxySecret 2>/dev/null | grep -q '200' && echo yes || "
+ "echo no); ")
+ + clientsCmd + QStringLiteral("CONF_TIME=$(sudo docker exec \"$CN\" sh -c 'stat -c \"%y\" ") + confFile
+ + QStringLiteral(" 2>/dev/null | cut -d. -f1' 2>/dev/null || echo unknown); ")
+ + QStringLiteral("echo \"PORT_OK=${PORT_OK}\"; ") + QStringLiteral("echo \"TG_OK=${TG_OK}\"; ")
+ + QStringLiteral("echo \"CLIENTS=${CLIENTS:-0}\"; ") + QStringLiteral("echo \"CONF_TIME=${CONF_TIME}\"; ")
+ + QStringLiteral("echo \"STATS=") + statsUrl + QStringLiteral("\";");
+
+ QString stdOut;
+ auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
+ stdOut += data;
+ return ErrorCode::NoError;
+ };
+ const ErrorCode errorCode = sshSession.runScript(credentials, script, cbReadStdOut);
+ if (errorCode != ErrorCode::NoError) {
+ return errorCode;
}
+ for (const QString &line : stdOut.split('\n', Qt::SkipEmptyParts)) {
+ if (line.startsWith(QLatin1String("PORT_OK="))) {
+ out.portReachable = line.mid(8).trimmed() == QLatin1String("yes");
+ } else if (line.startsWith(QLatin1String("TG_OK="))) {
+ out.upstreamReachable = line.mid(6).trimmed() == QLatin1String("yes");
+ } else if (line.startsWith(QLatin1String("CLIENTS="))) {
+ out.clientsConnected = line.mid(8).trimmed().toInt();
+ } else if (line.startsWith(QLatin1String("CONF_TIME="))) {
+ out.lastConfigRefresh = line.mid(10).trimmed();
+ } else if (line.startsWith(QLatin1String("STATS="))) {
+ out.statsEndpoint = line.mid(6).trimmed();
+ }
+ }
+ return ErrorCode::NoError;
}
- return ErrorCode::NoError;
+
+ return ErrorCode::InternalError;
}
void MtProxyInstaller::uploadClientSettingsSnapshot(SshSession &sshSession, const ServerCredentials &credentials,
diff --git a/client/core/utils/selfhosted/scriptsRegistry.cpp b/client/core/utils/selfhosted/scriptsRegistry.cpp
index 4e07ae752..3da6b8219 100644
--- a/client/core/utils/selfhosted/scriptsRegistry.cpp
+++ b/client/core/utils/selfhosted/scriptsRegistry.cpp
@@ -50,6 +50,7 @@ QString amnezia::scriptName(SharedScriptType type)
switch (type) {
case SharedScriptType::prepare_host: return QLatin1String("prepare_host.sh");
case SharedScriptType::install_docker: return QLatin1String("install_docker.sh");
+ case SharedScriptType::install_conntrack: return QLatin1String("install_conntrack.sh");
case SharedScriptType::build_container: return QLatin1String("build_container.sh");
case SharedScriptType::remove_container: return QLatin1String("remove_container.sh");
case SharedScriptType::remove_all_containers: return QLatin1String("remove_all_containers.sh");
diff --git a/client/core/utils/selfhosted/scriptsRegistry.h b/client/core/utils/selfhosted/scriptsRegistry.h
index f63b850a6..a1e5d202d 100644
--- a/client/core/utils/selfhosted/scriptsRegistry.h
+++ b/client/core/utils/selfhosted/scriptsRegistry.h
@@ -21,6 +21,7 @@ enum SharedScriptType {
// General scripts
prepare_host,
install_docker,
+ install_conntrack,
build_container,
remove_container,
remove_all_containers,
diff --git a/client/server_scripts/install_conntrack.sh b/client/server_scripts/install_conntrack.sh
new file mode 100644
index 000000000..c372fee08
--- /dev/null
+++ b/client/server_scripts/install_conntrack.sh
@@ -0,0 +1,10 @@
+if command -v conntrack > /dev/null 2>&1; then echo "conntrack already installed"; exit 0; fi;\
+if which apt-get > /dev/null 2>&1; then pm=$(which apt-get); silent_inst="-yq install --install-recommends"; check_pkgs="-yq update"; conntrack_pkg="conntrack"; dist="debian";\
+elif which dnf > /dev/null 2>&1; then pm=$(which dnf); silent_inst="-yq install"; check_pkgs="-yq check-update"; conntrack_pkg="conntrack-tools"; dist="fedora";\
+elif which yum > /dev/null 2>&1; then pm=$(which yum); silent_inst="-y -q install"; check_pkgs="-y -q check-update"; conntrack_pkg="conntrack-tools"; dist="centos";\
+elif which zypper > /dev/null 2>&1; then pm=$(which zypper); silent_inst="-nq install"; check_pkgs="-nq refresh"; conntrack_pkg="conntrack-tools"; dist="opensuse";\
+elif which pacman > /dev/null 2>&1; then pm=$(which pacman); silent_inst="-S --noconfirm --noprogressbar --quiet"; check_pkgs="-Sup"; conntrack_pkg="conntrack-tools"; dist="archlinux";\
+else echo "Packet manager not found"; exit 0; fi;\
+if [ "$dist" = "debian" ]; then export DEBIAN_FRONTEND=noninteractive; fi;\
+sudo $pm $check_pkgs; sudo $pm $silent_inst $conntrack_pkg;\
+command -v conntrack > /dev/null 2>&1 && echo "conntrack installed" || echo "conntrack install failed"
diff --git a/client/server_scripts/serverScripts.qrc b/client/server_scripts/serverScripts.qrc
index 278e16953..2d1ae6059 100644
--- a/client/server_scripts/serverScripts.qrc
+++ b/client/server_scripts/serverScripts.qrc
@@ -18,6 +18,7 @@
dns/Dockerfile
dns/run_container.sh
install_docker.sh
+ install_conntrack.sh
ipsec/configure_container.sh
ipsec/Dockerfile
ipsec/mobileconfig.plist