summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2016-11-21 18:24:51 +0100
committerGitHub <noreply@github.com>2016-11-21 18:24:51 +0100
commitc5066640a1a82bc74f538fe9d2ecc52ea81613b3 (patch)
treeb3e8d885fb1732adc318d17980ca856b06c28ea3
parent270f419316758162bfead87608cbaeeb4fd6987e (diff)
parent89748b0af1aeed4126a6faaf493f7be7230c804a (diff)
Merge pull request #4701 from martinpitt/networkd-polkit
hostnamed: allow networkd to set the transient hostname
-rw-r--r--Makefile.am16
-rw-r--r--src/hostname/systemd-networkd-hostname.pkla4
-rw-r--r--src/hostname/systemd-networkd-hostname.rules5
-rwxr-xr-xtest/networkd-test.py56
4 files changed, 76 insertions, 5 deletions
diff --git a/Makefile.am b/Makefile.am
index 47c2ec8a8d..10ce363347 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -55,6 +55,8 @@ pamconfdir=@pamconfdir@
pkgconfigdatadir=$(datadir)/pkgconfig
pkgconfiglibdir=$(libdir)/pkgconfig
polkitpolicydir=$(datadir)/polkit-1/actions
+polkitrulesdir=$(datadir)/polkit-1/rules.d
+polkitpkladir=$(localstatedir)/lib/polkit-1/localauthority/10-vendor.d
bashcompletiondir=@bashcompletiondir@
zshcompletiondir=@zshcompletiondir@
rpmmacrosdir=$(prefix)/lib/rpm/macros.d
@@ -116,6 +118,8 @@ pkgconfiglib_DATA =
polkitpolicy_in_in_files =
polkitpolicy_in_files =
polkitpolicy_files =
+polkitrules_files =
+polkitpkla_files =
dist_udevrules_DATA =
nodist_udevrules_DATA =
dist_pkgsysconf_DATA =
@@ -4836,8 +4840,16 @@ endif
polkitpolicy_in_files += \
src/hostname/org.freedesktop.hostname1.policy.in
+polkitrules_files += \
+ src/hostname/systemd-networkd-hostname.rules
+
+polkitpkla_files += \
+ src/hostname/systemd-networkd-hostname.pkla
+
EXTRA_DIST += \
- units/systemd-hostnamed.service.in
+ units/systemd-hostnamed.service.in \
+ src/hostname/systemd-networkd-hostname.rules \
+ src/hostname/systemd-networkd-hostname.pkla
# ------------------------------------------------------------------------------
dist_systemunit_DATA_busnames += \
@@ -6189,6 +6201,8 @@ if ENABLE_POLKIT
nodist_polkitpolicy_DATA = \
$(polkitpolicy_files) \
$(polkitpolicy_in_in_files:.policy.in.in=.policy)
+polkitrules_DATA = $(polkitrules_files)
+polkitpkla_DATA = $(polkitpkla_files)
endif
EXTRA_DIST += \
diff --git a/src/hostname/systemd-networkd-hostname.pkla b/src/hostname/systemd-networkd-hostname.pkla
new file mode 100644
index 0000000000..345ce617c6
--- /dev/null
+++ b/src/hostname/systemd-networkd-hostname.pkla
@@ -0,0 +1,4 @@
+[Allow systemd-networkd to set transient hostname]
+Identity=unix-user:systemd-network
+Action=org.freedesktop.hostname1.set-hostname
+ResultAny=yes
diff --git a/src/hostname/systemd-networkd-hostname.rules b/src/hostname/systemd-networkd-hostname.rules
new file mode 100644
index 0000000000..b7b780da9e
--- /dev/null
+++ b/src/hostname/systemd-networkd-hostname.rules
@@ -0,0 +1,5 @@
+polkit.addRule(function(action, subject) {
+ if (action.id == "org.freedesktop.hostname1.set-hostname" && subject.user == "systemd-network") {
+ return polkit.Result.YES;
+ }
+});
diff --git a/test/networkd-test.py b/test/networkd-test.py
index 3091722fc1..a00941095b 100755
--- a/test/networkd-test.py
+++ b/test/networkd-test.py
@@ -37,6 +37,7 @@ import unittest
import tempfile
import subprocess
import shutil
+import socket
networkd_active = subprocess.call(['systemctl', 'is-active', '--quiet',
'systemd-networkd']) == 0
@@ -77,6 +78,8 @@ class ClientTestBase:
def tearDown(self):
self.shutdown_iface()
subprocess.call(['systemctl', 'stop', 'systemd-networkd'])
+ subprocess.call(['ip', 'link', 'del', 'dummy0'],
+ stderr=subprocess.DEVNULL)
def writeConfig(self, fname, contents):
os.makedirs(os.path.dirname(fname), exist_ok=True)
@@ -121,10 +124,13 @@ DHCP=%s
# create interface first, then start networkd
self.create_iface(ipv6=ipv6)
subprocess.check_call(['systemctl', 'start', 'systemd-networkd'])
- else:
+ elif coldplug is not None:
# start networkd first, then create interface
subprocess.check_call(['systemctl', 'start', 'systemd-networkd'])
self.create_iface(ipv6=ipv6)
+ else:
+ # "None" means test sets up interface by itself
+ subprocess.check_call(['systemctl', 'start', 'systemd-networkd'])
try:
subprocess.check_call([self.networkd_wait_online, '--interface',
@@ -194,7 +200,7 @@ DHCP=%s
else:
self.fail('nameserver 192.168.5.1 not found in ' + RESOLV_CONF)
- if not coldplug:
+ if coldplug is False:
# check post-down.d hook
self.shutdown_iface()
@@ -291,13 +297,15 @@ class DnsmasqClientTest(ClientTestBase, unittest.TestCase):
def setUp(self):
super().setUp()
self.dnsmasq = None
+ self.iface_mac = 'de:ad:be:ef:47:11'
def create_iface(self, ipv6=False, dnsmasq_opts=None):
'''Create test interface with DHCP server behind it'''
# add veth pair
- subprocess.check_call(['ip', 'link', 'add', 'name', self.iface, 'type',
- 'veth', 'peer', 'name', self.if_router])
+ subprocess.check_call(['ip', 'link', 'add', 'name', self.iface,
+ 'address', self.iface_mac,
+ 'type', 'veth', 'peer', 'name', self.if_router])
# give our router an IP
subprocess.check_call(['ip', 'a', 'flush', 'dev', self.if_router])
@@ -413,6 +421,46 @@ Domains= ~company ~lab''')
self.assertRegex(general_log, 'query.*megasearch.net')
self.assertNotIn('megasearch.net', vpn_log)
+ def test_transient_hostname(self):
+ '''networkd sets transient hostname from DHCP'''
+
+ orig_hostname = socket.gethostname()
+ self.addCleanup(socket.sethostname, orig_hostname)
+ # temporarily move /etc/hostname away; restart hostnamed to pick it up
+ if os.path.exists('/etc/hostname'):
+ subprocess.check_call(['mount', '--bind', '/dev/null', '/etc/hostname'])
+ self.addCleanup(subprocess.call, ['umount', '/etc/hostname'])
+ subprocess.check_call(['systemctl', 'stop', 'systemd-hostnamed.service'])
+
+ self.create_iface(dnsmasq_opts=['--dhcp-host=%s,192.168.5.210,testgreen' % self.iface_mac])
+ self.do_test(coldplug=None, extra_opts='IPv6AcceptRA=False', dhcp_mode='ipv4')
+
+ # should have received the fixed IP above
+ out = subprocess.check_output(['ip', '-4', 'a', 'show', 'dev', self.iface])
+ self.assertRegex(out, b'inet 192.168.5.210/24 .* scope global dynamic')
+ # should have set transient hostname in hostnamed
+ self.assertIn(b'testgreen', subprocess.check_output(['hostnamectl']))
+ # and also applied to the system
+ self.assertEqual(socket.gethostname(), 'testgreen')
+
+ def test_transient_hostname_with_static(self):
+ '''transient hostname is not applied if static hostname exists'''
+
+ orig_hostname = socket.gethostname()
+ self.addCleanup(socket.sethostname, orig_hostname)
+ if not os.path.exists('/etc/hostname'):
+ self.writeConfig('/etc/hostname', orig_hostname)
+ subprocess.check_call(['systemctl', 'stop', 'systemd-hostnamed.service'])
+
+ self.create_iface(dnsmasq_opts=['--dhcp-host=%s,192.168.5.210,testgreen' % self.iface_mac])
+ self.do_test(coldplug=None, extra_opts='IPv6AcceptRA=False', dhcp_mode='ipv4')
+
+ # should have received the fixed IP above
+ out = subprocess.check_output(['ip', '-4', 'a', 'show', 'dev', self.iface])
+ self.assertRegex(out, b'inet 192.168.5.210/24 .* scope global dynamic')
+ # static hostname wins over transient one, thus *not* applied
+ self.assertEqual(socket.gethostname(), orig_hostname)
+
class NetworkdClientTest(ClientTestBase, unittest.TestCase):
'''Test networkd client against networkd server'''