1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6
7 inherit (pkgs) ntp;
8
9 cfg = config.services.ntp;
10
11 stateDir = "/var/lib/ntp";
12
13 ntpUser = "ntp";
14
15 configFile = pkgs.writeText "ntp.conf" ''
16 driftfile ${stateDir}/ntp.drift
17
18 restrict default ${toString cfg.restrictDefault}
19 restrict -6 default ${toString cfg.restrictDefault}
20 restrict source ${toString cfg.restrictSource}
21
22 restrict 127.0.0.1
23 restrict -6 ::1
24
25 ${toString (map (server: "server " + server + " iburst\n") cfg.servers)}
26
27 ${cfg.extraConfig}
28 '';
29
30 ntpFlags = "-c ${configFile} -u ${ntpUser}:nogroup ${toString cfg.extraFlags}";
31
32in
33
34{
35
36 ###### interface
37
38 options = {
39
40 services.ntp = {
41
42 enable = mkOption {
43 type = types.bool;
44 default = false;
45 description = ''
46 Whether to synchronise your machine's time using ntpd, as a peer in
47 the NTP network.
48 </para>
49 <para>
50 Disables <literal>systemd.timesyncd</literal> if enabled.
51 '';
52 };
53
54 restrictDefault = mkOption {
55 type = types.listOf types.str;
56 description = ''
57 The restriction flags to be set by default.
58 </para>
59 <para>
60 The default flags prevent external hosts from using ntpd as a DDoS
61 reflector, setting system time, and querying OS/ntpd version. As
62 recommended in section 6.5.1.1.3, answer "No" of
63 http://support.ntp.org/bin/view/Support/AccessRestrictions
64 '';
65 default = [ "limited" "kod" "nomodify" "notrap" "noquery" "nopeer" ];
66 };
67
68 restrictSource = mkOption {
69 type = types.listOf types.str;
70 description = ''
71 The restriction flags to be set on source.
72 </para>
73 <para>
74 The default flags allow peers to be added by ntpd from configured
75 pool(s), but not by other means.
76 '';
77 default = [ "limited" "kod" "nomodify" "notrap" "noquery" ];
78 };
79
80 servers = mkOption {
81 default = config.networking.timeServers;
82 type = types.listOf types.str;
83 description = ''
84 The set of NTP servers from which to synchronise.
85 '';
86 };
87
88 extraConfig = mkOption {
89 type = types.lines;
90 default = "";
91 example = ''
92 fudge 127.127.1.0 stratum 10
93 '';
94 description = ''
95 Additional text appended to <filename>ntp.conf</filename>.
96 '';
97 };
98
99 extraFlags = mkOption {
100 type = types.listOf types.str;
101 description = "Extra flags passed to the ntpd command.";
102 example = literalExample ''[ "--interface=eth0" ]'';
103 default = [];
104 };
105
106 };
107
108 };
109
110
111 ###### implementation
112
113 config = mkIf config.services.ntp.enable {
114 meta.maintainers = with lib.maintainers; [ thoughtpolice ];
115
116 # Make tools such as ntpq available in the system path.
117 environment.systemPackages = [ pkgs.ntp ];
118 services.timesyncd.enable = mkForce false;
119
120 systemd.services.systemd-timedated.environment = { SYSTEMD_TIMEDATED_NTP_SERVICES = "ntpd.service"; };
121
122 users.users.${ntpUser} =
123 { uid = config.ids.uids.ntp;
124 description = "NTP daemon user";
125 home = stateDir;
126 };
127
128 systemd.services.ntpd =
129 { description = "NTP Daemon";
130
131 wantedBy = [ "multi-user.target" ];
132 wants = [ "time-sync.target" ];
133 before = [ "time-sync.target" ];
134
135 preStart =
136 ''
137 mkdir -m 0755 -p ${stateDir}
138 chown ${ntpUser} ${stateDir}
139 '';
140
141 serviceConfig = {
142 ExecStart = "@${ntp}/bin/ntpd ntpd -g ${ntpFlags}";
143 Type = "forking";
144 };
145 };
146
147 };
148
149}