mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-22 02:01:08 +07:00
feat: multipeer support mac/linux/windows
This commit is contained in:
@@ -441,6 +441,37 @@ bool Daemon::parseConfig(const QJsonObject& obj, InterfaceConfig& config) {
|
|||||||
config.m_specialJunk["I5"] = obj.value("I5").toString();
|
config.m_specialJunk["I5"] = obj.value("I5").toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (obj.contains("primaryPeerAllowedIPAddressRanges") &&
|
||||||
|
obj.value("primaryPeerAllowedIPAddressRanges").isArray()) {
|
||||||
|
for (const QJsonValue& ipVal : obj.value("primaryPeerAllowedIPAddressRanges").toArray()) {
|
||||||
|
if (!ipVal.isObject()) continue;
|
||||||
|
QJsonObject ipObj = ipVal.toObject();
|
||||||
|
config.m_primaryPeerAllowedIPRanges.append(
|
||||||
|
IPAddress(QHostAddress(ipObj.value("address").toString()),
|
||||||
|
ipObj.value("range").toInt()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj.contains("additionalPeers") && obj.value("additionalPeers").isArray()) {
|
||||||
|
for (const QJsonValue& peerVal : obj.value("additionalPeers").toArray()) {
|
||||||
|
if (!peerVal.isObject()) continue;
|
||||||
|
QJsonObject peerObj = peerVal.toObject();
|
||||||
|
InterfaceConfig::AdditionalPeerConfig peer;
|
||||||
|
peer.m_serverPublicKey = peerObj.value("serverPublicKey").toString();
|
||||||
|
peer.m_serverPskKey = peerObj.value("serverPskKey").toString();
|
||||||
|
peer.m_serverIpv4AddrIn = peerObj.value("serverIpv4AddrIn").toString();
|
||||||
|
peer.m_serverPort = peerObj.value("serverPort").toInt();
|
||||||
|
for (const QJsonValue& ipVal : peerObj.value("allowedIPAddressRanges").toArray()) {
|
||||||
|
if (!ipVal.isObject()) continue;
|
||||||
|
QJsonObject ipObj = ipVal.toObject();
|
||||||
|
peer.m_allowedIPAddressRanges.append(
|
||||||
|
IPAddress(QHostAddress(ipObj.value("address").toString()),
|
||||||
|
ipObj.value("range").toInt()));
|
||||||
|
}
|
||||||
|
config.m_additionalPeers.append(peer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,9 @@ class InterfaceConfig {
|
|||||||
int m_serverPort = 0;
|
int m_serverPort = 0;
|
||||||
int m_deviceMTU = 1420;
|
int m_deviceMTU = 1420;
|
||||||
QList<IPAddress> m_allowedIPAddressRanges;
|
QList<IPAddress> m_allowedIPAddressRanges;
|
||||||
|
// For multi-peer: primary peer's own IPs only (used for UAPI allowed_ips).
|
||||||
|
// Empty for single-peer (falls back to m_allowedIPAddressRanges).
|
||||||
|
QList<IPAddress> m_primaryPeerAllowedIPRanges;
|
||||||
QStringList m_excludedAddresses;
|
QStringList m_excludedAddresses;
|
||||||
QStringList m_vpnDisabledApps;
|
QStringList m_vpnDisabledApps;
|
||||||
QStringList m_allowedDnsServers;
|
QStringList m_allowedDnsServers;
|
||||||
@@ -58,6 +61,15 @@ class InterfaceConfig {
|
|||||||
QString m_transportPacketMagicHeader;
|
QString m_transportPacketMagicHeader;
|
||||||
QMap<QString, QString> m_specialJunk;
|
QMap<QString, QString> m_specialJunk;
|
||||||
|
|
||||||
|
struct AdditionalPeerConfig {
|
||||||
|
QString m_serverPublicKey;
|
||||||
|
QString m_serverPskKey;
|
||||||
|
QString m_serverIpv4AddrIn;
|
||||||
|
int m_serverPort = 0;
|
||||||
|
QList<IPAddress> m_allowedIPAddressRanges;
|
||||||
|
};
|
||||||
|
QList<AdditionalPeerConfig> m_additionalPeers;
|
||||||
|
|
||||||
QJsonObject toJson() const;
|
QJsonObject toJson() const;
|
||||||
QString toWgConf(
|
QString toWgConf(
|
||||||
const QMap<QString, QString>& extra = QMap<QString, QString>()) const;
|
const QMap<QString, QString>& extra = QMap<QString, QString>()) const;
|
||||||
|
|||||||
@@ -169,29 +169,63 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
|
|||||||
|
|
||||||
QJsonArray jsAllowedIPAddesses;
|
QJsonArray jsAllowedIPAddesses;
|
||||||
|
|
||||||
|
auto ipRangeToJson = [](const QString& ipRange) -> QJsonObject {
|
||||||
|
QJsonObject range;
|
||||||
|
const QStringList parts = ipRange.split('/');
|
||||||
|
range.insert("address", parts[0]);
|
||||||
|
range.insert("range", parts.size() > 1 ? parts[1].toInt() : 32);
|
||||||
|
range.insert("isIpv6", ipRange.contains(':'));
|
||||||
|
return range;
|
||||||
|
};
|
||||||
|
|
||||||
|
QJsonArray peersArray = wgConfig.value("peers").toArray();
|
||||||
|
bool isMultiPeer = peersArray.size() > 1;
|
||||||
|
|
||||||
|
if (isMultiPeer) {
|
||||||
|
// Union of all peers' IPs goes into allowedIPAddressRanges (used for route setup).
|
||||||
|
QSet<QString> seenIps;
|
||||||
|
for (const QJsonValue& peerVal : std::as_const(peersArray)) {
|
||||||
|
for (const QJsonValue& ipVal : peerVal.toObject().value(amnezia::configKey::allowedIps).toArray()) {
|
||||||
|
const QString ipRange = ipVal.toString().trimmed();
|
||||||
|
if (seenIps.contains(ipRange)) continue;
|
||||||
|
seenIps.insert(ipRange);
|
||||||
|
jsAllowedIPAddesses.append(ipRangeToJson(ipRange));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Primary peer's own IPs only — used for UAPI allowed_ips to avoid trie conflicts.
|
||||||
|
QJsonArray primaryPeerIpsJson;
|
||||||
|
for (const QJsonValue& ipVal : peersArray[0].toObject().value(amnezia::configKey::allowedIps).toArray()) {
|
||||||
|
primaryPeerIpsJson.append(ipRangeToJson(ipVal.toString().trimmed()));
|
||||||
|
}
|
||||||
|
json.insert("primaryPeerAllowedIPAddressRanges", primaryPeerIpsJson);
|
||||||
|
|
||||||
|
QJsonArray additionalPeersJson;
|
||||||
|
for (int i = 1; i < peersArray.size(); ++i) {
|
||||||
|
const QJsonObject peerObj = peersArray[i].toObject();
|
||||||
|
QJsonObject additionalPeer;
|
||||||
|
additionalPeer.insert("serverPublicKey", peerObj.value(amnezia::configKey::serverPubKey));
|
||||||
|
additionalPeer.insert("serverPskKey", peerObj.value(amnezia::configKey::pskKey));
|
||||||
|
additionalPeer.insert("serverIpv4AddrIn", peerObj.value(amnezia::configKey::hostName));
|
||||||
|
additionalPeer.insert("serverPort", peerObj.value(amnezia::configKey::port).toInt());
|
||||||
|
QJsonArray additionalPeerIps;
|
||||||
|
for (const QJsonValue& ipVal : peerObj.value(amnezia::configKey::allowedIps).toArray()) {
|
||||||
|
additionalPeerIps.append(ipRangeToJson(ipVal.toString().trimmed()));
|
||||||
|
}
|
||||||
|
additionalPeer.insert("allowedIPAddressRanges", additionalPeerIps);
|
||||||
|
additionalPeersJson.append(additionalPeer);
|
||||||
|
}
|
||||||
|
json.insert("additionalPeers", additionalPeersJson);
|
||||||
|
} else {
|
||||||
QJsonArray plainAllowedIP = wgConfig.value(amnezia::configKey::allowedIps).toArray();
|
QJsonArray plainAllowedIP = wgConfig.value(amnezia::configKey::allowedIps).toArray();
|
||||||
QJsonArray defaultAllowedIP = { "0.0.0.0/0", "::/0" };
|
QJsonArray defaultAllowedIP = { "0.0.0.0/0", "::/0" };
|
||||||
|
|
||||||
if (plainAllowedIP != defaultAllowedIP && !plainAllowedIP.isEmpty()) {
|
if (plainAllowedIP != defaultAllowedIP && !plainAllowedIP.isEmpty()) {
|
||||||
// Use AllowedIP list from WG config because of higher priority
|
// Use AllowedIP list from WG config because of higher priority
|
||||||
for (auto v : plainAllowedIP) {
|
for (auto v : plainAllowedIP) {
|
||||||
QString ipRange = v.toString();
|
jsAllowedIPAddesses.append(ipRangeToJson(v.toString().trimmed()));
|
||||||
if (ipRange.split('/').size() > 1){
|
|
||||||
QJsonObject range;
|
|
||||||
range.insert("address", ipRange.split('/')[0]);
|
|
||||||
range.insert("range", atoi(ipRange.split('/')[1].toLocal8Bit()));
|
|
||||||
range.insert("isIpv6", false);
|
|
||||||
jsAllowedIPAddesses.append(range);
|
|
||||||
} else {
|
|
||||||
QJsonObject range;
|
|
||||||
range.insert("address",ipRange);
|
|
||||||
range.insert("range", 32);
|
|
||||||
range.insert("isIpv6", false);
|
|
||||||
jsAllowedIPAddesses.append(range);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Use APP split tunnel
|
// Use APP split tunnel
|
||||||
if (splitTunnelType == 0 || splitTunnelType == 2) {
|
if (splitTunnelType == 0 || splitTunnelType == 2) {
|
||||||
QJsonObject range_ipv4;
|
QJsonObject range_ipv4;
|
||||||
@@ -209,19 +243,7 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
|
|||||||
|
|
||||||
if (splitTunnelType == 1) {
|
if (splitTunnelType == 1) {
|
||||||
for (auto v : splitTunnelSites) {
|
for (auto v : splitTunnelSites) {
|
||||||
QString ipRange = v.toString();
|
jsAllowedIPAddesses.append(ipRangeToJson(v.toString().trimmed()));
|
||||||
if (ipRange.split('/').size() > 1){
|
|
||||||
QJsonObject range;
|
|
||||||
range.insert("address", ipRange.split('/')[0]);
|
|
||||||
range.insert("range", atoi(ipRange.split('/')[1].toLocal8Bit()));
|
|
||||||
range.insert("isIpv6", false);
|
|
||||||
jsAllowedIPAddesses.append(range);
|
|
||||||
} else {
|
|
||||||
QJsonObject range;
|
|
||||||
range.insert("address",ipRange);
|
|
||||||
range.insert("range", 32);
|
|
||||||
range.insert("isIpv6", false);
|
|
||||||
jsAllowedIPAddesses.append(range);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -230,7 +252,13 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
|
|||||||
json.insert("allowedIPAddressRanges", jsAllowedIPAddesses);
|
json.insert("allowedIPAddressRanges", jsAllowedIPAddesses);
|
||||||
|
|
||||||
QJsonArray jsExcludedAddresses;
|
QJsonArray jsExcludedAddresses;
|
||||||
|
if (isMultiPeer) {
|
||||||
|
for (const QJsonValue& peerVal : std::as_const(peersArray)) {
|
||||||
|
jsExcludedAddresses.append(peerVal.toObject().value(amnezia::configKey::hostName));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
jsExcludedAddresses.append(wgConfig.value(amnezia::configKey::hostName));
|
jsExcludedAddresses.append(wgConfig.value(amnezia::configKey::hostName));
|
||||||
|
}
|
||||||
if (splitTunnelType == 2) {
|
if (splitTunnelType == 2) {
|
||||||
for (auto v : splitTunnelSites) {
|
for (auto v : splitTunnelSites) {
|
||||||
QString ipRange = v.toString();
|
QString ipRange = v.toString();
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ struct WGConfig: Decodable {
|
|||||||
\(interfaceSection)
|
\(interfaceSection)
|
||||||
[Peer]
|
[Peer]
|
||||||
PublicKey = \(serverPublicKey)
|
PublicKey = \(serverPublicKey)
|
||||||
\(presharedKey == nil ? "" : "PresharedKey = \(presharedKey!)")
|
\((presharedKey?.isEmpty ?? true) ? "" : "PresharedKey = \(presharedKey!)")
|
||||||
AllowedIPs = \(allowedIPs.joined(separator: ", "))
|
AllowedIPs = \(allowedIPs.joined(separator: ", "))
|
||||||
Endpoint = \(hostName):\(port)
|
Endpoint = \(hostName):\(port)
|
||||||
PersistentKeepalive = \(persistentKeepAlive)
|
PersistentKeepalive = \(persistentKeepAlive)
|
||||||
|
|||||||
@@ -230,7 +230,10 @@ bool WireguardUtilsLinux::updatePeer(const InterfaceConfig& config) {
|
|||||||
|
|
||||||
out << "replace_allowed_ips=true\n";
|
out << "replace_allowed_ips=true\n";
|
||||||
out << "persistent_keepalive_interval=" << WG_KEEPALIVE_PERIOD << "\n";
|
out << "persistent_keepalive_interval=" << WG_KEEPALIVE_PERIOD << "\n";
|
||||||
for (const IPAddress& ip : config.m_allowedIPAddressRanges) {
|
const QList<IPAddress>& primaryIPs = config.m_primaryPeerAllowedIPRanges.isEmpty()
|
||||||
|
? config.m_allowedIPAddressRanges
|
||||||
|
: config.m_primaryPeerAllowedIPRanges;
|
||||||
|
for (const IPAddress& ip : primaryIPs) {
|
||||||
out << "allowed_ip=" << ip.toString() << "\n";
|
out << "allowed_ip=" << ip.toString() << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,8 +247,38 @@ bool WireguardUtilsLinux::updatePeer(const InterfaceConfig& config) {
|
|||||||
int err = uapiErrno(uapiCommand(message));
|
int err = uapiErrno(uapiCommand(message));
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
logger.error() << "Peer configuration failed:" << strerror(err);
|
logger.error() << "Peer configuration failed:" << strerror(err);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return (err == 0);
|
|
||||||
|
for (const InterfaceConfig::AdditionalPeerConfig& peer : config.m_additionalPeers) {
|
||||||
|
QByteArray pubKey = QByteArray::fromBase64(peer.m_serverPublicKey.toUtf8());
|
||||||
|
QByteArray pskKey = QByteArray::fromBase64(peer.m_serverPskKey.toUtf8());
|
||||||
|
|
||||||
|
QString peerMsg;
|
||||||
|
QTextStream peerOut(&peerMsg);
|
||||||
|
peerOut << "set=1\n";
|
||||||
|
peerOut << "public_key=" << QString(pubKey.toHex()) << "\n";
|
||||||
|
if (!peer.m_serverPskKey.isEmpty()) {
|
||||||
|
peerOut << "preshared_key=" << QString(pskKey.toHex()) << "\n";
|
||||||
|
}
|
||||||
|
peerOut << "endpoint=" << peer.m_serverIpv4AddrIn << ":" << peer.m_serverPort << "\n";
|
||||||
|
peerOut << "replace_allowed_ips=true\n";
|
||||||
|
peerOut << "persistent_keepalive_interval=" << WG_KEEPALIVE_PERIOD << "\n";
|
||||||
|
for (const IPAddress& ip : peer.m_allowedIPAddressRanges) {
|
||||||
|
peerOut << "allowed_ip=" << ip.toString() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((config.m_hopType != InterfaceConfig::MultiHopExit) && m_rtmonitor) {
|
||||||
|
m_rtmonitor->addExclusionRoute(IPAddress(peer.m_serverIpv4AddrIn));
|
||||||
|
}
|
||||||
|
|
||||||
|
int peerErr = uapiErrno(uapiCommand(peerMsg));
|
||||||
|
if (peerErr != 0) {
|
||||||
|
logger.error() << "Additional peer configuration failed:" << strerror(peerErr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WireguardUtilsLinux::deletePeer(const InterfaceConfig& config) {
|
bool WireguardUtilsLinux::deletePeer(const InterfaceConfig& config) {
|
||||||
|
|||||||
@@ -80,7 +80,9 @@ bool IPUtilsMacos::setMTUAndUp(const InterfaceConfig& config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool IPUtilsMacos::addIP4AddressToDevice(const InterfaceConfig& config) {
|
bool IPUtilsMacos::addIP4AddressToDevice(const InterfaceConfig& config) {
|
||||||
Q_UNUSED(config);
|
if (config.m_deviceIpv4Address.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
QString ifname = MacOSDaemon::instance()->m_wgutils->interfaceName();
|
QString ifname = MacOSDaemon::instance()->m_wgutils->interfaceName();
|
||||||
struct ifaliasreq ifr;
|
struct ifaliasreq ifr;
|
||||||
struct sockaddr_in* ifrAddr = (struct sockaddr_in*)&ifr.ifra_addr;
|
struct sockaddr_in* ifrAddr = (struct sockaddr_in*)&ifr.ifra_addr;
|
||||||
@@ -91,25 +93,28 @@ bool IPUtilsMacos::addIP4AddressToDevice(const InterfaceConfig& config) {
|
|||||||
memset(&ifr, 0, sizeof(ifr));
|
memset(&ifr, 0, sizeof(ifr));
|
||||||
strncpy(ifr.ifra_name, qPrintable(ifname), IFNAMSIZ);
|
strncpy(ifr.ifra_name, qPrintable(ifname), IFNAMSIZ);
|
||||||
|
|
||||||
// Get the device address to add to interface
|
// Extract the host IP from CIDR notation (e.g. "10.8.0.2/24" → "10.8.0.2").
|
||||||
QPair<QHostAddress, int> parsedAddr =
|
// parseSubnet() zeroes host bits so we split manually to preserve the host address.
|
||||||
QHostAddress::parseSubnet(config.m_deviceIpv4Address);
|
QByteArray _deviceAddr = config.m_deviceIpv4Address.split('/').first().toLocal8Bit();
|
||||||
QByteArray _deviceAddr = parsedAddr.first.toString().toLocal8Bit();
|
|
||||||
char* deviceAddr = _deviceAddr.data();
|
char* deviceAddr = _deviceAddr.data();
|
||||||
ifrAddr->sin_family = AF_INET;
|
ifrAddr->sin_family = AF_INET;
|
||||||
ifrAddr->sin_len = sizeof(struct sockaddr_in);
|
ifrAddr->sin_len = sizeof(struct sockaddr_in);
|
||||||
inet_pton(AF_INET, deviceAddr, &ifrAddr->sin_addr);
|
if (inet_pton(AF_INET, deviceAddr, &ifrAddr->sin_addr) != 1) {
|
||||||
|
logger.error() << "Failed to parse IPv4 address:" << deviceAddr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Set the netmask to /32
|
// Set the netmask to /32
|
||||||
ifrMask->sin_family = AF_INET;
|
ifrMask->sin_family = AF_INET;
|
||||||
ifrMask->sin_len = sizeof(struct sockaddr_in);
|
ifrMask->sin_len = sizeof(struct sockaddr_in);
|
||||||
memset(&ifrMask->sin_addr, 0xff, sizeof(ifrMask->sin_addr));
|
memset(&ifrMask->sin_addr, 0xff, sizeof(ifrMask->sin_addr));
|
||||||
|
|
||||||
// Set the broadcast address.
|
// For P2P (utun) interfaces, ifra_broadaddr is the destination address.
|
||||||
|
// Set it equal to the local address to create only a host route (not a network
|
||||||
|
// route that would cause a routing loop).
|
||||||
ifrBcast->sin_family = AF_INET;
|
ifrBcast->sin_family = AF_INET;
|
||||||
ifrBcast->sin_len = sizeof(struct sockaddr_in);
|
ifrBcast->sin_len = sizeof(struct sockaddr_in);
|
||||||
ifrBcast->sin_addr.s_addr =
|
ifrBcast->sin_addr.s_addr = ifrAddr->sin_addr.s_addr;
|
||||||
(ifrAddr->sin_addr.s_addr | ~ifrMask->sin_addr.s_addr);
|
|
||||||
|
|
||||||
// Create an IPv4 socket to perform the ioctl operations on
|
// Create an IPv4 socket to perform the ioctl operations on
|
||||||
int sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
|
int sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
|
||||||
|
|||||||
@@ -230,7 +230,11 @@ bool WireguardUtilsMacos::updatePeer(const InterfaceConfig& config) {
|
|||||||
|
|
||||||
out << "replace_allowed_ips=true\n";
|
out << "replace_allowed_ips=true\n";
|
||||||
out << "persistent_keepalive_interval=" << WG_KEEPALIVE_PERIOD << "\n";
|
out << "persistent_keepalive_interval=" << WG_KEEPALIVE_PERIOD << "\n";
|
||||||
for (const IPAddress& ip : config.m_allowedIPAddressRanges) {
|
// For multi-peer use only the primary peer's own IPs to avoid routing trie conflicts.
|
||||||
|
const QList<IPAddress>& primaryIPs = config.m_primaryPeerAllowedIPRanges.isEmpty()
|
||||||
|
? config.m_allowedIPAddressRanges
|
||||||
|
: config.m_primaryPeerAllowedIPRanges;
|
||||||
|
for (const IPAddress& ip : primaryIPs) {
|
||||||
out << "allowed_ip=" << ip.toString() << "\n";
|
out << "allowed_ip=" << ip.toString() << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,8 +248,38 @@ bool WireguardUtilsMacos::updatePeer(const InterfaceConfig& config) {
|
|||||||
int err = uapiErrno(uapiCommand(message));
|
int err = uapiErrno(uapiCommand(message));
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
logger.error() << "Peer configuration failed:" << strerror(err);
|
logger.error() << "Peer configuration failed:" << strerror(err);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return (err == 0);
|
|
||||||
|
for (const InterfaceConfig::AdditionalPeerConfig& peer : config.m_additionalPeers) {
|
||||||
|
QByteArray pubKey = QByteArray::fromBase64(peer.m_serverPublicKey.toUtf8());
|
||||||
|
QByteArray pskKey = QByteArray::fromBase64(peer.m_serverPskKey.toUtf8());
|
||||||
|
|
||||||
|
QString peerMsg;
|
||||||
|
QTextStream peerOut(&peerMsg);
|
||||||
|
peerOut << "set=1\n";
|
||||||
|
peerOut << "public_key=" << QString(pubKey.toHex()) << "\n";
|
||||||
|
if (!peer.m_serverPskKey.isEmpty()) {
|
||||||
|
peerOut << "preshared_key=" << QString(pskKey.toHex()) << "\n";
|
||||||
|
}
|
||||||
|
peerOut << "endpoint=" << peer.m_serverIpv4AddrIn << ":" << peer.m_serverPort << "\n";
|
||||||
|
peerOut << "replace_allowed_ips=true\n";
|
||||||
|
peerOut << "persistent_keepalive_interval=" << WG_KEEPALIVE_PERIOD << "\n";
|
||||||
|
for (const IPAddress& ip : peer.m_allowedIPAddressRanges) {
|
||||||
|
peerOut << "allowed_ip=" << ip.toString() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((config.m_hopType != InterfaceConfig::MultiHopExit) && m_rtmonitor) {
|
||||||
|
m_rtmonitor->addExclusionRoute(IPAddress(peer.m_serverIpv4AddrIn));
|
||||||
|
}
|
||||||
|
|
||||||
|
int peerErr = uapiErrno(uapiCommand(peerMsg));
|
||||||
|
if (peerErr != 0) {
|
||||||
|
logger.error() << "Additional peer configuration failed:" << strerror(peerErr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WireguardUtilsMacos::deletePeer(const InterfaceConfig& config) {
|
bool WireguardUtilsMacos::deletePeer(const InterfaceConfig& config) {
|
||||||
|
|||||||
@@ -181,7 +181,10 @@ bool WireguardUtilsWindows::updatePeer(const InterfaceConfig& config) {
|
|||||||
|
|
||||||
out << "replace_allowed_ips=true\n";
|
out << "replace_allowed_ips=true\n";
|
||||||
out << "persistent_keepalive_interval=" << WG_KEEPALIVE_PERIOD << "\n";
|
out << "persistent_keepalive_interval=" << WG_KEEPALIVE_PERIOD << "\n";
|
||||||
for (const IPAddress& ip : config.m_allowedIPAddressRanges) {
|
const QList<IPAddress>& primaryIPs = config.m_primaryPeerAllowedIPRanges.isEmpty()
|
||||||
|
? config.m_allowedIPAddressRanges
|
||||||
|
: config.m_primaryPeerAllowedIPRanges;
|
||||||
|
for (const IPAddress& ip : primaryIPs) {
|
||||||
out << "allowed_ip=" << ip.toString() << "\n";
|
out << "allowed_ip=" << ip.toString() << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,6 +196,33 @@ bool WireguardUtilsWindows::updatePeer(const InterfaceConfig& config) {
|
|||||||
|
|
||||||
QString reply = m_tunnel.uapiCommand(message);
|
QString reply = m_tunnel.uapiCommand(message);
|
||||||
logger.debug() << "DATA:" << reply;
|
logger.debug() << "DATA:" << reply;
|
||||||
|
|
||||||
|
for (const InterfaceConfig::AdditionalPeerConfig& peer : config.m_additionalPeers) {
|
||||||
|
QByteArray pubKey = QByteArray::fromBase64(peer.m_serverPublicKey.toUtf8());
|
||||||
|
QByteArray pskKey = QByteArray::fromBase64(peer.m_serverPskKey.toUtf8());
|
||||||
|
|
||||||
|
QString peerMsg;
|
||||||
|
QTextStream peerOut(&peerMsg);
|
||||||
|
peerOut << "set=1\n";
|
||||||
|
peerOut << "public_key=" << QString(pubKey.toHex()) << "\n";
|
||||||
|
if (!peer.m_serverPskKey.isEmpty()) {
|
||||||
|
peerOut << "preshared_key=" << QString(pskKey.toHex()) << "\n";
|
||||||
|
}
|
||||||
|
peerOut << "endpoint=" << peer.m_serverIpv4AddrIn << ":" << peer.m_serverPort << "\n";
|
||||||
|
peerOut << "replace_allowed_ips=true\n";
|
||||||
|
peerOut << "persistent_keepalive_interval=" << WG_KEEPALIVE_PERIOD << "\n";
|
||||||
|
for (const IPAddress& ip : peer.m_allowedIPAddressRanges) {
|
||||||
|
peerOut << "allowed_ip=" << ip.toString() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_routeMonitor && config.m_hopType != InterfaceConfig::MultiHopExit) {
|
||||||
|
m_routeMonitor->addExclusionRoute(IPAddress(peer.m_serverIpv4AddrIn));
|
||||||
|
}
|
||||||
|
|
||||||
|
QString peerReply = m_tunnel.uapiCommand(peerMsg);
|
||||||
|
logger.debug() << "Additional peer DATA:" << peerReply;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user