diff --git a/src/base/bittorrent/session.cpp b/src/base/bittorrent/session.cpp index e15466fbf..677a88881 100644 --- a/src/base/bittorrent/session.cpp +++ b/src/base/bittorrent/session.cpp @@ -1735,9 +1735,11 @@ const QStringList Session::getListeningIPs() QStringList IPs; const QString ifaceName = pref->getNetworkInterface(); + const QString ifaceAddr = pref->getNetworkInterfaceAddress(); const bool listenIPv6 = pref->getListenIPv6(); - if (ifaceName.isEmpty()) { + //No interface name or address defined just use an empty list + if (ifaceName.isEmpty() && ifaceAddr.isEmpty()) { IPs.append(QString()); return IPs; } @@ -1764,6 +1766,13 @@ const QStringList Session::getListeningIPs() if ((!listenIPv6 && (protocol == QAbstractSocket::IPv6Protocol)) || (listenIPv6 && (protocol == QAbstractSocket::IPv4Protocol))) continue; + + //If an iface address has been defined only allow ip's that match it to go through + if (!ifaceAddr.isEmpty()) { + if (ipString != ifaceAddr) { + continue; + } + } IPs.append(ipString); } diff --git a/src/base/preferences.cpp b/src/base/preferences.cpp index b2b16bc1f..e1351164b 100644 --- a/src/base/preferences.cpp +++ b/src/base/preferences.cpp @@ -1339,6 +1339,16 @@ QString Preferences::getNetworkInterfaceName() const return value("Preferences/Connection/InterfaceName").toString(); } +void Preferences::setNetworkInterfaceAddress(const QString& addr) +{ + setValue("Preferences/Connection/InterfaceAddress", addr); +} + +QString Preferences::getNetworkInterfaceAddress() const +{ + return value("Preferences/Connection/InterfaceAddress").toString(); +} + void Preferences::setNetworkInterfaceName(const QString& iface) { setValue("Preferences/Connection/InterfaceName", iface); diff --git a/src/base/preferences.h b/src/base/preferences.h index 584765432..a6355a941 100644 --- a/src/base/preferences.h +++ b/src/base/preferences.h @@ -361,6 +361,8 @@ public: void setMaxHalfOpenConnections(int value); QString getNetworkInterface() const; void setNetworkInterface(const QString& iface); + QString getNetworkInterfaceAddress() const; + void setNetworkInterfaceAddress(const QString& addr); QString getNetworkInterfaceName() const; void setNetworkInterfaceName(const QString& iface); bool getListenIPv6() const; diff --git a/src/gui/advancedsettings.cpp b/src/gui/advancedsettings.cpp index 0f62e3e34..f62967167 100644 --- a/src/gui/advancedsettings.cpp +++ b/src/gui/advancedsettings.cpp @@ -47,6 +47,8 @@ enum AdvSettingsRows QBITTORRENT_HEADER, // network interface NETWORK_IFACE, + //Optional network address + NETWORK_IFACE_ADDRESS, NETWORK_LISTEN_IPV6, // behavior SAVE_RESUME_DATA_INTERVAL, @@ -104,6 +106,7 @@ AdvancedSettings::AdvancedSettings(QWidget *parent) setEditTriggers(QAbstractItemView::NoEditTriggers); // Signals connect(&spin_cache, SIGNAL(valueChanged(int)), SLOT(updateCacheSpinSuffix(int))); + connect(&combo_iface, SIGNAL(currentIndexChanged(int)), SLOT(updateInterfaceAddressCombo(int))); // Load settings loadAdvancedSettings(); resizeColumnToContents(0); @@ -146,12 +149,26 @@ void AdvancedSettings::saveAdvancedSettings() } // Listen on IPv6 address pref->setListenIPv6(cb_listen_ipv6.isChecked()); - // Network address - QHostAddress addr(txt_network_address.text().trimmed()); - if (addr.isNull()) + // Interface address + if (combo_iface_address.currentIndex() == 0) { + // All addresses (default) + pref->setNetworkInterfaceAddress(QString::null); + } + else { + QHostAddress ifaceAddr(combo_iface_address.currentText().trimmed()); + if (ifaceAddr.isNull()) { + pref->setNetworkInterfaceAddress(QString::null); + } else { + pref->setNetworkInterfaceAddress(ifaceAddr.toString()); + } + } + // Network Announce address + QHostAddress networkAddr(txt_network_address.text().trimmed()); + if (networkAddr.isNull()) pref->setNetworkAddress(""); else - pref->setNetworkAddress(addr.toString()); + pref->setNetworkAddress(networkAddr.toString()); + // Program notification MainWindow * const mainWindow = static_cast(QCoreApplication::instance())->mainWindow(); mainWindow->setNotificationsEnabled(cb_program_notifications.isChecked()); @@ -180,6 +197,45 @@ void AdvancedSettings::updateCacheSpinSuffix(int value) spin_cache.setSuffix(tr(" MiB")); } +void AdvancedSettings::updateInterfaceAddressCombo(int) { + //Try to get the currently selected interface name + QString ifaceName; + if (combo_iface.currentIndex() == 0) { + ifaceName = QString(); + } + else { + ifaceName = combo_iface.itemData(combo_iface.currentIndex()).toString(); + } + const QNetworkInterface iface = QNetworkInterface::interfaceFromName(ifaceName); + + //Clear all items and reinsert them, default to all + combo_iface_address.clear(); + combo_iface_address.addItem(tr("All Addresses")); + combo_iface_address.setCurrentIndex(0); + if (!iface.isValid()) { + return; + } + //Found a valid interface, try to get the addresses + const QList addresses = iface.addressEntries(); + const Preferences* const pref = Preferences::instance(); + const QString currentAddress = pref->getNetworkInterfaceAddress(); + + foreach (const QNetworkAddressEntry &entry, addresses) { + QHostAddress ip = entry.ip(); + QString ipString = ip.toString(); + QAbstractSocket::NetworkLayerProtocol protocol = ip.protocol(); + Q_ASSERT(protocol == QAbstractSocket::IPv4Protocol || protocol == QAbstractSocket::IPv6Protocol); + //Only take ipv4 for now? + if (protocol != QAbstractSocket::IPv4Protocol) + continue; + combo_iface_address.addItem( ipString ); + //Try to select the last added one + if (ipString == currentAddress) { + combo_iface_address.setCurrentIndex(combo_iface_address.count() - 1); + } + } +} + void AdvancedSettings::loadAdvancedSettings() { const Preferences* const pref = Preferences::instance(); @@ -282,12 +338,16 @@ void AdvancedSettings::loadAdvancedSettings() combo_iface.setCurrentIndex(i); } addRow(NETWORK_IFACE, tr("Network Interface (requires restart)"), &combo_iface); + // Network interface address + updateInterfaceAddressCombo(combo_iface.currentIndex()); + addRow(NETWORK_IFACE_ADDRESS, tr("Optional IP Address to bind to (requires restart)"), &combo_iface_address); // Listen on IPv6 address cb_listen_ipv6.setChecked(pref->getListenIPv6()); addRow(NETWORK_LISTEN_IPV6, tr("Listen on IPv6 address (requires restart)"), &cb_listen_ipv6); - // Network address + // Announce address txt_network_address.setText(pref->getNetworkAddress()); addRow(NETWORK_ADDRESS, tr("IP Address to report to trackers (requires restart)"), &txt_network_address); + // Program notifications const MainWindow * const mainWindow = static_cast(QCoreApplication::instance())->mainWindow(); cb_program_notifications.setChecked(mainWindow->isNotificationsEnabled()); diff --git a/src/gui/advancedsettings.h b/src/gui/advancedsettings.h index 30fecd1d4..ef61d52f1 100644 --- a/src/gui/advancedsettings.h +++ b/src/gui/advancedsettings.h @@ -52,7 +52,7 @@ signals: private slots: void updateCacheSpinSuffix(int value); - + void updateInterfaceAddressCombo(int index); private: void loadAdvancedSettings(); template void addRow(int row, const QString &rowText, T* widget); @@ -62,7 +62,7 @@ private: QCheckBox cb_os_cache, cb_recheck_completed, cb_resolve_countries, cb_resolve_hosts, cb_super_seeding, cb_program_notifications, cb_torrent_added_notifications, cb_tracker_status, cb_confirm_torrent_recheck, cb_enable_tracker_ext, cb_listen_ipv6, cb_announce_all_trackers; - QComboBox combo_iface; + QComboBox combo_iface, combo_iface_address; QLineEdit txt_network_address; // OS dependent settings