diff --git a/pyanaconda/ntp.py b/pyanaconda/ntp.py index eed4b34307c..cde27258aaa 100644 --- a/pyanaconda/ntp.py +++ b/pyanaconda/ntp.py @@ -40,7 +40,9 @@ #example line: #server 0.fedora.pool.ntp.org iburst -SRV_LINE_REGEXP = re.compile(r"^\s*(server|pool)\s*([-a-zA-Z.0-9]+)\s*[a-zA-Z]+\s*$") +SRV_LINE_REGEXP = re.compile(r"^\s*(server|pool)\s*([-a-zA-Z.0-9]+)\s?([a-zA-Z0-9\s]*)$") +SRV_NOARG_OPTIONS = ["burst", "iburst", "nts", "prefer", "require", "trust", "noselect", "xleave"] +SRV_ARG_OPTIONS = ["key", "minpoll", "maxpoll"] #treat pools as four servers with the same name SERVERS_PER_POOL = 4 @@ -95,18 +97,24 @@ def get_ntp_servers_summary(servers, states): return summary -def ntp_server_working(server_hostname): +def ntp_server_working(server_hostname, nts_enabled): """Tries to do an NTP request to the server (timeout may take some time). + If NTS is enabled, try making a TCP connection to the NTS-KE port instead. + :param server_hostname: a host name or an IP address of an NTP server :type server_hostname: string :return: True if the given server is reachable and working, False otherwise :rtype: bool """ - client = ntplib.NTPClient() - try: - client.request(server_hostname) + # ntplib doesn't support NTS + if nts_enabled: + s = socket.create_connection((server_hostname, 4460), 2) + s.close() + else: + client = ntplib.NTPClient() + client.request(server_hostname) except ntplib.NTPException: return False # address related error @@ -143,7 +151,23 @@ def get_servers_from_config(conf_file_path=NTP_CONFIG_FILE): server = TimeSourceData() server.type = match.group(1).upper() server.hostname = match.group(2) - server.options = ["iburst"] + server.options = [] + + words = match.group(3).lower().split() + skip_argument = False + + for i in range(len(words)): + if skip_argument: + skip_argument = False + continue + if words[i] in SRV_NOARG_OPTIONS: + server.options.append(words[i]) + elif words[i] in SRV_ARG_OPTIONS and i + 1 < len(words): + server.options.append(' '.join(words[i:i+2])) + skip_argument = True + else: + log.debug("Unknown NTP server option %s", words[i]) + servers.append(server) except IOError as ioerr: @@ -306,8 +330,9 @@ def check_status(self, server): :param TimeSourceData server: an NTP server """ - # Get a hostname. + # Get a hostname and NTS option. hostname = server.hostname + nts_enabled = "nts" in server.options # Reset the current status. self._set_status(hostname, NTP_SERVER_QUERY) @@ -316,7 +341,7 @@ def check_status(self, server): threadMgr.add(AnacondaThread( prefix=THREAD_NTP_SERVER_CHECK, target=self._check_status, - args=(hostname, )) + args=(hostname, nts_enabled)) ) def _set_status(self, hostname, status): @@ -327,13 +352,13 @@ def _set_status(self, hostname, status): """ self._cache[hostname] = status - def _check_status(self, hostname): + def _check_status(self, hostname, nts_enabled): """Check if an NTP server appears to be working. :param str hostname: a hostname of an NTP server """ log.debug("Checking NTP server %s", hostname) - result = ntp_server_working(hostname) + result = ntp_server_working(hostname, nts_enabled) if result: log.debug("NTP server %s appears to be working.", hostname) diff --git a/pyanaconda/ui/gui/spokes/datetime_spoke.glade b/pyanaconda/ui/gui/spokes/datetime_spoke.glade index 49e33776f51..3ebc12a4467 100644 --- a/pyanaconda/ui/gui/spokes/datetime_spoke.glade +++ b/pyanaconda/ui/gui/spokes/datetime_spoke.glade @@ -83,6 +83,8 @@ + + @@ -220,6 +222,21 @@ 3 + + + Server supports Network Time Security (NTS) authentication + True + True + False + 0 + True + + + False + True + 4 + + True @@ -266,6 +283,19 @@ + + + NTS + + + + + + 2 + + + + Working @@ -282,7 +312,7 @@ - 3 + 4 @@ -293,7 +323,7 @@ True True - 4 + 5 diff --git a/pyanaconda/ui/gui/spokes/datetime_spoke.py b/pyanaconda/ui/gui/spokes/datetime_spoke.py index ea121e7e4de..a8036cdb888 100644 --- a/pyanaconda/ui/gui/spokes/datetime_spoke.py +++ b/pyanaconda/ui/gui/spokes/datetime_spoke.py @@ -63,9 +63,10 @@ SERVER_HOSTNAME = 0 SERVER_POOL = 1 -SERVER_WORKING = 2 -SERVER_USE = 3 -SERVER_OBJECT = 4 +SERVER_NTS = 2 +SERVER_WORKING = 3 +SERVER_USE = 4 +SERVER_OBJECT = 5 DEFAULT_TZ = "America/New_York" @@ -184,6 +185,7 @@ def __init__(self, data, servers, states): self._serversStore = self.builder.get_object("serversStore") self._addButton = self.builder.get_object("addButton") self._poolCheckButton = self.builder.get_object("poolCheckButton") + self._ntsCheckButton = self.builder.get_object("ntsCheckButton") self._serverCheck = self.add_check(self._serverEntry, self._validate_server) self._serverCheck.update_check_status() @@ -256,6 +258,7 @@ def _add_row(self, server): itr = self._serversStore.append([ "", False, + False, constants.NTP_SERVER_QUERY, True, server @@ -268,6 +271,7 @@ def _refresh_row(self, itr): server = self._serversStore[itr][SERVER_OBJECT] self._serversStore.set_value(itr, SERVER_HOSTNAME, server.hostname) self._serversStore.set_value(itr, SERVER_POOL, server.type == TIME_SOURCE_POOL) + self._serversStore.set_value(itr, SERVER_NTS, "nts" in server.options) def _update_rows(self): """Periodically update the status of all rows. @@ -300,12 +304,16 @@ def on_entry_activated(self, entry, *args): server.hostname = entry.get_text() server.options = ["iburst"] + if self._ntsCheckButton.get_active(): + server.options.append("nts") + self._servers.append(server) self._states.check_status(server) self._add_row(server) entry.set_text("") self._poolCheckButton.set_active(False) + self._ntsCheckButton.set_active(False) def on_add_clicked(self, *args): self._serverEntry.emit("activate") @@ -326,6 +334,18 @@ def on_pool_toggled(self, renderer, path, *args): self._refresh_row(itr) + def on_nts_toggled(self, renderer, path, *args): + itr = self._serversStore.get_iter(path) + server = self._serversStore[itr][SERVER_OBJECT] + + if "nts" in server.options: + server.options.remove("nts") + else: + server.options.append("nts") + + self._states.check_status(server) + self._refresh_row(itr) + def on_server_editing_started(self, renderer, editable, path): itr = self._serversStore.get_iter(path) self._active_server = self._serversStore[itr][SERVER_OBJECT]