mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-22 02:01:08 +07:00
fix: allocate utun-pattern interface names on macOS
This commit is contained in:
@@ -125,13 +125,29 @@ Vpn::ConnectionState VpnConnection::connectionState() const
|
|||||||
|
|
||||||
QString VpnConnection::allocateIfname()
|
QString VpnConnection::allocateIfname()
|
||||||
{
|
{
|
||||||
|
#ifdef Q_OS_MACOS
|
||||||
|
QString kernelAssigned;
|
||||||
|
IpcClient::withInterface([&kernelAssigned](QSharedPointer<IpcInterfaceReplica> iface) {
|
||||||
|
auto reply = iface->reserveUtunName();
|
||||||
|
if (reply.waitForFinished(2000)) {
|
||||||
|
kernelAssigned = reply.returnValue();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (kernelAssigned.isEmpty() || m_ifnamesInUse.contains(kernelAssigned)) {
|
||||||
|
qCritical() << "allocateIfname: kernel utun reservation failed";
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
m_ifnamesInUse.insert(kernelAssigned);
|
||||||
|
return kernelAssigned;
|
||||||
|
#else
|
||||||
for (int i = 0; ; ++i) {
|
for (int i = 0; ; ++i) {
|
||||||
const QString name = QStringLiteral("amn") + QString::number(i);
|
const QString name = QStringLiteral("amn%1").arg(i);
|
||||||
if (!m_ifnamesInUse.contains(name)) {
|
if (!m_ifnamesInUse.contains(name)) {
|
||||||
m_ifnamesInUse.insert(name);
|
m_ifnamesInUse.insert(name);
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void VpnConnection::releaseIfname(const QString& ifname)
|
void VpnConnection::releaseIfname(const QString& ifname)
|
||||||
@@ -171,6 +187,11 @@ void VpnConnection::connectToVpn(const QString &serverId, DockerContainer contai
|
|||||||
const bool isXray = VpnProtocol::isXrayBased(container);
|
const bool isXray = VpnProtocol::isXrayBased(container);
|
||||||
const bool useTunnelPath = isWg || isXray;
|
const bool useTunnelPath = isWg || isXray;
|
||||||
const QString preAllocatedIfname = useTunnelPath ? allocateIfname() : QString();
|
const QString preAllocatedIfname = useTunnelPath ? allocateIfname() : QString();
|
||||||
|
if (useTunnelPath && preAllocatedIfname.isEmpty()) {
|
||||||
|
setConnectionState(Vpn::ConnectionState::Error);
|
||||||
|
emit vpnProtocolError(ErrorCode::AmneziaServiceConnectionFailed);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_active
|
if (m_active
|
||||||
&& m_connectionState == Vpn::ConnectionState::Connected
|
&& m_connectionState == Vpn::ConnectionState::Connected
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ class IpcInterface
|
|||||||
SLOT( bool createTun(const QString &dev, const QString &subnet) );
|
SLOT( bool createTun(const QString &dev, const QString &subnet) );
|
||||||
SLOT( bool deleteTun(const QString &dev) );
|
SLOT( bool deleteTun(const QString &dev) );
|
||||||
|
|
||||||
|
SLOT( QString reserveUtunName() );
|
||||||
|
|
||||||
SLOT( bool applyAdapterAddress(const QString &ifname, const QString &ipv4, const QString &ipv6) );
|
SLOT( bool applyAdapterAddress(const QString &ifname, const QString &ipv4, const QString &ipv6) );
|
||||||
|
|
||||||
SLOT( bool removeAdapterAddress(const QString &ifname, const QString &ipv4, const QString &ipv6) );
|
SLOT( bool removeAdapterAddress(const QString &ifname, const QString &ipv4, const QString &ipv6) );
|
||||||
|
|||||||
@@ -35,6 +35,17 @@
|
|||||||
#include "tapcontroller_win.h"
|
#include "tapcontroller_win.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef Q_OS_MAC
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/sys_domain.h>
|
||||||
|
#include <sys/kern_control.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <net/if_utun.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <cstring>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
IpcServer::IpcServer(QObject *parent) : IpcInterfaceSource(parent)
|
IpcServer::IpcServer(QObject *parent) : IpcInterfaceSource(parent)
|
||||||
{
|
{
|
||||||
@@ -215,6 +226,53 @@ bool IpcServer::deleteTun(const QString &dev)
|
|||||||
return Router::deleteTun(dev);
|
return Router::deleteTun(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString IpcServer::reserveUtunName()
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_MAC
|
||||||
|
int fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
|
||||||
|
if (fd < 0) {
|
||||||
|
qWarning() << "reserveUtunName: socket() failed:" << strerror(errno);
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ctl_info info;
|
||||||
|
std::memset(&info, 0, sizeof(info));
|
||||||
|
std::strncpy(info.ctl_name, UTUN_CONTROL_NAME, sizeof(info.ctl_name) - 1);
|
||||||
|
if (ioctl(fd, CTLIOCGINFO, &info) < 0) {
|
||||||
|
qWarning() << "reserveUtunName: CTLIOCGINFO failed:" << strerror(errno);
|
||||||
|
::close(fd);
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_ctl addr;
|
||||||
|
std::memset(&addr, 0, sizeof(addr));
|
||||||
|
addr.sc_len = sizeof(addr);
|
||||||
|
addr.sc_family = AF_SYSTEM;
|
||||||
|
addr.ss_sysaddr = AF_SYS_CONTROL;
|
||||||
|
addr.sc_id = info.ctl_id;
|
||||||
|
addr.sc_unit = 0;
|
||||||
|
|
||||||
|
if (::connect(fd, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)) < 0) {
|
||||||
|
qWarning() << "reserveUtunName: connect() failed:" << strerror(errno);
|
||||||
|
::close(fd);
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
char ifname[IFNAMSIZ] = {0};
|
||||||
|
socklen_t len = sizeof(ifname);
|
||||||
|
if (getsockopt(fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, ifname, &len) < 0) {
|
||||||
|
qWarning() << "reserveUtunName: getsockopt UTUN_OPT_IFNAME failed:" << strerror(errno);
|
||||||
|
::close(fd);
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
::close(fd);
|
||||||
|
return QString::fromUtf8(ifname);
|
||||||
|
#else
|
||||||
|
return QString();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
bool IpcServer::applyAdapterAddress(const QString &ifname, const QString &ipv4, const QString &ipv6)
|
bool IpcServer::applyAdapterAddress(const QString &ifname, const QString &ipv4, const QString &ipv6)
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ public:
|
|||||||
virtual void setLogsEnabled(bool enabled) override;
|
virtual void setLogsEnabled(bool enabled) override;
|
||||||
virtual bool createTun(const QString &dev, const QString &subnet) override;
|
virtual bool createTun(const QString &dev, const QString &subnet) override;
|
||||||
virtual bool deleteTun(const QString &dev) override;
|
virtual bool deleteTun(const QString &dev) override;
|
||||||
|
virtual QString reserveUtunName() override;
|
||||||
virtual bool applyAdapterAddress(const QString &ifname, const QString &ipv4, const QString &ipv6) override;
|
virtual bool applyAdapterAddress(const QString &ifname, const QString &ipv4, const QString &ipv6) override;
|
||||||
virtual bool removeAdapterAddress(const QString &ifname, const QString &ipv4, const QString &ipv6) override;
|
virtual bool removeAdapterAddress(const QString &ifname, const QString &ipv4, const QString &ipv6) override;
|
||||||
virtual bool StartRoutingIpv6() override;
|
virtual bool StartRoutingIpv6() override;
|
||||||
|
|||||||
Reference in New Issue
Block a user