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:
Sunil Mohan Adapa 2016-09-18 23:19:15 +05:30 committed by James Valleroy
parent c8cfcd03d9
commit dce51fd6d7
No known key found for this signature in database
GPG Key ID: 77C0C75E7B650808
5 changed files with 214 additions and 18 deletions

View File

@ -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'),

View File

@ -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':

View File

@ -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

View File

@ -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'])

View File

@ -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')