[#3171] Add Option To Specify Outgoing Connection Interface
This commit is contained in:
parent
af2972f697
commit
196aa48727
|
@ -9,6 +9,7 @@
|
||||||
* Enforced the use of the "deluge.plugins" namespace to reduce package
|
* Enforced the use of the "deluge.plugins" namespace to reduce package
|
||||||
names clashing beetween regular packages and deluge plugins.
|
names clashing beetween regular packages and deluge plugins.
|
||||||
* Fix potential for host_id collision when creating hostlist entries.
|
* Fix potential for host_id collision when creating hostlist entries.
|
||||||
|
* Add Option To Specify Outgoing Connection Interface.
|
||||||
|
|
||||||
==== Core ====
|
==== Core ====
|
||||||
* Make the distinction between adding to the session new unmanaged torrents
|
* Make the distinction between adding to the session new unmanaged torrents
|
||||||
|
|
|
@ -101,7 +101,7 @@ DELUGE_VER = deluge.common.get_version()
|
||||||
|
|
||||||
|
|
||||||
class Core(component.Component):
|
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')
|
component.Component.__init__(self, 'Core')
|
||||||
|
|
||||||
# Start the libtorrent session.
|
# Start the libtorrent session.
|
||||||
|
@ -163,6 +163,13 @@ class Core(component.Component):
|
||||||
self.config['listen_interface'] = listen_interface
|
self.config['listen_interface'] = listen_interface
|
||||||
else:
|
else:
|
||||||
log.error('Invalid listen interface (must be IP Address): %s', listen_interface)
|
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
|
# New release check information
|
||||||
self.__new_release = None
|
self.__new_release = None
|
||||||
|
@ -197,6 +204,9 @@ class Core(component.Component):
|
||||||
if self.__old_interface:
|
if self.__old_interface:
|
||||||
self.config['listen_interface'] = 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
|
# Make sure the config file has been saved
|
||||||
self.config.save()
|
self.config.save()
|
||||||
|
|
||||||
|
|
|
@ -65,11 +65,12 @@ def is_daemon_running(pid_file):
|
||||||
class Daemon(object):
|
class Daemon(object):
|
||||||
"""The Deluge Daemon class"""
|
"""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):
|
read_only_config_keys=None):
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
listen_interface (str, optional): The IP address to listen to bittorrent connections on.
|
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.
|
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.
|
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
|
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
|
# Start the core as a thread and join it until it's done
|
||||||
self.core = Core(listen_interface=listen_interface,
|
self.core = Core(listen_interface=listen_interface,
|
||||||
|
outgoing_interface=outgoing_interface,
|
||||||
read_only_config_keys=read_only_config_keys)
|
read_only_config_keys=read_only_config_keys)
|
||||||
|
|
||||||
if port is None:
|
if port is None:
|
||||||
|
@ -115,7 +117,8 @@ class Daemon(object):
|
||||||
interface=interface
|
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):
|
def start(self):
|
||||||
# Register the daemon and the core RPCs
|
# Register the daemon and the core RPCs
|
||||||
|
|
|
@ -29,6 +29,8 @@ def add_daemon_options(parser):
|
||||||
help=_('Port to listen for UI connections on'))
|
help=_('Port to listen for UI connections on'))
|
||||||
group.add_argument('-i', '--interface', metavar='<ip-addr>', dest='listen_interface', action='store',
|
group.add_argument('-i', '--interface', metavar='<ip-addr>', dest='listen_interface', action='store',
|
||||||
help=_('IP address to listen for BitTorrent connections'))
|
help=_('IP address to listen for BitTorrent connections'))
|
||||||
|
group.add_argument('-o', '--outinterface', metavar='<ip-addr>', dest='outgoing_interface',
|
||||||
|
action='store', help=_('The IP address for outgoing BitTorrent connections.'))
|
||||||
group.add_argument('--read-only-config-keys', metavar='<comma-separated-keys>', action='store',
|
group.add_argument('--read-only-config-keys', metavar='<comma-separated-keys>', action='store',
|
||||||
help=_('Config keys to be unmodified by `set_config` RPC'), type=str, default='')
|
help=_('Config keys to be unmodified by `set_config` RPC'), type=str, default='')
|
||||||
parser.add_process_arg_group()
|
parser.add_process_arg_group()
|
||||||
|
@ -73,6 +75,7 @@ def start_daemon(skip_start=False):
|
||||||
try:
|
try:
|
||||||
from deluge.core.daemon import Daemon
|
from deluge.core.daemon import Daemon
|
||||||
daemon = Daemon(listen_interface=options.listen_interface,
|
daemon = Daemon(listen_interface=options.listen_interface,
|
||||||
|
outgoing_interface=options.outgoing_interface,
|
||||||
interface=options.ui_interface,
|
interface=options.ui_interface,
|
||||||
port=options.port,
|
port=options.port,
|
||||||
read_only_config_keys=options.read_only_config_keys.split(','))
|
read_only_config_keys=options.read_only_config_keys.split(','))
|
||||||
|
|
|
@ -47,6 +47,7 @@ DEFAULT_PREFS = {
|
||||||
'download_location': deluge.common.get_default_download_dir(),
|
'download_location': deluge.common.get_default_download_dir(),
|
||||||
'listen_ports': [6881, 6891],
|
'listen_ports': [6881, 6891],
|
||||||
'listen_interface': '',
|
'listen_interface': '',
|
||||||
|
'outgoing_interface': '',
|
||||||
'random_port': True,
|
'random_port': True,
|
||||||
'listen_random_port': None,
|
'listen_random_port': None,
|
||||||
'listen_use_sys_port': False,
|
'listen_use_sys_port': False,
|
||||||
|
@ -187,6 +188,9 @@ class PreferencesManager(component.Component):
|
||||||
def _on_set_listen_interface(self, key, value):
|
def _on_set_listen_interface(self, key, value):
|
||||||
self.__set_listen_on()
|
self.__set_listen_on()
|
||||||
|
|
||||||
|
def _on_set_outgoing_interface(self, key, value):
|
||||||
|
self.__set_outgoing_on()
|
||||||
|
|
||||||
def _on_set_random_port(self, key, value):
|
def _on_set_random_port(self, key, value):
|
||||||
self.__set_listen_on()
|
self.__set_listen_on()
|
||||||
|
|
||||||
|
@ -210,6 +214,13 @@ class PreferencesManager(component.Component):
|
||||||
{'listen_system_port_fallback': self.config['listen_use_sys_port'],
|
{'listen_system_port_fallback': self.config['listen_use_sys_port'],
|
||||||
'listen_interfaces': ''.join(interfaces)})
|
'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):
|
def _on_set_outgoing_ports(self, key, value):
|
||||||
self.__set_outgoing_ports()
|
self.__set_outgoing_ports()
|
||||||
|
|
||||||
|
|
|
@ -83,6 +83,10 @@ class BasePreferencePane(BaseInputPane, BaseWindow, PopupsHandler):
|
||||||
interface = ipt.get_value().strip()
|
interface = ipt.get_value().strip()
|
||||||
if is_ip(interface) or not interface:
|
if is_ip(interface) or not interface:
|
||||||
conf_dict['listen_interface'] = 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_'):
|
elif ipt.name.startswith('proxy_'):
|
||||||
if ipt.name == 'proxy_type':
|
if ipt.name == 'proxy_type':
|
||||||
conf_dict.setdefault('proxy', {})['type'] = ipt.get_value()
|
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)
|
value=out_ports[1], min_val=0, max_val=65535)
|
||||||
self.outto.set_depend(outrand, inverse=True)
|
self.outto.set_depend(outrand, inverse=True)
|
||||||
|
|
||||||
self.add_header(_('Interface'), space_above=True)
|
self.add_header(_('Incoming Interface'), space_above=True)
|
||||||
self.add_text_input('listen_interface', '%s:' % _('IP address of the interface to listen on '
|
self.add_text_input(
|
||||||
'(leave empty for default)'),
|
'listen_interface',
|
||||||
core_conf['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_header('TOS', space_above=True)
|
||||||
self.add_text_input('peer_tos', 'Peer TOS Byte:', core_conf['peer_tos'])
|
self.add_text_input('peer_tos', 'Peer TOS Byte:', core_conf['peer_tos'])
|
||||||
|
|
|
@ -2906,6 +2906,56 @@ used sparingly.</property>
|
||||||
<property name="position">1</property>
|
<property name="position">1</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkFrame" id="frame9">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label_xalign">0</property>
|
||||||
|
<property name="shadow_type">none</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkAlignment" id="alignment17">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="xscale">0</property>
|
||||||
|
<property name="top_padding">5</property>
|
||||||
|
<property name="left_padding">12</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="entry_outgoing_interface">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="tooltip_text" translatable="yes">IP address for outgoing BitTorrent connections. Leave this empty if you want to use the default.</property>
|
||||||
|
<property name="max_length">15</property>
|
||||||
|
<property name="invisible_char">●</property>
|
||||||
|
<property name="width_chars">15</property>
|
||||||
|
<property name="truncate_multiline">True</property>
|
||||||
|
<property name="invisible_char_set">True</property>
|
||||||
|
<property name="primary_icon_activatable">False</property>
|
||||||
|
<property name="secondary_icon_activatable">False</property>
|
||||||
|
<property name="primary_icon_sensitive">True</property>
|
||||||
|
<property name="secondary_icon_sensitive">True</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child type="label">
|
||||||
|
<object class="GtkLabel" id="label1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Outgoing Address</property>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="weight" value="bold"/>
|
||||||
|
</attributes>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="padding">5</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkFrame" id="frame26">
|
<object class="GtkFrame" id="frame26">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -3028,7 +3078,7 @@ used sparingly.</property>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
<property name="fill">False</property>
|
<property name="fill">False</property>
|
||||||
<property name="padding">5</property>
|
<property name="padding">5</property>
|
||||||
<property name="position">2</property>
|
<property name="position">3</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
@ -3190,7 +3240,7 @@ used sparingly.</property>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
<property name="fill">False</property>
|
<property name="fill">False</property>
|
||||||
<property name="padding">5</property>
|
<property name="padding">5</property>
|
||||||
<property name="position">3</property>
|
<property name="position">4</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
@ -3361,7 +3411,7 @@ used sparingly.</property>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
<property name="fill">True</property>
|
<property name="fill">True</property>
|
||||||
<property name="padding">5</property>
|
<property name="padding">5</property>
|
||||||
<property name="position">4</property>
|
<property name="position">5</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
|
|
@ -317,6 +317,7 @@ class Preferences(component.Component):
|
||||||
'spin_outgoing_port_max': ('value', lambda: self.core_config['outgoing_ports'][1]),
|
'spin_outgoing_port_max': ('value', lambda: self.core_config['outgoing_ports'][1]),
|
||||||
'chk_random_outgoing_ports': ('active', 'random_outgoing_ports'),
|
'chk_random_outgoing_ports': ('active', 'random_outgoing_ports'),
|
||||||
'entry_interface': ('text', 'listen_interface'),
|
'entry_interface': ('text', 'listen_interface'),
|
||||||
|
'entry_outgoing_interface': ('text', 'outgoing_interface'),
|
||||||
'entry_peer_tos': ('text', 'peer_tos'),
|
'entry_peer_tos': ('text', 'peer_tos'),
|
||||||
'chk_dht': ('active', 'dht'),
|
'chk_dht': ('active', 'dht'),
|
||||||
'chk_upnp': ('active', 'upnp'),
|
'chk_upnp': ('active', 'upnp'),
|
||||||
|
@ -519,8 +520,11 @@ class Preferences(component.Component):
|
||||||
new_core_config['random_outgoing_ports'] = self.builder.get_object(
|
new_core_config['random_outgoing_ports'] = self.builder.get_object(
|
||||||
'chk_random_outgoing_ports').get_active()
|
'chk_random_outgoing_ports').get_active()
|
||||||
incoming_address = self.builder.get_object('entry_interface').get_text().strip()
|
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:
|
if deluge.common.is_ip(incoming_address) or not incoming_address:
|
||||||
new_core_config['listen_interface'] = 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['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['dht'] = self.builder.get_object('chk_dht').get_active()
|
||||||
new_core_config['upnp'] = self.builder.get_object('chk_upnp').get_active()
|
new_core_config['upnp'] = self.builder.get_object('chk_upnp').get_active()
|
||||||
|
|
|
@ -90,6 +90,23 @@ Deluge.preferences.Network = Ext.extend(Ext.form.FormPanel, {
|
||||||
});
|
});
|
||||||
optMan.bind('listen_ports', this.listenPort);
|
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({
|
fieldset = this.add({
|
||||||
xtype: 'fieldset',
|
xtype: 'fieldset',
|
||||||
border: false,
|
border: false,
|
||||||
|
|
Loading…
Reference in New Issue