From 196aa48727276fafeb16bc7d845c91e55995652e Mon Sep 17 00:00:00 2001 From: Doadin Date: Wed, 2 May 2018 00:14:02 -0400 Subject: [PATCH] [#3171] Add Option To Specify Outgoing Connection Interface --- ChangeLog | 1 + deluge/core/core.py | 12 +++- deluge/core/daemon.py | 7 ++- deluge/core/daemon_entry.py | 3 + deluge/core/preferencesmanager.py | 11 ++++ .../modes/preferences/preference_panes.py | 21 +++++-- deluge/ui/gtkui/glade/preferences_dialog.ui | 56 ++++++++++++++++++- deluge/ui/gtkui/preferences.py | 4 ++ .../js/deluge-all/preferences/NetworkPage.js | 17 ++++++ 9 files changed, 122 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index badc7562c..3bedfc9d6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,6 +9,7 @@ * Enforced the use of the "deluge.plugins" namespace to reduce package names clashing beetween regular packages and deluge plugins. * Fix potential for host_id collision when creating hostlist entries. + * Add Option To Specify Outgoing Connection Interface. ==== Core ==== * Make the distinction between adding to the session new unmanaged torrents diff --git a/deluge/core/core.py b/deluge/core/core.py index 4b80a55d8..10861c631 100644 --- a/deluge/core/core.py +++ b/deluge/core/core.py @@ -101,7 +101,7 @@ DELUGE_VER = deluge.common.get_version() class Core(component.Component): - def __init__(self, listen_interface=None, read_only_config_keys=None): + def __init__(self, listen_interface=None, outgoing_interface=None, read_only_config_keys=None): component.Component.__init__(self, 'Core') # Start the libtorrent session. @@ -163,6 +163,13 @@ class Core(component.Component): self.config['listen_interface'] = listen_interface else: log.error('Invalid listen interface (must be IP Address): %s', listen_interface) + self.__old_outgoing_interface = None + if outgoing_interface: + if deluge.common.is_ip(outgoing_interface): + self.__old_outgoing_interface = self.config['outgoing_interface'] + self.config['outgoing_interface'] = outgoing_interface + else: + log.error('Invalid outgoing interface (must be IP Address): %s', outgoing_interface) # New release check information self.__new_release = None @@ -197,6 +204,9 @@ class Core(component.Component): if self.__old_interface: self.config['listen_interface'] = self.__old_interface + if self.__old_outgoing_interface: + self.config['outgoing_interface'] = self.__old_outgoing_interface + # Make sure the config file has been saved self.config.save() diff --git a/deluge/core/daemon.py b/deluge/core/daemon.py index 842924b02..5f4ae4fb1 100644 --- a/deluge/core/daemon.py +++ b/deluge/core/daemon.py @@ -65,11 +65,12 @@ def is_daemon_running(pid_file): class Daemon(object): """The Deluge Daemon class""" - def __init__(self, listen_interface=None, interface=None, port=None, standalone=False, + def __init__(self, listen_interface=None, outgoing_interface=None, interface=None, port=None, standalone=False, read_only_config_keys=None): """ Args: listen_interface (str, optional): The IP address to listen to bittorrent connections on. + outgoing_interface (str, optional): The IP address to open outgoing BitTorrent connections on. interface (str, optional): The IP address the daemon will listen for UI connections on. port (int, optional): The port the daemon will listen for UI connections on. standalone (bool, optional): If True the client is in Standalone mode otherwise, if @@ -98,6 +99,7 @@ class Daemon(object): # Start the core as a thread and join it until it's done self.core = Core(listen_interface=listen_interface, + outgoing_interface=outgoing_interface, read_only_config_keys=read_only_config_keys) if port is None: @@ -115,7 +117,8 @@ class Daemon(object): interface=interface ) - log.debug('Listening to UI on: %s:%s and bittorrent on: %s', interface, port, listen_interface) + log.debug('Listening to UI on: %s:%s and bittorrent on: %s Making connections out on: %s', + interface, port, listen_interface, outgoing_interface) def start(self): # Register the daemon and the core RPCs diff --git a/deluge/core/daemon_entry.py b/deluge/core/daemon_entry.py index d822f1f94..d045ca10d 100644 --- a/deluge/core/daemon_entry.py +++ b/deluge/core/daemon_entry.py @@ -29,6 +29,8 @@ def add_daemon_options(parser): help=_('Port to listen for UI connections on')) group.add_argument('-i', '--interface', metavar='', dest='listen_interface', action='store', help=_('IP address to listen for BitTorrent connections')) + group.add_argument('-o', '--outinterface', metavar='', dest='outgoing_interface', + action='store', help=_('The IP address for outgoing BitTorrent connections.')) group.add_argument('--read-only-config-keys', metavar='', action='store', help=_('Config keys to be unmodified by `set_config` RPC'), type=str, default='') parser.add_process_arg_group() @@ -73,6 +75,7 @@ def start_daemon(skip_start=False): try: from deluge.core.daemon import Daemon daemon = Daemon(listen_interface=options.listen_interface, + outgoing_interface=options.outgoing_interface, interface=options.ui_interface, port=options.port, read_only_config_keys=options.read_only_config_keys.split(',')) diff --git a/deluge/core/preferencesmanager.py b/deluge/core/preferencesmanager.py index 39b1b4ebe..54a94e42a 100644 --- a/deluge/core/preferencesmanager.py +++ b/deluge/core/preferencesmanager.py @@ -47,6 +47,7 @@ DEFAULT_PREFS = { 'download_location': deluge.common.get_default_download_dir(), 'listen_ports': [6881, 6891], 'listen_interface': '', + 'outgoing_interface': '', 'random_port': True, 'listen_random_port': None, 'listen_use_sys_port': False, @@ -187,6 +188,9 @@ class PreferencesManager(component.Component): def _on_set_listen_interface(self, key, value): self.__set_listen_on() + def _on_set_outgoing_interface(self, key, value): + self.__set_outgoing_on() + def _on_set_random_port(self, key, value): self.__set_listen_on() @@ -210,6 +214,13 @@ class PreferencesManager(component.Component): {'listen_system_port_fallback': self.config['listen_use_sys_port'], 'listen_interfaces': ''.join(interfaces)}) + def __set_outgoing_on(self): + """ Set the interface address for outgoing BitTorrent connections.""" + outinterface = self.config['outgoing_interface'].strip() + outinterface = outinterface if outinterface else '0.0.0.0' + self.core.apply_session_settings( + {'outgoing_interfaces': outinterface}) + def _on_set_outgoing_ports(self, key, value): self.__set_outgoing_ports() diff --git a/deluge/ui/console/modes/preferences/preference_panes.py b/deluge/ui/console/modes/preferences/preference_panes.py index e709f1e20..b1c7894f5 100644 --- a/deluge/ui/console/modes/preferences/preference_panes.py +++ b/deluge/ui/console/modes/preferences/preference_panes.py @@ -83,6 +83,10 @@ class BasePreferencePane(BaseInputPane, BaseWindow, PopupsHandler): interface = ipt.get_value().strip() if is_ip(interface) or not interface: conf_dict['listen_interface'] = interface + elif ipt.name == 'outgoing_interface': + outinterface = ipt.get_value().strip() + if is_ip(outinterface) or not outinterface: + conf_dict['outgoing_interface'] = outinterface elif ipt.name.startswith('proxy_'): if ipt.name == 'proxy_type': conf_dict.setdefault('proxy', {})['type'] = ipt.get_value() @@ -240,10 +244,19 @@ class NetworkPane(BasePreferencePane): value=out_ports[1], min_val=0, max_val=65535) self.outto.set_depend(outrand, inverse=True) - self.add_header(_('Interface'), space_above=True) - self.add_text_input('listen_interface', '%s:' % _('IP address of the interface to listen on ' - '(leave empty for default)'), - core_conf['listen_interface']) + self.add_header(_('Incoming Interface'), space_above=True) + self.add_text_input( + 'listen_interface', + _('IP address of the interface to listen on (leave empty for default):'), + core_conf['listen_interface'], + ) + + self.add_header(_('Outgoing Interface'), space_above=True) + self.add_text_input( + 'outgoing_interface', + _('IP address of the interface to open outgoing connections on. (leave empty for default):'), + core_conf['outgoing_interface'], + ) self.add_header('TOS', space_above=True) self.add_text_input('peer_tos', 'Peer TOS Byte:', core_conf['peer_tos']) diff --git a/deluge/ui/gtkui/glade/preferences_dialog.ui b/deluge/ui/gtkui/glade/preferences_dialog.ui index c8c7697ef..edfeed534 100644 --- a/deluge/ui/gtkui/glade/preferences_dialog.ui +++ b/deluge/ui/gtkui/glade/preferences_dialog.ui @@ -2906,6 +2906,56 @@ used sparingly. 1 + + + True + False + 0 + none + + + True + False + 0 + 0 + 5 + 12 + + + True + True + IP address for outgoing BitTorrent connections. Leave this empty if you want to use the default. + 15 + + 15 + True + True + False + False + True + True + + + + + + + True + False + Outgoing Address + + + + + + + + False + False + 5 + 2 + + True @@ -3028,7 +3078,7 @@ used sparingly. False False 5 - 2 + 3 @@ -3190,7 +3240,7 @@ used sparingly. False False 5 - 3 + 4 @@ -3361,7 +3411,7 @@ used sparingly. False True 5 - 4 + 5 diff --git a/deluge/ui/gtkui/preferences.py b/deluge/ui/gtkui/preferences.py index dc51faea7..ba4f80f03 100644 --- a/deluge/ui/gtkui/preferences.py +++ b/deluge/ui/gtkui/preferences.py @@ -317,6 +317,7 @@ class Preferences(component.Component): 'spin_outgoing_port_max': ('value', lambda: self.core_config['outgoing_ports'][1]), 'chk_random_outgoing_ports': ('active', 'random_outgoing_ports'), 'entry_interface': ('text', 'listen_interface'), + 'entry_outgoing_interface': ('text', 'outgoing_interface'), 'entry_peer_tos': ('text', 'peer_tos'), 'chk_dht': ('active', 'dht'), 'chk_upnp': ('active', 'upnp'), @@ -519,8 +520,11 @@ class Preferences(component.Component): new_core_config['random_outgoing_ports'] = self.builder.get_object( 'chk_random_outgoing_ports').get_active() incoming_address = self.builder.get_object('entry_interface').get_text().strip() + outgoing_address = self.builder.get_object('entry_outgoing_interface').get_text().strip() if deluge.common.is_ip(incoming_address) or not incoming_address: new_core_config['listen_interface'] = incoming_address + if deluge.common.is_ip(outgoing_address) or not outgoing_address: + new_core_config['outgoing_interface'] = outgoing_address new_core_config['peer_tos'] = self.builder.get_object('entry_peer_tos').get_text() new_core_config['dht'] = self.builder.get_object('chk_dht').get_active() new_core_config['upnp'] = self.builder.get_object('chk_upnp').get_active() diff --git a/deluge/ui/web/js/deluge-all/preferences/NetworkPage.js b/deluge/ui/web/js/deluge-all/preferences/NetworkPage.js index 25d227282..f110be335 100644 --- a/deluge/ui/web/js/deluge-all/preferences/NetworkPage.js +++ b/deluge/ui/web/js/deluge-all/preferences/NetworkPage.js @@ -90,6 +90,23 @@ Deluge.preferences.Network = Ext.extend(Ext.form.FormPanel, { }); optMan.bind('listen_ports', this.listenPort); + fieldset = this.add({ + xtype: 'fieldset', + border: false, + title: _('Outgoing Address'), + style: 'margin-bottom: 5px; padding-bottom: 0px;', + autoHeight: true, + labelWidth: 1, + defaultType: 'textfield' + }); + optMan.bind('outgoing_interface', fieldset.add({ + name: 'outgoing_interface', + fieldLabel: '', + labelSeparator: '', + width: 200, + vtype: 'IPAddress' + })); + fieldset = this.add({ xtype: 'fieldset', border: false,