mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2024-11-26 11:16:20 +03:00
parent
d051519eff
commit
8200ef6bd5
9 changed files with 198 additions and 163 deletions
|
@ -436,7 +436,6 @@ Session::Session(QObject *parent)
|
||||||
, m_networkInterface(BITTORRENT_SESSION_KEY("Interface"))
|
, m_networkInterface(BITTORRENT_SESSION_KEY("Interface"))
|
||||||
, m_networkInterfaceName(BITTORRENT_SESSION_KEY("InterfaceName"))
|
, m_networkInterfaceName(BITTORRENT_SESSION_KEY("InterfaceName"))
|
||||||
, m_networkInterfaceAddress(BITTORRENT_SESSION_KEY("InterfaceAddress"))
|
, m_networkInterfaceAddress(BITTORRENT_SESSION_KEY("InterfaceAddress"))
|
||||||
, m_isIPv6Enabled(BITTORRENT_SESSION_KEY("IPv6Enabled"), false)
|
|
||||||
, m_encryption(BITTORRENT_SESSION_KEY("Encryption"), 0)
|
, m_encryption(BITTORRENT_SESSION_KEY("Encryption"), 0)
|
||||||
, m_isProxyPeerConnectionsEnabled(BITTORRENT_SESSION_KEY("ProxyPeerConnections"), false)
|
, m_isProxyPeerConnectionsEnabled(BITTORRENT_SESSION_KEY("ProxyPeerConnections"), false)
|
||||||
, m_chokingAlgorithm(BITTORRENT_SESSION_KEY("ChokingAlgorithm"), ChokingAlgorithm::FixedSlots
|
, m_chokingAlgorithm(BITTORRENT_SESSION_KEY("ChokingAlgorithm"), ChokingAlgorithm::FixedSlots
|
||||||
|
@ -1244,68 +1243,7 @@ void Session::loadLTSettings(lt::settings_pack &settingsPack)
|
||||||
// It will not take affect until the listen_interfaces settings is updated
|
// It will not take affect until the listen_interfaces settings is updated
|
||||||
settingsPack.set_int(lt::settings_pack::listen_queue_size, socketBacklogSize());
|
settingsPack.set_int(lt::settings_pack::listen_queue_size, socketBacklogSize());
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
configureNetworkInterfaces(settingsPack);
|
||||||
QString chosenIP;
|
|
||||||
#endif
|
|
||||||
if (!m_listenInterfaceConfigured) {
|
|
||||||
const int port = useRandomPort() ? 0 : this->port();
|
|
||||||
if (port > 0) // user specified port
|
|
||||||
settingsPack.set_int(lt::settings_pack::max_retry_port_bind, 0);
|
|
||||||
|
|
||||||
for (const QString &ip : asConst(getListeningIPs())) {
|
|
||||||
if (ip.isEmpty()) {
|
|
||||||
const QString anyIP = QHostAddress(QHostAddress::AnyIPv4).toString();
|
|
||||||
const std::string endpoint = anyIP.toStdString() + ':' + std::to_string(port);
|
|
||||||
settingsPack.set_str(lt::settings_pack::listen_interfaces, endpoint);
|
|
||||||
LogMsg(tr("Trying to listen on IP: %1, port: %2"
|
|
||||||
, "e.g: Trying to listen on IP: 192.168.0.1, port: 6881")
|
|
||||||
.arg(anyIP, QString::number(port))
|
|
||||||
, Log::INFO);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
lt::error_code ec;
|
|
||||||
const lt::address addr = lt::address::from_string(ip.toStdString(), ec);
|
|
||||||
if (!ec) {
|
|
||||||
const std::string endpoint = (addr.is_v6()
|
|
||||||
? ('[' + addr.to_string() + ']')
|
|
||||||
: addr.to_string())
|
|
||||||
+ ':' + std::to_string(port);
|
|
||||||
settingsPack.set_str(lt::settings_pack::listen_interfaces, endpoint);
|
|
||||||
LogMsg(tr("Trying to listen on IP: %1, port: %2"
|
|
||||||
, "e.g: Trying to listen on IP: 192.168.0.1, port: 6881")
|
|
||||||
.arg(ip, QString::number(port))
|
|
||||||
, Log::INFO);
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
chosenIP = ip;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
// On Vista+ versions and after Qt 5.5 QNetworkInterface::name() returns
|
|
||||||
// the interface's LUID and not the GUID.
|
|
||||||
// Libtorrent expects GUIDs for the 'outgoing_interfaces' setting.
|
|
||||||
const QString netInterface = networkInterface();
|
|
||||||
if (!netInterface.isEmpty()) {
|
|
||||||
const QString guid = convertIfaceNameToGuid(netInterface);
|
|
||||||
if (!guid.isEmpty()) {
|
|
||||||
settingsPack.set_str(lt::settings_pack::outgoing_interfaces, guid.toStdString());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
settingsPack.set_str(lt::settings_pack::outgoing_interfaces, chosenIP.toStdString());
|
|
||||||
LogMsg(tr("Could not get GUID of configured network interface. Binding to IP: %1").arg(chosenIP)
|
|
||||||
, Log::WARNING);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
settingsPack.set_str(lt::settings_pack::outgoing_interfaces, networkInterface().toStdString());
|
|
||||||
#endif // Q_OS_WIN
|
|
||||||
|
|
||||||
m_listenInterfaceConfigured = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
applyBandwidthLimits(settingsPack);
|
applyBandwidthLimits(settingsPack);
|
||||||
|
|
||||||
// The most secure, rc4 only so that all streams are encrypted
|
// The most secure, rc4 only so that all streams are encrypted
|
||||||
|
@ -1496,6 +1434,75 @@ void Session::loadLTSettings(lt::settings_pack &settingsPack)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Session::configureNetworkInterfaces(lt::settings_pack &settingsPack)
|
||||||
|
{
|
||||||
|
if (m_listenInterfaceConfigured)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const int port = useRandomPort() ? 0 : this->port();
|
||||||
|
if (port > 0) // user specified port
|
||||||
|
settingsPack.set_int(lt::settings_pack::max_retry_port_bind, 0);
|
||||||
|
|
||||||
|
QStringList endpoints;
|
||||||
|
QStringList outgoingInterfaces;
|
||||||
|
const QString portString = ':' + QString::number(port);
|
||||||
|
|
||||||
|
for (const QString &ip : asConst(getListeningIPs())) {
|
||||||
|
const QHostAddress addr {ip};
|
||||||
|
if (!addr.isNull()) {
|
||||||
|
endpoints << ((addr.protocol() == QAbstractSocket::IPv6Protocol)
|
||||||
|
? ('[' + Utils::Net::canonicalIPv6Addr(addr).toString() + ']')
|
||||||
|
: addr.toString())
|
||||||
|
+ portString;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// ip holds an interface name
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
// On Vista+ versions and after Qt 5.5 QNetworkInterface::name() returns
|
||||||
|
// the interface's LUID and not the GUID.
|
||||||
|
// Libtorrent expects GUIDs for the 'listen_interfaces' setting.
|
||||||
|
const QString guid = convertIfaceNameToGuid(ip);
|
||||||
|
if (!guid.isEmpty()) {
|
||||||
|
endpoints << (guid + portString);
|
||||||
|
outgoingInterfaces << guid;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LogMsg(tr("Could not get GUID of network interface: %1").arg(ip) , Log::WARNING);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
endpoints << (ip + portString);
|
||||||
|
outgoingInterfaces << ip;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outgoingInterfaces.isEmpty()) {
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
// On Vista+ versions and after Qt 5.5 QNetworkInterface::name() returns
|
||||||
|
// the interface's LUID and not the GUID.
|
||||||
|
// Libtorrent expects GUIDs for the 'outgoing_interfaces' setting.
|
||||||
|
const QString netInterface = networkInterface();
|
||||||
|
if (!netInterface.isEmpty()) {
|
||||||
|
const QString guid = convertIfaceNameToGuid(netInterface);
|
||||||
|
if (!guid.isEmpty())
|
||||||
|
outgoingInterfaces << guid;
|
||||||
|
else
|
||||||
|
LogMsg(tr("Could not get GUID of network interface: %1").arg(netInterface) , Log::WARNING);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
outgoingInterfaces << networkInterface();
|
||||||
|
#endif // Q_OS_WIN
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString finalEndpoints = endpoints.join(',');
|
||||||
|
settingsPack.set_str(lt::settings_pack::listen_interfaces, finalEndpoints.toStdString());
|
||||||
|
LogMsg(tr("Trying to listen on: %1", "e.g: Trying to listen on: 192.168.0.1:6881")
|
||||||
|
.arg(finalEndpoints), Log::INFO);
|
||||||
|
|
||||||
|
settingsPack.set_str(lt::settings_pack::outgoing_interfaces, outgoingInterfaces.join(',').toStdString());
|
||||||
|
m_listenInterfaceConfigured = true;
|
||||||
|
}
|
||||||
|
|
||||||
void Session::configurePeerClasses()
|
void Session::configurePeerClasses()
|
||||||
{
|
{
|
||||||
lt::ip_filter f;
|
lt::ip_filter f;
|
||||||
|
@ -2416,22 +2423,50 @@ QStringList Session::getListeningIPs() const
|
||||||
|
|
||||||
const QString ifaceName = networkInterface();
|
const QString ifaceName = networkInterface();
|
||||||
const QString ifaceAddr = networkInterfaceAddress();
|
const QString ifaceAddr = networkInterfaceAddress();
|
||||||
const bool listenIPv6 = isIPv6Enabled();
|
const QHostAddress configuredAddr(ifaceAddr);
|
||||||
|
const bool allIPv4 = (ifaceAddr == QLatin1String("0.0.0.0")); // Means All IPv4 addresses
|
||||||
|
const bool allIPv6 = (ifaceAddr == QLatin1String("::")); // Means All IPv6 addresses
|
||||||
|
|
||||||
if (!ifaceAddr.isEmpty()) {
|
if (!ifaceAddr.isEmpty() && !allIPv4 && !allIPv6 && configuredAddr.isNull()) {
|
||||||
QHostAddress addr(ifaceAddr);
|
LogMsg(tr("Configured network interface address %1 isn't valid.", "Configured network interface address 124.5.158.1 isn't valid.").arg(ifaceAddr), Log::CRITICAL);
|
||||||
if (addr.isNull()) {
|
IPs.append("127.0.0.1"); // Force listening to localhost and avoid accidental connection that will expose user data.
|
||||||
LogMsg(tr("Configured network interface address %1 isn't valid.", "Configured network interface address 124.5.1568.1 isn't valid.").arg(ifaceAddr), Log::CRITICAL);
|
return IPs;
|
||||||
IPs.append("127.0.0.1"); // Force listening to localhost and avoid accidental connection that will expose user data.
|
|
||||||
return IPs;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ifaceName.isEmpty()) {
|
if (ifaceName.isEmpty()) {
|
||||||
if (!ifaceAddr.isEmpty())
|
if (ifaceAddr.isEmpty())
|
||||||
IPs.append(ifaceAddr);
|
return {QLatin1String("0.0.0.0"), QLatin1String("::")}; // Indicates all interfaces + all addresses (aka default)
|
||||||
else
|
|
||||||
IPs.append(QString());
|
if (allIPv4)
|
||||||
|
return {QLatin1String("0.0.0.0")};
|
||||||
|
|
||||||
|
if (allIPv6)
|
||||||
|
return {QLatin1String("::")};
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto checkAndAddIP = [allIPv4, allIPv6, &IPs](const QHostAddress &addr, const QHostAddress &match)
|
||||||
|
{
|
||||||
|
if ((allIPv4 && (addr.protocol() != QAbstractSocket::IPv4Protocol))
|
||||||
|
|| (allIPv6 && (addr.protocol() != QAbstractSocket::IPv6Protocol)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((match == addr) || allIPv4 || allIPv6)
|
||||||
|
IPs.append(addr.toString());
|
||||||
|
};
|
||||||
|
|
||||||
|
if (ifaceName.isEmpty()) {
|
||||||
|
const QList<QHostAddress> addresses = QNetworkInterface::allAddresses();
|
||||||
|
for (const auto &addr : addresses)
|
||||||
|
checkAndAddIP(addr, configuredAddr);
|
||||||
|
|
||||||
|
// At this point ifaceAddr was non-empty
|
||||||
|
// If IPs.isEmpty() it means the configured Address was not found
|
||||||
|
if (IPs.isEmpty()) {
|
||||||
|
LogMsg(tr("Can't find the configured address '%1' to listen on"
|
||||||
|
, "Can't find the configured address '192.168.1.3' to listen on")
|
||||||
|
.arg(ifaceAddr), Log::CRITICAL);
|
||||||
|
IPs.append("127.0.0.1"); // Force listening to localhost and avoid accidental connection that will expose user data.
|
||||||
|
}
|
||||||
|
|
||||||
return IPs;
|
return IPs;
|
||||||
}
|
}
|
||||||
|
@ -2445,40 +2480,24 @@ QStringList Session::getListeningIPs() const
|
||||||
return IPs;
|
return IPs;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QList<QNetworkAddressEntry> addresses = networkIFace.addressEntries();
|
if (ifaceAddr.isEmpty()) {
|
||||||
qDebug("This network interface has %d IP addresses", addresses.size());
|
IPs.append(ifaceName);
|
||||||
QHostAddress ip;
|
return IPs; // On Windows calling code converts it to GUID
|
||||||
QString ipString;
|
|
||||||
QAbstractSocket::NetworkLayerProtocol protocol;
|
|
||||||
for (const QNetworkAddressEntry &entry : addresses) {
|
|
||||||
ip = entry.ip();
|
|
||||||
ipString = ip.toString();
|
|
||||||
protocol = ip.protocol();
|
|
||||||
Q_ASSERT((protocol == QAbstractSocket::IPv4Protocol) || (protocol == QAbstractSocket::IPv6Protocol));
|
|
||||||
if ((!listenIPv6 && (protocol == QAbstractSocket::IPv6Protocol))
|
|
||||||
|| (listenIPv6 && (protocol == QAbstractSocket::IPv4Protocol)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// If an iface address has been defined to only allow ip's that match it to go through
|
|
||||||
if (!ifaceAddr.isEmpty()) {
|
|
||||||
if (ifaceAddr == ipString) {
|
|
||||||
IPs.append(ipString);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
IPs.append(ipString);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QList<QNetworkAddressEntry> addresses = networkIFace.addressEntries();
|
||||||
|
qDebug("This network interface has %d IP addresses", addresses.size());
|
||||||
|
for (const QNetworkAddressEntry &entry : addresses)
|
||||||
|
checkAndAddIP(entry.ip(), configuredAddr);
|
||||||
|
|
||||||
// Make sure there is at least one IP
|
// Make sure there is at least one IP
|
||||||
// At this point there was a valid network interface, with no suitable IP.
|
// At this point there was an explicit interface and an explicit address set
|
||||||
if (IPs.size() == 0) {
|
// and the address should have been found
|
||||||
LogMsg(tr("qBittorrent didn't find an %1 local address to listen on"
|
if (IPs.isEmpty()) {
|
||||||
, "qBittorrent didn't find an IPv4 local address to listen on")
|
LogMsg(tr("Can't find the configured address '%1' to listen on"
|
||||||
.arg(listenIPv6 ? "IPv6" : "IPv4"), Log::CRITICAL);
|
, "Can't find the configured address '192.168.1.3' to listen on")
|
||||||
|
.arg(ifaceAddr), Log::CRITICAL);
|
||||||
IPs.append("127.0.0.1"); // Force listening to localhost and avoid accidental connection that will expose user data.
|
IPs.append("127.0.0.1"); // Force listening to localhost and avoid accidental connection that will expose user data.
|
||||||
return IPs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return IPs;
|
return IPs;
|
||||||
|
@ -2734,19 +2753,6 @@ void Session::setNetworkInterfaceAddress(const QString &address)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Session::isIPv6Enabled() const
|
|
||||||
{
|
|
||||||
return m_isIPv6Enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::setIPv6Enabled(const bool enabled)
|
|
||||||
{
|
|
||||||
if (enabled != isIPv6Enabled()) {
|
|
||||||
m_isIPv6Enabled = enabled;
|
|
||||||
configureListeningInterface();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int Session::encryption() const
|
int Session::encryption() const
|
||||||
{
|
{
|
||||||
return m_encryption;
|
return m_encryption;
|
||||||
|
|
|
@ -303,8 +303,6 @@ namespace BitTorrent
|
||||||
void setNetworkInterfaceName(const QString &name);
|
void setNetworkInterfaceName(const QString &name);
|
||||||
QString networkInterfaceAddress() const;
|
QString networkInterfaceAddress() const;
|
||||||
void setNetworkInterfaceAddress(const QString &address);
|
void setNetworkInterfaceAddress(const QString &address);
|
||||||
bool isIPv6Enabled() const;
|
|
||||||
void setIPv6Enabled(bool enabled);
|
|
||||||
int encryption() const;
|
int encryption() const;
|
||||||
void setEncryption(int state);
|
void setEncryption(int state);
|
||||||
bool isProxyPeerConnectionsEnabled() const;
|
bool isProxyPeerConnectionsEnabled() const;
|
||||||
|
@ -532,6 +530,7 @@ namespace BitTorrent
|
||||||
void configureComponents();
|
void configureComponents();
|
||||||
void initializeNativeSession();
|
void initializeNativeSession();
|
||||||
void loadLTSettings(lt::settings_pack &settingsPack);
|
void loadLTSettings(lt::settings_pack &settingsPack);
|
||||||
|
void configureNetworkInterfaces(lt::settings_pack &settingsPack);
|
||||||
void configurePeerClasses();
|
void configurePeerClasses();
|
||||||
void adjustLimits(lt::settings_pack &settingsPack);
|
void adjustLimits(lt::settings_pack &settingsPack);
|
||||||
void applyBandwidthLimits(lt::settings_pack &settingsPack) const;
|
void applyBandwidthLimits(lt::settings_pack &settingsPack) const;
|
||||||
|
@ -662,7 +661,6 @@ namespace BitTorrent
|
||||||
CachedSettingValue<QString> m_networkInterface;
|
CachedSettingValue<QString> m_networkInterface;
|
||||||
CachedSettingValue<QString> m_networkInterfaceName;
|
CachedSettingValue<QString> m_networkInterfaceName;
|
||||||
CachedSettingValue<QString> m_networkInterfaceAddress;
|
CachedSettingValue<QString> m_networkInterfaceAddress;
|
||||||
CachedSettingValue<bool> m_isIPv6Enabled;
|
|
||||||
CachedSettingValue<int> m_encryption;
|
CachedSettingValue<int> m_encryption;
|
||||||
CachedSettingValue<bool> m_isProxyPeerConnectionsEnabled;
|
CachedSettingValue<bool> m_isProxyPeerConnectionsEnabled;
|
||||||
CachedSettingValue<ChokingAlgorithm> m_chokingAlgorithm;
|
CachedSettingValue<ChokingAlgorithm> m_chokingAlgorithm;
|
||||||
|
|
|
@ -86,7 +86,6 @@ namespace
|
||||||
{"BitTorrent/Session/BandwidthSchedulerEnabled", "Preferences/Scheduler/Enabled"},
|
{"BitTorrent/Session/BandwidthSchedulerEnabled", "Preferences/Scheduler/Enabled"},
|
||||||
{"BitTorrent/Session/Port", "Preferences/Connection/PortRangeMin"},
|
{"BitTorrent/Session/Port", "Preferences/Connection/PortRangeMin"},
|
||||||
{"BitTorrent/Session/UseRandomPort", "Preferences/General/UseRandomPort"},
|
{"BitTorrent/Session/UseRandomPort", "Preferences/General/UseRandomPort"},
|
||||||
{"BitTorrent/Session/IPv6Enabled", "Preferences/Connection/InterfaceListenIPv6"},
|
|
||||||
{"BitTorrent/Session/Interface", "Preferences/Connection/Interface"},
|
{"BitTorrent/Session/Interface", "Preferences/Connection/Interface"},
|
||||||
{"BitTorrent/Session/InterfaceName", "Preferences/Connection/InterfaceName"},
|
{"BitTorrent/Session/InterfaceName", "Preferences/Connection/InterfaceName"},
|
||||||
{"BitTorrent/Session/InterfaceAddress", "Preferences/Connection/InterfaceAddress"},
|
{"BitTorrent/Session/InterfaceAddress", "Preferences/Connection/InterfaceAddress"},
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
|
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
|
|
||||||
|
#include <QNetworkInterface>
|
||||||
#include <QSslCertificate>
|
#include <QSslCertificate>
|
||||||
#include <QSslKey>
|
#include <QSslKey>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
@ -91,6 +92,37 @@ namespace Utils
|
||||||
return subnet.first.toString() + '/' + QString::number(subnet.second);
|
return subnet.first.toString() + '/' + QString::number(subnet.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QHostAddress canonicalIPv6Addr(const QHostAddress &addr)
|
||||||
|
{
|
||||||
|
// Link-local IPv6 textual address always contains a scope id (or zone index)
|
||||||
|
// The scope id is appended to the IPv6 address using the '%' character
|
||||||
|
// The scope id can be either a interface name or an interface number
|
||||||
|
// Examples:
|
||||||
|
// fe80::1%ethernet_17
|
||||||
|
// fe80::1%13
|
||||||
|
// The interface number is the mandatory supported way
|
||||||
|
// Unfortunately for us QHostAddress::toString() outputs (at least on Windows)
|
||||||
|
// the interface name, and libtorrent/boost.asio only support an interface number
|
||||||
|
// as scope id. Furthermore, QHostAddress doesn't have any convenient method to
|
||||||
|
// affect this, so we jump through hoops here.
|
||||||
|
if (addr.protocol() != QAbstractSocket::IPv6Protocol)
|
||||||
|
return QHostAddress{addr.toIPv6Address()};
|
||||||
|
|
||||||
|
// QHostAddress::setScopeId(addr.scopeId()); // Even though the docs say that setScopeId
|
||||||
|
// will convert a name to a number, this doesn't happen. Probably a Qt bug.
|
||||||
|
const QString scopeIdTxt = addr.scopeId();
|
||||||
|
if (scopeIdTxt.isEmpty())
|
||||||
|
return addr;
|
||||||
|
|
||||||
|
const int id = QNetworkInterface::interfaceIndexFromName(scopeIdTxt);
|
||||||
|
if (id == 0) // This failure might mean that the scope id was already a number
|
||||||
|
return addr;
|
||||||
|
|
||||||
|
QHostAddress canonical(addr.toIPv6Address());
|
||||||
|
canonical.setScopeId(QString::number(id));
|
||||||
|
return canonical;
|
||||||
|
}
|
||||||
|
|
||||||
QList<QSslCertificate> loadSSLCertificate(const QByteArray &data)
|
QList<QSslCertificate> loadSSLCertificate(const QByteArray &data)
|
||||||
{
|
{
|
||||||
const QList<QSslCertificate> certs {QSslCertificate::fromData(data)};
|
const QList<QSslCertificate> certs {QSslCertificate::fromData(data)};
|
||||||
|
|
|
@ -50,6 +50,7 @@ namespace Utils
|
||||||
bool isLoopbackAddress(const QHostAddress &addr);
|
bool isLoopbackAddress(const QHostAddress &addr);
|
||||||
bool isIPInRange(const QHostAddress &addr, const QVector<Subnet> &subnets);
|
bool isIPInRange(const QHostAddress &addr, const QVector<Subnet> &subnets);
|
||||||
QString subnetToString(const Subnet &subnet);
|
QString subnetToString(const Subnet &subnet);
|
||||||
|
QHostAddress canonicalIPv6Addr(const QHostAddress &addr);
|
||||||
|
|
||||||
const int MAX_SSL_FILE_SIZE = 1024 * 1024;
|
const int MAX_SSL_FILE_SIZE = 1024 * 1024;
|
||||||
QList<QSslCertificate> loadSSLCertificate(const QByteArray &data);
|
QList<QSslCertificate> loadSSLCertificate(const QByteArray &data);
|
||||||
|
|
|
@ -68,7 +68,6 @@ enum AdvSettingsRows
|
||||||
NETWORK_IFACE,
|
NETWORK_IFACE,
|
||||||
//Optional network address
|
//Optional network address
|
||||||
NETWORK_IFACE_ADDRESS,
|
NETWORK_IFACE_ADDRESS,
|
||||||
NETWORK_LISTEN_IPV6,
|
|
||||||
// behavior
|
// behavior
|
||||||
SAVE_RESUME_DATA_INTERVAL,
|
SAVE_RESUME_DATA_INTERVAL,
|
||||||
CONFIRM_RECHECK_TORRENT,
|
CONFIRM_RECHECK_TORRENT,
|
||||||
|
@ -227,18 +226,14 @@ void AdvancedSettings::saveAdvancedSettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interface address
|
// Interface address
|
||||||
if (m_comboBoxInterfaceAddress.currentIndex() == 0) {
|
// Construct a QHostAddress to filter malformed strings
|
||||||
// All addresses (default)
|
const QHostAddress ifaceAddr(m_comboBoxInterfaceAddress.currentData().toString().trimmed());
|
||||||
session->setNetworkInterfaceAddress({});
|
session->setNetworkInterfaceAddress(ifaceAddr.toString());
|
||||||
}
|
|
||||||
else {
|
|
||||||
QHostAddress ifaceAddr(m_comboBoxInterfaceAddress.currentText().trimmed());
|
|
||||||
ifaceAddr.isNull() ? session->setNetworkInterfaceAddress({}) : session->setNetworkInterfaceAddress(ifaceAddr.toString());
|
|
||||||
}
|
|
||||||
session->setIPv6Enabled(m_checkBoxListenIPv6.isChecked());
|
|
||||||
// Announce IP
|
// Announce IP
|
||||||
QHostAddress addr(m_lineEditAnnounceIP.text().trimmed());
|
// Construct a QHostAddress to filter malformed strings
|
||||||
session->setAnnounceIP(addr.isNull() ? "" : addr.toString());
|
const QHostAddress addr(m_lineEditAnnounceIP.text().trimmed());
|
||||||
|
session->setAnnounceIP(addr.toString());
|
||||||
|
|
||||||
// Program notification
|
// Program notification
|
||||||
MainWindow *const mainWindow = static_cast<Application*>(QCoreApplication::instance())->mainWindow();
|
MainWindow *const mainWindow = static_cast<Application*>(QCoreApplication::instance())->mainWindow();
|
||||||
|
@ -295,33 +290,35 @@ void AdvancedSettings::updateInterfaceAddressCombo()
|
||||||
|
|
||||||
// Clear all items and reinsert them, default to all
|
// Clear all items and reinsert them, default to all
|
||||||
m_comboBoxInterfaceAddress.clear();
|
m_comboBoxInterfaceAddress.clear();
|
||||||
m_comboBoxInterfaceAddress.addItem(tr("All addresses"));
|
m_comboBoxInterfaceAddress.addItem(tr("All addresses"), {});
|
||||||
m_comboBoxInterfaceAddress.setCurrentIndex(0);
|
m_comboBoxInterfaceAddress.addItem(tr("All IPv4 addresses"), QLatin1String("0.0.0.0"));
|
||||||
|
m_comboBoxInterfaceAddress.addItem(tr("All IPv6 addresses"), QLatin1String("::"));
|
||||||
|
|
||||||
auto populateCombo = [this, ¤tAddress](const QString &ip, const QAbstractSocket::NetworkLayerProtocol &protocol)
|
const auto populateCombo = [this, ¤tAddress](const QHostAddress &addr)
|
||||||
{
|
{
|
||||||
Q_ASSERT((protocol == QAbstractSocket::IPv4Protocol) || (protocol == QAbstractSocket::IPv6Protocol));
|
if (addr.protocol() == QAbstractSocket::IPv4Protocol) {
|
||||||
// Only take ipv4 for now?
|
const QString str = addr.toString();
|
||||||
if ((protocol != QAbstractSocket::IPv4Protocol) && (protocol != QAbstractSocket::IPv6Protocol))
|
m_comboBoxInterfaceAddress.addItem(str, str);
|
||||||
return;
|
}
|
||||||
m_comboBoxInterfaceAddress.addItem(ip);
|
else if (addr.protocol() == QAbstractSocket::IPv6Protocol) {
|
||||||
//Try to select the last added one
|
const QString str = Utils::Net::canonicalIPv6Addr(addr).toString();
|
||||||
if (ip == currentAddress)
|
m_comboBoxInterfaceAddress.addItem(str, str);
|
||||||
m_comboBoxInterfaceAddress.setCurrentIndex(m_comboBoxInterfaceAddress.count() - 1);
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (ifaceName.isEmpty()) {
|
if (ifaceName.isEmpty()) {
|
||||||
for (const QHostAddress &ip : asConst(QNetworkInterface::allAddresses()))
|
for (const QHostAddress &addr : asConst(QNetworkInterface::allAddresses()))
|
||||||
populateCombo(ip.toString(), ip.protocol());
|
populateCombo(addr);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const QNetworkInterface iface = QNetworkInterface::interfaceFromName(ifaceName);
|
const QNetworkInterface iface = QNetworkInterface::interfaceFromName(ifaceName);
|
||||||
const QList<QNetworkAddressEntry> addresses = iface.addressEntries();
|
const QList<QNetworkAddressEntry> addresses = iface.addressEntries();
|
||||||
for (const QNetworkAddressEntry &entry : addresses) {
|
for (const QNetworkAddressEntry &entry : addresses)
|
||||||
const QHostAddress ip = entry.ip();
|
populateCombo(entry.ip());
|
||||||
populateCombo(ip.toString(), ip.protocol());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const int index = m_comboBoxInterfaceAddress.findData(currentAddress);
|
||||||
|
m_comboBoxInterfaceAddress.setCurrentIndex(std::max(index, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvancedSettings::loadAdvancedSettings()
|
void AdvancedSettings::loadAdvancedSettings()
|
||||||
|
@ -524,9 +521,6 @@ void AdvancedSettings::loadAdvancedSettings()
|
||||||
// Network interface address
|
// Network interface address
|
||||||
updateInterfaceAddressCombo();
|
updateInterfaceAddressCombo();
|
||||||
addRow(NETWORK_IFACE_ADDRESS, tr("Optional IP Address to bind to (requires restart)"), &m_comboBoxInterfaceAddress);
|
addRow(NETWORK_IFACE_ADDRESS, tr("Optional IP Address to bind to (requires restart)"), &m_comboBoxInterfaceAddress);
|
||||||
// Listen on IPv6 address
|
|
||||||
m_checkBoxListenIPv6.setChecked(session->isIPv6Enabled());
|
|
||||||
addRow(NETWORK_LISTEN_IPV6, tr("Listen on IPv6 address (requires restart)"), &m_checkBoxListenIPv6);
|
|
||||||
// Announce IP
|
// Announce IP
|
||||||
m_lineEditAnnounceIP.setText(session->announceIP());
|
m_lineEditAnnounceIP.setText(session->announceIP());
|
||||||
addRow(ANNOUNCE_IP, tr("IP Address to report to trackers (requires restart)"), &m_lineEditAnnounceIP);
|
addRow(ANNOUNCE_IP, tr("IP Address to report to trackers (requires restart)"), &m_lineEditAnnounceIP);
|
||||||
|
|
|
@ -63,7 +63,7 @@ private:
|
||||||
m_spinBoxSendBufferWatermarkFactor, m_spinBoxSocketBacklogSize, m_spinBoxSavePathHistoryLength;
|
m_spinBoxSendBufferWatermarkFactor, m_spinBoxSocketBacklogSize, m_spinBoxSavePathHistoryLength;
|
||||||
QCheckBox m_checkBoxOsCache, m_checkBoxRecheckCompleted, m_checkBoxResolveCountries, m_checkBoxResolveHosts, m_checkBoxSuperSeeding,
|
QCheckBox m_checkBoxOsCache, m_checkBoxRecheckCompleted, m_checkBoxResolveCountries, m_checkBoxResolveHosts, m_checkBoxSuperSeeding,
|
||||||
m_checkBoxProgramNotifications, m_checkBoxTorrentAddedNotifications, m_checkBoxTrackerFavicon, m_checkBoxTrackerStatus,
|
m_checkBoxProgramNotifications, m_checkBoxTorrentAddedNotifications, m_checkBoxTrackerFavicon, m_checkBoxTrackerStatus,
|
||||||
m_checkBoxConfirmTorrentRecheck, m_checkBoxConfirmRemoveAllTags, m_checkBoxListenIPv6, m_checkBoxAnnounceAllTrackers, m_checkBoxAnnounceAllTiers,
|
m_checkBoxConfirmTorrentRecheck, m_checkBoxConfirmRemoveAllTags, m_checkBoxAnnounceAllTrackers, m_checkBoxAnnounceAllTiers,
|
||||||
m_checkBoxMultiConnectionsPerIp, m_checkBoxSuggestMode, m_checkBoxCoalesceRW, m_checkBoxSpeedWidgetEnabled;
|
m_checkBoxMultiConnectionsPerIp, m_checkBoxSuggestMode, m_checkBoxCoalesceRW, m_checkBoxSpeedWidgetEnabled;
|
||||||
QComboBox m_comboBoxInterface, m_comboBoxInterfaceAddress, m_comboBoxUtpMixedMode, m_comboBoxChokingAlgorithm, m_comboBoxSeedChokingAlgorithm;
|
QComboBox m_comboBoxInterface, m_comboBoxInterfaceAddress, m_comboBoxUtpMixedMode, m_comboBoxChokingAlgorithm, m_comboBoxSeedChokingAlgorithm;
|
||||||
QLineEdit m_lineEditAnnounceIP;
|
QLineEdit m_lineEditAnnounceIP;
|
||||||
|
|
|
@ -259,8 +259,6 @@ void AppController::preferencesAction()
|
||||||
data["current_network_interface"] = session->networkInterface();
|
data["current_network_interface"] = session->networkInterface();
|
||||||
// Current network interface address
|
// Current network interface address
|
||||||
data["current_interface_address"] = BitTorrent::Session::instance()->networkInterfaceAddress();
|
data["current_interface_address"] = BitTorrent::Session::instance()->networkInterfaceAddress();
|
||||||
// Listen on IPv6 address
|
|
||||||
data["listen_on_ipv6_address"] = session->isIPv6Enabled();
|
|
||||||
// Save resume data interval
|
// Save resume data interval
|
||||||
data["save_resume_data_interval"] = static_cast<double>(session->saveResumeDataInterval());
|
data["save_resume_data_interval"] = static_cast<double>(session->saveResumeDataInterval());
|
||||||
// Recheck completed torrents
|
// Recheck completed torrents
|
||||||
|
@ -654,9 +652,6 @@ void AppController::setPreferencesAction()
|
||||||
const QHostAddress ifaceAddress {it.value().toString().trimmed()};
|
const QHostAddress ifaceAddress {it.value().toString().trimmed()};
|
||||||
session->setNetworkInterfaceAddress(ifaceAddress.isNull() ? QString {} : ifaceAddress.toString());
|
session->setNetworkInterfaceAddress(ifaceAddress.isNull() ? QString {} : ifaceAddress.toString());
|
||||||
}
|
}
|
||||||
// Listen on IPv6 address
|
|
||||||
if (hasKey("listen_on_ipv6_address"))
|
|
||||||
session->setIPv6Enabled(it.value().toBool());
|
|
||||||
// Save resume data interval
|
// Save resume data interval
|
||||||
if (hasKey("save_resume_data_interval"))
|
if (hasKey("save_resume_data_interval"))
|
||||||
session->setSaveResumeDataInterval(it.value().toInt());
|
session->setSaveResumeDataInterval(it.value().toInt());
|
||||||
|
@ -767,14 +762,22 @@ void AppController::networkInterfaceAddressListAction()
|
||||||
const QString ifaceName = params().value("iface");
|
const QString ifaceName = params().value("iface");
|
||||||
QJsonArray addressList;
|
QJsonArray addressList;
|
||||||
|
|
||||||
|
const auto appendAddress = [&addressList](const QHostAddress &addr)
|
||||||
|
{
|
||||||
|
if (addr.protocol() == QAbstractSocket::IPv6Protocol)
|
||||||
|
addressList.append(Utils::Net::canonicalIPv6Addr(addr).toString());
|
||||||
|
else
|
||||||
|
addressList.append(addr.toString());
|
||||||
|
};
|
||||||
|
|
||||||
if (ifaceName.isEmpty()) {
|
if (ifaceName.isEmpty()) {
|
||||||
for (const QHostAddress &ip : asConst(QNetworkInterface::allAddresses()))
|
for (const QHostAddress &addr : asConst(QNetworkInterface::allAddresses()))
|
||||||
addressList.append(ip.toString());
|
appendAddress(addr);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const QNetworkInterface iface = QNetworkInterface::interfaceFromName(ifaceName);
|
const QNetworkInterface iface = QNetworkInterface::interfaceFromName(ifaceName);
|
||||||
for (const QNetworkAddressEntry &entry : asConst(iface.addressEntries()))
|
for (const QNetworkAddressEntry &entry : asConst(iface.addressEntries()))
|
||||||
addressList.append(entry.ip().toString());
|
appendAddress(entry.ip());
|
||||||
}
|
}
|
||||||
|
|
||||||
setResult(addressList);
|
setResult(addressList);
|
||||||
|
|
|
@ -1438,6 +1438,8 @@
|
||||||
if (!addresses) return;
|
if (!addresses) return;
|
||||||
|
|
||||||
$('optionalIPAddressToBind').options.add(new Option('QBT_TR(All addresses)QBT_TR[CONTEXT=OptionDialog]', ''));
|
$('optionalIPAddressToBind').options.add(new Option('QBT_TR(All addresses)QBT_TR[CONTEXT=OptionDialog]', ''));
|
||||||
|
$('optionalIPAddressToBind').options.add(new Option('QBT_TR(All IPv4 addresses)QBT_TR[CONTEXT=OptionDialog]', '0.0.0.0'));
|
||||||
|
$('optionalIPAddressToBind').options.add(new Option('QBT_TR(All IPv6 addresses)QBT_TR[CONTEXT=OptionDialog]', '::'));
|
||||||
addresses.forEach(function(item, index) {
|
addresses.forEach(function(item, index) {
|
||||||
$('optionalIPAddressToBind').options.add(new Option(item, item));
|
$('optionalIPAddressToBind').options.add(new Option(item, item));
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue