Skip to content
This repository has been archived by the owner on Aug 3, 2022. It is now read-only.

Support reading DNS settings from NetworkManager on Linux #36

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions platformsettings.py
Original file line number Diff line number Diff line change
Expand Up @@ -477,9 +477,14 @@ class _LinuxPlatformSettings(_PosixPlatformSettings):
"""
RESOLV_CONF = '/etc/resolv.conf'
ROUTE_RE = re.compile('initcwnd (\d+)')
NM_DNS_RE = re.compile('IP4.DNS\[\d+\]:(\d+.\d+.\d+.\d+)')
TCP_BASE_MSS = 'net.ipv4.tcp_base_mss'
TCP_MTU_PROBING = 'net.ipv4.tcp_mtu_probing'

def __init__(self):
super(_LinuxPlatformSettings, self).__init__()
self._nmcli_executable = FindExecutable('nmcli')

def _get_default_route_line(self):
stdout = self._check_output('ip', 'route')
for line in stdout.split('\n'):
Expand Down Expand Up @@ -534,7 +539,22 @@ def _write_resolve_conf(self, dns):
raise DnsUpdateError('Could not find a suitable nameserver entry in %s' %
self.RESOLV_CONF)

def _use_network_manager(self):
if self._nmcli_executable != None:
stdout = self._nmcli('-t', '-f', 'state', 'nm')
if stdout.strip() == 'connected':
return True
return False

def _nmcli(self, *args):
return self._check_output(self._nmcli_executable, *args)

def _get_primary_nameserver(self):
if self._use_network_manager():
stdout = self._nmcli('-t', '-f', 'IP4', 'dev', 'list')
m = self.NM_DNS_RE.search(stdout)
if m:
return m.group(1)
try:
resolv_file = open(self.RESOLV_CONF)
except IOError:
Expand All @@ -546,6 +566,9 @@ def _get_primary_nameserver(self):

def _set_primary_nameserver(self, dns):
"""Replace the first nameserver entry with the one given."""
if self._use_network_manager():
raise DnsUpdateError('Connection is managed by NetworkManager. Only --no-dns_forwarding is supported.')

try:
self._write_resolve_conf(dns)
except OSError, e:
Expand Down
46 changes: 46 additions & 0 deletions platformsettings_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,11 @@
}
"""

LINUX_NM_DEV_LIST = """
IP4.ADDRESS[1]:ip = 111.222.123.234/22, gw = 111.222.123.1
IP4.DNS[1]:111.222.0.1
IP4.DNS[2]:111.222.0.2
"""

class SystemProxyTest(unittest.TestCase):

Expand Down Expand Up @@ -236,6 +241,47 @@ def test_get_primary_nameserver_unexpected_dns_state_raises(self):
self.assertRaises(platformsettings.DnsReadError,
self.settings._get_primary_nameserver)

class LinuxSettingsNM(platformsettings._LinuxPlatformSettings):
def __init__(self):
super(LinuxSettingsNM, self).__init__()
self.state = None # varies by test
self._nmcli_executable = "/usr/bin/nmcli" # make sure it is tested.

def _nmcli(self, *args):
if args[2] == 'state' and args[3] == 'nm':
return self.state + '\n'
if self.state == 'connected' and args[3] == 'dev' and args[4] == 'list':
return LINUX_NM_DEV_LIST
if self.state == 'disconnected' or self.state == 'asleep':
return ""

class LinuxPlatformSettingsNMTest(unittest.TestCase):
def setUp(self):
self.settings = LinuxSettingsNM()

def test_get_primary_nameserver_nm(self):
self.settings.state = 'connected'
self.assertEqual('111.222.0.1', self.settings._get_primary_nameserver())
try:
self.settings.state = 'disconnected'
self.assertNotEqual('111.222.0.1', self.settings._get_primary_nameserver())
except platformsettings.DnsReadError, e:
pass
try:
self.settings.state = 'asleep'
self.assertNotEqual('111.222.0.1', self.settings._get_primary_nameserver())
except platformsettings.DnsReadError, e:
pass

def test_set_primary_nameserver_nm(self):
self.settings.state = 'connected'
with self.assertRaises(platformsettings.DnsUpdateError) as e1:
self.settings._set_primary_nameserver('127.0.0.1')
self.assertTrue('--no-dns_forwarding' in e1.exception.message)
self.settings.state = 'disconnected'
with self.assertRaises(platformsettings.DnsUpdateError) as e2:
self.settings._set_primary_nameserver('127.0.0.1')
self.assertTrue('sudo' in e2.exception.message)

if __name__ == '__main__':
unittest.main()