mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-01-21 07:55:00 +00:00
networks: Support configuring IPv6 networks
- Very similar to configuration of IPv4 networks. - Supports 'auto', 'dhcp', 'manual' and 'ignored' modes as supported by network manager. 'shared' mode is not yet implemented by network manager.
This commit is contained in:
parent
c8cfcd03d9
commit
dce51fd6d7
@ -89,6 +89,46 @@ available over this interfaces. Select Internal only for trusted networks.'),
|
||||
'provided by a DHCP server will be ignored.'),
|
||||
validators=[validators.validate_ipv4_address],
|
||||
required=False)
|
||||
ipv6_method = forms.ChoiceField(
|
||||
label=_('IPv6 Addressing Method'),
|
||||
help_text=format_lazy(
|
||||
ugettext_lazy(
|
||||
'"Automatic" methods will make {box_name} acquire '
|
||||
'configuration from this network making it a client.'),
|
||||
box_name=ugettext_lazy(cfg.box_name)),
|
||||
choices=[('auto', _('Automatic')),
|
||||
('dhcp', _('Automatic, DHCP only')),
|
||||
('manual', _('Manual')),
|
||||
('ignore', _('Ignore'))])
|
||||
ipv6_address = forms.CharField(
|
||||
label=_('Address'),
|
||||
validators=[validators.validate_ipv6_address],
|
||||
required=False)
|
||||
ipv6_prefix = forms.IntegerField(
|
||||
label=_('Prefix'),
|
||||
help_text=_('Value between 1 and 128.'),
|
||||
min_value=1,
|
||||
max_value=128,
|
||||
required=False)
|
||||
ipv6_gateway = forms.CharField(
|
||||
label=_('Gateway'),
|
||||
help_text=_('Optional value.'),
|
||||
validators=[validators.validate_ipv6_address],
|
||||
required=False)
|
||||
ipv6_dns = forms.CharField(
|
||||
label=_('DNS Server'),
|
||||
help_text=_('Optional value. If this value is given and IPv6 '
|
||||
'addressing method is "Automatic", the DNS Servers '
|
||||
'provided by a DHCP server will be ignored.'),
|
||||
validators=[validators.validate_ipv6_address],
|
||||
required=False)
|
||||
ipv6_second_dns = forms.CharField(
|
||||
label=_('Second DNS Server'),
|
||||
help_text=_('Optional value. If this value is given and IPv6 '
|
||||
'Addressing Method is "Automatic", the DNS Servers '
|
||||
'provided by a DHCP server will be ignored.'),
|
||||
validators=[validators.validate_ipv6_address],
|
||||
required=False)
|
||||
|
||||
@staticmethod
|
||||
def _get_interface_choices(device_type):
|
||||
@ -111,6 +151,7 @@ available over this interfaces. Select Internal only for trusted networks.'),
|
||||
'zone': self.cleaned_data['zone'],
|
||||
}
|
||||
settings['ipv4'] = self.get_ipv4_settings()
|
||||
settings['ipv6'] = self.get_ipv6_settings()
|
||||
return settings
|
||||
|
||||
def get_ipv4_settings(self):
|
||||
@ -125,6 +166,18 @@ available over this interfaces. Select Internal only for trusted networks.'),
|
||||
}
|
||||
return ipv4
|
||||
|
||||
def get_ipv6_settings(self):
|
||||
"""Return IPv6 dict from cleaned data."""
|
||||
ipv6 = {
|
||||
'method': self.cleaned_data['ipv6_method'],
|
||||
'address': self.cleaned_data['ipv6_address'],
|
||||
'prefix': self.cleaned_data['ipv6_prefix'],
|
||||
'gateway': self.cleaned_data['ipv6_gateway'],
|
||||
'dns': self.cleaned_data['ipv6_dns'],
|
||||
'second_dns': self.cleaned_data['ipv6_second_dns'],
|
||||
}
|
||||
return ipv6
|
||||
|
||||
|
||||
class GenericForm(ConnectionForm):
|
||||
"""Form to create/edit a generic connection."""
|
||||
@ -164,6 +217,12 @@ class PPPoEForm(EthernetForm):
|
||||
ipv4_gateway = None
|
||||
ipv4_dns = None
|
||||
ipv4_second_dns = None
|
||||
ipv6_method = None
|
||||
ipv6_address = None
|
||||
ipv6_prefix = None
|
||||
ipv6_gateway = None
|
||||
ipv6_dns = None
|
||||
ipv6_second_dns = None
|
||||
|
||||
username = forms.CharField(label=_('Username'))
|
||||
password = forms.CharField(label=_('Password'),
|
||||
@ -185,13 +244,19 @@ class PPPoEForm(EthernetForm):
|
||||
"""Return IPv4 settings from cleaned data."""
|
||||
return None
|
||||
|
||||
def get_ipv6_settings(self):
|
||||
"""Return IPv6 settings from cleaned data."""
|
||||
return None
|
||||
|
||||
|
||||
class WifiForm(ConnectionForm):
|
||||
"""Form to create/edit a Wi-Fi connection."""
|
||||
field_order = ['name', 'interface', 'zone', 'ssid', 'mode', 'band',
|
||||
'channel', 'bssid', 'auth_mode', 'passphrase',
|
||||
'ipv4_method', 'ipv4_address', 'ipv4_netmask',
|
||||
'ipv4_gateway', 'ipv4_dns', 'ipv4_second_dns']
|
||||
'ipv4_gateway', 'ipv4_dns', 'ipv4_second_dns',
|
||||
'ipv6_method', 'ipv6_address', 'ipv6_prefix',
|
||||
'ipv6_gateway', 'ipv6_dns', 'ipv6_second_dns']
|
||||
|
||||
ssid = forms.CharField(
|
||||
label=_('SSID'),
|
||||
|
||||
@ -160,6 +160,24 @@ def edit(request, uuid):
|
||||
if number_of_dns > 1:
|
||||
form_data['ipv4_second_dns'] = settings_ipv4.get_dns(1)
|
||||
|
||||
settings_ipv6 = connection.get_setting_ip6_config()
|
||||
form_data['ipv6_method'] = settings_ipv6.get_method()
|
||||
if settings_ipv6.get_num_addresses():
|
||||
address = settings_ipv6.get_address(0)
|
||||
form_data['ipv6_address'] = address.get_address()
|
||||
form_data['ipv6_prefix'] = address.get_prefix()
|
||||
|
||||
gateway = settings_ipv6.get_gateway()
|
||||
if gateway:
|
||||
form_data['ipv6_gateway'] = gateway
|
||||
|
||||
number_of_dns = settings_ipv6.get_num_dns()
|
||||
if number_of_dns:
|
||||
form_data['ipv6_dns'] = settings_ipv6.get_dns(0)
|
||||
|
||||
if number_of_dns > 1:
|
||||
form_data['ipv6_second_dns'] = settings_ipv6.get_dns(1)
|
||||
|
||||
if settings_connection.get_connection_type() == 'generic':
|
||||
form = GenericForm(form_data)
|
||||
elif settings_connection.get_connection_type() == '802-11-wireless':
|
||||
|
||||
@ -39,43 +39,61 @@
|
||||
<script type="text/javascript">
|
||||
(function($) {
|
||||
|
||||
function ipv4_required(required, fields) {
|
||||
function ip_required(required, ip_version, fields) {
|
||||
var prefix = '#id_' + ip_version + '_';
|
||||
for (var i = 0; i < fields.length; i++) {
|
||||
$('#id_ipv4_' + fields[i]).prop("required", required);
|
||||
$(prefix + fields[i]).prop("required", required);
|
||||
}
|
||||
}
|
||||
|
||||
function ipv4_readonly(readonly, fields) {
|
||||
function ip_readonly(readonly, ip_version, fields) {
|
||||
var prefix = '#id_' + ip_version + '_';
|
||||
for (var i = 0; i < fields.length; i++) {
|
||||
$('#id_ipv4_' + fields[i]).prop("readOnly", readonly);
|
||||
$(prefix + fields[i]).prop("readOnly", readonly);
|
||||
if (readonly) {
|
||||
$('#id_ipv4_' + fields[i]).val("");
|
||||
$('#id_ipv4_' + fields[i]).prop("required", false);
|
||||
$(prefix + fields[i]).val("");
|
||||
$(prefix + fields[i]).prop("required", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function on_ipv4_method_change() {
|
||||
if ($("#id_ipv4_method").prop("value") == "manual") {
|
||||
ipv4_required(true, ['address']);
|
||||
ipv4_readonly(false, ['address', 'netmask', 'gateway', 'dns',
|
||||
'second_dns']);
|
||||
ip_required(true, 'ipv4', ['address']);
|
||||
ip_readonly(false, 'ipv4', ['address', 'netmask', 'gateway',
|
||||
'dns', 'second_dns']);
|
||||
} else if ($("#id_ipv4_method").prop("value") == "shared") {
|
||||
ipv4_required(false, ['address']);
|
||||
ipv4_readonly(false, ['address', 'netmask']);
|
||||
ipv4_readonly(true, ['gateway', 'dns', 'second_dns']);
|
||||
ip_required(false, 'ipv4', ['address']);
|
||||
ip_readonly(false, 'ipv4', ['address', 'netmask']);
|
||||
ip_readonly(true, 'ipv4', ['gateway', 'dns', 'second_dns']);
|
||||
} else if ($("#id_ipv4_method").prop("value") == "auto") {
|
||||
ipv4_readonly(true, ['address', 'netmask', 'gateway']);
|
||||
ipv4_readonly(false, ['dns', 'second_dns']);
|
||||
ip_readonly(true, 'ipv4', ['address', 'netmask', 'gateway']);
|
||||
ip_readonly(false, 'ipv4', ['dns', 'second_dns']);
|
||||
} else {
|
||||
ipv4_readonly(true, ['address', 'netmask', 'gateway', 'dns',
|
||||
'second_dns']);
|
||||
ip_readonly(true, 'ipv4', ['address', 'netmask', 'gateway',
|
||||
'dns', 'second_dns']);
|
||||
}
|
||||
}
|
||||
|
||||
function on_ipv6_method_change() {
|
||||
if ($("#id_ipv6_method").prop("value") == "manual") {
|
||||
ip_required(true, 'ipv6', ['address', 'prefix']);
|
||||
ip_readonly(false, 'ipv6', ['address', 'prefix', 'gateway',
|
||||
'dns', 'second_dns']);
|
||||
} else if ($("#id_ipv6_method").prop("value") == "auto" ||
|
||||
$("#id_ipv6_method").prop("value") == "dhcp") {
|
||||
ip_readonly(true, 'ipv6', ['address', 'prefix', 'gateway']);
|
||||
ip_readonly(false, 'ipv6', ['dns', 'second_dns']);
|
||||
} else {
|
||||
ip_readonly(true, 'ipv6', ['address', 'prefix', 'gateway',
|
||||
'dns', 'second_dns']);
|
||||
}
|
||||
}
|
||||
|
||||
$("#id_name").focus();
|
||||
|
||||
$("#id_ipv4_method").change(on_ipv4_method_change).change();
|
||||
$("#id_ipv6_method").change(on_ipv6_method_change).change();
|
||||
|
||||
$('#id_show_password').change(function() {
|
||||
// Changing type attribute from password to text is prevented by
|
||||
|
||||
@ -325,6 +325,34 @@ def _update_ipv4_settings(connection, ipv4):
|
||||
settings.add_dns(ipv4['second_dns'])
|
||||
|
||||
|
||||
def _update_ipv6_settings(connection, ipv6):
|
||||
"""Edit IPv6 settings for network manager connections."""
|
||||
settings = nm.SettingIP6Config.new()
|
||||
connection.add_setting(settings)
|
||||
|
||||
settings.set_property(nm.SETTING_IP_CONFIG_METHOD, ipv6['method'])
|
||||
if ipv6['method'] == nm.SETTING_IP6_CONFIG_METHOD_MANUAL and \
|
||||
ipv6['address'] and ipv6['prefix']:
|
||||
address = nm.IPAddress.new(socket.AF_INET6, ipv6['address'],
|
||||
int(ipv6['prefix']))
|
||||
settings.add_address(address)
|
||||
|
||||
if not ipv6['gateway']:
|
||||
settings.set_property(nm.SETTING_IP_CONFIG_GATEWAY, '::')
|
||||
else:
|
||||
settings.set_property(nm.SETTING_IP_CONFIG_GATEWAY,
|
||||
ipv6['gateway'])
|
||||
else:
|
||||
if ipv6['dns'] or ipv6['second_dns']:
|
||||
settings.set_property(nm.SETTING_IP_CONFIG_IGNORE_AUTO_DNS, True)
|
||||
|
||||
if ipv6['dns']:
|
||||
settings.add_dns(ipv6['dns'])
|
||||
|
||||
if ipv6['second_dns']:
|
||||
settings.add_dns(ipv6['second_dns'])
|
||||
|
||||
|
||||
def _update_pppoe_settings(connection, pppoe):
|
||||
"""Create/edit PPPoE settings for network manager connections."""
|
||||
# PPPoE
|
||||
@ -394,6 +422,9 @@ def _update_settings(connection, connection_uuid, settings):
|
||||
if 'ipv4' in settings and settings['ipv4']:
|
||||
_update_ipv4_settings(connection, settings['ipv4'])
|
||||
|
||||
if 'ipv6' in settings and settings['ipv6']:
|
||||
_update_ipv6_settings(connection, settings['ipv6'])
|
||||
|
||||
if 'pppoe' in settings and settings['pppoe']:
|
||||
_update_pppoe_settings(connection, settings['pppoe'])
|
||||
|
||||
|
||||
@ -40,6 +40,11 @@ ethernet_settings = {
|
||||
'dns': '',
|
||||
'second_dns': '',
|
||||
},
|
||||
'ipv6': {
|
||||
'method': 'auto',
|
||||
'dns': '',
|
||||
'second_dns': '',
|
||||
},
|
||||
}
|
||||
|
||||
wifi_settings = {
|
||||
@ -54,6 +59,11 @@ wifi_settings = {
|
||||
'dns': '',
|
||||
'second_dns': '',
|
||||
},
|
||||
'ipv6': {
|
||||
'method': 'auto',
|
||||
'dns': '',
|
||||
'second_dns': '',
|
||||
},
|
||||
'wireless': {
|
||||
'ssid': 'plinthtestwifi',
|
||||
'mode': 'adhoc',
|
||||
@ -104,7 +114,8 @@ class TestNetwork(unittest.TestCase):
|
||||
|
||||
self.assertTrue('plinth_test_eth' in [x['name'] for x in connections])
|
||||
self.assertTrue('plinth_test_wifi' in [x['name'] for x in connections])
|
||||
self.assertTrue('plinth_test_pppoe' in [x['name'] for x in connections])
|
||||
self.assertTrue('plinth_test_pppoe' in
|
||||
[x['name'] for x in connections])
|
||||
|
||||
@unittest.skipUnless(euid == 0, 'Needs to be root')
|
||||
def test_get_connection(self):
|
||||
@ -230,6 +241,31 @@ class TestNetwork(unittest.TestCase):
|
||||
self.assertEqual(settings_ipv4.get_dns(0), '1.2.3.4')
|
||||
self.assertEqual(settings_ipv4.get_dns(1), '1.2.3.5')
|
||||
|
||||
@unittest.skipUnless(euid == 0, 'Needs to be root')
|
||||
def test_ethernet_manual_ipv6_address(self):
|
||||
"""Check that we can manually set IPv6 address on ethernet."""
|
||||
connection = network.get_connection(self.ethernet_uuid)
|
||||
ethernet_settings2 = copy.deepcopy(ethernet_settings)
|
||||
ethernet_settings2['ipv6']['method'] = 'manual'
|
||||
ethernet_settings2['ipv6']['address'] = '::ffff:169.254.0.1'
|
||||
ethernet_settings2['ipv6']['prefix'] = '63'
|
||||
ethernet_settings2['ipv6']['gateway'] = '::ffff:169.254.0.254'
|
||||
ethernet_settings2['ipv6']['dns'] = '::ffff:1.2.3.4'
|
||||
ethernet_settings2['ipv6']['second_dns'] = '::ffff:1.2.3.5'
|
||||
network.edit_connection(connection, ethernet_settings2)
|
||||
|
||||
connection = network.get_connection(self.ethernet_uuid)
|
||||
settings_ipv6 = connection.get_setting_ip6_config()
|
||||
self.assertEqual(settings_ipv6.get_method(), 'manual')
|
||||
|
||||
address = settings_ipv6.get_address(0)
|
||||
self.assertEqual(address.get_address(), '::ffff:169.254.0.1')
|
||||
self.assertEqual(address.get_prefix(), 63)
|
||||
self.assertEqual(settings_ipv6.get_gateway(), '::ffff:169.254.0.254')
|
||||
self.assertEqual(settings_ipv6.get_num_dns(), 2)
|
||||
self.assertEqual(settings_ipv6.get_dns(0), '::ffff:1.2.3.4')
|
||||
self.assertEqual(settings_ipv6.get_dns(1), '::ffff:1.2.3.5')
|
||||
|
||||
@unittest.skipUnless(euid == 0, 'Needs to be root')
|
||||
def test_wifi_manual_ipv4_address(self):
|
||||
"""Check that we can manually set IPv4 address on wifi."""
|
||||
@ -257,3 +293,31 @@ class TestNetwork(unittest.TestCase):
|
||||
self.assertEqual(settings_ipv4.get_num_dns(), 2)
|
||||
self.assertEqual(settings_ipv4.get_dns(0), '1.2.3.4')
|
||||
self.assertEqual(settings_ipv4.get_dns(1), '1.2.3.5')
|
||||
|
||||
@unittest.skipUnless(euid == 0, 'Needs to be root')
|
||||
def test_wifi_manual_ipv6_address(self):
|
||||
"""Check that we can manually set IPv6 address on wifi."""
|
||||
connection = network.get_connection(self.wifi_uuid)
|
||||
wifi_settings2 = copy.deepcopy(wifi_settings)
|
||||
wifi_settings2['ipv6']['method'] = 'manual'
|
||||
wifi_settings2['ipv6']['address'] = '::ffff:169.254.0.2'
|
||||
wifi_settings2['ipv6']['prefix'] = 63
|
||||
wifi_settings2['ipv6']['gateway'] = '::ffff:169.254.0.254'
|
||||
wifi_settings2['ipv6']['dns'] = '::ffff:1.2.3.4'
|
||||
wifi_settings2['ipv6']['second_dns'] = '::ffff:1.2.3.5'
|
||||
wifi_settings2['wireless']['ssid'] = 'plinthtestwifi'
|
||||
wifi_settings2['wireless']['mode'] = 'adhoc'
|
||||
wifi_settings2['wireless']['auth_mode'] = 'open'
|
||||
network.edit_connection(connection, wifi_settings2)
|
||||
|
||||
connection = network.get_connection(self.wifi_uuid)
|
||||
settings_ipv6 = connection.get_setting_ip6_config()
|
||||
self.assertEqual(settings_ipv6.get_method(), 'manual')
|
||||
|
||||
address = settings_ipv6.get_address(0)
|
||||
self.assertEqual(address.get_address(), '::ffff:169.254.0.2')
|
||||
self.assertEqual(address.get_prefix(), 63)
|
||||
self.assertEqual(settings_ipv6.get_gateway(), '::ffff:169.254.0.254')
|
||||
self.assertEqual(settings_ipv6.get_num_dns(), 2)
|
||||
self.assertEqual(settings_ipv6.get_dns(0), '::ffff:1.2.3.4')
|
||||
self.assertEqual(settings_ipv6.get_dns(1), '::ffff:1.2.3.5')
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user