mirror of
https://gitlab.com/chrony/chrony.git
synced 2025-12-03 16:55:07 -05:00
Compare commits
2153 Commits
2.0-pre2
...
6fe4a60a1d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6fe4a60a1d | ||
|
|
2da8fbc4c3 | ||
|
|
c252e52ee2 | ||
|
|
c8a9ca4cf0 | ||
|
|
4659b574bf | ||
|
|
5436618c05 | ||
|
|
a0f460569e | ||
|
|
3c39afa13c | ||
|
|
03875f1ea5 | ||
|
|
2e29935c54 | ||
|
|
8084961011 | ||
|
|
120bf44989 | ||
|
|
9e8541e3c4 | ||
|
|
e95d5a161d | ||
|
|
2c63dfee34 | ||
|
|
42e6b5577a | ||
|
|
830c8bb18a | ||
|
|
0289442998 | ||
|
|
e9848c0176 | ||
|
|
2cfe969940 | ||
|
|
487cf3840f | ||
|
|
4886c776d5 | ||
|
|
d3f3638b3d | ||
|
|
6c5973741b | ||
|
|
51d161a028 | ||
|
|
5535384878 | ||
|
|
f78e4681ef | ||
|
|
b365edb48e | ||
|
|
93a78c73ad | ||
|
|
abc267a556 | ||
|
|
9b183fe98f | ||
|
|
be7f5e8916 | ||
|
|
5e2cd47ad1 | ||
|
|
9eaf8bc521 | ||
|
|
54010586aa | ||
|
|
90d808ed28 | ||
|
|
1d9e080749 | ||
|
|
d30913e78c | ||
|
|
c5d3be8cc4 | ||
|
|
3e32e7e694 | ||
|
|
52cce3dea8 | ||
|
|
1bcbea9bd2 | ||
|
|
2ac581e04a | ||
|
|
4a8da7e02d | ||
|
|
e463fcab49 | ||
|
|
df98fb4fc7 | ||
|
|
551bc266e4 | ||
|
|
c4234dd1f7 | ||
|
|
fd50f3c80c | ||
|
|
9b9823b377 | ||
|
|
c900dff314 | ||
|
|
2c6cbde058 | ||
|
|
cacd64bf4a | ||
|
|
6c2ee89970 | ||
|
|
68b2ffa97c | ||
|
|
f591133f4c | ||
|
|
48cc072c06 | ||
|
|
8211978570 | ||
|
|
4b2b6bbf97 | ||
|
|
551ad40a04 | ||
|
|
09cd057c23 | ||
|
|
363aa86861 | ||
|
|
bda2ff77e8 | ||
|
|
545bd59563 | ||
|
|
082af24114 | ||
|
|
577221295f | ||
|
|
eb08c3b013 | ||
|
|
391882dc41 | ||
|
|
b32d85bc54 | ||
|
|
0bf7e49148 | ||
|
|
f5fdfee150 | ||
|
|
c17f481a20 | ||
|
|
8140feb4fd | ||
|
|
6e541afbe9 | ||
|
|
81362fa201 | ||
|
|
ec57de02c7 | ||
|
|
f7da309b83 | ||
|
|
9b28b2f493 | ||
|
|
ebf19ca760 | ||
|
|
2d96077b9f | ||
|
|
2c2dd2d126 | ||
|
|
f7daec0693 | ||
|
|
d115449e85 | ||
|
|
dab98fa8da | ||
|
|
dd8738119b | ||
|
|
75bbccf518 | ||
|
|
1b24a66b3c | ||
|
|
8fd386f287 | ||
|
|
e694ae769a | ||
|
|
2b127b2e93 | ||
|
|
2d3c89e1a3 | ||
|
|
b5d1ae147d | ||
|
|
bf964673cb | ||
|
|
c66c774e26 | ||
|
|
274c1767f2 | ||
|
|
c27a298d9c | ||
|
|
072ec20e2c | ||
|
|
711c7c0c8a | ||
|
|
454ce62672 | ||
|
|
ab850d41f4 | ||
|
|
744768306b | ||
|
|
26d4f0c401 | ||
|
|
717db2cfdd | ||
|
|
55898e9b07 | ||
|
|
f7bb283536 | ||
|
|
1967fbf1f2 | ||
|
|
51da7a0694 | ||
|
|
9ba6e7655c | ||
|
|
3dea7dd723 | ||
|
|
cb1118456b | ||
|
|
8ee725ff18 | ||
|
|
a90a7cf51c | ||
|
|
4f22883f4e | ||
|
|
65be9d9a02 | ||
|
|
a1191f8392 | ||
|
|
924199ef69 | ||
|
|
8028984f34 | ||
|
|
68301238a0 | ||
|
|
13db3d6902 | ||
|
|
8c24086c6d | ||
|
|
e30d5a6e6f | ||
|
|
a0d34eb372 | ||
|
|
7196943f11 | ||
|
|
26fef1751a | ||
|
|
d71e22594e | ||
|
|
d7a578fed2 | ||
|
|
014a67b29e | ||
|
|
d22c8fbcb2 | ||
|
|
2da4e3ce53 | ||
|
|
c92358e041 | ||
|
|
77962bb527 | ||
|
|
65b5f111d2 | ||
|
|
9856bf2d5f | ||
|
|
2205eae2a1 | ||
|
|
6f381fa78b | ||
|
|
bb8050d884 | ||
|
|
c85ec4ff0f | ||
|
|
d9d97f76d7 | ||
|
|
837323d687 | ||
|
|
12237bf283 | ||
|
|
b9b338a8df | ||
|
|
a5d73f692f | ||
|
|
b0ac5992fb | ||
|
|
cd65e32cf0 | ||
|
|
b9f5278846 | ||
|
|
b8b166044f | ||
|
|
42fbf41686 | ||
|
|
79a790e6b5 | ||
|
|
f5cd79d2df | ||
|
|
689605b6a2 | ||
|
|
0707865413 | ||
|
|
2adda9c12c | ||
|
|
113d1134d1 | ||
|
|
b363af754d | ||
|
|
0f5cf57bc2 | ||
|
|
5a43f0c39b | ||
|
|
5a6fbe7a4b | ||
|
|
bb34e92f96 | ||
|
|
78b9c13a11 | ||
|
|
1ab5b88939 | ||
|
|
e30f937f6a | ||
|
|
08b67dba98 | ||
|
|
61f15fedcd | ||
|
|
6d59234995 | ||
|
|
d4a4f89329 | ||
|
|
916ed70c4a | ||
|
|
8ba2da52df | ||
|
|
fd9e956d27 | ||
|
|
43189651b0 | ||
|
|
f518b8d00f | ||
|
|
42b3c40c32 | ||
|
|
66512ebcb3 | ||
|
|
3940d2aae3 | ||
|
|
34be117c9c | ||
|
|
7915f52495 | ||
|
|
05bd4898a9 | ||
|
|
4da088ec2f | ||
|
|
c46e0549ab | ||
|
|
8f5b308414 | ||
|
|
084fe6b0cc | ||
|
|
ebfc676d74 | ||
|
|
adaca0ff19 | ||
|
|
84d6c7a527 | ||
|
|
c43efccf02 | ||
|
|
1affd03cca | ||
|
|
276591172e | ||
|
|
989ef702aa | ||
|
|
1920b1efde | ||
|
|
bb5db828c6 | ||
|
|
dcc94a4c10 | ||
|
|
2ed72c49c9 | ||
|
|
342b588e3b | ||
|
|
a914140bd4 | ||
|
|
28e4eec1c4 | ||
|
|
5235c51801 | ||
|
|
26ea4e35e7 | ||
|
|
9397ae2b0a | ||
|
|
b8ead3485b | ||
|
|
24d28cd679 | ||
|
|
aac898343e | ||
|
|
c8c7f518b1 | ||
|
|
ce956c99a8 | ||
|
|
863866354d | ||
|
|
6e5513c80b | ||
|
|
6d0143e963 | ||
|
|
f49be7f063 | ||
|
|
7fe98a83b8 | ||
|
|
ad37c409c9 | ||
|
|
719c6f6a8a | ||
|
|
b0750136b5 | ||
|
|
ad79aec946 | ||
|
|
008dc16727 | ||
|
|
6cf9fe2f16 | ||
|
|
637b77d1bd | ||
|
|
53823b9f1c | ||
|
|
83f90279b0 | ||
|
|
02ae9a8607 | ||
|
|
017d6f8f56 | ||
|
|
eb26d13140 | ||
|
|
8d19f49341 | ||
|
|
637fa29e1e | ||
|
|
2d349595ee | ||
|
|
5cb584d6c1 | ||
|
|
d7c2b1d2f3 | ||
|
|
e11b518a1f | ||
|
|
120dfb8b36 | ||
|
|
598b893e1d | ||
|
|
89aa8fa342 | ||
|
|
42fdad5dcc | ||
|
|
3ee7b3e786 | ||
|
|
426fe2ee58 | ||
|
|
3f66202d79 | ||
|
|
ed6b0b55c7 | ||
|
|
5e5adbea0c | ||
|
|
82959431df | ||
|
|
b92b2da24a | ||
|
|
68a3d52086 | ||
|
|
1a15be1e9e | ||
|
|
5dd288dc0c | ||
|
|
cbee464c75 | ||
|
|
4e36295889 | ||
|
|
2d2642bb82 | ||
|
|
9c6eaccc32 | ||
|
|
0aa4d5ac14 | ||
|
|
ee9d721b7b | ||
|
|
b6eec0068a | ||
|
|
e6a0476eb7 | ||
|
|
c063b9e78a | ||
|
|
f6f1863fe2 | ||
|
|
51a621bc2b | ||
|
|
1488b31a38 | ||
|
|
70cdd8b1ef | ||
|
|
8eef631009 | ||
|
|
d9ae724c60 | ||
|
|
6372a9f93f | ||
|
|
b0267475e3 | ||
|
|
07134f2625 | ||
|
|
85db8e3a9c | ||
|
|
05f4f79cbf | ||
|
|
bf616eafa1 | ||
|
|
e08a0ee668 | ||
|
|
f2d7baa94f | ||
|
|
558931524d | ||
|
|
a74b63277a | ||
|
|
aa8196328c | ||
|
|
37deee7140 | ||
|
|
7ff74d9efe | ||
|
|
43320a1d6b | ||
|
|
8caaa0b056 | ||
|
|
e48a34392c | ||
|
|
8bc8bf9cc4 | ||
|
|
3dc9f1ff92 | ||
|
|
7bc7d00297 | ||
|
|
b5cf861cd7 | ||
|
|
25cc84d5e2 | ||
|
|
f74e4cf1fe | ||
|
|
5f66722b66 | ||
|
|
b31461af7a | ||
|
|
ae177f2742 | ||
|
|
1a736078df | ||
|
|
9b46ea7255 | ||
|
|
ff4e932f17 | ||
|
|
68c35a0072 | ||
|
|
b6c634298d | ||
|
|
010df12459 | ||
|
|
22ef2fbb0e | ||
|
|
7a03206222 | ||
|
|
b86c50bb9f | ||
|
|
36f9b24dfe | ||
|
|
e0b75b87bf | ||
|
|
6661a61486 | ||
|
|
bc76291750 | ||
|
|
2aefadd129 | ||
|
|
123cb497b9 | ||
|
|
0c38e4a6ca | ||
|
|
0db30fd0b1 | ||
|
|
b90d2c084f | ||
|
|
ab8da7ecb9 | ||
|
|
05809e937c | ||
|
|
8265fe2e30 | ||
|
|
c11a052955 | ||
|
|
109970f687 | ||
|
|
ca10b9e072 | ||
|
|
19da1d95a8 | ||
|
|
61da7d0913 | ||
|
|
105f1f90c1 | ||
|
|
c9d791e02d | ||
|
|
de678ff780 | ||
|
|
e16bcca617 | ||
|
|
b57d7040b3 | ||
|
|
c80858f738 | ||
|
|
81bf7cdcdc | ||
|
|
b8b3830dc4 | ||
|
|
d4738e1259 | ||
|
|
5ba42cee45 | ||
|
|
b2dac47c82 | ||
|
|
6a6161dc0f | ||
|
|
a4eb5be8ea | ||
|
|
3050e29b1d | ||
|
|
fb1af6e55b | ||
|
|
47a13ae88c | ||
|
|
a8496658a0 | ||
|
|
6ea1082a72 | ||
|
|
4f674539fd | ||
|
|
68d3fb4af8 | ||
|
|
3c24f2c2ed | ||
|
|
0189dac7d8 | ||
|
|
4a11399c2e | ||
|
|
cf98551ea1 | ||
|
|
5508b01bd8 | ||
|
|
907accec87 | ||
|
|
a511029cc2 | ||
|
|
0845df7684 | ||
|
|
2f961ab36a | ||
|
|
a0cf7f7f12 | ||
|
|
a5f1a113f0 | ||
|
|
5160f14fdc | ||
|
|
b0a2ad2535 | ||
|
|
ecdde75f8f | ||
|
|
2d80be9541 | ||
|
|
ab776ed9d8 | ||
|
|
ccebec3eb6 | ||
|
|
3ea3e0efd7 | ||
|
|
c3e4e3e47a | ||
|
|
e949e1d991 | ||
|
|
c8649ccb7e | ||
|
|
39ff7ceeca | ||
|
|
06945d927b | ||
|
|
caf82b1a45 | ||
|
|
f99b2f633b | ||
|
|
6270a3eb7c | ||
|
|
1daa40a2f7 | ||
|
|
a1406eded3 | ||
|
|
1eb8994c00 | ||
|
|
221e5fb501 | ||
|
|
ecfbde9872 | ||
|
|
dec07aa844 | ||
|
|
5b3d4dfe76 | ||
|
|
dc0f0cd134 | ||
|
|
bd37efa52e | ||
|
|
c71185a0e5 | ||
|
|
f149b7b758 | ||
|
|
883b0dde94 | ||
|
|
9cba9c8585 | ||
|
|
88e711ad9a | ||
|
|
badaa83c31 | ||
|
|
bbeec7361c | ||
|
|
6fba5a4a7f | ||
|
|
26889a8cb7 | ||
|
|
cd278d1826 | ||
|
|
3877734814 | ||
|
|
19f2ab9e09 | ||
|
|
3260dc82fe | ||
|
|
1a98c5ffa9 | ||
|
|
8247b8525f | ||
|
|
8901293be8 | ||
|
|
e789b0817f | ||
|
|
d0fd04c0a2 | ||
|
|
7122321249 | ||
|
|
b328c8c348 | ||
|
|
7b97668319 | ||
|
|
6f5df7e4a4 | ||
|
|
5a39074e01 | ||
|
|
c8e57f4350 | ||
|
|
b1230efac3 | ||
|
|
4e1ce88981 | ||
|
|
790a336eb2 | ||
|
|
cc706b50b9 | ||
|
|
73042494bd | ||
|
|
ec89739d50 | ||
|
|
4baf999cc3 | ||
|
|
9afd19c29b | ||
|
|
5dd173c050 | ||
|
|
5caf0ad187 | ||
|
|
17d2291a84 | ||
|
|
a6179261a7 | ||
|
|
098e0c43fc | ||
|
|
7b197953e8 | ||
|
|
9dcace0fc4 | ||
|
|
a07ac38331 | ||
|
|
166e43b13e | ||
|
|
b84d6759f9 | ||
|
|
f323c814af | ||
|
|
19b47dcbc9 | ||
|
|
5edeadcbd9 | ||
|
|
d91ae2094f | ||
|
|
30a5845098 | ||
|
|
0f367efac5 | ||
|
|
24c011d4a6 | ||
|
|
0c2cdd2fb1 | ||
|
|
cd1a666e1b | ||
|
|
070b4f69d0 | ||
|
|
851c823b42 | ||
|
|
df80274644 | ||
|
|
bb2d68ddf9 | ||
|
|
685d8f725b | ||
|
|
4234732b08 | ||
|
|
a16094adfb | ||
|
|
a4349b13df | ||
|
|
3556dadea1 | ||
|
|
220e6d1907 | ||
|
|
a738037705 | ||
|
|
7daf34675a | ||
|
|
de598c2310 | ||
|
|
91cc4dbb12 | ||
|
|
0ae6f2485b | ||
|
|
52ec694d2b | ||
|
|
e2e07af8a4 | ||
|
|
2ed88c31c7 | ||
|
|
af8e4a5115 | ||
|
|
f503a9a490 | ||
|
|
9c64fbb9c4 | ||
|
|
b428f901c7 | ||
|
|
09b7f77f9a | ||
|
|
c23c0b8484 | ||
|
|
d530055917 | ||
|
|
f41d09e19f | ||
|
|
46030d9d3e | ||
|
|
02ccd3a3c7 | ||
|
|
9cc609c4b0 | ||
|
|
a0a496dcb4 | ||
|
|
8d08486edf | ||
|
|
a3b376cf0a | ||
|
|
e66f1df89d | ||
|
|
35220aac9d | ||
|
|
5b04f3ca90 | ||
|
|
beb1c36136 | ||
|
|
da3495c472 | ||
|
|
356771c0c3 | ||
|
|
fca8966ada | ||
|
|
25f80a1a9d | ||
|
|
1219f99935 | ||
|
|
33a1fe7a9c | ||
|
|
eed0a0de56 | ||
|
|
07600cbd71 | ||
|
|
f2e341b5ed | ||
|
|
55717c1ccd | ||
|
|
d5e645eb38 | ||
|
|
3196630fb9 | ||
|
|
663dde1ad7 | ||
|
|
62757cda49 | ||
|
|
af6ae9186b | ||
|
|
4c29f8888c | ||
|
|
d06ae4a60e | ||
|
|
f9af2f9733 | ||
|
|
43ae0131cd | ||
|
|
8bb8f15a7d | ||
|
|
e55f174bd3 | ||
|
|
5bd13c8d59 | ||
|
|
759580aa6f | ||
|
|
b61cbed689 | ||
|
|
2ac2247756 | ||
|
|
55f48b14b7 | ||
|
|
3dfac33858 | ||
|
|
d5f2401421 | ||
|
|
fb0570cc73 | ||
|
|
43936ba0d1 | ||
|
|
f2ba20f293 | ||
|
|
fcd384523b | ||
|
|
48bce351bf | ||
|
|
25f93875d9 | ||
|
|
ebc610fcb3 | ||
|
|
264957a443 | ||
|
|
af611b5842 | ||
|
|
1c1ca1d12f | ||
|
|
c506b9aac8 | ||
|
|
2eefa61f10 | ||
|
|
89a5e21e4d | ||
|
|
6a79771898 | ||
|
|
53353529cf | ||
|
|
22bfdf204f | ||
|
|
fc28e9ae56 | ||
|
|
17e6258694 | ||
|
|
d7a444593f | ||
|
|
701b9415a5 | ||
|
|
d5894c0738 | ||
|
|
a0a9560258 | ||
|
|
09067e06d3 | ||
|
|
dbbdd5af06 | ||
|
|
7f984cf7fa | ||
|
|
8df49b799f | ||
|
|
e7c2f71cea | ||
|
|
219085b8f6 | ||
|
|
2319f72b29 | ||
|
|
72f7d09f58 | ||
|
|
0bf39c0ab9 | ||
|
|
2e126ed2b5 | ||
|
|
a652ce7d0e | ||
|
|
a97ca73704 | ||
|
|
125d7a5c32 | ||
|
|
36356ef033 | ||
|
|
a2d1569455 | ||
|
|
952c3b2528 | ||
|
|
d92d24ad7f | ||
|
|
bc33e1cda1 | ||
|
|
189bf9c536 | ||
|
|
c5dde9b66a | ||
|
|
1fb60f8db8 | ||
|
|
2f05287e15 | ||
|
|
61226cda8c | ||
|
|
26b51d841e | ||
|
|
5f4cbaab7e | ||
|
|
7a80647fb4 | ||
|
|
14b8df3702 | ||
|
|
5cb469b204 | ||
|
|
29d7d3176d | ||
|
|
76a905d652 | ||
|
|
83f96efdfd | ||
|
|
127826a399 | ||
|
|
7ee5f4888e | ||
|
|
9ed1d1afc2 | ||
|
|
d0d9a3fa43 | ||
|
|
9600993c28 | ||
|
|
5e6f8458ff | ||
|
|
f5fe5452f6 | ||
|
|
3ac6a0c26c | ||
|
|
c2872d1e12 | ||
|
|
e47e7e3661 | ||
|
|
d8f14ec59b | ||
|
|
274a51bc38 | ||
|
|
92700e194c | ||
|
|
87df268723 | ||
|
|
17a9caf5c8 | ||
|
|
36441fabde | ||
|
|
f363998517 | ||
|
|
6fc30baba8 | ||
|
|
70a0f18d52 | ||
|
|
0ad5f5ea89 | ||
|
|
d676f39b84 | ||
|
|
31690261f5 | ||
|
|
93326488a3 | ||
|
|
d5ca98eaaa | ||
|
|
be3158c4e5 | ||
|
|
2f1d5d9255 | ||
|
|
b2c2132e4b | ||
|
|
aab6d1b153 | ||
|
|
bbbd80bf03 | ||
|
|
f27d719a4e | ||
|
|
789817cd91 | ||
|
|
885e7774fd | ||
|
|
883b7eed8a | ||
|
|
4049ed8766 | ||
|
|
f9f6803b8a | ||
|
|
385f7ebfd9 | ||
|
|
f9cbc4803d | ||
|
|
97973b1833 | ||
|
|
9cdfc15e31 | ||
|
|
fc99317291 | ||
|
|
bb9ba3e4bd | ||
|
|
649f54a1e6 | ||
|
|
4070d7ffa6 | ||
|
|
0493abb68a | ||
|
|
8c1e16711d | ||
|
|
1d03908646 | ||
|
|
49d718c025 | ||
|
|
c536b2561b | ||
|
|
b9f5ce83b0 | ||
|
|
8baab00ae0 | ||
|
|
d01cb5af46 | ||
|
|
7925ed39b8 | ||
|
|
9d869d8709 | ||
|
|
4f94e22b4b | ||
|
|
d9b720471d | ||
|
|
039b388c82 | ||
|
|
3f6528da77 | ||
|
|
4f43c060a3 | ||
|
|
3e55fe6919 | ||
|
|
754097944b | ||
|
|
dd6a25edf2 | ||
|
|
e697833976 | ||
|
|
40d80624f6 | ||
|
|
9a716cc284 | ||
|
|
13a78ecd2f | ||
|
|
a9f0c681cb | ||
|
|
862aa285a2 | ||
|
|
84d2811800 | ||
|
|
635a9d3f5a | ||
|
|
81f7f6ddf0 | ||
|
|
aa22c515ce | ||
|
|
2ca2c85365 | ||
|
|
966e6fd939 | ||
|
|
4f0dd72cf0 | ||
|
|
69aa2eff99 | ||
|
|
3e1ec36ca5 | ||
|
|
224ab8ddb1 | ||
|
|
307c2ec70f | ||
|
|
5381fb4ee9 | ||
|
|
3812ec2aa2 | ||
|
|
4e7690ebec | ||
|
|
cf3d976a68 | ||
|
|
26fc28c056 | ||
|
|
d2117ab697 | ||
|
|
52b29f673f | ||
|
|
e86b60a9d7 | ||
|
|
53501b743f | ||
|
|
c61ddb70da | ||
|
|
9339766bfe | ||
|
|
f60410016a | ||
|
|
7a02371698 | ||
|
|
579d8c9907 | ||
|
|
10c760a80c | ||
|
|
2d39a12f51 | ||
|
|
517b1ae29a | ||
|
|
b7347d931b | ||
|
|
4f878ba144 | ||
|
|
8acdb5d1e2 | ||
|
|
62f2d5736d | ||
|
|
dc22df93f5 | ||
|
|
d898bd246b | ||
|
|
ebf0ff2c0d | ||
|
|
cc77b0e9fd | ||
|
|
a8bc25e543 | ||
|
|
6615bb1b78 | ||
|
|
f650b8c515 | ||
|
|
ae2e0318d1 | ||
|
|
26ce610155 | ||
|
|
316d47e3b4 | ||
|
|
90557cf1ba | ||
|
|
80e627c86b | ||
|
|
0e4995e10b | ||
|
|
a598983f9b | ||
|
|
27641876c5 | ||
|
|
4d139eeca6 | ||
|
|
3f2806c19c | ||
|
|
e297df78e4 | ||
|
|
c1d56ede3f | ||
|
|
2e52aca3bf | ||
|
|
b0fc5832f4 | ||
|
|
cf6af112e1 | ||
|
|
fa3052e776 | ||
|
|
f8610d69f0 | ||
|
|
1a8dcce84f | ||
|
|
f74eb67567 | ||
|
|
144fcdde34 | ||
|
|
3cef7f975c | ||
|
|
a2372b0c3a | ||
|
|
362d7c517d | ||
|
|
62389b7e50 | ||
|
|
eb9e6701fd | ||
|
|
b585954b21 | ||
|
|
82ddc6a883 | ||
|
|
624b76e86e | ||
|
|
4dd0aece02 | ||
|
|
e85fb0c25e | ||
|
|
fc8783a933 | ||
|
|
e7897eb9cc | ||
|
|
59e8b79034 | ||
|
|
fb7475bf59 | ||
|
|
cd98516cae | ||
|
|
e399d8dd1f | ||
|
|
d327cfea5a | ||
|
|
c94e7c72e7 | ||
|
|
f3aea33ad4 | ||
|
|
48709d9c4a | ||
|
|
4779adcb50 | ||
|
|
01e29ec685 | ||
|
|
e4cccc115d | ||
|
|
8e9716d5d4 | ||
|
|
a96d288027 | ||
|
|
545d2563ef | ||
|
|
1494ef1df3 | ||
|
|
698f270b5b | ||
|
|
f15f6a86b0 | ||
|
|
5d60d611ae | ||
|
|
6e71e902c8 | ||
|
|
473cb3c968 | ||
|
|
df43ebe9e0 | ||
|
|
642173e864 | ||
|
|
944cf6e318 | ||
|
|
a655eab34f | ||
|
|
f020d479e0 | ||
|
|
de752b28de | ||
|
|
f41d370e6a | ||
|
|
a97830d9d6 | ||
|
|
ea4fc47cda | ||
|
|
0e08ca7c89 | ||
|
|
068cd3c311 | ||
|
|
455b8e4b44 | ||
|
|
d9a363606b | ||
|
|
59ad433b6b | ||
|
|
35b3a42ed9 | ||
|
|
0639205617 | ||
|
|
3916c3366b | ||
|
|
f0a33e7b28 | ||
|
|
c9b8f8bc70 | ||
|
|
983b0723f6 | ||
|
|
02c38934ea | ||
|
|
c28c2cde43 | ||
|
|
349323dec7 | ||
|
|
ddfaf2e542 | ||
|
|
3177474ae8 | ||
|
|
cc535632d1 | ||
|
|
cb8ee57b9e | ||
|
|
c0b19b3fea | ||
|
|
8235da6885 | ||
|
|
f6625717cd | ||
|
|
fdfcabd79b | ||
|
|
2bb88b45c6 | ||
|
|
9820c22c1d | ||
|
|
bcd7bad467 | ||
|
|
83ea9fe284 | ||
|
|
c74d6e458d | ||
|
|
ff466439fc | ||
|
|
0fcdf4389b | ||
|
|
9cb9021c87 | ||
|
|
9c36236742 | ||
|
|
adebb027be | ||
|
|
7d3798d7cd | ||
|
|
b7c7c293e5 | ||
|
|
9ca250755f | ||
|
|
bd3b36865e | ||
|
|
538e1c5eb1 | ||
|
|
009f1a5ae8 | ||
|
|
4f1418abf9 | ||
|
|
79b348f075 | ||
|
|
9d88c028e2 | ||
|
|
51172b3510 | ||
|
|
892636036a | ||
|
|
4cf6b29397 | ||
|
|
571359b366 | ||
|
|
0f009e7718 | ||
|
|
24effd7340 | ||
|
|
5289fc5f80 | ||
|
|
ca49304bd6 | ||
|
|
b7fbac617d | ||
|
|
839e9aa4af | ||
|
|
c5ac15ad33 | ||
|
|
598cd10c34 | ||
|
|
1885729024 | ||
|
|
2127f63961 | ||
|
|
97a8b1e43b | ||
|
|
aeee1feda6 | ||
|
|
18d9243eb9 | ||
|
|
1aa4827b3b | ||
|
|
ed1077a788 | ||
|
|
356c475a6a | ||
|
|
9ac582fa35 | ||
|
|
8c75f44603 | ||
|
|
0a63ad95ce | ||
|
|
d274fe44da | ||
|
|
6d1cb58d8f | ||
|
|
784122d44f | ||
|
|
32fb8d41ca | ||
|
|
4993c35e11 | ||
|
|
6a5665ca58 | ||
|
|
e5cf006378 | ||
|
|
0e51552d2d | ||
|
|
cc007ad93b | ||
|
|
3096926547 | ||
|
|
d48f012809 | ||
|
|
def137bc80 | ||
|
|
3e0272e55f | ||
|
|
be503bbcf6 | ||
|
|
72bf3d26eb | ||
|
|
cc20ead3dc | ||
|
|
fd8fbcd090 | ||
|
|
77bd0f83fe | ||
|
|
32a82a38fd | ||
|
|
66e097e3e6 | ||
|
|
51d77d6cfc | ||
|
|
2bb0769516 | ||
|
|
58da0c0ad2 | ||
|
|
c10b66b579 | ||
|
|
55a90c3735 | ||
|
|
962afb9e7d | ||
|
|
7abd982f87 | ||
|
|
c099aac79c | ||
|
|
828e6ce30f | ||
|
|
dc08cbfe59 | ||
|
|
3bdcce6903 | ||
|
|
d93aa10bac | ||
|
|
de4ecc72d1 | ||
|
|
db54bfc0c1 | ||
|
|
72ee80debe | ||
|
|
a3436c26f0 | ||
|
|
b0f5024d56 | ||
|
|
eae4b2abe5 | ||
|
|
ff03b813b0 | ||
|
|
4e747da4b4 | ||
|
|
99e3c67a81 | ||
|
|
c4a2550518 | ||
|
|
4ef944b734 | ||
|
|
0f04baeb97 | ||
|
|
bf7f63eaed | ||
|
|
59cf4e0b96 | ||
|
|
3fc72c0cfa | ||
|
|
ad69f4f32b | ||
|
|
81c2b2e886 | ||
|
|
c9f03fb222 | ||
|
|
b0fe443632 | ||
|
|
8882fb21e0 | ||
|
|
7d551d34a0 | ||
|
|
feef0dd983 | ||
|
|
d29f7b7c70 | ||
|
|
e3cd248f0d | ||
|
|
27e20a568b | ||
|
|
80316de3b8 | ||
|
|
f9e2a5852d | ||
|
|
500c9cbf3b | ||
|
|
46714fec2d | ||
|
|
e1d9a57bd0 | ||
|
|
1b82604f61 | ||
|
|
d69ac07183 | ||
|
|
519796de37 | ||
|
|
ea4811b3b3 | ||
|
|
951f14ae06 | ||
|
|
428f9e4228 | ||
|
|
ea425bf01e | ||
|
|
8567a0e466 | ||
|
|
f6bf12bdcd | ||
|
|
e8968ea429 | ||
|
|
cf10ce1b68 | ||
|
|
15dc83420d | ||
|
|
37dbc211cd | ||
|
|
ed78cda6ad | ||
|
|
faff931a76 | ||
|
|
1e68671690 | ||
|
|
8eb167fd21 | ||
|
|
bc46174e98 | ||
|
|
b86c89460a | ||
|
|
03541f3626 | ||
|
|
39a462496a | ||
|
|
7ba8994838 | ||
|
|
8da025da99 | ||
|
|
5dc7242703 | ||
|
|
11bffa0d55 | ||
|
|
5f6f265f80 | ||
|
|
bf92314dc4 | ||
|
|
a3fda9f992 | ||
|
|
cd34b377aa | ||
|
|
145423068b | ||
|
|
fb4c3f31c0 | ||
|
|
60049f1551 | ||
|
|
e555548dda | ||
|
|
eedf61b3a2 | ||
|
|
ab54f76a38 | ||
|
|
f8df4789b1 | ||
|
|
6366ebc17e | ||
|
|
3a2d33d5a3 | ||
|
|
1afd5b23d7 | ||
|
|
17fb9e3709 | ||
|
|
7a7295992f | ||
|
|
526974366f | ||
|
|
51fe589aeb | ||
|
|
28cf4acf13 | ||
|
|
ee2220f2e7 | ||
|
|
a6ec6ec3ac | ||
|
|
4f5343f086 | ||
|
|
79c7384e5e | ||
|
|
75beeaf2b0 | ||
|
|
f4ed2abdca | ||
|
|
11a5c7337a | ||
|
|
972c476c5a | ||
|
|
a8c8f2f309 | ||
|
|
a0d2513be6 | ||
|
|
43dc0b3295 | ||
|
|
195ff5c51b | ||
|
|
e49aececce | ||
|
|
814b07c3a2 | ||
|
|
3470ab66f0 | ||
|
|
6901df5c18 | ||
|
|
bddb3b3228 | ||
|
|
dfe877144a | ||
|
|
59a9b7a9f6 | ||
|
|
ad8fb64276 | ||
|
|
436c1d3ea2 | ||
|
|
7fc5da5f80 | ||
|
|
105b3faa46 | ||
|
|
709223826f | ||
|
|
eace93f2af | ||
|
|
2775846db7 | ||
|
|
4aff08e95d | ||
|
|
958d66f8a7 | ||
|
|
85fa29c43d | ||
|
|
0344b9a9c9 | ||
|
|
04f6329773 | ||
|
|
d690faeb19 | ||
|
|
0b2e77ae64 | ||
|
|
2a4fd0a5c6 | ||
|
|
e569e1c9d9 | ||
|
|
7be360041c | ||
|
|
2fa83b541c | ||
|
|
8db9d59dac | ||
|
|
adcf073484 | ||
|
|
5296858411 | ||
|
|
d603426389 | ||
|
|
d3f4292968 | ||
|
|
4dde7198c8 | ||
|
|
b145d3ff51 | ||
|
|
9b98247d9c | ||
|
|
eedabb3d27 | ||
|
|
66dc2b6d6b | ||
|
|
bcdbbbd694 | ||
|
|
7b07e47c08 | ||
|
|
a608496faf | ||
|
|
c687224a11 | ||
|
|
a6f2a613f3 | ||
|
|
cfa39af345 | ||
|
|
8bab35c122 | ||
|
|
b20ef4cd7f | ||
|
|
b8b751a932 | ||
|
|
4a390841eb | ||
|
|
f506f44033 | ||
|
|
1f8355f154 | ||
|
|
ddc2761498 | ||
|
|
8b50a8298a | ||
|
|
3eab329042 | ||
|
|
552d3b53b1 | ||
|
|
8afd62d954 | ||
|
|
4883086fc1 | ||
|
|
2582be8754 | ||
|
|
ff9301567e | ||
|
|
e7a254265f | ||
|
|
d5311adafb | ||
|
|
18d7ea62b3 | ||
|
|
fb2849b230 | ||
|
|
fd59877692 | ||
|
|
bb0553e4c4 | ||
|
|
46f954490d | ||
|
|
31e6a50386 | ||
|
|
9a9c0d7b99 | ||
|
|
0c80f00d0b | ||
|
|
27b3bf48ea | ||
|
|
c3e34b8145 | ||
|
|
7bf3ec4aeb | ||
|
|
50204a125b | ||
|
|
111d170542 | ||
|
|
d6dd6f0bc9 | ||
|
|
44aac84feb | ||
|
|
c41508723f | ||
|
|
6043632f80 | ||
|
|
a420ed57a1 | ||
|
|
72f99033fe | ||
|
|
2d798bc4cf | ||
|
|
881d07fa0a | ||
|
|
c5306bed39 | ||
|
|
934b8712a5 | ||
|
|
1d4690eb64 | ||
|
|
e6848b1e3f | ||
|
|
3e537416a9 | ||
|
|
26a1ed8bc3 | ||
|
|
24538fe3e9 | ||
|
|
e43d699973 | ||
|
|
1e727c4497 | ||
|
|
83010590af | ||
|
|
fa402a173a | ||
|
|
ca83d2a804 | ||
|
|
725beb360a | ||
|
|
86d29221f3 | ||
|
|
e8062b7ff1 | ||
|
|
9468fd4aa6 | ||
|
|
5ed9b888ff | ||
|
|
7661a6e95b | ||
|
|
aca1daf7c9 | ||
|
|
46cac4e22f | ||
|
|
56a102ed4d | ||
|
|
ca28dbd2c3 | ||
|
|
588785e160 | ||
|
|
cabcccd6c3 | ||
|
|
567e66a0bb | ||
|
|
b8ee6d6e56 | ||
|
|
9ea1e4e40f | ||
|
|
2d492eacb5 | ||
|
|
cb8660e79a | ||
|
|
d29bef93e9 | ||
|
|
5a09adebfd | ||
|
|
8c0ee9c175 | ||
|
|
f20fabdbf4 | ||
|
|
57cea56e6e | ||
|
|
db7d9639b4 | ||
|
|
beb40d63ed | ||
|
|
672b98dd3f | ||
|
|
a24d2713cd | ||
|
|
a5110d3ed9 | ||
|
|
9d1c1505b9 | ||
|
|
8c25632321 | ||
|
|
2507b66640 | ||
|
|
d7e3ad17ff | ||
|
|
84902d0e00 | ||
|
|
f7f3667bcb | ||
|
|
794cbfbbb5 | ||
|
|
1858104b5c | ||
|
|
994409a036 | ||
|
|
2d9eb5b6fa | ||
|
|
3477cbe28f | ||
|
|
8634158de0 | ||
|
|
3eaf0765b0 | ||
|
|
dd0679ad45 | ||
|
|
bfcd8ecc56 | ||
|
|
50e5865c73 | ||
|
|
93f6358916 | ||
|
|
9300854439 | ||
|
|
02914ac637 | ||
|
|
00fff161cf | ||
|
|
3763befd62 | ||
|
|
2ae008bcee | ||
|
|
ea41f7ab09 | ||
|
|
c673b1e8b7 | ||
|
|
2bf1ba22f2 | ||
|
|
dfc2f70876 | ||
|
|
0dba2b9689 | ||
|
|
e7fc2d31cc | ||
|
|
f231efb811 | ||
|
|
c4d6f98bed | ||
|
|
bff3f51d13 | ||
|
|
f5eb7daf20 | ||
|
|
d66b2f2b24 | ||
|
|
a57e1eb542 | ||
|
|
25bdee7a0e | ||
|
|
f6001202ec | ||
|
|
0cf506c929 | ||
|
|
d05e9fb2ec | ||
|
|
54d7e3e94a | ||
|
|
c7223f4c8f | ||
|
|
07badbede7 | ||
|
|
468cfeeb71 | ||
|
|
b3fc549622 | ||
|
|
077dbd5692 | ||
|
|
e18903a6b5 | ||
|
|
7dfd4ae556 | ||
|
|
429c4468b0 | ||
|
|
7a4c396bba | ||
|
|
88f846f656 | ||
|
|
27c8a64977 | ||
|
|
2fc8edacb8 | ||
|
|
903fa247f8 | ||
|
|
96771d6857 | ||
|
|
f4c6a00b2a | ||
|
|
990f8cd89b | ||
|
|
813ea71b50 | ||
|
|
e8be384cdf | ||
|
|
61773a2c07 | ||
|
|
510aa8b050 | ||
|
|
57957ab6cf | ||
|
|
e8069a0179 | ||
|
|
f3f840551a | ||
|
|
10a42c1e04 | ||
|
|
4a219ecbf1 | ||
|
|
0d298bfc4c | ||
|
|
792c241e3a | ||
|
|
6336a87855 | ||
|
|
f5721b1212 | ||
|
|
7d3e9180c6 | ||
|
|
03b8ca186a | ||
|
|
435cbef31a | ||
|
|
4adcf58368 | ||
|
|
004986310d | ||
|
|
7a88e0a87b | ||
|
|
64e21d6281 | ||
|
|
9ef7ea2bcb | ||
|
|
6d1796d6be | ||
|
|
fcaba98101 | ||
|
|
9bbda5c964 | ||
|
|
2c81d38861 | ||
|
|
78fec3f05a | ||
|
|
392a1a5ff6 | ||
|
|
219a414cb7 | ||
|
|
58fc81441b | ||
|
|
02ada36838 | ||
|
|
81978f0ba0 | ||
|
|
622769cdfd | ||
|
|
3038047f9b | ||
|
|
3e3f045ab7 | ||
|
|
a6d9f41eda | ||
|
|
bf6a4e1a81 | ||
|
|
5982d96b75 | ||
|
|
28e3e4cdca | ||
|
|
24134c78e8 | ||
|
|
5e8ed72b89 | ||
|
|
45e41b7ac1 | ||
|
|
27fd751915 | ||
|
|
4d26cfc92b | ||
|
|
d78680912e | ||
|
|
47e4cb31b2 | ||
|
|
91da65a782 | ||
|
|
bb1c02e9f5 | ||
|
|
c651ea9b6b | ||
|
|
207f9fb128 | ||
|
|
f06c1cfa97 | ||
|
|
6cd47bff8f | ||
|
|
2de24cfd82 | ||
|
|
86a3ef9ed1 | ||
|
|
3f8c57c8f2 | ||
|
|
ca96946416 | ||
|
|
e5b9b6d701 | ||
|
|
8cb689a5e6 | ||
|
|
2270234115 | ||
|
|
a073f383e6 | ||
|
|
8e74655b03 | ||
|
|
70fa3a6905 | ||
|
|
1227873b88 | ||
|
|
d30e73d0d9 | ||
|
|
9e7a7008de | ||
|
|
62d6aed6a6 | ||
|
|
ffb9887cce | ||
|
|
9220c9b8a2 | ||
|
|
2e28b19112 | ||
|
|
636a4e2794 | ||
|
|
5c9e1e0b69 | ||
|
|
64fd1b8ba5 | ||
|
|
69d3913f3e | ||
|
|
08fd011b6a | ||
|
|
c172268cfe | ||
|
|
94b014865c | ||
|
|
099aaf2cb1 | ||
|
|
4481a8b24f | ||
|
|
b626fe661e | ||
|
|
ba8fcd145d | ||
|
|
981d09de40 | ||
|
|
86a99bb257 | ||
|
|
3093a11cd0 | ||
|
|
058b788d38 | ||
|
|
66a42fa493 | ||
|
|
a85f63cc15 | ||
|
|
bbe1e69dcc | ||
|
|
1b52bba7b9 | ||
|
|
c5c80ef400 | ||
|
|
a78031ce0d | ||
|
|
34e9dd13ce | ||
|
|
6e52a9be7a | ||
|
|
69c6dffd63 | ||
|
|
2ddd0ae231 | ||
|
|
79db0b7eca | ||
|
|
2ebba7fbaa | ||
|
|
e392d1fde9 | ||
|
|
d7c93ec950 | ||
|
|
6af39d63aa | ||
|
|
cc8414b1b3 | ||
|
|
6b44055e3d | ||
|
|
9f9c6cc6ab | ||
|
|
f176193d35 | ||
|
|
e8bc41e862 | ||
|
|
91dbe3c6c2 | ||
|
|
3e876d4218 | ||
|
|
31b1f2e8a1 | ||
|
|
4169e94b1d | ||
|
|
948ecf8431 | ||
|
|
91f3f97ea7 | ||
|
|
65bb65b440 | ||
|
|
ea6e8d85a3 | ||
|
|
add932501f | ||
|
|
89390a738f | ||
|
|
ac4f6ab93b | ||
|
|
dbcb1b9b0b | ||
|
|
6375307798 | ||
|
|
fb78e60d26 | ||
|
|
b822c7164f | ||
|
|
aa295730a0 | ||
|
|
69d70703b2 | ||
|
|
b2b6ef00dc | ||
|
|
5dc86c236b | ||
|
|
2563dd9d29 | ||
|
|
a899e3df33 | ||
|
|
692cea49f8 | ||
|
|
bcedacaa3d | ||
|
|
be3c1b5243 | ||
|
|
e626ec6c37 | ||
|
|
49d52b547f | ||
|
|
74a546a9e7 | ||
|
|
d1777087c1 | ||
|
|
cf7b5363cd | ||
|
|
7f3183cc72 | ||
|
|
f1b8da085b | ||
|
|
09dfca49ec | ||
|
|
88e0ec07aa | ||
|
|
0adc8e8f92 | ||
|
|
5fc7674e36 | ||
|
|
018977044a | ||
|
|
cc49d8e6e6 | ||
|
|
933bd017b4 | ||
|
|
d558b33d85 | ||
|
|
9268bf2cff | ||
|
|
dbf2c22467 | ||
|
|
af4fe92095 | ||
|
|
e034a07be8 | ||
|
|
eb8c9ad601 | ||
|
|
6847536669 | ||
|
|
f5206db9b0 | ||
|
|
6ab2ed0da6 | ||
|
|
7352e470e1 | ||
|
|
5bc9c0d07a | ||
|
|
a2146e82ef | ||
|
|
6e10e6740c | ||
|
|
bfaa10f2b0 | ||
|
|
9f167a7997 | ||
|
|
6908163464 | ||
|
|
671daf06b8 | ||
|
|
b189a5386b | ||
|
|
7889d108c2 | ||
|
|
3cfa8ce9d3 | ||
|
|
570573fe28 | ||
|
|
62b1a11736 | ||
|
|
c00d517e12 | ||
|
|
001f3d5e27 | ||
|
|
6045023a49 | ||
|
|
bba29a0ee7 | ||
|
|
cffc856b50 | ||
|
|
419077e04b | ||
|
|
7db9d4acea | ||
|
|
8d5b86efe7 | ||
|
|
6cf16aea7b | ||
|
|
870545d3cb | ||
|
|
2a030c0d0c | ||
|
|
0b709ab1bc | ||
|
|
a1f2f17385 | ||
|
|
2240eefbd0 | ||
|
|
706d0c281a | ||
|
|
ca73e34f30 | ||
|
|
cca2ef4649 | ||
|
|
05d9edbf8f | ||
|
|
c5bdc52a59 | ||
|
|
74f0c0924a | ||
|
|
05492d1d23 | ||
|
|
eea343b93f | ||
|
|
afff06c88c | ||
|
|
c0717a27f6 | ||
|
|
159bd73f76 | ||
|
|
9931a9166b | ||
|
|
8aa4ae027b | ||
|
|
dcce79fdbe | ||
|
|
189aafde9d | ||
|
|
99e3045df4 | ||
|
|
c498c21fad | ||
|
|
6bef8aa0e9 | ||
|
|
108d112272 | ||
|
|
05078e4252 | ||
|
|
4ceb9e4cd0 | ||
|
|
a9f237a395 | ||
|
|
e7ca560c3d | ||
|
|
d9f86f6f70 | ||
|
|
879d936277 | ||
|
|
5bb2bf9361 | ||
|
|
a8167b7959 | ||
|
|
b33b682356 | ||
|
|
2c47602c33 | ||
|
|
59d1b41716 | ||
|
|
5b75d4afef | ||
|
|
e15c7cd236 | ||
|
|
9bc774d6af | ||
|
|
9b34556952 | ||
|
|
9a6369d8f1 | ||
|
|
49cdd6bf09 | ||
|
|
63fe34e890 | ||
|
|
85465afb62 | ||
|
|
339cb06a49 | ||
|
|
10150bfcab | ||
|
|
e50dc739d8 | ||
|
|
26e08abe71 | ||
|
|
7637faa0d0 | ||
|
|
8a57a28177 | ||
|
|
34db671b57 | ||
|
|
8b9021bf34 | ||
|
|
ce6b896948 | ||
|
|
2962fc6286 | ||
|
|
76bed76289 | ||
|
|
113f2ebec0 | ||
|
|
7c5bd948bb | ||
|
|
8cbc68f28f | ||
|
|
bf7aa52394 | ||
|
|
366345790d | ||
|
|
f881c153bf | ||
|
|
19f3ab2225 | ||
|
|
fd1e80802f | ||
|
|
4b7cb161a8 | ||
|
|
7848794222 | ||
|
|
94822d5156 | ||
|
|
e3f840aae9 | ||
|
|
5aae563277 | ||
|
|
02de782fa3 | ||
|
|
3f6df33feb | ||
|
|
a94f5fe007 | ||
|
|
63f0234748 | ||
|
|
47921c7c0c | ||
|
|
42a85f685e | ||
|
|
feca2399e4 | ||
|
|
d34e611ec8 | ||
|
|
02098ed830 | ||
|
|
aa4228bf1b | ||
|
|
b296441708 | ||
|
|
b827475378 | ||
|
|
78a6698ae1 | ||
|
|
e7b6feb34b | ||
|
|
84be834385 | ||
|
|
e83d808dfd | ||
|
|
35a68d5b59 | ||
|
|
3c593137b0 | ||
|
|
deaf0ffed3 | ||
|
|
af145e871e | ||
|
|
fbca570d0b | ||
|
|
448ef779c2 | ||
|
|
499a69e611 | ||
|
|
58c2915878 | ||
|
|
eda4b111d3 | ||
|
|
c6dd749687 | ||
|
|
d2a96f5fbc | ||
|
|
499f513d40 | ||
|
|
8b1f68b1b4 | ||
|
|
8e4c776900 | ||
|
|
d0eb9427c2 | ||
|
|
7d100b89fc | ||
|
|
a4bd7f1800 | ||
|
|
5308e0a25f | ||
|
|
da862158bf | ||
|
|
7b98443a13 | ||
|
|
4da9f74d24 | ||
|
|
e41042e258 | ||
|
|
5581466c63 | ||
|
|
e79a6c2116 | ||
|
|
666ece122e | ||
|
|
2c7ab98370 | ||
|
|
f0f18a02a7 | ||
|
|
c5d8af0285 | ||
|
|
0ce15a8472 | ||
|
|
da60629201 | ||
|
|
2343e7a89c | ||
|
|
45f27f4f5e | ||
|
|
0bc112f8b4 | ||
|
|
bfc2fa645c | ||
|
|
11111804fd | ||
|
|
87ec67247e | ||
|
|
0df8328ceb | ||
|
|
b563048ee2 | ||
|
|
e8096330be | ||
|
|
b1647dbcb7 | ||
|
|
4ddadd5622 | ||
|
|
3e854006c7 | ||
|
|
2c4c235147 | ||
|
|
6863e43269 | ||
|
|
de8708f331 | ||
|
|
d0b2486036 | ||
|
|
5384a93645 | ||
|
|
4bbc768652 | ||
|
|
fead915b45 | ||
|
|
5422e49026 | ||
|
|
77a1f27a1d | ||
|
|
b45d864f73 | ||
|
|
f35c81c871 | ||
|
|
a349b2803c | ||
|
|
f5d1b8fb74 | ||
|
|
a0fe71eef1 | ||
|
|
154b39cf7a | ||
|
|
6f54210db2 | ||
|
|
f6539449c5 | ||
|
|
b8d546a0d1 | ||
|
|
04e6474b75 | ||
|
|
eb51c500e8 | ||
|
|
6f8fba9a3f | ||
|
|
750afc30f2 | ||
|
|
e0e6ec0d84 | ||
|
|
c9f50fc686 | ||
|
|
83c26b458b | ||
|
|
b711873f45 | ||
|
|
c68ca40ce4 | ||
|
|
51fe80ad95 | ||
|
|
7ffee73524 | ||
|
|
f40b0024bd | ||
|
|
a06c9909a6 | ||
|
|
aee42fada8 | ||
|
|
3e93068c43 | ||
|
|
36291b707b | ||
|
|
6dad2c24bf | ||
|
|
27cbf20d23 | ||
|
|
5c571bbbe7 | ||
|
|
33d65c8614 | ||
|
|
d87db7cdb8 | ||
|
|
45fa4750da | ||
|
|
8472fd8133 | ||
|
|
5ab645e310 | ||
|
|
8ccda538d3 | ||
|
|
b06d74ab73 | ||
|
|
d0964ffa83 | ||
|
|
3d08815efb | ||
|
|
a83f0d3cdc | ||
|
|
702db726d3 | ||
|
|
ed5c43204b | ||
|
|
f91bdd604d | ||
|
|
3a1dbb1354 | ||
|
|
4b511143b8 | ||
|
|
93076e7e1c | ||
|
|
1c51feb3c5 | ||
|
|
c2773dbc2f | ||
|
|
4534db84c4 | ||
|
|
be8215e181 | ||
|
|
ae82bbbace | ||
|
|
2b6ea41062 | ||
|
|
d9f745fe70 | ||
|
|
9aac179367 | ||
|
|
b896bb5a78 | ||
|
|
64c2fd9888 | ||
|
|
2668a12e4e | ||
|
|
e1645966ec | ||
|
|
4f1fc1ee78 | ||
|
|
d70df3daab | ||
|
|
554b9b06de | ||
|
|
f734bd1a7c | ||
|
|
77fc5c42b9 | ||
|
|
ea85bc43e0 | ||
|
|
e8fb11c433 | ||
|
|
01a29c7a11 | ||
|
|
6ec3dc1650 | ||
|
|
0c54cf316d | ||
|
|
bd3fb49a1e | ||
|
|
f6e72a80e1 | ||
|
|
c2ab1426e5 | ||
|
|
fa2c59d78d | ||
|
|
16afa8eb50 | ||
|
|
992590e99c | ||
|
|
0baa35eade | ||
|
|
2e0870ee0c | ||
|
|
43cd119d6d | ||
|
|
62cd319a51 | ||
|
|
d0f789425b | ||
|
|
30e6549692 | ||
|
|
043c7d7c9f | ||
|
|
1c277a8850 | ||
|
|
ccb94ac5fb | ||
|
|
778fce4039 | ||
|
|
9983185d6d | ||
|
|
7bd1c02781 | ||
|
|
760285218f | ||
|
|
4fe0e6b7fd | ||
|
|
0773a1e630 | ||
|
|
4a24368763 | ||
|
|
577290c5bc | ||
|
|
854ff69f78 | ||
|
|
29b0ad894c | ||
|
|
cde0a20307 | ||
|
|
a768578a26 | ||
|
|
5d838729ef | ||
|
|
d6b763dc24 | ||
|
|
95adb52a45 | ||
|
|
707d9a3484 | ||
|
|
1872d4d195 | ||
|
|
17f32c266e | ||
|
|
6207655ab2 | ||
|
|
5e1e31ad5f | ||
|
|
13111c1dd8 | ||
|
|
85c84073c1 | ||
|
|
c2944d8727 | ||
|
|
e118b9b1e8 | ||
|
|
7fb7f95979 | ||
|
|
cc507bffae | ||
|
|
0dbfe020ad | ||
|
|
018a1c42b0 | ||
|
|
c5735ebfe9 | ||
|
|
db93180ce1 | ||
|
|
39da10d939 | ||
|
|
f2da253bc3 | ||
|
|
934d4047f1 | ||
|
|
b799cfd1c4 | ||
|
|
b712c100d7 | ||
|
|
c049bce007 | ||
|
|
46fad717e5 | ||
|
|
ae0c3bbbe8 | ||
|
|
f95d57e0d9 | ||
|
|
a1cbd4eb82 | ||
|
|
6cbeb107db | ||
|
|
3a5566c6c3 | ||
|
|
73c548ad01 | ||
|
|
82203e12c8 | ||
|
|
1ca099473f | ||
|
|
eceb8d9937 | ||
|
|
4ba92bb6d6 | ||
|
|
f31f68ae8e | ||
|
|
cff15f91d4 | ||
|
|
6b74917954 | ||
|
|
1bf2384a1f | ||
|
|
54a12779e2 | ||
|
|
e8b06fef9f | ||
|
|
653d70ec4e | ||
|
|
abb09418b1 | ||
|
|
c103bebd9f | ||
|
|
935d855b47 | ||
|
|
f8f9100a0d | ||
|
|
6de7b98e76 | ||
|
|
c390351c65 | ||
|
|
768bce799b | ||
|
|
d3a30142e5 | ||
|
|
3a635fc51f | ||
|
|
10078566da | ||
|
|
c44346096c | ||
|
|
0ff449e6a6 | ||
|
|
f3a16383b9 | ||
|
|
539ef3f770 | ||
|
|
f282856c72 | ||
|
|
6db8ec1ba2 | ||
|
|
5187c08c90 | ||
|
|
c8076ac10d | ||
|
|
362d155558 | ||
|
|
7b7eb0a6e5 | ||
|
|
d96f49f67d | ||
|
|
43ba5d2126 | ||
|
|
48f7598fed | ||
|
|
510b22e96b | ||
|
|
0a0aff14d8 | ||
|
|
e225ac68bc | ||
|
|
58060c40a5 | ||
|
|
2ac1b3d5c4 | ||
|
|
c174566982 | ||
|
|
60fca19d40 | ||
|
|
8bcb15b02f | ||
|
|
65c2cebcd5 | ||
|
|
2a51b45a43 | ||
|
|
5ac791665e | ||
|
|
a4e3f83611 | ||
|
|
8a837f9c2b | ||
|
|
da2d33e9a8 | ||
|
|
4b98dadae9 | ||
|
|
86acea5c46 | ||
|
|
a60fc73e7b | ||
|
|
50f99ec5f4 | ||
|
|
31b6a14444 | ||
|
|
9df4d36157 | ||
|
|
b70f0b674f | ||
|
|
510784077f | ||
|
|
9800e397fb | ||
|
|
1436d9961f | ||
|
|
98f5d05925 | ||
|
|
7a937c7652 | ||
|
|
b198d76676 | ||
|
|
97d4203354 | ||
|
|
beaaaad162 | ||
|
|
4e78975909 | ||
|
|
99147ed8f2 | ||
|
|
dec0d3bfc2 | ||
|
|
cd84c99e70 | ||
|
|
d5c507975c | ||
|
|
b4235abd36 | ||
|
|
1966085a97 | ||
|
|
e31e7af48f | ||
|
|
adb9123fc3 | ||
|
|
b0f7efd59e | ||
|
|
e28dfada8c | ||
|
|
ac0b28cce6 | ||
|
|
48b16ae66c | ||
|
|
061579ec28 | ||
|
|
f2f834e7e7 | ||
|
|
a7802e9a76 | ||
|
|
8f7ab95ff0 | ||
|
|
042c670747 | ||
|
|
cacbe9976f | ||
|
|
8efec1d640 | ||
|
|
c44d282f0b | ||
|
|
4432f29bd2 | ||
|
|
5fee3ed5e9 | ||
|
|
b76ea64263 | ||
|
|
ed904f08a4 | ||
|
|
96cc80ffc8 | ||
|
|
ab99373cfc | ||
|
|
dbfb49384b | ||
|
|
14bb9f29a3 | ||
|
|
16519ee2cc | ||
|
|
50022e9286 | ||
|
|
5059019535 | ||
|
|
c6a38f5069 | ||
|
|
11ed197663 | ||
|
|
5634e6b963 | ||
|
|
db312a5ff6 | ||
|
|
88c31b3785 | ||
|
|
967f3e4f77 | ||
|
|
2e311d1766 | ||
|
|
11f7cc0507 | ||
|
|
a4f28892a5 | ||
|
|
5bc53741be | ||
|
|
95a4f33265 | ||
|
|
fac1093ebf | ||
|
|
1b1384ccaa | ||
|
|
0c9a19ded5 | ||
|
|
b7bd7469b7 | ||
|
|
9568ff3f06 | ||
|
|
742ddcce11 | ||
|
|
e72cc9e3da | ||
|
|
3156e5a293 | ||
|
|
9a901e1cb0 | ||
|
|
8c11044ee2 | ||
|
|
a75d2db75b | ||
|
|
6aac72fd80 | ||
|
|
b692cb720c | ||
|
|
25102489f5 | ||
|
|
a2d2cad384 | ||
|
|
859e0c2323 | ||
|
|
e62a39cafe | ||
|
|
8bbb8fa062 | ||
|
|
68039e0d14 | ||
|
|
65fd30a547 | ||
|
|
23a4e8b38d | ||
|
|
979b53866d | ||
|
|
46061d8eec | ||
|
|
946ee8f611 | ||
|
|
7f757f09ce | ||
|
|
9ba8a33966 | ||
|
|
492940568d | ||
|
|
b95c2a3f78 | ||
|
|
53b661b59d | ||
|
|
a049c9e0f8 | ||
|
|
3513484852 | ||
|
|
2d67871bbf | ||
|
|
e6e9a472db | ||
|
|
1d5d768545 | ||
|
|
6c8588c13c | ||
|
|
89b127bf6c | ||
|
|
38c4a7ff97 | ||
|
|
2f5b4aea91 | ||
|
|
4fc6a1b424 | ||
|
|
6b3800cc94 | ||
|
|
633a007b7b | ||
|
|
756c2e9afb | ||
|
|
27ea58d5fd | ||
|
|
64f9205189 | ||
|
|
535ca64bba | ||
|
|
7255f9ef74 | ||
|
|
cdb0b6124f | ||
|
|
5fb1107cc7 | ||
|
|
1045adaa88 | ||
|
|
ed286f3617 | ||
|
|
9f9dd7948b | ||
|
|
9c760de676 | ||
|
|
90229984cf | ||
|
|
2b3d64c31d | ||
|
|
d23c647e34 | ||
|
|
2408bbcd77 | ||
|
|
d75f6830f1 | ||
|
|
4d7eb2f7a6 | ||
|
|
3a67dedad6 | ||
|
|
518837e17a | ||
|
|
c7e778757a | ||
|
|
c45be946ce | ||
|
|
258bcc21b8 | ||
|
|
db286ca6ea | ||
|
|
85fbfd9b15 | ||
|
|
b819c7fe55 | ||
|
|
2b5c86b9a3 | ||
|
|
0a848e2528 | ||
|
|
b443ec5ea5 | ||
|
|
37d1467368 | ||
|
|
1d9d19d76b | ||
|
|
9603f0552a | ||
|
|
12befc2afd | ||
|
|
78f20f7b3e | ||
|
|
875b0e262c | ||
|
|
8823e2b064 | ||
|
|
5b2caf48dc | ||
|
|
7ec048ce7f | ||
|
|
cfb3c3ba44 | ||
|
|
4b0ef09221 | ||
|
|
74f581e7ab | ||
|
|
07aa54b183 | ||
|
|
00da177e51 | ||
|
|
6e9bfac07d | ||
|
|
06f93e7bf0 | ||
|
|
d84a706c08 | ||
|
|
ea58a1e72c | ||
|
|
5c691a5460 | ||
|
|
2c877fa149 | ||
|
|
33053a5e14 | ||
|
|
8662652192 | ||
|
|
227c7e60a4 | ||
|
|
6e9c04896b | ||
|
|
0e273939d2 | ||
|
|
14647032b2 | ||
|
|
14a1059e43 | ||
|
|
4449259d88 | ||
|
|
01e5ea7d31 | ||
|
|
94522bfed1 | ||
|
|
9bdd35c9fa | ||
|
|
d366530699 | ||
|
|
96d652e5bd | ||
|
|
bd736f9234 | ||
|
|
90b25f5b83 | ||
|
|
997406fe47 | ||
|
|
14c8f07629 | ||
|
|
8f6a1b5318 | ||
|
|
a8c6bea2d5 | ||
|
|
19fde8f49c | ||
|
|
8f85291d23 | ||
|
|
9c48166e90 | ||
|
|
b536296c05 | ||
|
|
d36c522453 | ||
|
|
2577e20f09 | ||
|
|
c169ad3f58 | ||
|
|
411f4697ca | ||
|
|
6c5de8dcb0 | ||
|
|
c8373f1649 | ||
|
|
45f86122fa | ||
|
|
c0a8afdb68 | ||
|
|
1afb285aad | ||
|
|
c08e7e716d | ||
|
|
a06a5f1baa | ||
|
|
fb5d4f1da4 | ||
|
|
d2e5b41369 | ||
|
|
4b6b6e5cba | ||
|
|
27b4c396d0 | ||
|
|
41eb5b79cb | ||
|
|
23cf74d5c7 | ||
|
|
1a038bfd50 | ||
|
|
dd02d67224 | ||
|
|
648bf8bd3e | ||
|
|
82c4bfe5d2 | ||
|
|
98ba4ce4d5 | ||
|
|
f63e414024 | ||
|
|
a8886603c2 | ||
|
|
4f10144b09 | ||
|
|
af664e6cec | ||
|
|
c30816eb65 | ||
|
|
b1accfd0ff | ||
|
|
5c45e4ccb5 | ||
|
|
41cf867738 | ||
|
|
02844e9b01 | ||
|
|
7a1ebc3467 | ||
|
|
8d89610ff6 | ||
|
|
cfe706f032 | ||
|
|
99cc94529d | ||
|
|
d0dfa1de9e | ||
|
|
0899ab52dd | ||
|
|
71e0ebcb6b | ||
|
|
e488371b01 | ||
|
|
39f34eb674 | ||
|
|
9d9d6c30cf | ||
|
|
27d59e54cc | ||
|
|
507a01ab17 | ||
|
|
f7b8cd1a09 | ||
|
|
8bc48af630 | ||
|
|
b0838280a9 | ||
|
|
cea21adbbb | ||
|
|
c619d555f0 | ||
|
|
e306199588 | ||
|
|
895c15d677 | ||
|
|
d18f9ca75a | ||
|
|
82e76c39d9 | ||
|
|
577aed4842 | ||
|
|
2a8ce63fc7 | ||
|
|
61dd4e0ccb | ||
|
|
8220e51ae4 | ||
|
|
d322c8e6e5 | ||
|
|
3dec266dd5 | ||
|
|
862938cc79 | ||
|
|
ee396702f2 | ||
|
|
316d50d6f1 | ||
|
|
5e92aaf8a5 | ||
|
|
7ffe59a734 | ||
|
|
6cd558398a | ||
|
|
632cd1a177 | ||
|
|
223ad0e8aa | ||
|
|
f8bd9ab378 | ||
|
|
d78e8f096c | ||
|
|
57fc2ff1be | ||
|
|
d8d096aa54 | ||
|
|
0a10545314 | ||
|
|
aeb57a36b2 | ||
|
|
b703bc32c9 | ||
|
|
09afdd4b36 | ||
|
|
5cadaf8d55 | ||
|
|
89ac745184 | ||
|
|
e2422023c4 | ||
|
|
1ec0813663 | ||
|
|
6ba7fad2a7 | ||
|
|
962ca91574 | ||
|
|
91cbebb629 | ||
|
|
722f038f1f | ||
|
|
5e61c002a6 | ||
|
|
46e1e79921 | ||
|
|
546e5e236c | ||
|
|
16a1a89bf4 | ||
|
|
8a996572d2 | ||
|
|
5f082b9a4d | ||
|
|
4622173135 | ||
|
|
99e1c44c25 | ||
|
|
b48e4421de | ||
|
|
d1f4e5876b | ||
|
|
71b7e689c0 | ||
|
|
26b87b844d | ||
|
|
1834ee05e5 | ||
|
|
7d7bf915ac | ||
|
|
d86e9f4aa3 | ||
|
|
942b52a3ca | ||
|
|
b252c57a22 | ||
|
|
2aab6a85a4 | ||
|
|
10719d6d35 | ||
|
|
59938efd23 | ||
|
|
53b15bd5c7 | ||
|
|
5084a8b342 | ||
|
|
4d1c795804 | ||
|
|
a9049569af | ||
|
|
dec1d2bfb2 | ||
|
|
62e66bda60 | ||
|
|
3abaa92926 | ||
|
|
37e6357c02 | ||
|
|
6accd19eb3 | ||
|
|
da96d334ab | ||
|
|
5a92dbe784 | ||
|
|
8fe5e9cf1e | ||
|
|
81f440a882 | ||
|
|
981f897c96 | ||
|
|
eb75ce7d07 | ||
|
|
5645e57ce0 | ||
|
|
a12c7c422b | ||
|
|
d70e815e9f | ||
|
|
eb329e9f52 | ||
|
|
5833be6ccf | ||
|
|
ea3950d57e | ||
|
|
3f51805e62 | ||
|
|
b45f53dd20 | ||
|
|
9749a1c6fc | ||
|
|
5ca5d279d7 | ||
|
|
7b52c1578f | ||
|
|
72975ce1f0 | ||
|
|
9a4c22db03 | ||
|
|
e7af875b68 | ||
|
|
4acca9b727 | ||
|
|
b2d93b2e38 | ||
|
|
74afffed0c | ||
|
|
5828426977 | ||
|
|
d04fb4b7fa | ||
|
|
f5fe3ab4a1 | ||
|
|
6b6b097fe8 | ||
|
|
4998afc9bb | ||
|
|
80f4d75968 | ||
|
|
910663c37b | ||
|
|
34a4695e81 | ||
|
|
fe00319f45 | ||
|
|
4c77d18416 | ||
|
|
a63e18edb8 | ||
|
|
8b676502de | ||
|
|
cf5b344ea8 | ||
|
|
4ab98f62e9 | ||
|
|
e6cc682f86 | ||
|
|
ff541e24fb | ||
|
|
008615370a | ||
|
|
beaf275222 | ||
|
|
400820d3f3 | ||
|
|
4eabc84a0c | ||
|
|
cf636a969e | ||
|
|
e3191e372b | ||
|
|
705e32acdc | ||
|
|
6e4dd9302d | ||
|
|
ea002130d7 | ||
|
|
7ba5ffa706 | ||
|
|
861ac013bc | ||
|
|
a6da963f45 | ||
|
|
55ba7ee2a1 | ||
|
|
3121f31ced | ||
|
|
da296db91d | ||
|
|
d36ca9288a | ||
|
|
8549043a3f | ||
|
|
e0ae2b4bb5 | ||
|
|
aad42ceaec | ||
|
|
f225469e6e | ||
|
|
7cc432ff7e | ||
|
|
0a9d75bfb8 | ||
|
|
070f2706b7 | ||
|
|
9b019a03e7 | ||
|
|
f52a738660 | ||
|
|
b80df5152a | ||
|
|
beb275a769 | ||
|
|
86c21a3a85 | ||
|
|
05236a4f23 | ||
|
|
a78bf9725a | ||
|
|
82fbb5c2f5 | ||
|
|
a592d82ad9 | ||
|
|
7fcf69ce5f | ||
|
|
32ac6ffa26 | ||
|
|
0d12410eaa | ||
|
|
54c8732c46 | ||
|
|
9b9d6ab150 | ||
|
|
c6554bfd30 | ||
|
|
83cd8ae39b | ||
|
|
23b9d80897 | ||
|
|
e98f76e084 | ||
|
|
936f5cb0f1 | ||
|
|
fa15fb3d53 | ||
|
|
62d61de93d | ||
|
|
ba81d68b07 | ||
|
|
ba25fb1bcc | ||
|
|
69642dd440 | ||
|
|
e5a593f013 | ||
|
|
acec7d0e28 | ||
|
|
a4c89e5bbe | ||
|
|
c5265f6070 | ||
|
|
0a10df1cf5 | ||
|
|
30f2a2003c | ||
|
|
67b108d1ce | ||
|
|
8a95631e39 | ||
|
|
82510e6b1f | ||
|
|
12ee4bf6ac | ||
|
|
3cb0351aff | ||
|
|
d5bc4e92e6 | ||
|
|
8e327bb0a3 | ||
|
|
fbf170a6c2 | ||
|
|
cd472e6aaf | ||
|
|
e9487b1a1a | ||
|
|
3cf6acdf24 | ||
|
|
334ac06102 | ||
|
|
2d9486ec7c | ||
|
|
fe502128b8 | ||
|
|
46f0ad6b53 | ||
|
|
fedc605956 | ||
|
|
d44e26ba22 | ||
|
|
610f234043 | ||
|
|
aa9a4c697c | ||
|
|
1b8ee3259e | ||
|
|
c7ae4940c3 | ||
|
|
aa4bf41400 | ||
|
|
4e32de09a2 | ||
|
|
86e0399ea9 | ||
|
|
302abf8480 | ||
|
|
f50b520557 | ||
|
|
d4074c7993 | ||
|
|
d3096c3b5e | ||
|
|
98947a4e52 | ||
|
|
bafb434f06 | ||
|
|
8e71a46173 | ||
|
|
934df19c52 | ||
|
|
024842a38b | ||
|
|
657929f8ec | ||
|
|
b506594c2d | ||
|
|
830135edea | ||
|
|
464cdbbb6e | ||
|
|
086e886d1e | ||
|
|
f2b82c1e1d | ||
|
|
801830df57 | ||
|
|
8b235297a5 | ||
|
|
59a3140621 | ||
|
|
16bd56ae7e | ||
|
|
750d82f1d1 | ||
|
|
139fc667aa | ||
|
|
f21e5f6cc5 | ||
|
|
f660aa9d7a | ||
|
|
d28d644b04 | ||
|
|
a634fd3a2d | ||
|
|
045794df4c | ||
|
|
dfc96e4702 | ||
|
|
8225bf01f7 | ||
|
|
116c697282 | ||
|
|
6199a89170 | ||
|
|
cbd77c9752 | ||
|
|
df9b5d8c22 | ||
|
|
66d534417b | ||
|
|
8803ab27c6 | ||
|
|
38910424f2 | ||
|
|
0076458e9d | ||
|
|
bdb1650ed8 | ||
|
|
a030ed4f39 | ||
|
|
9fc15394de | ||
|
|
34ea8770d0 | ||
|
|
a5897840a0 | ||
|
|
59087dd0ff | ||
|
|
1924481077 | ||
|
|
da1f7563e9 | ||
|
|
7496a14d2d | ||
|
|
6e6dead680 | ||
|
|
55dbbab5eb | ||
|
|
d6b6461658 | ||
|
|
85f7a4054d | ||
|
|
01965d147a | ||
|
|
6a84126c28 | ||
|
|
32f8bec92d | ||
|
|
00a6394b48 | ||
|
|
ca5a791d09 | ||
|
|
6a9c756cf0 | ||
|
|
1714d3e8ae | ||
|
|
25b7d47b34 | ||
|
|
9e8b4bae11 | ||
|
|
a466395a19 | ||
|
|
a3cb3fc490 | ||
|
|
3396778061 | ||
|
|
01cef64070 | ||
|
|
a9bfaf9e54 | ||
|
|
cec7c44f61 | ||
|
|
38ac2b39ce | ||
|
|
967e358dbc | ||
|
|
60721d2cc1 | ||
|
|
b698184939 | ||
|
|
c6c833fb9c | ||
|
|
3eb43f4619 | ||
|
|
440c159217 | ||
|
|
b49dcfbef7 | ||
|
|
a4d9cfaaeb | ||
|
|
7b2430fc3c | ||
|
|
bd8be7133d | ||
|
|
692ef0549b | ||
|
|
d6fdae5f1d | ||
|
|
8feb37df2b | ||
|
|
1d2b481069 | ||
|
|
c062fa2fa9 | ||
|
|
f444561a10 | ||
|
|
046f219a0e | ||
|
|
3cd32ed660 | ||
|
|
4f172f6f9f | ||
|
|
22fc0a6846 | ||
|
|
71e596b443 | ||
|
|
98c245ed7b | ||
|
|
bf57222e96 | ||
|
|
c075c070f0 | ||
|
|
4bc6950632 | ||
|
|
bde279c093 | ||
|
|
4f6ab8ac93 | ||
|
|
d2d82e2e5f | ||
|
|
1b2510e4b2 | ||
|
|
e735be59a7 | ||
|
|
5190539ce1 | ||
|
|
5776eb35b6 | ||
|
|
f102acd423 | ||
|
|
06486f3162 | ||
|
|
1619453b2b | ||
|
|
5a40950ffd | ||
|
|
16eb18e797 | ||
|
|
7bf0684557 | ||
|
|
961c490436 | ||
|
|
d8b0a4a288 | ||
|
|
76d12ac136 | ||
|
|
434faeecb8 | ||
|
|
ea2858b323 | ||
|
|
3391d5f846 | ||
|
|
7d6de7afe6 | ||
|
|
67ce6bd279 | ||
|
|
770db1fe02 | ||
|
|
d73394dde1 | ||
|
|
eb0c7e33d2 | ||
|
|
b9cfdaf666 | ||
|
|
5039f959e0 | ||
|
|
b7a54f8cd8 | ||
|
|
7b6435b2b8 | ||
|
|
8854c00d48 | ||
|
|
c0867b58f5 | ||
|
|
05183748a8 | ||
|
|
e56154a687 | ||
|
|
e5784c1ca8 | ||
|
|
282a9c7d7c | ||
|
|
b11ca92ca6 | ||
|
|
49846b3e68 | ||
|
|
0887824324 | ||
|
|
fbe65f2c71 | ||
|
|
eb5a412bed | ||
|
|
0cc8f68754 | ||
|
|
7079ca2718 | ||
|
|
70ad0bc573 | ||
|
|
22345c5ddf | ||
|
|
28b0a23949 | ||
|
|
1b57a796b1 | ||
|
|
0abb470022 | ||
|
|
b7a4b84f0a | ||
|
|
794a1e6cfe | ||
|
|
7c4db99d44 | ||
|
|
30b6213910 | ||
|
|
b6a27df5b9 | ||
|
|
18d514d552 | ||
|
|
f1ed08abf0 | ||
|
|
6d42dd8603 | ||
|
|
e7100e106d | ||
|
|
6402350c83 | ||
|
|
236576c124 | ||
|
|
9a83cab2f8 | ||
|
|
92706b158e | ||
|
|
ad34b26955 | ||
|
|
12c434fdc0 | ||
|
|
9ceaef6479 | ||
|
|
abb56bded2 | ||
|
|
0bcd10560a | ||
|
|
46b7148f3b | ||
|
|
37732130e1 | ||
|
|
7a3b1414cd | ||
|
|
a4a21c1dca | ||
|
|
206e597b04 | ||
|
|
ceef8ad2d8 | ||
|
|
2d581a6a86 | ||
|
|
82f7fa3887 | ||
|
|
f88a01e8c7 | ||
|
|
ca8e03b785 | ||
|
|
15932c9d7b | ||
|
|
0fc0f906e1 | ||
|
|
7f58852ec0 | ||
|
|
85a9a53e69 | ||
|
|
aa0c0fc401 | ||
|
|
0e694e08fc | ||
|
|
c2ddcc9f36 | ||
|
|
7a7cf6a5ce | ||
|
|
c2f83bd8a4 | ||
|
|
1f0e6296c6 | ||
|
|
ab1f01bacd | ||
|
|
b9b896d8e7 | ||
|
|
6be54f366c | ||
|
|
802cdb3230 | ||
|
|
7e27880cb6 | ||
|
|
d3ad85aa43 | ||
|
|
59192fc695 | ||
|
|
9095b80c5b | ||
|
|
ed5b78bf09 | ||
|
|
d6aafa3f64 | ||
|
|
8de04a808d | ||
|
|
2a299233b3 | ||
|
|
64f83c8861 | ||
|
|
1009fe3d9c | ||
|
|
ba341fe81a | ||
|
|
36e8cb6530 | ||
|
|
273da62aec | ||
|
|
41788184a7 | ||
|
|
fb9c2c7dc8 | ||
|
|
43116be122 | ||
|
|
ee038d5de5 | ||
|
|
ea7fae5277 | ||
|
|
70b108ab69 | ||
|
|
08b152d6a2 | ||
|
|
83c6213c67 | ||
|
|
4253075a97 | ||
|
|
0abdc2a350 | ||
|
|
31669f343a | ||
|
|
438b881ab4 | ||
|
|
27863146a3 | ||
|
|
cd4b73612b | ||
|
|
3c217a9e37 | ||
|
|
cde3a003ea | ||
|
|
2c35f56612 | ||
|
|
4295db25d7 | ||
|
|
3c06e57f24 | ||
|
|
e949cf5967 | ||
|
|
4eeaf34295 | ||
|
|
2212a90698 | ||
|
|
dc52b61dad | ||
|
|
bbf4c3186b | ||
|
|
f72016a78e | ||
|
|
29b587a9c5 | ||
|
|
cec4f2b140 | ||
|
|
05278c3b4c | ||
|
|
1769b8ea0f | ||
|
|
5686bd87d7 | ||
|
|
1cda2db45d | ||
|
|
fdf9640349 | ||
|
|
8f2d5d99f1 | ||
|
|
61272e7ce8 | ||
|
|
88b76f49cc | ||
|
|
ad942e352d | ||
|
|
39c2bcd462 | ||
|
|
ae10664b24 |
35
.gitignore
vendored
35
.gitignore
vendored
@@ -1,21 +1,28 @@
|
||||
.deps
|
||||
.vimrc
|
||||
*.gcda
|
||||
*.gcno
|
||||
*.o
|
||||
*.swp
|
||||
RELEASES
|
||||
Makefile
|
||||
chrony.conf.5
|
||||
chrony.info
|
||||
chrony.html
|
||||
chrony.texi
|
||||
chrony.txt
|
||||
chronyc
|
||||
chronyc.1
|
||||
chronyd
|
||||
chronyd.8
|
||||
config.h
|
||||
config.log
|
||||
*.dSYM
|
||||
*.DS_Store
|
||||
core.*
|
||||
tags
|
||||
version.h
|
||||
/RELEASES
|
||||
/Makefile
|
||||
/chronyc
|
||||
/chronyd
|
||||
/config.h
|
||||
/config.log
|
||||
/doc/Makefile
|
||||
/doc/*.html
|
||||
/doc/*.man
|
||||
/doc/*.man.in
|
||||
/doc/*.txt
|
||||
/getdate.c
|
||||
/version.h
|
||||
/test/simulation/clknetsim
|
||||
/test/simulation/tmp
|
||||
/test/unit/Makefile
|
||||
/test/unit/*.test
|
||||
/test/unit/*.o
|
||||
|
||||
140
Makefile.in
140
Makefile.in
@@ -21,66 +21,66 @@
|
||||
#
|
||||
# Makefile template
|
||||
|
||||
SYSCONFDIR=@SYSCONFDIR@
|
||||
BINDIR=@BINDIR@
|
||||
SBINDIR=@SBINDIR@
|
||||
MANDIR=@MANDIR@
|
||||
INFODIR=@INFODIR@
|
||||
DOCDIR=@DOCDIR@
|
||||
LOCALSTATEDIR=@LOCALSTATEDIR@
|
||||
CHRONYVARDIR=@CHRONYVARDIR@
|
||||
SYSCONFDIR = @SYSCONFDIR@
|
||||
BINDIR = @BINDIR@
|
||||
SBINDIR = @SBINDIR@
|
||||
LOCALSTATEDIR = @LOCALSTATEDIR@
|
||||
CHRONYVARDIR = @CHRONYVARDIR@
|
||||
DESTDIR =
|
||||
|
||||
CC = @CC@
|
||||
CFLAGS = @CFLAGS@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
|
||||
DESTDIR=
|
||||
|
||||
HASH_OBJ = @HASH_OBJ@
|
||||
|
||||
OBJS = array.o cmdparse.o conf.o local.o logging.o main.o memory.o mkdirpp.o \
|
||||
reference.o regress.o rtc.o sched.o sources.o sourcestats.o stubs.o \
|
||||
sys.o smooth.o tempcomp.o util.o $(HASH_OBJ)
|
||||
|
||||
EXTRA_OBJS=@EXTRA_OBJECTS@
|
||||
|
||||
CLI_OBJS = client.o nameserv.o getdate.o cmdparse.o \
|
||||
pktlength.o util.o $(HASH_OBJ)
|
||||
|
||||
ALL_OBJS = $(OBJS) $(EXTRA_OBJS) $(CLI_OBJS)
|
||||
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBS = @LIBS@
|
||||
|
||||
EXTRA_LIBS=@EXTRA_LIBS@
|
||||
EXTRA_CLI_LIBS=@EXTRA_CLI_LIBS@
|
||||
GETDATE_CFLAGS = @GETDATE_CFLAGS@
|
||||
|
||||
EXTRA_OBJS = @EXTRA_OBJS@
|
||||
|
||||
OBJS = addrfilt.o array.o clientlog.o cmdparse.o conf.o keys.o leapdb.o \
|
||||
local.o logging.o main.o memory.o nameserv.o nameserv_async.o \
|
||||
ntp_auth.o ntp_core.o ntp_ext.o ntp_io.o ntp_sources.o quantiles.o \
|
||||
reference.o regress.o rtc.o samplefilt.o sched.o socket.o sources.o sourcestats.o \
|
||||
stubs.o smooth.o sys.o sys_null.o tempcomp.o util.o $(EXTRA_OBJS)
|
||||
|
||||
EXTRA_CLI_OBJS = @EXTRA_CLI_OBJS@
|
||||
|
||||
CLI_OBJS = array.o client.o cmdparse.o getdate.o memory.o nameserv.o \
|
||||
pktlength.o socket.o util.o $(EXTRA_CLI_OBJS)
|
||||
|
||||
ALL_OBJS = $(OBJS) $(CLI_OBJS)
|
||||
|
||||
LIBS = @LIBS@
|
||||
EXTRA_LIBS = @EXTRA_LIBS@
|
||||
EXTRA_CLI_LIBS = @EXTRA_CLI_LIBS@
|
||||
|
||||
# Until we have a main procedure we can link, just build object files
|
||||
# to test compilation
|
||||
|
||||
all : chronyd chronyc
|
||||
|
||||
chronyd : $(OBJS) $(EXTRA_OBJS)
|
||||
$(CC) $(CFLAGS) -o chronyd $(OBJS) $(EXTRA_OBJS) $(LDFLAGS) $(LIBS) $(EXTRA_LIBS)
|
||||
chronyd : $(OBJS)
|
||||
$(CC) $(CFLAGS) -o chronyd $(OBJS) $(LDFLAGS) $(LIBS) $(EXTRA_LIBS)
|
||||
|
||||
chronyc : $(CLI_OBJS)
|
||||
$(CC) $(CFLAGS) -o chronyc $(CLI_OBJS) $(LDFLAGS) $(LIBS) $(EXTRA_CLI_LIBS)
|
||||
|
||||
client.o : client.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) @READLINE_COMPILE@ -c $<
|
||||
|
||||
$(HASH_OBJ) : $(patsubst %.o,%.c,$(HASH_OBJ))
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) @HASH_COMPILE@ -c $<
|
||||
getdate.o: CFLAGS += $(GETDATE_CFLAGS)
|
||||
|
||||
distclean : clean
|
||||
-rm -f Makefile
|
||||
-rm -f chrony.conf.5 chrony.texi chronyc.1 chronyd.8
|
||||
$(MAKE) -C doc distclean
|
||||
$(MAKE) -C test/unit distclean
|
||||
-rm -f .DS_Store
|
||||
-rm -f Makefile config.h config.log
|
||||
|
||||
clean :
|
||||
-rm -f *.o *.s chronyc chronyd core *~ chrony.info chrony.html chrony.txt
|
||||
$(MAKE) -C test/unit clean
|
||||
-rm -f *.o *.s chronyc chronyd core.* *~
|
||||
-rm -f *.gcda *.gcno
|
||||
-rm -rf .deps
|
||||
-rm -rf *.dSYM
|
||||
|
||||
getdate.c :
|
||||
getdate.c : getdate.y
|
||||
bison -o getdate.c getdate.y
|
||||
|
||||
# This can be used to force regeneration of getdate.c
|
||||
@@ -90,15 +90,10 @@ getdate :
|
||||
# For install, don't use the install command, because its switches
|
||||
# seem to vary between systems.
|
||||
|
||||
install: chronyd chronyc chrony.txt
|
||||
install: chronyd chronyc
|
||||
[ -d $(DESTDIR)$(SYSCONFDIR) ] || mkdir -p $(DESTDIR)$(SYSCONFDIR)
|
||||
[ -d $(DESTDIR)$(SBINDIR) ] || mkdir -p $(DESTDIR)$(SBINDIR)
|
||||
[ -d $(DESTDIR)$(BINDIR) ] || mkdir -p $(DESTDIR)$(BINDIR)
|
||||
[ -d $(DESTDIR)$(DOCDIR) ] || mkdir -p $(DESTDIR)$(DOCDIR)
|
||||
[ -d $(DESTDIR)$(MANDIR)/man1 ] || mkdir -p $(DESTDIR)$(MANDIR)/man1
|
||||
[ -d $(DESTDIR)$(MANDIR)/man5 ] || mkdir -p $(DESTDIR)$(MANDIR)/man5
|
||||
[ -d $(DESTDIR)$(MANDIR)/man8 ] || mkdir -p $(DESTDIR)$(MANDIR)/man8
|
||||
[ -d $(DESTDIR)$(DOCDIR) ] || mkdir -p $(DESTDIR)$(DOCDIR)
|
||||
[ -d $(DESTDIR)$(CHRONYVARDIR) ] || mkdir -p $(DESTDIR)$(CHRONYVARDIR)
|
||||
if [ -f $(DESTDIR)$(SBINDIR)/chronyd ]; then rm -f $(DESTDIR)$(SBINDIR)/chronyd ; fi
|
||||
if [ -f $(DESTDIR)$(BINDIR)/chronyc ]; then rm -f $(DESTDIR)$(BINDIR)/chronyc ; fi
|
||||
@@ -106,20 +101,13 @@ install: chronyd chronyc chrony.txt
|
||||
chmod 755 $(DESTDIR)$(SBINDIR)/chronyd
|
||||
cp chronyc $(DESTDIR)$(BINDIR)/chronyc
|
||||
chmod 755 $(DESTDIR)$(BINDIR)/chronyc
|
||||
cp chrony.txt $(DESTDIR)$(DOCDIR)/chrony.txt
|
||||
chmod 644 $(DESTDIR)$(DOCDIR)/chrony.txt
|
||||
cp COPYING $(DESTDIR)$(DOCDIR)/COPYING
|
||||
chmod 644 $(DESTDIR)$(DOCDIR)/COPYING
|
||||
cp README $(DESTDIR)$(DOCDIR)/README
|
||||
chmod 644 $(DESTDIR)$(DOCDIR)/README
|
||||
cp chrony.1 $(DESTDIR)$(MANDIR)/man1
|
||||
chmod 644 $(DESTDIR)$(MANDIR)/man1/chrony.1
|
||||
cp chronyc.1 $(DESTDIR)$(MANDIR)/man1
|
||||
chmod 644 $(DESTDIR)$(MANDIR)/man1/chronyc.1
|
||||
cp chronyd.8 $(DESTDIR)$(MANDIR)/man8
|
||||
chmod 644 $(DESTDIR)$(MANDIR)/man8/chronyd.8
|
||||
cp chrony.conf.5 $(DESTDIR)$(MANDIR)/man5
|
||||
chmod 644 $(DESTDIR)$(MANDIR)/man5/chrony.conf.5
|
||||
$(MAKE) -C doc install
|
||||
|
||||
docs :
|
||||
$(MAKE) -C doc docs
|
||||
|
||||
install-docs :
|
||||
$(MAKE) -C doc install-docs
|
||||
|
||||
%.o : %.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -c $<
|
||||
@@ -127,30 +115,24 @@ install: chronyd chronyc chrony.txt
|
||||
%.s : %.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -S $<
|
||||
|
||||
check : chronyd chronyc
|
||||
quickcheck : chronyd chronyc
|
||||
$(MAKE) -C test/unit check
|
||||
cd test/simulation && ./run
|
||||
cd test/system && ./run
|
||||
|
||||
install-docs : docs
|
||||
[ -d $(DESTDIR)$(DOCDIR) ] || mkdir -p $(DESTDIR)$(DOCDIR)
|
||||
cp chrony.txt $(DESTDIR)$(DOCDIR)/chrony.txt
|
||||
chmod 644 $(DESTDIR)$(DOCDIR)/chrony.txt
|
||||
cp chrony.html $(DESTDIR)$(DOCDIR)/chrony.html
|
||||
chmod 644 $(DESTDIR)$(DOCDIR)/chrony.html
|
||||
[ -d $(DESTDIR)$(INFODIR) ] || mkdir -p $(DESTDIR)$(INFODIR)
|
||||
cp chrony.info* $(DESTDIR)$(INFODIR)
|
||||
chmod 644 $(DESTDIR)$(INFODIR)/chrony.info*
|
||||
check : chronyd chronyc
|
||||
$(MAKE) -C test/unit check
|
||||
cd test/simulation && ./run -i 20 -m 2
|
||||
cd test/system && ./run
|
||||
|
||||
docs : chrony.txt chrony.html chrony.info
|
||||
print-chronyd-objects :
|
||||
@echo $(OBJS)
|
||||
|
||||
chrony.txt : chrony.texi
|
||||
makeinfo --no-headers --number-sections -o chrony.txt chrony.texi
|
||||
|
||||
chrony.html : chrony.texi
|
||||
command -v texi2html > /dev/null 2>&1 && texi2html chrony.texi || \
|
||||
makeinfo --no-split --html --number-sections -o chrony.html chrony.texi
|
||||
|
||||
chrony.info : chrony.texi
|
||||
makeinfo chrony.texi
|
||||
Makefile : Makefile.in configure
|
||||
@echo
|
||||
@echo Makefile needs to be regenerated, run ./configure
|
||||
@echo
|
||||
@exit 1
|
||||
|
||||
.deps:
|
||||
@mkdir .deps
|
||||
@@ -158,4 +140,6 @@ chrony.info : chrony.texi
|
||||
.deps/%.d: %.c | .deps
|
||||
@$(CC) -MM $(CPPFLAGS) -MT '$(<:%.c=%.o) $@' $< -o $@
|
||||
|
||||
ifndef NODEPS
|
||||
-include $(ALL_OBJS:%.o=.deps/%.d)
|
||||
endif
|
||||
|
||||
533
NEWS
533
NEWS
@@ -1,3 +1,531 @@
|
||||
New in version 4.8
|
||||
==================
|
||||
|
||||
Enhancements
|
||||
------------
|
||||
* Add maxunreach option to limit selection of unreachable sources
|
||||
* Add -u option to chronyc to drop root privileges (default chronyc
|
||||
user is set by configure script)
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Hide chronyc socket to mitigate unsafe permissions change
|
||||
* Fix refclock extpps option to work on Linux >= 6.15
|
||||
* Validate refclock samples for reachability updates
|
||||
|
||||
New in version 4.7
|
||||
==================
|
||||
|
||||
Enhancements
|
||||
------------
|
||||
* Add opencommands directive to select remote monitoring commands
|
||||
* Add interval option to driftfile directive
|
||||
* Add waitsynced and waitunsynced options to local directive
|
||||
* Add sanity checks for integer values in configuration
|
||||
* Add support for systemd Type=notify service
|
||||
* Add RTC refclock driver
|
||||
* Allow PHC refclock to be specified with network interface name
|
||||
* Don't require multiple refclock samples per poll to simplify
|
||||
filter configuration
|
||||
* Keep refclock reachable when dropping samples with large delay
|
||||
* Improve quantile-based filtering to adapt faster to larger delay
|
||||
* Improve logging of selection failures
|
||||
* Detect clock interference from other processes
|
||||
* Try to reopen message log (-l option) on cyclelogs command
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Fix sourcedir reloading to not multiply sources
|
||||
* Fix tracking offset after failed clock step
|
||||
|
||||
Removed features
|
||||
----------------
|
||||
* Drop support for NTS with Nettle < 3.6 and GnuTLS < 3.6.14
|
||||
* Drop support for building without POSIX threads
|
||||
|
||||
New in version 4.6.1
|
||||
====================
|
||||
|
||||
Enhancements
|
||||
------------
|
||||
* Add ntsaeads directive to enable only selected AEAD algorithms for NTS
|
||||
|
||||
Workarounds
|
||||
-----------
|
||||
* Negotiate use of compliant NTS keys with AES-128-GCM-SIV AEAD algorithm
|
||||
(by default the keys are generated differently than in RFC 8915 for
|
||||
compatibility with chrony server and client versions 4.4, 4.5, and 4.6)
|
||||
* Switch to compliant NTS keys if first response from server is NTS NAK
|
||||
|
||||
New in version 4.6
|
||||
==================
|
||||
|
||||
Enhancements
|
||||
------------
|
||||
* Add activate option to local directive to set activation threshold
|
||||
* Add ipv4 and ipv6 options to server/pool/peer directive
|
||||
* Add kod option to ratelimit directive for server KoD RATE support
|
||||
* Add leapseclist directive to read NIST/IERS leap-seconds.list file
|
||||
* Add ptpdomain directive to set PTP domain for NTP over PTP
|
||||
* Allow disabling pidfile
|
||||
* Improve copy server option to accept unsynchronised status instantly
|
||||
* Log one selection failure on start
|
||||
* Add offset command to modify source offset correction
|
||||
* Add timestamp sources to ntpdata report
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Fix crash on sources reload during initstepslew or RTC initialisation
|
||||
* Fix source refreshment to not repeat failed name resolving attempts
|
||||
|
||||
New in version 4.5
|
||||
==================
|
||||
|
||||
Enhancements
|
||||
------------
|
||||
* Add support for AES-GCM-SIV in GnuTLS
|
||||
* Add support for corrections from PTP transparent clocks
|
||||
* Add support for systemd socket activation
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Fix presend in interleaved mode
|
||||
* Fix reloading of modified sources from sourcedir
|
||||
|
||||
New in version 4.4
|
||||
==================
|
||||
|
||||
Enhancements
|
||||
------------
|
||||
* Add support for AES-GCM-SIV with Nettle >= 3.9 to shorten NTS
|
||||
cookies to avoid some length-specific blocking of NTP on Internet
|
||||
* Add support for multiple refclocks using extpps option on one PHC
|
||||
* Add maxpoll option to hwtimestamp directive to improve PHC tracking
|
||||
with low packet rates
|
||||
* Add hwtstimeout directive to configure timeout for late timestamps
|
||||
* Handle late hardware transmit timestamps of NTP requests on all sockets
|
||||
* Handle mismatched 32/64-bit time_t in SOCK refclock samples
|
||||
* Improve source replacement
|
||||
* Log important changes made by command requests (chronyc)
|
||||
* Refresh address of NTP sources periodically
|
||||
* Request nanosecond kernel RX timestamping on FreeBSD
|
||||
* Set DSCP for IPv6 packets
|
||||
* Shorten NTS-KE retry interval when network is down
|
||||
* Update seccomp filter for musl
|
||||
* Warn if loading keys from file with unexpected permissions
|
||||
* Warn if source selection fails or falseticker is detected
|
||||
* Add selectopts command to modify source-specific selection options
|
||||
* Add timestamp sources to serverstats report and make its fields 64-bit
|
||||
* Add -e option to chronyc to indicate end of response
|
||||
|
||||
New in version 4.3
|
||||
==================
|
||||
|
||||
Enhancements
|
||||
------------
|
||||
* Add local option to refclock directive to stabilise system clock
|
||||
with more stable free-running clock (e.g. TCXO, OCXO)
|
||||
* Add maxdelayquant option to server/pool/peer directive to replace
|
||||
maxdelaydevratio filter with long-term quantile-based filtering
|
||||
* Add selection option to log directive
|
||||
* Allow external PPS in PHC refclock without configurable pin
|
||||
* Don't accept first interleaved response to minimise error in delay
|
||||
* Don't use arc4random on Linux to avoid server performance loss
|
||||
* Improve filter option to better handle missing NTP samples
|
||||
* Improve stability with hardware timestamping and PHC refclock
|
||||
* Update seccomp filter
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Fix waitsync command to reconnect when not getting response
|
||||
|
||||
New in version 4.2
|
||||
==================
|
||||
|
||||
Enhancements
|
||||
------------
|
||||
* Add support for NTPv4 extension field improving synchronisation
|
||||
stability and resolution of root delay and dispersion (experimental)
|
||||
* Add support for NTP over PTP (experimental)
|
||||
* Add support for AES-CMAC and hash functions in GnuTLS
|
||||
* Improve server interleaved mode to be more reliable and support
|
||||
multiple clients behind NAT
|
||||
* Update seccomp filter
|
||||
* Add statistics about interleaved mode to serverstats report
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Fix RTC support with 64-bit time_t on 32-bit Linux
|
||||
* Fix seccomp filter to work correctly with bind*device directives
|
||||
* Suppress kernel adjustments of system clock (dosynctodr) on illumos
|
||||
|
||||
Other changes
|
||||
-------------
|
||||
* Switch Solaris support to illumos
|
||||
|
||||
New in version 4.1
|
||||
==================
|
||||
|
||||
Enhancements
|
||||
------------
|
||||
* Add support for NTS servers specified by IP address (matching
|
||||
Subject Alternative Name in server certificate)
|
||||
* Add source-specific configuration of trusted certificates
|
||||
* Allow multiple files and directories with trusted certificates
|
||||
* Allow multiple pairs of server keys and certificates
|
||||
* Add copy option to server/pool directive
|
||||
* Increase PPS lock limit to 40% of pulse interval
|
||||
* Perform source selection immediately after loading dump files
|
||||
* Reload dump files for addresses negotiated by NTS-KE server
|
||||
* Update seccomp filter and add less restrictive level
|
||||
* Restart ongoing name resolution on online command
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Fix responding to IPv4 command requests on FreeBSD
|
||||
* Fix dump files to not include uncorrected offset
|
||||
* Fix initstepslew to accept time from own NTP clients
|
||||
* Reset NTP address and port when no longer negotiated by NTS-KE server
|
||||
|
||||
New in version 4.0
|
||||
==================
|
||||
|
||||
Enhancements
|
||||
------------
|
||||
* Add support for Network Time Security (NTS) authentication
|
||||
* Add support for AES-CMAC keys (AES128, AES256) with Nettle
|
||||
* Add authselectmode directive to control selection of unauthenticated sources
|
||||
* Add binddevice, bindacqdevice, bindcmddevice directives
|
||||
* Add confdir directive to better support fragmented configuration
|
||||
* Add sourcedir directive and "reload sources" command to support dynamic
|
||||
NTP sources specified in files
|
||||
* Add clockprecision directive
|
||||
* Add dscp directive to set Differentiated Services Code Point (DSCP)
|
||||
* Add -L option to limit log messages by severity
|
||||
* Add -p option to print whole configuration with included files
|
||||
* Add -U option to allow start under non-root user
|
||||
* Allow maxsamples to be set to 1 for faster update with -q/-Q option
|
||||
* Avoid replacing NTP sources with sources that have unreachable address
|
||||
* Improve pools to repeat name resolution to get "maxsources" sources
|
||||
* Improve source selection with trusted sources
|
||||
* Improve NTP loop test to prevent synchronisation to itself
|
||||
* Repeat iburst when NTP source is switched from offline state to online
|
||||
* Update clock synchronisation status and leap status more frequently
|
||||
* Update seccomp filter
|
||||
* Add "add pool" command
|
||||
* Add "reset sources" command to drop all measurements
|
||||
* Add authdata command to print details about NTP authentication
|
||||
* Add selectdata command to print details about source selection
|
||||
* Add -N option and sourcename command to print original names of sources
|
||||
* Add -a option to some commands to print also unresolved sources
|
||||
* Add -k, -p, -r options to clients command to select, limit, reset data
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Don't set interface for NTP responses to allow asymmetric routing
|
||||
* Handle RTCs that don't support interrupts
|
||||
* Respond to command requests with correct address on multihomed hosts
|
||||
|
||||
Removed features
|
||||
----------------
|
||||
* Drop support for RIPEMD keys (RMD128, RMD160, RMD256, RMD320)
|
||||
* Drop support for long (non-standard) MACs in NTPv4 packets (chrony 2.x
|
||||
clients using non-MD5/SHA1 keys need to use option "version 3")
|
||||
* Drop support for line editing with GNU Readline
|
||||
|
||||
New in version 3.5.1
|
||||
====================
|
||||
|
||||
Security fixes
|
||||
--------------
|
||||
* Create new file when writing pidfile (CVE-2020-14367)
|
||||
|
||||
New in version 3.5
|
||||
==================
|
||||
|
||||
Enhancements
|
||||
------------
|
||||
* Add support for more accurate reading of PHC on Linux 5.0
|
||||
* Add support for hardware timestamping on interfaces with read-only
|
||||
timestamping configuration
|
||||
* Add support for memory locking and real-time priority on FreeBSD,
|
||||
NetBSD, Solaris
|
||||
* Update seccomp filter to work on more architectures
|
||||
* Validate refclock driver options
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Fix bindaddress directive on FreeBSD
|
||||
* Fix transposition of hardware RX timestamp on Linux 4.13 and later
|
||||
* Fix building on non-glibc systems
|
||||
|
||||
New in version 3.4
|
||||
==================
|
||||
|
||||
Enhancements
|
||||
------------
|
||||
* Add filter option to server/pool/peer directive
|
||||
* Add minsamples and maxsamples options to hwtimestamp directive
|
||||
* Add support for faster frequency adjustments in Linux 4.19
|
||||
* Change default pidfile to /var/run/chrony/chronyd.pid to allow
|
||||
chronyd without root privileges to remove it on exit
|
||||
* Disable sub-second polling intervals for distant NTP sources
|
||||
* Extend range of supported sub-second polling intervals
|
||||
* Get/set IPv4 destination/source address of NTP packets on FreeBSD
|
||||
* Make burst options and command useful with short polling intervals
|
||||
* Modify auto_offline option to activate when sending request failed
|
||||
* Respond from interface that received NTP request if possible
|
||||
* Add onoffline command to switch between online and offline state
|
||||
according to current system network configuration
|
||||
* Improve example NetworkManager dispatcher script
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Avoid waiting in Linux getrandom system call
|
||||
* Fix PPS support on FreeBSD and NetBSD
|
||||
|
||||
New in version 3.3
|
||||
==================
|
||||
|
||||
Enhancements
|
||||
------------
|
||||
* Add burst option to server/pool directive
|
||||
* Add stratum and tai options to refclock directive
|
||||
* Add support for Nettle crypto library
|
||||
* Add workaround for missing kernel receive timestamps on Linux
|
||||
* Wait for late hardware transmit timestamps
|
||||
* Improve source selection with unreachable sources
|
||||
* Improve protection against replay attacks on symmetric mode
|
||||
* Allow PHC refclock to use socket in /var/run/chrony
|
||||
* Add shutdown command to stop chronyd
|
||||
* Simplify format of response to manual list command
|
||||
* Improve handling of unknown responses in chronyc
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Respond to NTPv1 client requests with zero mode
|
||||
* Fix -x option to not require CAP_SYS_TIME under non-root user
|
||||
* Fix acquisitionport directive to work with privilege separation
|
||||
* Fix handling of socket errors on Linux to avoid high CPU usage
|
||||
* Fix chronyc to not get stuck in infinite loop after clock step
|
||||
|
||||
New in version 3.2
|
||||
==================
|
||||
|
||||
Enhancements
|
||||
------------
|
||||
* Improve stability with NTP sources and reference clocks
|
||||
* Improve stability with hardware timestamping
|
||||
* Improve support for NTP interleaved modes
|
||||
* Control frequency of system clock on macOS 10.13 and later
|
||||
* Set TAI-UTC offset of system clock with leapsectz directive
|
||||
* Minimise data in client requests to improve privacy
|
||||
* Allow transmit-only hardware timestamping
|
||||
* Add support for new timestamping options introduced in Linux 4.13
|
||||
* Add root delay, root dispersion and maximum error to tracking log
|
||||
* Add mindelay and asymmetry options to server/peer/pool directive
|
||||
* Add extpps option to PHC refclock to timestamp external PPS signal
|
||||
* Add pps option to refclock directive to treat any refclock as PPS
|
||||
* Add width option to refclock directive to filter wrong pulse edges
|
||||
* Add rxfilter option to hwtimestamp directive
|
||||
* Add -x option to disable control of system clock
|
||||
* Add -l option to log to specified file instead of syslog
|
||||
* Allow multiple command-line options to be specified together
|
||||
* Allow starting without root privileges with -Q option
|
||||
* Update seccomp filter for new glibc versions
|
||||
* Dump history on exit by default with dumpdir directive
|
||||
* Use hardening compiler options by default
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Don't drop PHC samples with low-resolution system clock
|
||||
* Ignore outliers in PHC tracking, RTC tracking, manual input
|
||||
* Increase polling interval when peer is not responding
|
||||
* Exit with error message when include directive fails
|
||||
* Don't allow slash after hostname in allow/deny directive/command
|
||||
* Try to connect to all addresses in chronyc before giving up
|
||||
|
||||
New in version 3.1
|
||||
==================
|
||||
|
||||
Enhancements
|
||||
------------
|
||||
* Add support for precise cross timestamping of PHC on Linux
|
||||
* Add minpoll, precision, nocrossts options to hwtimestamp directive
|
||||
* Add rawmeasurements option to log directive and modify measurements
|
||||
option to log only valid measurements from synchronised sources
|
||||
* Allow sub-second polling interval with NTP sources
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Fix time smoothing in interleaved mode
|
||||
|
||||
New in version 3.0
|
||||
==================
|
||||
|
||||
Enhancements
|
||||
------------
|
||||
* Add support for software and hardware timestamping on Linux
|
||||
* Add support for client/server and symmetric interleaved modes
|
||||
* Add support for MS-SNTP authentication in Samba
|
||||
* Add support for truncated MACs in NTPv4 packets
|
||||
* Estimate and correct for asymmetric network jitter
|
||||
* Increase default minsamples and polltarget to improve stability
|
||||
with very low jitter
|
||||
* Add maxjitter directive to limit source selection by jitter
|
||||
* Add offset option to server/pool/peer directive
|
||||
* Add maxlockage option to refclock directive
|
||||
* Add -t option to chronyd to exit after specified time
|
||||
* Add partial protection against replay attacks on symmetric mode
|
||||
* Don't reset polling interval when switching sources to online state
|
||||
* Allow rate limiting with very short intervals
|
||||
* Improve maximum server throughput on Linux and NetBSD
|
||||
* Remove dump files after start
|
||||
* Add tab-completion to chronyc with libedit/readline
|
||||
* Add ntpdata command to print details about NTP measurements
|
||||
* Allow all source options to be set in add server/peer command
|
||||
* Indicate truncated addresses/hostnames in chronyc output
|
||||
* Print reference IDs as hexadecimal numbers to avoid confusion with
|
||||
IPv4 addresses
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Fix crash with disabled asynchronous name resolving
|
||||
|
||||
New in version 2.4.1
|
||||
====================
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Fix processing of kernel timestamps on non-Linux systems
|
||||
* Fix crash with smoothtime directive
|
||||
* Fix validation of refclock sample times
|
||||
* Fix parsing of refclock directive
|
||||
|
||||
New in version 2.4
|
||||
==================
|
||||
|
||||
Enhancements
|
||||
------------
|
||||
* Add orphan option to local directive for orphan mode compatible with ntpd
|
||||
* Add distance option to local directive to set activation threshold
|
||||
(1 second by default)
|
||||
* Add maxdrift directive to set maximum allowed drift of system clock
|
||||
* Try to replace NTP sources exceeding maximum distance
|
||||
* Randomise source replacement to avoid getting stuck with bad sources
|
||||
* Randomise selection of sources from pools on start
|
||||
* Ignore reference timestamp as ntpd doesn't always set it correctly
|
||||
* Modify tracking report to use same values as seen by NTP clients
|
||||
* Add -c option to chronyc to write reports in CSV format
|
||||
* Provide detailed manual pages
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Fix SOCK refclock to work correctly when not specified as last refclock
|
||||
* Fix initstepslew and -q/-Q options to accept time from own NTP clients
|
||||
* Fix authentication with keys using 512-bit hash functions
|
||||
* Fix crash on exit when multiple signals are received
|
||||
* Fix conversion of very small floating-point numbers in command packets
|
||||
|
||||
Removed features
|
||||
----------------
|
||||
* Drop documentation in Texinfo format
|
||||
|
||||
New in version 2.3
|
||||
==================
|
||||
|
||||
Enhancements
|
||||
------------
|
||||
* Add support for NTP and command response rate limiting
|
||||
* Add support for dropping root privileges on Mac OS X, FreeBSD, Solaris
|
||||
* Add require and trust options for source selection
|
||||
* Enable logchange by default (1 second threshold)
|
||||
* Set RTC on Mac OS X with rtcsync directive
|
||||
* Allow binding to NTP port after dropping root privileges on NetBSD
|
||||
* Drop CAP_NET_BIND_SERVICE capability on Linux when NTP port is disabled
|
||||
* Resolve names in separate process when seccomp filter is enabled
|
||||
* Replace old records in client log when memory limit is reached
|
||||
* Don't reveal local time and synchronisation state in client packets
|
||||
* Don't keep client sockets open for longer than necessary
|
||||
* Ignore poll in KoD RATE packets as ntpd doesn't always set it correctly
|
||||
* Warn when using keys shorter than 80 bits
|
||||
* Add keygen command to generate random keys easily
|
||||
* Add serverstats command to report NTP and command packet statistics
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Fix clock correction after making step on Mac OS X
|
||||
* Fix building on Solaris
|
||||
|
||||
New in version 2.2.1
|
||||
====================
|
||||
|
||||
Security fixes
|
||||
--------------
|
||||
* Restrict authentication of NTP server/peer to specified key (CVE-2016-1567)
|
||||
|
||||
New in version 2.2
|
||||
==================
|
||||
|
||||
Enhancements
|
||||
------------
|
||||
* Add support for configuration and monitoring over Unix domain socket
|
||||
(accessible by root or chrony user when root privileges are dropped)
|
||||
* Add support for system call filtering with seccomp on Linux (experimental)
|
||||
* Add support for dropping root privileges on NetBSD
|
||||
* Control frequency of system clock on FreeBSD, NetBSD, Solaris
|
||||
* Add system leap second handling mode on FreeBSD, NetBSD, Solaris
|
||||
* Add dynamic drift removal on Mac OS X
|
||||
* Add support for setting real-time priority on Mac OS X
|
||||
* Add maxdistance directive to limit source selection by root distance
|
||||
(3 seconds by default)
|
||||
* Add refresh command to get new addresses of NTP sources
|
||||
* Allow wildcard patterns in include directive
|
||||
* Restore time from driftfile with -s option if later than RTC time
|
||||
* Add configure option to set default hwclockfile
|
||||
* Add -d option to chronyc to enable debug messages
|
||||
* Allow multiple addresses to be specified for chronyc with -h option
|
||||
and reconnect when no valid reply is received
|
||||
* Make check interval in waitsync command configurable
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Fix building on NetBSD, Solaris
|
||||
* Restore time from driftfile with -s option if reading RTC failed
|
||||
|
||||
Removed features
|
||||
----------------
|
||||
* Drop support for authentication with command key (run-time configuration
|
||||
is now allowed only for local users that can access the Unix domain socket)
|
||||
|
||||
New in version 2.1.1
|
||||
====================
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Fix clock stepping by integer number of seconds on Linux
|
||||
|
||||
New in version 2.1
|
||||
==================
|
||||
|
||||
Enhancements
|
||||
------------
|
||||
* Add support for Mac OS X
|
||||
* Try to replace unreachable and falseticker servers/peers specified
|
||||
by name like pool sources
|
||||
* Add leaponly option to smoothtime directive to allow synchronised
|
||||
leap smear between multiple servers
|
||||
* Use specific reference ID when smoothing served time
|
||||
* Add smoothing command to report time smoothing status
|
||||
* Add smoothtime command to activate or reset time smoothing
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Fix crash in source selection with preferred sources
|
||||
* Fix resetting of time smoothing
|
||||
* Include packet precision in peer dispersion
|
||||
* Fix crash in chronyc on invalid command syntax
|
||||
|
||||
New in version 2.0
|
||||
==================
|
||||
|
||||
@@ -15,7 +543,7 @@ Enhancements
|
||||
* Improve source selection
|
||||
* Handle offline sources as unreachable
|
||||
* Open NTP server port only when necessary (client access is allowed by
|
||||
allow directive/command, peer or broadcast is configured)
|
||||
allow directive/command or peer/broadcast is configured)
|
||||
* Change default bindcmdaddress to loopback address
|
||||
* Change default maxdelay to 3 seconds
|
||||
* Change default stratumweight to 0.001
|
||||
@@ -30,6 +558,7 @@ Bug fixes
|
||||
---------
|
||||
* Add sanity checks for time and frequency offset
|
||||
* Don't report synchronised status during leap second
|
||||
* Don't combine reference clocks with close NTP sources
|
||||
* Fix accepting requests from configured sources
|
||||
* Fix initial fallback drift setting
|
||||
|
||||
@@ -39,7 +568,7 @@ New in version 1.31.1
|
||||
Security fixes
|
||||
--------------
|
||||
* Protect authenticated symmetric NTP associations against DoS attacks
|
||||
(CVE-2015-1799)
|
||||
(CVE-2015-1853)
|
||||
* Fix access configuration with subnet size indivisible by 4 (CVE-2015-1821)
|
||||
* Fix initialization of reply slots for authenticated commands (CVE-2015-1822)
|
||||
|
||||
|
||||
277
README
277
README
@@ -3,249 +3,148 @@ This is the README for chrony.
|
||||
What is chrony?
|
||||
===============
|
||||
|
||||
Chrony is a pair of programs for maintaining the accuracy of computer
|
||||
clocks.
|
||||
chrony is a versatile implementation of the Network Time Protocol (NTP).
|
||||
It can synchronise the system clock with NTP servers, reference clocks
|
||||
(e.g. GPS receiver), and manual input using wristwatch and keyboard.
|
||||
It can also operate as an NTPv4 (RFC 5905) server and peer to provide
|
||||
a time service to other computers in the network.
|
||||
|
||||
chronyd is a (background) daemon program that can be started at boot
|
||||
time. This does most of the work.
|
||||
It is designed to perform well in a wide range of conditions, including
|
||||
intermittent network connections, heavily congested networks, changing
|
||||
temperatures (ordinary computer clocks are sensitive to temperature),
|
||||
and systems that do not run continuously, or run on a virtual machine.
|
||||
|
||||
chronyc is a command-line interface program which can be used to
|
||||
monitor chronyd's performance and to change various operating
|
||||
parameters whilst it is running.
|
||||
|
||||
chronyd's main function is to obtain measurements of the true (UTC)
|
||||
time from one of several sources, and correct the system clock
|
||||
accordingly. It also works out the rate at which the system clock
|
||||
gains or loses time and uses this information to keep it accurate
|
||||
between measurements from the reference.
|
||||
|
||||
The reference time can be derived from Network Time Protocol (NTP)
|
||||
servers, reference clocks, or wristwatch-and-keyboard (via chronyc).
|
||||
The main source of information about the Network Time Protocol is
|
||||
http://www.ntp.org.
|
||||
|
||||
It is designed so that it can work on computers which only have
|
||||
intermittent access to reference sources, for example computers which
|
||||
use a dial-up account to access the Internet or laptops. Of course, it
|
||||
will work well on computers with permanent connections too.
|
||||
|
||||
In addition, on Linux it can monitor the system's real time clock
|
||||
performance, so the system can maintain accurate time even across
|
||||
reboots.
|
||||
|
||||
Typical accuracies available between 2 machines are
|
||||
|
||||
On an ethernet LAN : 100-200 microseconds, often much better
|
||||
On a V32bis dial-up modem connection : 10's of milliseconds (from one
|
||||
session to the next)
|
||||
|
||||
With a good reference clock the accuracy can reach one microsecond.
|
||||
|
||||
chronyd can also operate as an NTPv4 (RFC 5905) server, peer and broadcast
|
||||
server.
|
||||
Typical accuracy between two machines synchronised over the Internet is
|
||||
within a few milliseconds; on a LAN, accuracy is typically in tens of
|
||||
microseconds. With hardware timestamping, or a hardware reference clock,
|
||||
sub-microsecond accuracy may be possible.
|
||||
|
||||
Two programs are included in chrony, chronyd is a daemon that can be
|
||||
started at boot time and chronyc is a command-line interface program
|
||||
which can be used to monitor chronyd's performance and to change various
|
||||
operating parameters whilst it is running.
|
||||
|
||||
What will chrony run on?
|
||||
========================
|
||||
|
||||
Chrony can be successfully built and run on
|
||||
|
||||
1. Linux 2.2.x, 2.3.x, 2.4.x, 2.6.x, 3.x
|
||||
|
||||
2. Solaris 2.5/2.5.1/2.6/2.7/2.8 (various platforms)
|
||||
|
||||
3. SunOS 4.1.4 (Sparc 2 and Sparc 20)
|
||||
|
||||
4. BSD/386 v1.1 has been reported to work using the SunOS 4.1 driver.
|
||||
|
||||
5. NetBSD.
|
||||
|
||||
Any other system will require a porting exercise. You would need to
|
||||
start from one of the existing system-specific drivers and look into
|
||||
the quirks of certain system calls and the kernel on your target
|
||||
system.
|
||||
The software is known to work on Linux, FreeBSD, NetBSD, macOS and
|
||||
illumos. Closely related systems may work too. Any other system will
|
||||
likely require a porting exercise.
|
||||
|
||||
How do I set it up?
|
||||
===================
|
||||
|
||||
The file INSTALL gives instructions. On supported systems the
|
||||
compilation process should be automatic.
|
||||
|
||||
You will need an ANSI C compiler -- gcc is recommended.
|
||||
|
||||
The manual (in texinfo and text formats) describes how to set the
|
||||
software up for the less straightforward cases.
|
||||
compilation process should be automatic. You will need a C compiler,
|
||||
e.g. gcc or clang.
|
||||
|
||||
What documentation is there?
|
||||
============================
|
||||
|
||||
A manual is supplied in Texinfo format (chrony.texi) and
|
||||
ready-formatted plain text (chrony.txt) in the distribution.
|
||||
The distribution includes manual pages and a document containing
|
||||
Frequently Asked Questions (FAQ).
|
||||
|
||||
There is also information available on the chrony web pages, accessible
|
||||
The documentation is also available on the chrony web pages, accessible
|
||||
through the URL
|
||||
|
||||
http://chrony.tuxfamily.org/
|
||||
https://chrony-project.org/
|
||||
|
||||
Where are new versions announced?
|
||||
=================================
|
||||
License
|
||||
=======
|
||||
|
||||
There is a low volume mailing list where new versions and other
|
||||
important news relating to chrony is announced. You can join this list
|
||||
by sending mail with the subject "subscribe" to
|
||||
chrony is distributed under the GNU General Public License version 2.
|
||||
|
||||
chrony-announce-request@chrony.tuxfamily.org
|
||||
|
||||
These messages will be copied to chrony-users (see below).
|
||||
|
||||
How can I get support for chrony?
|
||||
and where can I discuss new features, possible bugs etc?
|
||||
========================================================
|
||||
|
||||
There are 3 mailing lists relating to chrony. chrony-announce was
|
||||
mentioned above. chrony-users is a users' discussion list, e.g. for
|
||||
general questions and answers about using chrony. chrony-dev is a more
|
||||
technical list, e.g. for discussing how new features should be
|
||||
implemented, exchange of information between developers etc. To
|
||||
subscribe to either of these lists, send a message with the subject
|
||||
"subscribe" to
|
||||
|
||||
chrony-users-request@chrony.tuxfamily.org
|
||||
or
|
||||
chrony-dev-request@chrony.tuxfamily.org
|
||||
|
||||
as applicable.
|
||||
|
||||
|
||||
Author
|
||||
======
|
||||
Authors
|
||||
=======
|
||||
|
||||
Richard P. Curnow <rc@rc0.org.uk>
|
||||
|
||||
|
||||
Maintainers
|
||||
===========
|
||||
|
||||
Miroslav Lichvar <mlichvar@redhat.com>
|
||||
|
||||
|
||||
Acknowledgements
|
||||
================
|
||||
|
||||
In writing the chronyd program, extensive use has been made of the NTPv3 (RFC
|
||||
1305) and NTPv4 (RFC 5905) specification. The source code of the xntpd/ntpd
|
||||
implementation written by Dennis Fergusson, Lars Mathiesen, David Mills, and
|
||||
others has been used to check the details of the protocol.
|
||||
|
||||
The following people have provided patches and other major contributions
|
||||
to the program :
|
||||
to chrony:
|
||||
|
||||
Lonnie Abelbeck <lonnie@abelbeck.com>
|
||||
Benny Lyne Amorsen <benny@amorsen.dk>
|
||||
Patch to add minstratum option
|
||||
|
||||
Andrew Bishop <amb@gedanken.demon.co.uk>
|
||||
Fixes for bugs in logging when in daemon mode
|
||||
Fixes for compiler warnings
|
||||
Robustness improvements for drift file
|
||||
Improve installation (directory checking etc)
|
||||
Entries in contrib directory
|
||||
Improvements to 'sources' and 'sourcestats' output from chronyc
|
||||
Improvements to documentation
|
||||
Investigation of required dosynctodr behaviour for various Solaris
|
||||
versions.
|
||||
|
||||
Vincent Blut <vincent.debian@free.fr>
|
||||
Luca Boccassi <bluca@debian.org>
|
||||
Stephan I. Boettcher <stephan@nevis1.columbia.edu>
|
||||
Entries in contrib directory
|
||||
|
||||
David Bohman <debohman@gmail.com>
|
||||
Anthony Brandon <anthony@amarulasolutions.com>
|
||||
Goswin Brederlow <brederlo@informatik.uni-tuebingen.de>
|
||||
Leigh Brown <leigh@solinno.co.uk>
|
||||
Erik Bryer <ebryer@spots.ab.ca>
|
||||
Entries in contrib directory
|
||||
|
||||
Jonathan Cameron <jic23@cam.ac.uk>
|
||||
Bryan Christianson <bryan@whatroute.net>
|
||||
Juliusz Chroboczek <jch@pps.jussieu.fr>
|
||||
Fix install rule in Makefile if chronyd file is in use.
|
||||
|
||||
Paul Donald <newtwen+gitlab@gmail.com>
|
||||
Dan Drown <dan-ntp@drown.org>
|
||||
Kamil Dudka <kdudka@redhat.com>
|
||||
Christian Ehrhardt <christian.ehrhardt@canonical.com>
|
||||
Paul Elliott <pelliott@io.com>
|
||||
DNSchrony (in contrib directory), a tool for handling NTP servers
|
||||
with variable IP addresses.
|
||||
|
||||
Robert Fairley <rfairley@redhat.com>
|
||||
Ahmad Fatoum <a.fatoum@pengutronix.de>
|
||||
Andreas Fenkart <extern-afe@mission-embedded.com>
|
||||
Stefan R. Filipek <srfilipek@gmail.com>
|
||||
Andy Fiddaman <illumos@fiddaman.net>
|
||||
Mike Fleetwood <mike@rockover.demon.co.uk>
|
||||
Fixes for compiler warnings
|
||||
|
||||
Rob Gill <rrobgill@protonmail.com>
|
||||
Alexander Gretencord <arutha@gmx.de>
|
||||
Changes to installation directory system to make it easier for
|
||||
package builders.
|
||||
|
||||
Andrew Griffiths <agriffit@redhat.com>
|
||||
Walter Haidinger <walter.haidinger@gmx.at>
|
||||
Providing me with login access to a Linux installation where v1.12
|
||||
wouldn't compile, so I could develop the fixes for v1.13. Also, for
|
||||
providing the disc space so I can keep an independent backup of the
|
||||
sources.
|
||||
|
||||
Juergen Hannken-Illjes <hannken@eis.cs.tu-bs.de>
|
||||
Port to NetBSD
|
||||
|
||||
John Hasler <john@dhh.gt.org>
|
||||
Project and website at tuxfamily.org
|
||||
Changes to support 64 bit machines (i.e. those where
|
||||
sizeof(unsigned long) > 4)
|
||||
Bug fix to initstepslew directive
|
||||
Fix to remove potential buffer overrun errors.
|
||||
Memory locking and real-time scheduler support
|
||||
Fix fault where chronyd enters an endless loop
|
||||
|
||||
Tjalling Hattink <t.hattink@fugro.nl>
|
||||
Fix scheduler to allow stepping clock from timeout handler
|
||||
Patch to take leap second in PPS refclock from locked source
|
||||
Patch to make reading of RTC for initial trim more reliable
|
||||
|
||||
Liam Hatton <me@liamhatton.com>
|
||||
Advice on configuring for Linux on PPC
|
||||
|
||||
Holger Hoffstätte <holger@applied-asynchrony.com>
|
||||
Jachym Holecek <jakym@volny.cz>
|
||||
Patch to make Linux real time clock work with devfs
|
||||
|
||||
Håkan Johansson <f96hajo@chalmers.se>
|
||||
Patch to avoid large values in sources and sourcestats output
|
||||
|
||||
Jim Knoble <jmknoble@pobox.com>
|
||||
Fixes for compiler warnings
|
||||
|
||||
Antti Jrvinen <costello@iki.fi>
|
||||
Advice on configuring for BSD/386
|
||||
|
||||
Miroslav Lichvar <mlichvar@redhat.com>
|
||||
Reference clock support
|
||||
IPv6 support
|
||||
Linux capabilities support
|
||||
Leap second support
|
||||
Improved source selection
|
||||
Improved sample history trimming
|
||||
Improved polling interval adjustment
|
||||
Improved stability with temporary asymmetric delays
|
||||
Temperature compensation
|
||||
Many other bug fixes and improvements
|
||||
|
||||
Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
|
||||
Eric Lammerts <eric@lammerts.org>
|
||||
Stefan Lucke <stefan@lucke.in-berlin.de>
|
||||
Victor Lum <viclum@vanu.com>
|
||||
Kevin Lyda <kevin@ie.suberic.net>
|
||||
Paul Menzel <paulepanter@users.sourceforge.net>
|
||||
Vladimir Michl <vladimir.michl@seznam.cz>
|
||||
Victor Moroz <vim@prv.adlum.ru>
|
||||
Patch to support Linux with HZ!=100
|
||||
|
||||
Kalle Olavi Niemitalo <tosi@stekt.oulu.fi>
|
||||
acquisitionport support
|
||||
|
||||
Patrick Oppenlander <patrick.oppenlander@gmail.com>
|
||||
Frank Otto <sandwichmacher@web.de>
|
||||
Handling arbitrary HZ values
|
||||
|
||||
Denny Page <dennypage@me.com>
|
||||
Rupesh Patel <rupatel@redhat.com>
|
||||
Chris Perl <cperl@janestreet.com>
|
||||
Gautier PHILIPPON <gautier.philippon@ensimag.grenoble-inp.fr>
|
||||
Andreas Piesk <apiesk@virbus.de>
|
||||
Patch to make chronyc use the readline library if available
|
||||
|
||||
Shachar Raindel <shacharr@google.com>
|
||||
Mike Ryan <msr@hsilop.net>
|
||||
Baruch Siach <baruch@tkos.co.il>
|
||||
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
|
||||
Foster Snowhill <forst@forstwoof.ru>
|
||||
Andreas Steinmetz <ast@domdv.de>
|
||||
NAKAMURA Takumi <takumi@ps.sakura.ne.jp>
|
||||
Timo Teras <timo.teras@iki.fi>
|
||||
Patch to reply correctly on multihomed hosts
|
||||
|
||||
Bill Unruh <unruh@physics.ubc.ca>
|
||||
Luke Valenta <lvalenta@cloudflare.com>
|
||||
Stephen Wadeley <swadeley@redhat.com>
|
||||
Bernhard Weiss <lisnablagh@web.de>
|
||||
Wolfgang Weisselberg <weissel@netcologne.de>
|
||||
Entries in contrib directory
|
||||
|
||||
Bernhard M. Wiedemann <bwiedemann@suse.de>
|
||||
Joachim Wiedorn <ad_debian@joonet.de>
|
||||
Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
|
||||
Many robustness and security improvements
|
||||
|
||||
Ulrich Windl <ulrich.windl@rz.uni-regensburg.de> for the
|
||||
Providing me with information about the Linux 2.2 kernel
|
||||
functionality compared to 2.0.
|
||||
|
||||
Ulrich Windl <ulrich.windl@rz.uni-regensburg.de>
|
||||
Michael Witten <mfwitten@gmail.com>
|
||||
Doug Woodward <dougw@whistler.com>
|
||||
Advice on configuring for Solaris 2.8 on x86
|
||||
Thomas Zajic <zlatko@zlatko.fdns.net>
|
||||
|
||||
Many other people have contributed bug reports and suggestions. I'm
|
||||
sorry I can't identify all of you individually.
|
||||
Many other people have contributed bug reports and suggestions. We are sorry
|
||||
we cannot identify all of you individually.
|
||||
|
||||
13
addressing.h
13
addressing.h
@@ -30,27 +30,36 @@
|
||||
#include "sysincl.h"
|
||||
|
||||
/* This type is used to represent an IPv4 address or IPv6 address.
|
||||
Addresses which are not resolved yet can be represented with an ID.
|
||||
All parts are in HOST order, NOT network order. */
|
||||
|
||||
#define IPADDR_UNSPEC 0
|
||||
#define IPADDR_INET4 1
|
||||
#define IPADDR_INET6 2
|
||||
#define IPADDR_ID 3
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
uint32_t in4;
|
||||
uint8_t in6[16];
|
||||
uint32_t id;
|
||||
} addr;
|
||||
uint16_t family;
|
||||
uint16_t _pad;
|
||||
} IPAddr;
|
||||
|
||||
typedef struct {
|
||||
IPAddr ip_addr;
|
||||
unsigned short port;
|
||||
} NTP_Remote_Address;
|
||||
uint16_t port;
|
||||
} IPSockAddr;
|
||||
|
||||
typedef IPSockAddr NTP_Remote_Address;
|
||||
|
||||
#define INVALID_IF_INDEX -1
|
||||
|
||||
typedef struct {
|
||||
IPAddr ip_addr;
|
||||
int if_index;
|
||||
int sock_fd;
|
||||
} NTP_Local_Address;
|
||||
|
||||
|
||||
124
addrfilt.c
124
addrfilt.c
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997,1998,1999,2000,2001,2002,2005
|
||||
* Copyright (C) Miroslav Lichvar 2009
|
||||
* Copyright (C) Miroslav Lichvar 2009, 2015
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -62,7 +62,7 @@ split_ip6(IPAddr *ip, uint32_t *dst)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
dst[i] = ip->addr.in6[i * 4 + 0] << 24 |
|
||||
dst[i] = (uint32_t)ip->addr.in6[i * 4 + 0] << 24 |
|
||||
ip->addr.in6[i * 4 + 1] << 16 |
|
||||
ip->addr.in6[i * 4 + 2] << 8 |
|
||||
ip->addr.in6[i * 4 + 3];
|
||||
@@ -247,6 +247,8 @@ set_subnet_(ADF_AuthTable table,
|
||||
set_subnet(&table->base6, ip6, 4, 0, new_state, delete_children) == ADF_SUCCESS)
|
||||
return ADF_SUCCESS;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ADF_BADSUBNET;
|
||||
@@ -359,9 +361,9 @@ ADF_IsAllowed(ADF_AuthTable table,
|
||||
case IPADDR_INET6:
|
||||
split_ip6(ip_addr, ip6);
|
||||
return check_ip_in_node(&table->base6, ip6);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -401,117 +403,3 @@ ADF_IsAnyAllowed(ADF_AuthTable table, int family)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#if defined TEST
|
||||
|
||||
static void print_node(TableNode *node, uint32_t *addr, int ip_len, int shift, int subnet_bits)
|
||||
{
|
||||
uint32_t new_addr[4];
|
||||
int i;
|
||||
TableNode *sub_node;
|
||||
|
||||
for (i=0; i<subnet_bits; i++) putchar(' ');
|
||||
|
||||
if (ip_len == 1)
|
||||
printf("%d.%d.%d.%d",
|
||||
((addr[0] >> 24) & 255),
|
||||
((addr[0] >> 16) & 255),
|
||||
((addr[0] >> 8) & 255),
|
||||
((addr[0] ) & 255));
|
||||
else {
|
||||
for (i=0; i<4; i++) {
|
||||
if (addr[i])
|
||||
printf("%d.%d.%d.%d",
|
||||
((addr[i] >> 24) & 255),
|
||||
((addr[i] >> 16) & 255),
|
||||
((addr[i] >> 8) & 255),
|
||||
((addr[i] ) & 255));
|
||||
putchar(i < 3 ? ':' : '\0');
|
||||
}
|
||||
}
|
||||
printf("/%d : %s\n",
|
||||
subnet_bits,
|
||||
(node->state == ALLOW) ? "allow" :
|
||||
(node->state == DENY) ? "deny" : "as parent");
|
||||
if (node->extended) {
|
||||
for (i=0; i<16; i++) {
|
||||
sub_node = &(node->extended[i]);
|
||||
new_addr[0] = addr[0];
|
||||
new_addr[1] = addr[1];
|
||||
new_addr[2] = addr[2];
|
||||
new_addr[3] = addr[3];
|
||||
new_addr[ip_len - 1 - shift / 32] |= ((uint32_t)i << (shift % 32));
|
||||
print_node(sub_node, new_addr, ip_len, shift - 4, subnet_bits + 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void print_table(ADF_AuthTable table)
|
||||
{
|
||||
uint32_t addr[4];
|
||||
|
||||
memset(addr, 0, sizeof (addr));
|
||||
printf("IPv4 table:\n");
|
||||
print_node(&table->base4, addr, 1, 28, 0);
|
||||
|
||||
memset(addr, 0, sizeof (addr));
|
||||
printf("IPv6 table:\n");
|
||||
print_node(&table->base6, addr, 4, 124, 0);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
IPAddr ip;
|
||||
ADF_AuthTable table;
|
||||
table = ADF_CreateTable();
|
||||
|
||||
ip.family = IPADDR_INET4;
|
||||
|
||||
ip.addr.in4 = 0x7e800000;
|
||||
ADF_Allow(table, &ip, 9);
|
||||
ip.addr.in4 = 0x7ecc0000;
|
||||
ADF_Deny(table, &ip, 14);
|
||||
#if 0
|
||||
ip.addr.in4 = 0x7f000001;
|
||||
ADF_Deny(table, &ip, 32);
|
||||
ip.addr.in4 = 0x7f000000;
|
||||
ADF_Allow(table, &ip, 8);
|
||||
#endif
|
||||
|
||||
printf("allowed: %d\n", ADF_IsAllowed(table, &ip));
|
||||
ip.addr.in4 ^= 1;
|
||||
printf("allowed: %d\n", ADF_IsAllowed(table, &ip));
|
||||
|
||||
ip.family = IPADDR_INET6;
|
||||
|
||||
memcpy(ip.addr.in6, "abcdefghijklmnop", 16);
|
||||
ADF_Deny(table, &ip, 66);
|
||||
ADF_Allow(table, &ip, 59);
|
||||
|
||||
memcpy(ip.addr.in6, "xbcdefghijklmnop", 16);
|
||||
ADF_Deny(table, &ip, 128);
|
||||
ip.addr.in6[15] ^= 3;
|
||||
ADF_Allow(table, &ip, 127);
|
||||
|
||||
printf("allowed: %d\n", ADF_IsAllowed(table, &ip));
|
||||
ip.addr.in4 ^= 1;
|
||||
printf("allowed: %d\n", ADF_IsAllowed(table, &ip));
|
||||
|
||||
print_table(table);
|
||||
|
||||
ADF_DestroyTable(table);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* defined TEST */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
28
array.c
28
array.c
@@ -44,6 +44,8 @@ ARR_CreateInstance(unsigned int elem_size)
|
||||
{
|
||||
ARR_Instance array;
|
||||
|
||||
assert(elem_size > 0);
|
||||
|
||||
array = MallocNew(struct ARR_Instance_Record);
|
||||
|
||||
array->data = NULL;
|
||||
@@ -64,6 +66,7 @@ ARR_DestroyInstance(ARR_Instance array)
|
||||
static void
|
||||
realloc_array(ARR_Instance array, unsigned int min_size)
|
||||
{
|
||||
assert(min_size <= 2 * min_size);
|
||||
if (array->allocated >= min_size && array->allocated <= 2 * min_size)
|
||||
return;
|
||||
|
||||
@@ -74,7 +77,7 @@ realloc_array(ARR_Instance array, unsigned int min_size)
|
||||
array->allocated = min_size;
|
||||
}
|
||||
|
||||
array->data = Realloc(array->data, array->elem_size * array->allocated);
|
||||
array->data = Realloc2(array->data, array->allocated, array->elem_size);
|
||||
}
|
||||
|
||||
void *
|
||||
@@ -89,12 +92,18 @@ void *
|
||||
ARR_GetElement(ARR_Instance array, unsigned int index)
|
||||
{
|
||||
assert(index < array->used);
|
||||
return (void *)((char *)array->data + index * array->elem_size);
|
||||
return (void *)((char *)array->data + (size_t)index * array->elem_size);
|
||||
}
|
||||
|
||||
void *
|
||||
ARR_GetElements(ARR_Instance array)
|
||||
{
|
||||
/* Return a non-NULL pointer when the array has zero size */
|
||||
if (!array->data) {
|
||||
assert(!array->used);
|
||||
return array;
|
||||
}
|
||||
|
||||
return array->data;
|
||||
}
|
||||
|
||||
@@ -107,6 +116,21 @@ ARR_AppendElement(ARR_Instance array, void *element)
|
||||
memcpy(e, element, array->elem_size);
|
||||
}
|
||||
|
||||
void
|
||||
ARR_RemoveElement(ARR_Instance array, unsigned int index)
|
||||
{
|
||||
void *e, *l;
|
||||
|
||||
e = ARR_GetElement(array, index);
|
||||
l = ARR_GetElement(array, array->used - 1);
|
||||
|
||||
if (e < l)
|
||||
memmove(e, (char *)e + array->elem_size, (char *)l - (char *)e);
|
||||
array->used--;
|
||||
|
||||
realloc_array(array, array->used);
|
||||
}
|
||||
|
||||
void
|
||||
ARR_SetSize(ARR_Instance array, unsigned int size)
|
||||
{
|
||||
|
||||
3
array.h
3
array.h
@@ -47,6 +47,9 @@ extern void *ARR_GetElements(ARR_Instance array);
|
||||
/* Add a new element to the end of the array */
|
||||
extern void ARR_AppendElement(ARR_Instance array, void *element);
|
||||
|
||||
/* Remove element with given index */
|
||||
extern void ARR_RemoveElement(ARR_Instance array, unsigned int index);
|
||||
|
||||
/* Set the size of the array */
|
||||
extern void ARR_SetSize(ARR_Instance array, unsigned int size);
|
||||
|
||||
|
||||
430
candm.h
430
candm.h
@@ -31,14 +31,12 @@
|
||||
|
||||
#include "sysincl.h"
|
||||
#include "addressing.h"
|
||||
#include "hash.h"
|
||||
|
||||
/* This is the default port to use for CANDM, if no alternative is
|
||||
defined */
|
||||
#define DEFAULT_CANDM_PORT 323
|
||||
|
||||
/* Request codes */
|
||||
#define REQ_NULL 0
|
||||
#define REQ_ONLINE 1
|
||||
#define REQ_OFFLINE 2
|
||||
#define REQ_BURST 3
|
||||
@@ -89,22 +87,48 @@
|
||||
#define REQ_RESELECT 48
|
||||
#define REQ_RESELECTDISTANCE 49
|
||||
#define REQ_MODIFY_MAKESTEP 50
|
||||
#define N_REQUEST_TYPES 51
|
||||
#define REQ_SMOOTHING 51
|
||||
#define REQ_SMOOTHTIME 52
|
||||
#define REQ_REFRESH 53
|
||||
#define REQ_SERVER_STATS 54
|
||||
#define REQ_CLIENT_ACCESSES_BY_INDEX2 55
|
||||
#define REQ_LOCAL2 56
|
||||
#define REQ_NTP_DATA 57
|
||||
#define REQ_ADD_SERVER2 58
|
||||
#define REQ_ADD_PEER2 59
|
||||
#define REQ_ADD_SERVER3 60
|
||||
#define REQ_ADD_PEER3 61
|
||||
#define REQ_SHUTDOWN 62
|
||||
#define REQ_ONOFFLINE 63
|
||||
#define REQ_ADD_SOURCE 64
|
||||
#define REQ_NTP_SOURCE_NAME 65
|
||||
#define REQ_RESET_SOURCES 66
|
||||
#define REQ_AUTH_DATA 67
|
||||
#define REQ_CLIENT_ACCESSES_BY_INDEX3 68
|
||||
#define REQ_SELECT_DATA 69
|
||||
#define REQ_RELOAD_SOURCES 70
|
||||
#define REQ_DOFFSET2 71
|
||||
#define REQ_MODIFY_SELECTOPTS 72
|
||||
#define REQ_MODIFY_OFFSET 73
|
||||
#define REQ_LOCAL3 74
|
||||
#define N_REQUEST_TYPES 75
|
||||
|
||||
/* Special utoken value used to log on with first exchange being the
|
||||
password. (This time value has long since gone by) */
|
||||
#define SPECIAL_UTOKEN 0x10101010
|
||||
|
||||
/* Structure used to exchange timevals independent on size of time_t */
|
||||
/* Structure used to exchange timespecs independent of time_t size */
|
||||
typedef struct {
|
||||
uint32_t tv_sec_high;
|
||||
uint32_t tv_sec_low;
|
||||
uint32_t tv_nsec;
|
||||
} Timeval;
|
||||
} Timespec;
|
||||
|
||||
/* This is used in tv_sec_high for 32-bit timestamps */
|
||||
#define TV_NOHIGHSEC 0x7fffffff
|
||||
|
||||
/* Structure for 64-bit integers (not requiring 64-bit alignment) */
|
||||
typedef struct {
|
||||
uint32_t high;
|
||||
uint32_t low;
|
||||
} Integer64;
|
||||
|
||||
/* 32-bit floating-point format consisting of 7-bit signed exponent
|
||||
and 25-bit signed coefficient without hidden bit.
|
||||
The result is calculated as: 2^(exp - 25) * coef */
|
||||
@@ -116,6 +140,10 @@ typedef struct {
|
||||
pktlength.c, to get the number of bytes that ought to be
|
||||
transmitted for each packet type. */
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_Null;
|
||||
|
||||
typedef struct {
|
||||
IPAddr mask;
|
||||
IPAddr address;
|
||||
@@ -195,18 +223,18 @@ typedef struct {
|
||||
} REQ_Modify_Makestep;
|
||||
|
||||
typedef struct {
|
||||
Timeval ts;
|
||||
int32_t EOR;
|
||||
} REQ_Logon;
|
||||
|
||||
typedef struct {
|
||||
Timeval ts;
|
||||
Timespec ts;
|
||||
int32_t EOR;
|
||||
} REQ_Settime;
|
||||
|
||||
typedef struct {
|
||||
int32_t on_off;
|
||||
int32_t stratum;
|
||||
Float distance;
|
||||
int32_t orphan;
|
||||
Float activate;
|
||||
Float wait_synced;
|
||||
Float wait_unsynced;
|
||||
int32_t EOR;
|
||||
} REQ_Local;
|
||||
|
||||
@@ -215,19 +243,11 @@ typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_Manual;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_N_Sources;
|
||||
|
||||
typedef struct {
|
||||
int32_t index;
|
||||
int32_t EOR;
|
||||
} REQ_Source_Data;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_Rekey;
|
||||
|
||||
typedef struct {
|
||||
IPAddr ip;
|
||||
int32_t subnet_bits;
|
||||
@@ -239,23 +259,54 @@ typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_Ac_Check;
|
||||
|
||||
/* Source types in NTP source requests */
|
||||
#define REQ_ADDSRC_SERVER 1
|
||||
#define REQ_ADDSRC_PEER 2
|
||||
#define REQ_ADDSRC_POOL 3
|
||||
|
||||
/* Flags used in NTP source requests */
|
||||
#define REQ_ADDSRC_ONLINE 0x1
|
||||
#define REQ_ADDSRC_AUTOOFFLINE 0x2
|
||||
#define REQ_ADDSRC_IBURST 0x4
|
||||
#define REQ_ADDSRC_PREFER 0x8
|
||||
#define REQ_ADDSRC_NOSELECT 0x10
|
||||
#define REQ_ADDSRC_TRUST 0x20
|
||||
#define REQ_ADDSRC_REQUIRE 0x40
|
||||
#define REQ_ADDSRC_INTERLEAVED 0x80
|
||||
#define REQ_ADDSRC_BURST 0x100
|
||||
#define REQ_ADDSRC_NTS 0x200
|
||||
#define REQ_ADDSRC_COPY 0x400
|
||||
#define REQ_ADDSRC_EF_EXP_MONO_ROOT 0x800
|
||||
#define REQ_ADDSRC_EF_EXP_NET_CORRECTION 0x1000
|
||||
#define REQ_ADDSRC_IPV4 0x2000
|
||||
#define REQ_ADDSRC_IPV6 0x4000
|
||||
|
||||
typedef struct {
|
||||
IPAddr ip_addr;
|
||||
uint32_t type;
|
||||
uint8_t name[256];
|
||||
uint32_t port;
|
||||
int32_t minpoll;
|
||||
int32_t maxpoll;
|
||||
int32_t presend_minpoll;
|
||||
uint32_t min_stratum;
|
||||
uint32_t poll_target;
|
||||
uint32_t version;
|
||||
uint32_t max_sources;
|
||||
int32_t min_samples;
|
||||
int32_t max_samples;
|
||||
uint32_t authkey;
|
||||
uint32_t nts_port;
|
||||
Float max_delay;
|
||||
Float max_delay_ratio;
|
||||
Float max_delay_dev_ratio;
|
||||
Float min_delay;
|
||||
Float asymmetry;
|
||||
Float offset;
|
||||
uint32_t flags;
|
||||
int32_t filter_length;
|
||||
uint32_t cert_set;
|
||||
Float max_delay_quant;
|
||||
int32_t max_unreach;
|
||||
int32_t EOR;
|
||||
} REQ_NTP_Source;
|
||||
|
||||
@@ -264,78 +315,87 @@ typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_Del_Source;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_WriteRtc;
|
||||
|
||||
typedef struct {
|
||||
Float dfreq;
|
||||
int32_t EOR;
|
||||
} REQ_Dfreq;
|
||||
|
||||
typedef struct {
|
||||
int32_t sec;
|
||||
int32_t usec;
|
||||
Float doffset;
|
||||
int32_t EOR;
|
||||
} REQ_Doffset;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_Tracking;
|
||||
|
||||
typedef struct {
|
||||
uint32_t index;
|
||||
int32_t EOR;
|
||||
} REQ_Sourcestats;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_RTCReport;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_TrimRTC;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_CycleLogs;
|
||||
|
||||
/* This is based on the response size rather than the
|
||||
request size */
|
||||
#define MAX_CLIENT_ACCESSES 8
|
||||
|
||||
typedef struct {
|
||||
uint32_t first_index;
|
||||
uint32_t n_indices;
|
||||
uint32_t n_clients;
|
||||
uint32_t min_hits;
|
||||
uint32_t reset;
|
||||
int32_t EOR;
|
||||
} REQ_ClientAccessesByIndex;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_ManualList;
|
||||
|
||||
typedef struct {
|
||||
int32_t index;
|
||||
int32_t EOR;
|
||||
} REQ_ManualDelete;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_MakeStep;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_Activity;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_Reselect;
|
||||
|
||||
typedef struct {
|
||||
Float distance;
|
||||
int32_t EOR;
|
||||
} REQ_ReselectDistance;
|
||||
|
||||
#define REQ_SMOOTHTIME_RESET 0
|
||||
#define REQ_SMOOTHTIME_ACTIVATE 1
|
||||
|
||||
typedef struct {
|
||||
int32_t option;
|
||||
int32_t EOR;
|
||||
} REQ_SmoothTime;
|
||||
|
||||
typedef struct {
|
||||
IPAddr ip_addr;
|
||||
int32_t EOR;
|
||||
} REQ_NTPData;
|
||||
|
||||
typedef struct {
|
||||
IPAddr ip_addr;
|
||||
int32_t EOR;
|
||||
} REQ_NTPSourceName;
|
||||
|
||||
typedef struct {
|
||||
IPAddr ip_addr;
|
||||
int32_t EOR;
|
||||
} REQ_AuthData;
|
||||
|
||||
typedef struct {
|
||||
uint32_t index;
|
||||
int32_t EOR;
|
||||
} REQ_SelectData;
|
||||
|
||||
/* Mask and options reuse the REQ_ADDSRC flags */
|
||||
typedef struct {
|
||||
IPAddr address;
|
||||
uint32_t ref_id;
|
||||
uint32_t mask;
|
||||
uint32_t options;
|
||||
int32_t EOR;
|
||||
} REQ_Modify_SelectOpts;
|
||||
|
||||
typedef struct {
|
||||
IPAddr address;
|
||||
uint32_t ref_id;
|
||||
Float new_offset;
|
||||
int32_t EOR;
|
||||
} REQ_Modify_Offset;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#define PKT_TYPE_CMD_REQUEST 1
|
||||
@@ -365,7 +425,17 @@ typedef struct {
|
||||
|
||||
Version 6 : added padding to requests to prevent amplification attack,
|
||||
changed maximum number of samples in manual list to 16, new commands: modify
|
||||
makestep
|
||||
makestep, smoothing, smoothtime
|
||||
|
||||
Support for authentication was removed later in version 6 of the protocol
|
||||
and commands that required authentication are allowed only locally over Unix
|
||||
domain socket.
|
||||
|
||||
Version 6 (no authentication) : changed format of client accesses by index
|
||||
(two times), delta offset, and manual timestamp, added new fields and
|
||||
flags to NTP source request and report, made length of manual list constant,
|
||||
added new commands: authdata, ntpdata, onoffline, refresh, reset,
|
||||
selectdata, serverstats, shutdown, sourcename
|
||||
*/
|
||||
|
||||
#define PROTO_VERSION_NUMBER 6
|
||||
@@ -379,8 +449,8 @@ typedef struct {
|
||||
#define PROTO_VERSION_PADDING 6
|
||||
|
||||
/* The maximum length of padding in request packet, currently
|
||||
defined by CLIENT_ACCESSES_BY_INDEX and MANUAL_LIST */
|
||||
#define MAX_PADDING_LENGTH 396
|
||||
defined by CLIENT_ACCESSES_BY_INDEX3 */
|
||||
#define MAX_PADDING_LENGTH 484
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
@@ -394,10 +464,11 @@ typedef struct {
|
||||
(count up from zero for same sequence
|
||||
number) */
|
||||
uint32_t sequence; /* Client's sequence number */
|
||||
uint32_t utoken; /* Unique token per incarnation of daemon */
|
||||
uint32_t token; /* Command token (to prevent replay attack) */
|
||||
uint32_t pad1;
|
||||
uint32_t pad2;
|
||||
|
||||
union {
|
||||
REQ_Null null;
|
||||
REQ_Online online;
|
||||
REQ_Offline offline;
|
||||
REQ_Burst burst;
|
||||
@@ -411,52 +482,35 @@ typedef struct {
|
||||
REQ_Modify_Polltarget modify_polltarget;
|
||||
REQ_Modify_Maxupdateskew modify_maxupdateskew;
|
||||
REQ_Modify_Makestep modify_makestep;
|
||||
REQ_Logon logon;
|
||||
REQ_Settime settime;
|
||||
REQ_Local local;
|
||||
REQ_Manual manual;
|
||||
REQ_N_Sources n_sources;
|
||||
REQ_Source_Data source_data;
|
||||
REQ_Rekey rekey;
|
||||
REQ_Allow_Deny allow_deny;
|
||||
REQ_Ac_Check ac_check;
|
||||
REQ_NTP_Source ntp_source;
|
||||
REQ_Del_Source del_source;
|
||||
REQ_WriteRtc writertc;
|
||||
REQ_Dfreq dfreq;
|
||||
REQ_Doffset doffset;
|
||||
REQ_Tracking tracking;
|
||||
REQ_Sourcestats sourcestats;
|
||||
REQ_RTCReport rtcreport;
|
||||
REQ_TrimRTC trimrtc;
|
||||
REQ_CycleLogs cyclelogs;
|
||||
REQ_ClientAccessesByIndex client_accesses_by_index;
|
||||
REQ_ManualList manual_list;
|
||||
REQ_ManualDelete manual_delete;
|
||||
REQ_MakeStep make_step;
|
||||
REQ_Activity activity;
|
||||
REQ_Reselect reselect;
|
||||
REQ_ReselectDistance reselect_distance;
|
||||
REQ_SmoothTime smoothtime;
|
||||
REQ_NTPData ntp_data;
|
||||
REQ_NTPSourceName ntp_source_name;
|
||||
REQ_AuthData auth_data;
|
||||
REQ_SelectData select_data;
|
||||
REQ_Modify_SelectOpts modify_select_opts;
|
||||
REQ_Modify_Offset modify_offset;
|
||||
} data; /* Command specific parameters */
|
||||
|
||||
/* The following fields only set the maximum size of the packet.
|
||||
There are no holes between them and the actual data. */
|
||||
|
||||
/* Padding used to prevent traffic amplification */
|
||||
/* Padding used to prevent traffic amplification. It only defines the
|
||||
maximum size of the packet, there is no hole after the data field. */
|
||||
uint8_t padding[MAX_PADDING_LENGTH];
|
||||
|
||||
/* Authentication data */
|
||||
uint8_t auth[MAX_HASH_LENGTH];
|
||||
|
||||
} CMD_Request;
|
||||
|
||||
/* ================================================== */
|
||||
/* Authority codes for command types */
|
||||
|
||||
#define PERMIT_OPEN 0
|
||||
#define PERMIT_LOCAL 1
|
||||
#define PERMIT_AUTH 2
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Reply codes */
|
||||
@@ -472,7 +526,21 @@ typedef struct {
|
||||
#define RPY_CLIENT_ACCESSES_BY_INDEX 10
|
||||
#define RPY_MANUAL_LIST 11
|
||||
#define RPY_ACTIVITY 12
|
||||
#define N_REPLY_TYPES 13
|
||||
#define RPY_SMOOTHING 13
|
||||
#define RPY_SERVER_STATS 14
|
||||
#define RPY_CLIENT_ACCESSES_BY_INDEX2 15
|
||||
#define RPY_NTP_DATA 16
|
||||
#define RPY_MANUAL_TIMESTAMP2 17
|
||||
#define RPY_MANUAL_LIST2 18
|
||||
#define RPY_NTP_SOURCE_NAME 19
|
||||
#define RPY_AUTH_DATA 20
|
||||
#define RPY_CLIENT_ACCESSES_BY_INDEX3 21
|
||||
#define RPY_SERVER_STATS2 22
|
||||
#define RPY_SELECT_DATA 23
|
||||
#define RPY_SERVER_STATS3 24
|
||||
#define RPY_SERVER_STATS4 25
|
||||
#define RPY_NTP_DATA2 26
|
||||
#define N_REPLY_TYPES 27
|
||||
|
||||
/* Status codes */
|
||||
#define STT_SUCCESS 0
|
||||
@@ -485,8 +553,7 @@ typedef struct {
|
||||
#define STT_BADSUBNET 7
|
||||
#define STT_ACCESSALLOWED 8
|
||||
#define STT_ACCESSDENIED 9
|
||||
/* Deprecated */
|
||||
#define STT_NOHOSTACCESS 10
|
||||
#define STT_NOHOSTACCESS 10 /* Deprecated */
|
||||
#define STT_SOURCEALREADYKNOWN 11
|
||||
#define STT_TOOMANYSOURCES 12
|
||||
#define STT_NORTC 13
|
||||
@@ -496,6 +563,7 @@ typedef struct {
|
||||
#define STT_INVALIDAF 17
|
||||
#define STT_BADPKTVERSION 18
|
||||
#define STT_BADPKTLENGTH 19
|
||||
#define STT_INVALIDNAME 21
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
@@ -510,15 +578,12 @@ typedef struct {
|
||||
#define RPY_SD_MD_PEER 1
|
||||
#define RPY_SD_MD_REF 2
|
||||
|
||||
#define RPY_SD_ST_SYNC 0
|
||||
#define RPY_SD_ST_UNREACH 1
|
||||
#define RPY_SD_ST_SELECTED 0
|
||||
#define RPY_SD_ST_NONSELECTABLE 1
|
||||
#define RPY_SD_ST_FALSETICKER 2
|
||||
#define RPY_SD_ST_JITTERY 3
|
||||
#define RPY_SD_ST_CANDIDATE 4
|
||||
#define RPY_SD_ST_OUTLIER 5
|
||||
|
||||
#define RPY_SD_FLAG_NOSELECT 0x1
|
||||
#define RPY_SD_FLAG_PREFER 0x2
|
||||
#define RPY_SD_ST_UNSELECTED 4
|
||||
#define RPY_SD_ST_SELECTABLE 5
|
||||
|
||||
typedef struct {
|
||||
IPAddr ip_addr;
|
||||
@@ -540,7 +605,7 @@ typedef struct {
|
||||
IPAddr ip_addr;
|
||||
uint16_t stratum;
|
||||
uint16_t leap_status;
|
||||
Timeval ref_time;
|
||||
Timespec ref_time;
|
||||
Float current_correction;
|
||||
Float last_offset;
|
||||
Float rms_offset;
|
||||
@@ -568,7 +633,7 @@ typedef struct {
|
||||
} RPY_Sourcestats;
|
||||
|
||||
typedef struct {
|
||||
Timeval ref_time;
|
||||
Timespec ref_time;
|
||||
uint16_t n_samples;
|
||||
uint16_t n_runs;
|
||||
uint32_t span_seconds;
|
||||
@@ -578,7 +643,7 @@ typedef struct {
|
||||
} RPY_Rtc;
|
||||
|
||||
typedef struct {
|
||||
uint32_t centiseconds;
|
||||
Float offset;
|
||||
Float dfreq_ppm;
|
||||
Float new_afreq_ppm;
|
||||
int32_t EOR;
|
||||
@@ -586,12 +651,18 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
IPAddr ip;
|
||||
uint32_t client_hits;
|
||||
uint32_t peer_hits;
|
||||
uint32_t cmd_hits_auth;
|
||||
uint32_t cmd_hits_normal;
|
||||
uint32_t cmd_hits_bad;
|
||||
uint32_t ntp_hits;
|
||||
uint32_t nke_hits;
|
||||
uint32_t cmd_hits;
|
||||
uint32_t ntp_drops;
|
||||
uint32_t nke_drops;
|
||||
uint32_t cmd_drops;
|
||||
int8_t ntp_interval;
|
||||
int8_t nke_interval;
|
||||
int8_t cmd_interval;
|
||||
int8_t ntp_timeout_interval;
|
||||
uint32_t last_ntp_hit_ago;
|
||||
uint32_t last_nke_hit_ago;
|
||||
uint32_t last_cmd_hit_ago;
|
||||
} RPY_ClientAccesses_Client;
|
||||
|
||||
@@ -603,10 +674,32 @@ typedef struct {
|
||||
int32_t EOR;
|
||||
} RPY_ClientAccessesByIndex;
|
||||
|
||||
typedef struct {
|
||||
Integer64 ntp_hits;
|
||||
Integer64 nke_hits;
|
||||
Integer64 cmd_hits;
|
||||
Integer64 ntp_drops;
|
||||
Integer64 nke_drops;
|
||||
Integer64 cmd_drops;
|
||||
Integer64 log_drops;
|
||||
Integer64 ntp_auth_hits;
|
||||
Integer64 ntp_interleaved_hits;
|
||||
Integer64 ntp_timestamps;
|
||||
Integer64 ntp_span_seconds;
|
||||
Integer64 ntp_daemon_rx_timestamps;
|
||||
Integer64 ntp_daemon_tx_timestamps;
|
||||
Integer64 ntp_kernel_rx_timestamps;
|
||||
Integer64 ntp_kernel_tx_timestamps;
|
||||
Integer64 ntp_hw_rx_timestamps;
|
||||
Integer64 ntp_hw_tx_timestamps;
|
||||
Integer64 reserved[4];
|
||||
int32_t EOR;
|
||||
} RPY_ServerStats;
|
||||
|
||||
#define MAX_MANUAL_LIST_SAMPLES 16
|
||||
|
||||
typedef struct {
|
||||
Timeval when;
|
||||
Timespec when;
|
||||
Float slewed_offset;
|
||||
Float orig_offset;
|
||||
Float residual;
|
||||
@@ -627,6 +720,101 @@ typedef struct {
|
||||
int32_t EOR;
|
||||
} RPY_Activity;
|
||||
|
||||
#define RPY_SMT_FLAG_ACTIVE 0x1
|
||||
#define RPY_SMT_FLAG_LEAPONLY 0x2
|
||||
|
||||
typedef struct {
|
||||
uint32_t flags;
|
||||
Float offset;
|
||||
Float freq_ppm;
|
||||
Float wander_ppm;
|
||||
Float last_update_ago;
|
||||
Float remaining_time;
|
||||
int32_t EOR;
|
||||
} RPY_Smoothing;
|
||||
|
||||
#define RPY_NTP_FLAGS_TESTS 0x3ff
|
||||
#define RPY_NTP_FLAG_INTERLEAVED 0x4000
|
||||
#define RPY_NTP_FLAG_AUTHENTICATED 0x8000
|
||||
|
||||
typedef struct {
|
||||
IPAddr remote_addr;
|
||||
IPAddr local_addr;
|
||||
uint16_t remote_port;
|
||||
uint8_t leap;
|
||||
uint8_t version;
|
||||
uint8_t mode;
|
||||
uint8_t stratum;
|
||||
int8_t poll;
|
||||
int8_t precision;
|
||||
Float root_delay;
|
||||
Float root_dispersion;
|
||||
uint32_t ref_id;
|
||||
Timespec ref_time;
|
||||
Float offset;
|
||||
Float peer_delay;
|
||||
Float peer_dispersion;
|
||||
Float response_time;
|
||||
Float jitter_asymmetry;
|
||||
uint16_t flags;
|
||||
uint8_t tx_tss_char;
|
||||
uint8_t rx_tss_char;
|
||||
uint32_t total_tx_count;
|
||||
uint32_t total_rx_count;
|
||||
uint32_t total_valid_count;
|
||||
uint32_t total_good_count;
|
||||
uint32_t total_kernel_tx_ts;
|
||||
uint32_t total_kernel_rx_ts;
|
||||
uint32_t total_hw_tx_ts;
|
||||
uint32_t total_hw_rx_ts;
|
||||
uint32_t reserved[4];
|
||||
int32_t EOR;
|
||||
} RPY_NTPData;
|
||||
|
||||
typedef struct {
|
||||
uint8_t name[256];
|
||||
int32_t EOR;
|
||||
} RPY_NTPSourceName;
|
||||
|
||||
#define RPY_AD_MD_NONE 0
|
||||
#define RPY_AD_MD_SYMMETRIC 1
|
||||
#define RPY_AD_MD_NTS 2
|
||||
|
||||
typedef struct {
|
||||
uint16_t mode;
|
||||
uint16_t key_type;
|
||||
uint32_t key_id;
|
||||
uint16_t key_length;
|
||||
uint16_t ke_attempts;
|
||||
uint32_t last_ke_ago;
|
||||
uint16_t cookies;
|
||||
uint16_t cookie_length;
|
||||
uint16_t nak;
|
||||
uint16_t pad;
|
||||
int32_t EOR;
|
||||
} RPY_AuthData;
|
||||
|
||||
#define RPY_SD_OPTION_NOSELECT 0x1
|
||||
#define RPY_SD_OPTION_PREFER 0x2
|
||||
#define RPY_SD_OPTION_TRUST 0x4
|
||||
#define RPY_SD_OPTION_REQUIRE 0x8
|
||||
|
||||
typedef struct {
|
||||
uint32_t ref_id;
|
||||
IPAddr ip_addr;
|
||||
uint8_t state_char;
|
||||
uint8_t authentication;
|
||||
uint8_t leap;
|
||||
uint8_t pad;
|
||||
uint16_t conf_options;
|
||||
uint16_t eff_options;
|
||||
uint32_t last_sample_ago;
|
||||
Float score;
|
||||
Float lo_limit;
|
||||
Float hi_limit;
|
||||
int32_t EOR;
|
||||
} RPY_SelectData;
|
||||
|
||||
typedef struct {
|
||||
uint8_t version;
|
||||
uint8_t pkt_type;
|
||||
@@ -639,9 +827,9 @@ typedef struct {
|
||||
uint16_t pad2;
|
||||
uint16_t pad3;
|
||||
uint32_t sequence; /* Echo of client's sequence number */
|
||||
uint32_t utoken; /* Unique token per incarnation of daemon */
|
||||
uint32_t token; /* New command token (only if command was successfully
|
||||
authenticated) */
|
||||
uint32_t pad4;
|
||||
uint32_t pad5;
|
||||
|
||||
union {
|
||||
RPY_Null null;
|
||||
RPY_N_Sources n_sources;
|
||||
@@ -651,14 +839,16 @@ typedef struct {
|
||||
RPY_Sourcestats sourcestats;
|
||||
RPY_Rtc rtc;
|
||||
RPY_ClientAccessesByIndex client_accesses_by_index;
|
||||
RPY_ServerStats server_stats;
|
||||
RPY_ManualList manual_list;
|
||||
RPY_Activity activity;
|
||||
RPY_Smoothing smoothing;
|
||||
RPY_NTPData ntp_data;
|
||||
RPY_NTPSourceName ntp_source_name;
|
||||
RPY_AuthData auth_data;
|
||||
RPY_SelectData select_data;
|
||||
} data; /* Reply specific parameters */
|
||||
|
||||
/* authentication of the packet, there is no hole after the actual data
|
||||
from the data union, this field only sets the maximum auth size */
|
||||
uint8_t auth[MAX_HASH_LENGTH];
|
||||
|
||||
} CMD_Reply;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
72
chrony.1
72
chrony.1
@@ -1,72 +0,0 @@
|
||||
.TH CHRONY 1 "@MAN_DATE@" "chrony @VERSION@" "User's Manual"
|
||||
.SH NAME
|
||||
chrony \- programs for keeping computer clocks accurate
|
||||
|
||||
.SH SYNOPSIS
|
||||
\fBchronyc\fR [\fIOPTIONS\fR]
|
||||
|
||||
\fBchronyd\fR [\fIOPTIONS\fR]
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fBchrony\fR is a pair of programs for keeping computer clocks accurate.
|
||||
\fIchronyd\fR is a background (daemon) program and \fIchronyc\fR is a
|
||||
command-line interface to it. Time reference sources for chronyd can be
|
||||
NTP servers, human (via keyboard and \fIchronyc\fR), or the computer's
|
||||
real-time clock at boot time (Linux only). chronyd can determine the rate at
|
||||
which the computer gains or loses time and compensate for it while no external
|
||||
reference is present. Its use of NTP servers can be switched on and off
|
||||
(through \fIchronyc\fR) to support computers with dial-up/intermittent access
|
||||
to the Internet, and it can also act as an NTP server.
|
||||
|
||||
.SH USAGE
|
||||
\fIchronyc\fR is a command-line interface program which can be used to
|
||||
monitor \fIchronyd\fR's performance and to change various operating
|
||||
parameters whilst it is running.
|
||||
|
||||
\fIchronyd\fR's main function is to obtain measurements of the true (UTC)
|
||||
time from one of several sources, and correct the system clock
|
||||
accordingly. It also works out the rate at which the system clock
|
||||
gains or loses time and uses this information to keep it accurate
|
||||
between measurements from the reference.
|
||||
|
||||
The reference time can be derived from either Network Time Protocol
|
||||
(NTP) servers, reference clocks, or wristwatch-and-keyboard (via \fIchronyc\fR).
|
||||
The main source of information about the Network Time Protocol is
|
||||
\fIhttp://www.ntp.org\fR.
|
||||
|
||||
It is designed so that it can work on computers which only have
|
||||
intermittent access to reference sources, for example computers which
|
||||
use a dial-up account to access the Internet or laptops. Of course, it
|
||||
will work well on computers with permanent connections too.
|
||||
|
||||
In addition, on Linux it can monitor the system's real time clock
|
||||
performance, so the system can maintain accurate time even across
|
||||
reboots.
|
||||
|
||||
Typical accuracies available between 2 machines are
|
||||
|
||||
On an ethernet LAN : 100-200 microseconds, often much better
|
||||
On a V32bis dial-up modem connection : 10's of milliseconds (from one
|
||||
session to the next)
|
||||
|
||||
With a good reference clock the accuracy can reach one microsecond.
|
||||
|
||||
\fIchronyd\fR can also operate as an NTPv4 (RFC 5905) server, peer and
|
||||
broadcast server.
|
||||
|
||||
.SH "SEE ALSO"
|
||||
.BR chronyc(1),
|
||||
.BR chrony.conf(5),
|
||||
.BR chronyd(8)
|
||||
|
||||
.I http://chrony.tuxfamily.org/
|
||||
|
||||
.SH AUTHOR
|
||||
Richard Curnow <rc@rc0.org.uk>
|
||||
|
||||
This man-page was written by Jan Schaumann <jschauma@netmeister.org> as part
|
||||
of "The Missing Man Pages Project". Please see
|
||||
\fIhttp://www.netmeister.org/misc/m2p2/index.html\fR for details.
|
||||
|
||||
The complete chrony documentation is supplied in texinfo format.
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
.TH chrony.conf 5 "@MAN_DATE@" "chrony @VERSION@" "Configuration Files"
|
||||
.SH NAME
|
||||
chrony.conf \- chronyd configuration file
|
||||
|
||||
.SH SYNOPSIS
|
||||
.B @SYSCONFDIR@/chrony.conf
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fIchrony\fR is a pair of programs for maintaining the accuracy of computer
|
||||
clocks. \fIchronyd\fR is a background daemon program that can be started at
|
||||
boot time.
|
||||
|
||||
Assuming that you have found some servers, you need to set up a
|
||||
configuration file to run \fIchrony\fR. The (compiled-in) default location
|
||||
for this file is \fB@SYSCONFDIR@/chrony.conf\fR. Assuming that your NTP
|
||||
servers are called `foo.example.net', `bar.example.net' and `baz.example.net',
|
||||
your \fBchrony.conf\fR file could contain as a minimum
|
||||
|
||||
.EX
|
||||
server foo.example.net
|
||||
server bar.example.net
|
||||
server baz.example.net
|
||||
.EE
|
||||
|
||||
However, you will probably want to include some of the other directives
|
||||
described in detail in the documentation supplied with the distribution
|
||||
(\fIchrony.txt\fR and \fIchrony.texi\fR). The following directives may be
|
||||
particularly useful : `driftfile', `makestep', `rtcsync'. Also, the `iburst'
|
||||
server option is useful to speed up the initial synchronization. The smallest
|
||||
useful configuration file would look something like
|
||||
|
||||
.EX
|
||||
server foo.example.net iburst
|
||||
server bar.example.net iburst
|
||||
server baz.example.net iburst
|
||||
driftfile @CHRONYVARDIR@/drift
|
||||
makestep 10 3
|
||||
rtcsync
|
||||
.EE
|
||||
|
||||
When using a pool of NTP servers (one name is used for multiple servers which
|
||||
may change over time), it's better to specify them with the `pool' directive
|
||||
instead of multiple `server' directives in order to allow \fIchronyd\fR to
|
||||
replace unreachable or bad servers automatically. The configuration file could
|
||||
in this case look like
|
||||
|
||||
.EX
|
||||
pool pool.ntp.org iburst
|
||||
driftfile @CHRONYVARDIR@/drift
|
||||
makestep 10 3
|
||||
rtcsync
|
||||
.EE
|
||||
|
||||
.SH "SEE ALSO"
|
||||
.BR chrony(1),
|
||||
.BR chronyc(1),
|
||||
.BR chronyd(8)
|
||||
|
||||
.I http://chrony.tuxfamily.org/
|
||||
|
||||
.SH AUTHOR
|
||||
Richard Curnow <rc@rc0.org.uk>
|
||||
|
||||
This man-page was written by Jan Schaumann <jschauma@netmeister.org> as part of "The Missing
|
||||
Man Pages Project". Please see \fIhttp://www.netmeister.org/misc/m2p2/index.html\fR
|
||||
for details.
|
||||
|
||||
The complete chrony documentation is supplied in texinfo format.
|
||||
|
||||
5372
chrony.texi.in
5372
chrony.texi.in
File diff suppressed because it is too large
Load Diff
75
chronyc.1.in
75
chronyc.1.in
@@ -1,75 +0,0 @@
|
||||
.TH CHRONYC 1 "@MAN_DATE@" "chrony @VERSION@" "User's Manual"
|
||||
.SH NAME
|
||||
chronyc \- command-line interface for chronyd
|
||||
|
||||
.SH SYNOPSIS
|
||||
.B chronyc
|
||||
[\fIOPTIONS\fR]
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fIchrony\fR is a pair of programs for maintaining the accuracy of computer
|
||||
clocks.
|
||||
|
||||
\fBchronyc\fR is a command-line interface program which can be used to
|
||||
monitor \fIchronyd\fR's performance and to change various operating
|
||||
parameters whilst it is running.
|
||||
|
||||
.SH USAGE
|
||||
A detailed description of all commands supported by \fBchronyc\fR is available
|
||||
via the documentation supplied with the distribution (\fIchrony.txt\fR and
|
||||
\fIchrony.texi\fR).
|
||||
|
||||
.SH OPTIONS
|
||||
A summary of the options supported by \fBchronyc\fR is included below.
|
||||
|
||||
.TP
|
||||
\fB\-h\fR \fIhostname\fR
|
||||
specify hostname (default 127.0.0.1)
|
||||
.TP
|
||||
\fB\-p\fR \fIport-number\fR
|
||||
specify port-number
|
||||
.TP
|
||||
\fB\-n\fR
|
||||
display raw IP addresses (don't attempt to look up hostnames)
|
||||
.TP
|
||||
\fB\-4\fR
|
||||
resolve hostnames only to IPv4 addresses
|
||||
.TP
|
||||
\fB\-6\fR
|
||||
resolve hostnames only to IPv6 addresses
|
||||
.TP
|
||||
\fB\-m\fR
|
||||
allow multiple commands to be specified on the command line. Each argument
|
||||
will be interpreted as a whole command.
|
||||
.TP
|
||||
\fB\-f\fR \fIconf-file\fR
|
||||
This option can be used to specify an alternate location for the
|
||||
configuration file (default \fI@SYSCONFDIR@/chrony.conf\fR). The configuration file is
|
||||
needed for the \fB-a\fR option.
|
||||
.TP
|
||||
\fB\-a\fR
|
||||
With this option chronyc will try to authenticate automatically on
|
||||
start. It will read the configuration file, read the command key from the
|
||||
keyfile and run the authhash and password commands.
|
||||
.TP
|
||||
\fIcommand\fR
|
||||
specify command. If no command is given, chronyc will read commands
|
||||
interactively.
|
||||
|
||||
.SH BUGS
|
||||
To report bugs, please visit \fIhttp://chrony.tuxfamily.org\fR
|
||||
|
||||
.SH "SEE ALSO"
|
||||
.BR chronyd(8),
|
||||
.BR chrony(1)
|
||||
|
||||
.I http://chrony.tuxfamily.org/
|
||||
|
||||
.SH AUTHOR
|
||||
Richard Curnow <rc@rc0.org.uk>
|
||||
|
||||
This man-page was written by Jan Schaumann <jschauma@netmeister.org> as part of "The Missing
|
||||
Man Pages Project". Please see \fIhttp://www.netmeister.org/misc/m2p2/index.html\fR
|
||||
for details.
|
||||
|
||||
The complete chrony documentation is supplied in texinfo format.
|
||||
154
chronyd.8.in
154
chronyd.8.in
@@ -1,154 +0,0 @@
|
||||
.TH CHRONYD 8 "@MAN_DATE@" "chrony @VERSION@" "System Administration"
|
||||
.SH NAME
|
||||
chronyd \- chrony background daemon
|
||||
|
||||
.SH SYNOPSIS
|
||||
.B chronyd
|
||||
[\fIOPTIONS\fR] [\fIconfiguration commands\fR]
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fIchrony\fR is a pair of programs for maintaining the accuracy of computer
|
||||
clocks. \fBchronyd\fR is a background daemon program that can be started at boot
|
||||
time.
|
||||
|
||||
\fBchronyd\fR is a daemon which runs in background on the
|
||||
system. It obtains measurements (e.g. via the network) of the
|
||||
system's offset relative to other systems, and adjusts the system
|
||||
time accordingly. For isolated systems, the user can periodically
|
||||
enter the correct time by hand (using \fIchronyc\fR). In either case,
|
||||
\fBchronyd\fR determines the rate at which the computer
|
||||
gains or loses time, and compensates for this.
|
||||
|
||||
.SH USAGE
|
||||
\fBchronyd\fR is usually started at boot-time and requires superuser
|
||||
privileges.
|
||||
|
||||
If \fBchronyd\fR has been installed to its default location
|
||||
\fI@SBINDIR@/chronyd\fR, starting it is simply a matter of entering the
|
||||
command:
|
||||
|
||||
\fI@SBINDIR@/chronyd\fR
|
||||
|
||||
Information messages and warnings will be logged to syslog.
|
||||
|
||||
If no configuration commands are specified on the command line,
|
||||
\fBchronyd\fR will read the commands from the configuration file
|
||||
(default \fI@SYSCONFDIR@/chrony.conf\fR).
|
||||
|
||||
.SH OPTIONS
|
||||
A summary of the options supported by \fBchronyd\fR is included below.
|
||||
|
||||
.TP
|
||||
\fB\-P\fR \fIpriority\fR
|
||||
This option will select the SCHED_FIFO real-time scheduler at the specified
|
||||
priority (which must be between 0 and 100). This mode is supported only on
|
||||
Linux.
|
||||
.TP
|
||||
.B \-m
|
||||
This option will lock chronyd into RAM so that it will never be paged out.
|
||||
This mode is only supported on Linux.
|
||||
.TP
|
||||
.B \-n
|
||||
When run in this mode, the program will not detach itself from the
|
||||
terminal.
|
||||
.TP
|
||||
.B \-d
|
||||
When run in this mode, the program will not detach itself from the
|
||||
terminal, and all messages will be sent to the terminal instead of
|
||||
to syslog. When \fBchronyd\fR was compiled with debugging support,
|
||||
this option can be used twice to print also debugging messages.
|
||||
.TP
|
||||
\fB\-f\fR \fIconf-file\fR
|
||||
This option can be used to specify an alternate location for the
|
||||
configuration file (default \fI@SYSCONFDIR@/chrony.conf\fR).
|
||||
.TP
|
||||
.B \-r
|
||||
This option will reload sample histories for each of the servers being used.
|
||||
These histories are created by using the \fIdump\fR command in \fIchronyc\fR,
|
||||
or by setting the \fIdumponexit\fR directive in the configuration file. This
|
||||
option is useful if you want to stop and restart \fBchronyd\fR briefly for any
|
||||
reason, e.g. to install a new version. However, it only makes sense on
|
||||
systems where the kernel can maintain clock compensation whilst not under
|
||||
\fBchronyd\fR's control. The only version where this happens so far is Linux.
|
||||
On systems where this is not the case, e.g. Solaris and SunOS the option
|
||||
should not be used.
|
||||
.TP
|
||||
.B \-R
|
||||
When this option is used, the \fIinitstepslew\fR directive and the
|
||||
\fImakestep\fR directive used with a positive limit will be ignored. This
|
||||
option is useful when restarting \fBchronyd\fR and can be used in conjunction
|
||||
with the \fB-r\fR option.
|
||||
.TP
|
||||
.B \-s
|
||||
This option will set the system clock from the computer's real-time
|
||||
clock. This is analogous to supplying the \fI-s\fR flag to the
|
||||
\fI/sbin/hwclock\fR program during the Linux boot sequence.
|
||||
|
||||
Support for real-time clocks is limited at present - the criteria
|
||||
are described in the section on the \fIrtcfile\fR directive in the
|
||||
documentation supplied with the distribution.
|
||||
|
||||
If used in conjunction with the \fB-r\fR flag, \fBchronyd\fR will attempt
|
||||
to preserve the old samples after setting the system clock from
|
||||
the real time clock (RTC). This can be used to allow \fBchronyd\fR to
|
||||
perform long term averaging of the gain or loss rate across system
|
||||
reboots, and is useful for dial-up systems that are shut down when
|
||||
not in use. For this to work well, it relies on \fBchronyd\fR having
|
||||
been able to determine accurate statistics for the difference
|
||||
between the RTC and system clock last time the computer was on.
|
||||
|
||||
If \fBchronyd\fR doesn't support the RTC on your computer or there is no RTC
|
||||
installed, the system clock will be set with this option forward to the time of
|
||||
the last modification of the drift file (specified by the \fIdriftfile\fR
|
||||
directive) to restore the system time at which \fBchronyd\fR was previously
|
||||
stopped.
|
||||
.TP
|
||||
\fB\-u\fR \fIuser\fR
|
||||
This option sets the name of the user to which will \fBchronyd\fR switch to
|
||||
drop root privileges if compiled with Linux capabilities support (default
|
||||
\fB@DEFAULT_USER@\fR).
|
||||
.TP
|
||||
.B \-q
|
||||
When run in this mode, chronyd will set the system clock once
|
||||
and exit. It will not detach from the terminal.
|
||||
.TP
|
||||
.B \-Q
|
||||
This option is similar to \fB\-q\fR, but it will only print the offset and
|
||||
not correct the clock.
|
||||
.TP
|
||||
.B \-v
|
||||
This option displays \fBchronyd\fR's version number to the terminal and exits
|
||||
.TP
|
||||
.B \-4
|
||||
Resolve hostnames only to IPv4 addresses and create only IPv4 sockets.
|
||||
.TP
|
||||
.B \-6
|
||||
Resolve hostnames only to IPv6 addresses and create only IPv6 sockets.
|
||||
|
||||
.SH FILES
|
||||
\fI@SYSCONFDIR@/chrony.conf\fR
|
||||
|
||||
.SH BUGS
|
||||
To report bugs, please visit \fIhttp://chrony.tuxfamily.org/\fR
|
||||
|
||||
.SH "SEE ALSO"
|
||||
\fBchronyd\fR is documented in detail in the documentation supplied with the
|
||||
distribution (\fIchrony.txt\fR and \fIchrony.texi\fR).
|
||||
|
||||
.BR chrony(1),
|
||||
.BR chronyc(1),
|
||||
.BR chrony.conf(5),
|
||||
.BR hwclock(8),
|
||||
.BR ntpd(8)
|
||||
|
||||
.I http://chrony.tuxfamily.org/
|
||||
|
||||
.SH AUTHOR
|
||||
Richard Curnow <rc@rc0.org.uk>
|
||||
|
||||
This man-page was written by Jan Schaumann <jschauma@netmeister.org> as part
|
||||
of "The Missing Man Pages Project". Please see
|
||||
\fIhttp://www.netmeister.org/misc/m2p2/index.html\fR for details.
|
||||
|
||||
The complete chrony documentation is supplied in texinfo format.
|
||||
|
||||
1251
clientlog.c
1251
clientlog.c
File diff suppressed because it is too large
Load Diff
55
clientlog.h
55
clientlog.h
@@ -31,34 +31,43 @@
|
||||
#include "sysincl.h"
|
||||
#include "reports.h"
|
||||
|
||||
typedef enum {
|
||||
CLG_NTP = 0,
|
||||
CLG_NTSKE,
|
||||
CLG_CMDMON,
|
||||
} CLG_Service;
|
||||
|
||||
typedef enum {
|
||||
CLG_PASS = 0,
|
||||
CLG_DROP,
|
||||
CLG_KOD,
|
||||
} CLG_Limit;
|
||||
|
||||
extern void CLG_Initialise(void);
|
||||
extern void CLG_Finalise(void);
|
||||
extern void CLG_LogNTPClientAccess(IPAddr *client, time_t now);
|
||||
extern void CLG_LogNTPPeerAccess(IPAddr *client, time_t now);
|
||||
extern int CLG_GetClientIndex(IPAddr *client);
|
||||
extern int CLG_LogServiceAccess(CLG_Service service, IPAddr *client, struct timespec *now);
|
||||
extern CLG_Limit CLG_LimitServiceRate(CLG_Service service, int index);
|
||||
extern void CLG_UpdateNtpStats(int auth, NTP_Timestamp_Source rx_ts_src,
|
||||
NTP_Timestamp_Source tx_ts_src);
|
||||
extern int CLG_GetNtpMinPoll(void);
|
||||
|
||||
/* When logging command packets, there are several subtypes */
|
||||
|
||||
typedef enum {
|
||||
CLG_CMD_AUTH, /* authenticated */
|
||||
CLG_CMD_NORMAL, /* normal */
|
||||
CLG_CMD_BAD_PKT /* bad version or packet length */
|
||||
} CLG_Command_Type;
|
||||
|
||||
extern void CLG_LogCommandAccess(IPAddr *client, CLG_Command_Type type, time_t now);
|
||||
/* Functions to save and retrieve timestamps for server interleaved mode */
|
||||
extern void CLG_SaveNtpTimestamps(NTP_int64 *rx_ts, struct timespec *tx_ts,
|
||||
NTP_Timestamp_Source tx_src);
|
||||
extern void CLG_UndoNtpTxTimestampSlew(NTP_int64 *rx_ts, struct timespec *tx_ts);
|
||||
extern void CLG_UpdateNtpTxTimestamp(NTP_int64 *rx_ts, struct timespec *tx_ts,
|
||||
NTP_Timestamp_Source tx_src);
|
||||
extern int CLG_GetNtpTxTimestamp(NTP_int64 *rx_ts, struct timespec *tx_ts,
|
||||
NTP_Timestamp_Source *tx_src);
|
||||
extern void CLG_DisableNtpTimestamps(NTP_int64 *rx_ts);
|
||||
|
||||
/* And some reporting functions, for use by chronyc. */
|
||||
/* TBD */
|
||||
|
||||
typedef enum {
|
||||
CLG_SUCCESS, /* All is well */
|
||||
CLG_EMPTYSUBNET, /* No hosts logged in requested subnet */
|
||||
CLG_BADSUBNET, /* Subnet requested is not 0, 8, 16 or 24 bits */
|
||||
CLG_INACTIVE, /* Facility not active */
|
||||
CLG_INDEXTOOLARGE /* Node index is higher than number of nodes present */
|
||||
} CLG_Status;
|
||||
|
||||
CLG_Status
|
||||
CLG_GetClientAccessReportByIndex(int index, RPT_ClientAccessByIndex_Report *report,
|
||||
time_t now, unsigned long *n_indices);
|
||||
extern int CLG_GetNumberOfIndices(void);
|
||||
extern int CLG_GetClientAccessReportByIndex(int index, int reset, uint32_t min_hits,
|
||||
RPT_ClientAccessByIndex_Report *report,
|
||||
struct timespec *now);
|
||||
extern void CLG_GetServerStatsReport(RPT_ServerStatsReport *report);
|
||||
|
||||
#endif /* GOT_CLIENTLOG_H */
|
||||
|
||||
48
cmac.h
Normal file
48
cmac.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2019
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Header file for CMAC.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef GOT_CMAC_H
|
||||
#define GOT_CMAC_H
|
||||
|
||||
/* Avoid overlapping with the hash enumeration */
|
||||
typedef enum {
|
||||
CMC_INVALID = 0,
|
||||
CMC_AES128 = 13,
|
||||
CMC_AES256 = 14,
|
||||
} CMC_Algorithm;
|
||||
|
||||
typedef struct CMC_Instance_Record *CMC_Instance;
|
||||
|
||||
extern int CMC_GetKeyLength(CMC_Algorithm algorithm);
|
||||
extern CMC_Instance CMC_CreateInstance(CMC_Algorithm algorithm, const unsigned char *key,
|
||||
int length);
|
||||
extern int CMC_Hash(CMC_Instance inst, const void *in, int in_len,
|
||||
unsigned char *out, int out_len);
|
||||
extern void CMC_DestroyInstance(CMC_Instance inst);
|
||||
|
||||
#endif
|
||||
|
||||
189
cmac_gnutls.c
Normal file
189
cmac_gnutls.c
Normal file
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2021
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
CMAC using the GnuTLS library
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include <gnutls/crypto.h>
|
||||
|
||||
#include "cmac.h"
|
||||
#include "hash.h"
|
||||
#include "logging.h"
|
||||
#include "memory.h"
|
||||
|
||||
struct CMC_Instance_Record {
|
||||
gnutls_mac_algorithm_t algorithm;
|
||||
gnutls_hmac_hd_t mac;
|
||||
};
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int instance_counter = 0;
|
||||
static int gnutls_initialised = 0;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
init_gnutls(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (gnutls_initialised)
|
||||
return;
|
||||
|
||||
r = gnutls_global_init();
|
||||
if (r < 0)
|
||||
LOG_FATAL("Could not initialise %s : %s", "gnutls", gnutls_strerror(r));
|
||||
|
||||
DEBUG_LOG("Initialised");
|
||||
gnutls_initialised = 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
deinit_gnutls(void)
|
||||
{
|
||||
assert(gnutls_initialised);
|
||||
gnutls_global_deinit();
|
||||
gnutls_initialised = 0;
|
||||
DEBUG_LOG("Deinitialised");
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static gnutls_mac_algorithm_t
|
||||
get_mac_algorithm(CMC_Algorithm algorithm)
|
||||
{
|
||||
switch (algorithm) {
|
||||
case CMC_AES128:
|
||||
return GNUTLS_MAC_AES_CMAC_128;
|
||||
case CMC_AES256:
|
||||
return GNUTLS_MAC_AES_CMAC_256;
|
||||
default:
|
||||
return GNUTLS_MAC_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
CMC_GetKeyLength(CMC_Algorithm algorithm)
|
||||
{
|
||||
gnutls_mac_algorithm_t malgo = get_mac_algorithm(algorithm);
|
||||
int len;
|
||||
|
||||
if (malgo == GNUTLS_MAC_UNKNOWN)
|
||||
return 0;
|
||||
|
||||
len = gnutls_hmac_get_key_size(malgo);
|
||||
|
||||
if (len < 0)
|
||||
return 0;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
CMC_Instance
|
||||
CMC_CreateInstance(CMC_Algorithm algorithm, const unsigned char *key, int length)
|
||||
{
|
||||
gnutls_hmac_hd_t handle;
|
||||
CMC_Instance inst;
|
||||
|
||||
int r;
|
||||
|
||||
if (instance_counter == 0)
|
||||
init_gnutls();
|
||||
|
||||
if (length <= 0 || length != CMC_GetKeyLength(algorithm))
|
||||
goto error;
|
||||
|
||||
r = gnutls_hmac_init(&handle, get_mac_algorithm(algorithm), key, length);
|
||||
if (r < 0) {
|
||||
DEBUG_LOG("Could not initialise %s : %s", "mac", gnutls_strerror(r));
|
||||
goto error;
|
||||
}
|
||||
|
||||
inst = MallocNew(struct CMC_Instance_Record);
|
||||
inst->algorithm = get_mac_algorithm(algorithm);
|
||||
inst->mac = handle;
|
||||
|
||||
instance_counter++;
|
||||
|
||||
return inst;
|
||||
|
||||
error:
|
||||
if (instance_counter == 0)
|
||||
deinit_gnutls();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
CMC_Hash(CMC_Instance inst, const void *in, int in_len, unsigned char *out, int out_len)
|
||||
{
|
||||
unsigned char buf[MAX_HASH_LENGTH];
|
||||
int hash_len;
|
||||
|
||||
if (in_len < 0 || out_len < 0)
|
||||
return 0;
|
||||
|
||||
hash_len = gnutls_hmac_get_len(inst->algorithm);
|
||||
|
||||
if (out_len > hash_len)
|
||||
out_len = hash_len;
|
||||
|
||||
if (hash_len > sizeof (buf))
|
||||
return 0;
|
||||
|
||||
if (gnutls_hmac(inst->mac, in, in_len) < 0) {
|
||||
/* Reset the state */
|
||||
gnutls_hmac_output(inst->mac, buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
gnutls_hmac_output(inst->mac, buf);
|
||||
memcpy(out, buf, out_len);
|
||||
|
||||
return out_len;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
CMC_DestroyInstance(CMC_Instance inst)
|
||||
{
|
||||
gnutls_hmac_deinit(inst->mac, NULL);
|
||||
Free(inst);
|
||||
|
||||
instance_counter--;
|
||||
if (instance_counter == 0)
|
||||
deinit_gnutls();
|
||||
}
|
||||
117
cmac_nettle.c
Normal file
117
cmac_nettle.c
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2019
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Support for AES128 and AES256 CMAC in Nettle.
|
||||
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include <nettle/cmac.h>
|
||||
|
||||
#include "cmac.h"
|
||||
#include "memory.h"
|
||||
|
||||
struct CMC_Instance_Record {
|
||||
int key_length;
|
||||
union {
|
||||
struct cmac_aes128_ctx aes128;
|
||||
struct cmac_aes256_ctx aes256;
|
||||
} context;
|
||||
};
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
CMC_GetKeyLength(CMC_Algorithm algorithm)
|
||||
{
|
||||
if (algorithm == CMC_AES128)
|
||||
return AES128_KEY_SIZE;
|
||||
else if (algorithm == CMC_AES256)
|
||||
return AES256_KEY_SIZE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
CMC_Instance
|
||||
CMC_CreateInstance(CMC_Algorithm algorithm, const unsigned char *key, int length)
|
||||
{
|
||||
CMC_Instance inst;
|
||||
|
||||
if (length <= 0 || length != CMC_GetKeyLength(algorithm))
|
||||
return NULL;
|
||||
|
||||
inst = MallocNew(struct CMC_Instance_Record);
|
||||
inst->key_length = length;
|
||||
|
||||
switch (length) {
|
||||
case AES128_KEY_SIZE:
|
||||
cmac_aes128_set_key(&inst->context.aes128, key);
|
||||
break;
|
||||
case AES256_KEY_SIZE:
|
||||
cmac_aes256_set_key(&inst->context.aes256, key);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return inst;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
CMC_Hash(CMC_Instance inst, const void *in, int in_len, unsigned char *out, int out_len)
|
||||
{
|
||||
if (in_len < 0 || out_len < 0)
|
||||
return 0;
|
||||
|
||||
if (out_len > CMAC128_DIGEST_SIZE)
|
||||
out_len = CMAC128_DIGEST_SIZE;
|
||||
|
||||
switch (inst->key_length) {
|
||||
case AES128_KEY_SIZE:
|
||||
cmac_aes128_update(&inst->context.aes128, in_len, in);
|
||||
cmac_aes128_digest(&inst->context.aes128, out_len, out);
|
||||
break;
|
||||
case AES256_KEY_SIZE:
|
||||
cmac_aes256_update(&inst->context.aes256, in_len, in);
|
||||
cmac_aes256_digest(&inst->context.aes256, out_len, out);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return out_len;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
CMC_DestroyInstance(CMC_Instance inst)
|
||||
{
|
||||
Free(inst);
|
||||
}
|
||||
3
cmdmon.h
3
cmdmon.h
@@ -29,10 +29,11 @@
|
||||
|
||||
#include "addressing.h"
|
||||
|
||||
extern void CAM_Initialise(int family);
|
||||
extern void CAM_Initialise(void);
|
||||
|
||||
extern void CAM_Finalise(void);
|
||||
|
||||
extern void CAM_OpenUnixSocket(void);
|
||||
extern int CAM_AddAccessRestriction(IPAddr *ip_addr, int subnet_bits, int allow, int all);
|
||||
extern int CAM_CheckAccessRestriction(IPAddr *ip_addr);
|
||||
|
||||
|
||||
508
cmdparse.c
508
cmdparse.c
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2013
|
||||
* Copyright (C) Miroslav Lichvar 2013-2014, 2016, 2021, 2025
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -39,246 +39,318 @@
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#define SSCANF_IN_RANGE(s, f, x, n, min, max) \
|
||||
(sscanf((s), (f), (x), (n)) == 1 && *(x) >= (min) && *(x) <= (max))
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
CPS_Status
|
||||
CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
|
||||
{
|
||||
char *hostname, *cmd;
|
||||
int n, done;
|
||||
CPS_Status result;
|
||||
uint32_t ef_type;
|
||||
int n, sel_option;
|
||||
|
||||
src->family = IPADDR_UNSPEC;
|
||||
src->port = SRC_DEFAULT_PORT;
|
||||
src->params.minpoll = SRC_DEFAULT_MINPOLL;
|
||||
src->params.maxpoll = SRC_DEFAULT_MAXPOLL;
|
||||
src->params.presend_minpoll = SRC_DEFAULT_PRESEND_MINPOLL;
|
||||
src->params.authkey = INACTIVE_AUTHKEY;
|
||||
src->params.max_delay = SRC_DEFAULT_MAXDELAY;
|
||||
src->params.max_delay_ratio = SRC_DEFAULT_MAXDELAYRATIO;
|
||||
src->params.max_delay_dev_ratio = SRC_DEFAULT_MAXDELAYDEVRATIO;
|
||||
src->params.online = 1;
|
||||
src->params.connectivity = SRC_ONLINE;
|
||||
src->params.auto_offline = 0;
|
||||
src->params.presend_minpoll = SRC_DEFAULT_PRESEND_MINPOLL;
|
||||
src->params.burst = 0;
|
||||
src->params.iburst = 0;
|
||||
src->params.min_stratum = SRC_DEFAULT_MINSTRATUM;
|
||||
src->params.poll_target = SRC_DEFAULT_POLLTARGET;
|
||||
src->params.version = NTP_VERSION;
|
||||
src->params.version = 0;
|
||||
src->params.max_sources = SRC_DEFAULT_MAXSOURCES;
|
||||
src->params.min_samples = SRC_DEFAULT_MINSAMPLES;
|
||||
src->params.max_samples = SRC_DEFAULT_MAXSAMPLES;
|
||||
src->params.sel_option = SRC_SelectNormal;
|
||||
src->params.max_unreach = SRC_DEFAULT_MAXUNREACH;
|
||||
src->params.filter_length = 0;
|
||||
src->params.interleaved = 0;
|
||||
src->params.sel_options = 0;
|
||||
src->params.nts = 0;
|
||||
src->params.nts_port = SRC_DEFAULT_NTSPORT;
|
||||
src->params.copy = 0;
|
||||
src->params.ext_fields = 0;
|
||||
src->params.authkey = INACTIVE_AUTHKEY;
|
||||
src->params.cert_set = SRC_DEFAULT_CERTSET;
|
||||
src->params.max_delay = SRC_DEFAULT_MAXDELAY;
|
||||
src->params.max_delay_ratio = SRC_DEFAULT_MAXDELAYRATIO;
|
||||
src->params.max_delay_dev_ratio = SRC_DEFAULT_MAXDELAYDEVRATIO;
|
||||
src->params.max_delay_quant = 0.0;
|
||||
src->params.min_delay = 0.0;
|
||||
src->params.asymmetry = SRC_DEFAULT_ASYMMETRY;
|
||||
src->params.offset = 0.0;
|
||||
|
||||
result = CPS_Success;
|
||||
|
||||
hostname = line;
|
||||
line = CPS_SplitWord(line);
|
||||
|
||||
if (!*hostname) {
|
||||
result = CPS_BadHost;
|
||||
} else {
|
||||
src->name = hostname;
|
||||
if (!*hostname)
|
||||
return CPS_MissingArgument;
|
||||
|
||||
/* Parse subfields */
|
||||
done = 0;
|
||||
do {
|
||||
cmd = line;
|
||||
line = CPS_SplitWord(line);
|
||||
src->name = hostname;
|
||||
|
||||
if (*cmd) {
|
||||
if (!strcasecmp(cmd, "port")) {
|
||||
if (sscanf(line, "%hu%n", &src->port, &n) != 1) {
|
||||
result = CPS_BadPort;
|
||||
done = 1;
|
||||
} else {
|
||||
line += n;
|
||||
}
|
||||
} else if (!strcasecmp(cmd, "minpoll")) {
|
||||
if (sscanf(line, "%d%n", &src->params.minpoll, &n) != 1) {
|
||||
result = CPS_BadMinpoll;
|
||||
done = 1;
|
||||
} else {
|
||||
line += n;
|
||||
}
|
||||
} else if (!strcasecmp(cmd, "maxpoll")) {
|
||||
if (sscanf(line, "%d%n", &src->params.maxpoll, &n) != 1) {
|
||||
result = CPS_BadMaxpoll;
|
||||
done = 1;
|
||||
} else {
|
||||
line += n;
|
||||
}
|
||||
} else if (!strcasecmp(cmd, "presend")) {
|
||||
if (sscanf(line, "%d%n", &src->params.presend_minpoll, &n) != 1) {
|
||||
result = CPS_BadPresend;
|
||||
done = 1;
|
||||
} else {
|
||||
line += n;
|
||||
}
|
||||
} else if (!strcasecmp(cmd, "maxdelaydevratio")) {
|
||||
if (sscanf(line, "%lf%n", &src->params.max_delay_dev_ratio, &n) != 1) {
|
||||
result = CPS_BadMaxdelaydevratio;
|
||||
done = 1;
|
||||
} else {
|
||||
line += n;
|
||||
}
|
||||
} else if (!strcasecmp(cmd, "maxdelayratio")) {
|
||||
if (sscanf(line, "%lf%n", &src->params.max_delay_ratio, &n) != 1) {
|
||||
result = CPS_BadMaxdelayratio;
|
||||
done = 1;
|
||||
} else {
|
||||
line += n;
|
||||
}
|
||||
} else if (!strcasecmp(cmd, "maxdelay")) {
|
||||
if (sscanf(line, "%lf%n", &src->params.max_delay, &n) != 1) {
|
||||
result = CPS_BadMaxdelay;
|
||||
done = 1;
|
||||
} else {
|
||||
line += n;
|
||||
}
|
||||
} else if (!strcasecmp(cmd, "key")) {
|
||||
if (sscanf(line, "%"SCNu32"%n", &src->params.authkey, &n) != 1 ||
|
||||
src->params.authkey == INACTIVE_AUTHKEY) {
|
||||
result = CPS_BadKey;
|
||||
done = 1;
|
||||
} else {
|
||||
line += n;
|
||||
}
|
||||
} else if (!strcasecmp(cmd, "offline")) {
|
||||
src->params.online = 0;
|
||||
/* Parse options */
|
||||
for (; *line; line += n) {
|
||||
cmd = line;
|
||||
line = CPS_SplitWord(line);
|
||||
n = 0;
|
||||
|
||||
} else if (!strcasecmp(cmd, "auto_offline")) {
|
||||
src->params.auto_offline = 1;
|
||||
|
||||
} else if (!strcasecmp(cmd, "iburst")) {
|
||||
src->params.iburst = 1;
|
||||
|
||||
} else if (!strcasecmp(cmd, "minstratum")) {
|
||||
if (sscanf(line, "%d%n", &src->params.min_stratum, &n) != 1) {
|
||||
result = CPS_BadMinstratum;
|
||||
done = 1;
|
||||
} else {
|
||||
line += n;
|
||||
}
|
||||
|
||||
} else if (!strcasecmp(cmd, "polltarget")) {
|
||||
if (sscanf(line, "%d%n", &src->params.poll_target, &n) != 1) {
|
||||
result = CPS_BadPolltarget;
|
||||
done = 1;
|
||||
} else {
|
||||
line += n;
|
||||
}
|
||||
|
||||
} else if (!strcasecmp(cmd, "noselect")) {
|
||||
src->params.sel_option = SRC_SelectNoselect;
|
||||
|
||||
} else if (!strcasecmp(cmd, "prefer")) {
|
||||
src->params.sel_option = SRC_SelectPrefer;
|
||||
|
||||
} else if (!strcasecmp(cmd, "version")) {
|
||||
if (sscanf(line, "%d%n", &src->params.version, &n) != 1) {
|
||||
result = CPS_BadVersion;
|
||||
done = 1;
|
||||
} else {
|
||||
line += n;
|
||||
}
|
||||
|
||||
} else if (!strcasecmp(cmd, "maxsources")) {
|
||||
if (sscanf(line, "%d%n", &src->params.max_sources, &n) != 1) {
|
||||
result = CPS_BadMaxsources;
|
||||
done = 1;
|
||||
} else {
|
||||
line += n;
|
||||
}
|
||||
|
||||
} else if (!strcasecmp(cmd, "minsamples")) {
|
||||
if (sscanf(line, "%d%n", &src->params.min_samples, &n) != 1) {
|
||||
result = CPS_BadMinsamples;
|
||||
done = 1;
|
||||
} else {
|
||||
line += n;
|
||||
}
|
||||
|
||||
} else if (!strcasecmp(cmd, "maxsamples")) {
|
||||
if (sscanf(line, "%d%n", &src->params.max_samples, &n) != 1) {
|
||||
result = CPS_BadMaxsamples;
|
||||
done = 1;
|
||||
} else {
|
||||
line += n;
|
||||
}
|
||||
|
||||
} else {
|
||||
result = CPS_BadOption;
|
||||
done = 1;
|
||||
}
|
||||
} else {
|
||||
done = 1;
|
||||
if (!strcasecmp(cmd, "auto_offline")) {
|
||||
src->params.auto_offline = 1;
|
||||
} else if (!strcasecmp(cmd, "burst")) {
|
||||
src->params.burst = 1;
|
||||
} else if (!strcasecmp(cmd, "copy")) {
|
||||
src->params.copy = 1;
|
||||
} else if (!strcasecmp(cmd, "iburst")) {
|
||||
src->params.iburst = 1;
|
||||
} else if (!strcasecmp(cmd, "offline")) {
|
||||
src->params.connectivity = SRC_OFFLINE;
|
||||
} else if (!strcasecmp(cmd, "certset")) {
|
||||
if (sscanf(line, "%"SCNu32"%n", &src->params.cert_set, &n) != 1)
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "key")) {
|
||||
if (sscanf(line, "%"SCNu32"%n", &src->params.authkey, &n) != 1 ||
|
||||
src->params.authkey == INACTIVE_AUTHKEY)
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "asymmetry")) {
|
||||
if (sscanf(line, "%lf%n", &src->params.asymmetry, &n) != 1)
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "extfield")) {
|
||||
if (sscanf(line, "%"SCNx32"%n", &ef_type, &n) != 1)
|
||||
return CPS_InvalidValue;
|
||||
switch (ef_type) {
|
||||
case NTP_EF_EXP_MONO_ROOT:
|
||||
src->params.ext_fields |= NTP_EF_FLAG_EXP_MONO_ROOT;
|
||||
break;
|
||||
case NTP_EF_EXP_NET_CORRECTION:
|
||||
src->params.ext_fields |= NTP_EF_FLAG_EXP_NET_CORRECTION;
|
||||
break;
|
||||
default:
|
||||
return CPS_InvalidValue;
|
||||
}
|
||||
} while (!done);
|
||||
} else if (!strcasecmp(cmd, "filter")) {
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &src->params.filter_length, &n, 0, INT_MAX))
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "ipv4")) {
|
||||
src->family = IPADDR_INET4;
|
||||
} else if (!strcasecmp(cmd, "ipv6")) {
|
||||
src->family = IPADDR_INET6;
|
||||
} else if (!strcasecmp(cmd, "maxdelay")) {
|
||||
if (sscanf(line, "%lf%n", &src->params.max_delay, &n) != 1)
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "maxdelayratio")) {
|
||||
if (sscanf(line, "%lf%n", &src->params.max_delay_ratio, &n) != 1)
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "maxdelaydevratio")) {
|
||||
if (sscanf(line, "%lf%n", &src->params.max_delay_dev_ratio, &n) != 1)
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "maxdelayquant")) {
|
||||
if (sscanf(line, "%lf%n", &src->params.max_delay_quant, &n) != 1)
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "maxpoll")) {
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &src->params.maxpoll, &n, -32, 32))
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "maxsamples")) {
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &src->params.max_samples, &n, 0, INT_MAX))
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "maxsources")) {
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &src->params.max_sources, &n, 1, INT_MAX))
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "maxunreach")) {
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &src->params.max_unreach, &n, 0, INT_MAX))
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "mindelay")) {
|
||||
if (sscanf(line, "%lf%n", &src->params.min_delay, &n) != 1)
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "minpoll")) {
|
||||
if (sscanf(line, "%d%n", &src->params.minpoll, &n) != 1)
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "minsamples")) {
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &src->params.min_samples, &n, 0, INT_MAX))
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "minstratum")) {
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &src->params.min_stratum, &n, 0, NTP_MAX_STRATUM))
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "nts")) {
|
||||
src->params.nts = 1;
|
||||
} else if (!strcasecmp(cmd, "ntsport")) {
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &src->params.nts_port, &n, 0, 65535))
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "offset")) {
|
||||
if (sscanf(line, "%lf%n", &src->params.offset, &n) != 1)
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "port")) {
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &src->port, &n, 0, 65535))
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "polltarget")) {
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &src->params.poll_target, &n, 1, INT_MAX))
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "presend")) {
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &src->params.presend_minpoll, &n, -32, 32))
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "version")) {
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &src->params.version, &n, 1, NTP_VERSION))
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "xleave")) {
|
||||
src->params.interleaved = 1;
|
||||
} else if ((sel_option = CPS_GetSelectOption(cmd)) != 0) {
|
||||
src->params.sel_options |= sel_option;
|
||||
} else {
|
||||
return CPS_InvalidOption;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return CPS_Success;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
CPS_StatusToString(CPS_Status status, char *dest, int len)
|
||||
int
|
||||
CPS_GetSelectOption(char *option)
|
||||
{
|
||||
const char *s = NULL;
|
||||
if (!strcasecmp(option, "noselect")) {
|
||||
return SRC_SELECT_NOSELECT;
|
||||
} else if (!strcasecmp(option, "prefer")) {
|
||||
return SRC_SELECT_PREFER;
|
||||
} else if (!strcasecmp(option, "require")) {
|
||||
return SRC_SELECT_REQUIRE;
|
||||
} else if (!strcasecmp(option, "trust")) {
|
||||
return SRC_SELECT_TRUST;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (len > 0)
|
||||
dest[0] = '\0';
|
||||
/* ================================================== */
|
||||
|
||||
switch (status) {
|
||||
case CPS_Success:
|
||||
return;
|
||||
case CPS_BadOption:
|
||||
s = "server/peer/pool option";
|
||||
break;
|
||||
case CPS_BadHost:
|
||||
s = "address";
|
||||
break;
|
||||
case CPS_BadPort:
|
||||
s = "port";
|
||||
break;
|
||||
case CPS_BadMinpoll:
|
||||
s = "minpoll";
|
||||
break;
|
||||
case CPS_BadMaxpoll:
|
||||
s = "maxpoll";
|
||||
break;
|
||||
case CPS_BadPresend:
|
||||
s = "presend";
|
||||
break;
|
||||
case CPS_BadMaxdelaydevratio:
|
||||
s = "maxdelaydevratio";
|
||||
break;
|
||||
case CPS_BadMaxdelayratio:
|
||||
s = "maxdelayratio";
|
||||
break;
|
||||
case CPS_BadMaxdelay:
|
||||
s = "maxdelay";
|
||||
break;
|
||||
case CPS_BadKey:
|
||||
s = "key";
|
||||
break;
|
||||
case CPS_BadMinstratum:
|
||||
s = "minstratum";
|
||||
break;
|
||||
case CPS_BadPolltarget:
|
||||
s = "polltarget";
|
||||
break;
|
||||
case CPS_BadVersion:
|
||||
s = "version";
|
||||
break;
|
||||
case CPS_BadMaxsources:
|
||||
s = "maxsources";
|
||||
break;
|
||||
case CPS_BadMinsamples:
|
||||
s = "minsamples";
|
||||
break;
|
||||
case CPS_BadMaxsamples:
|
||||
s = "maxsamples";
|
||||
break;
|
||||
int
|
||||
CPS_ParseAllowDeny(char *line, int *all, IPAddr *ip, int *subnet_bits)
|
||||
{
|
||||
char *p, *net, *slash;
|
||||
uint32_t a, b, c;
|
||||
int bits, len, n;
|
||||
|
||||
p = CPS_SplitWord(line);
|
||||
|
||||
if (strcmp(line, "all") == 0) {
|
||||
*all = 1;
|
||||
net = p;
|
||||
p = CPS_SplitWord(p);
|
||||
} else {
|
||||
*all = 0;
|
||||
net = line;
|
||||
}
|
||||
|
||||
snprintf(dest, len, "Invalid %s", s);
|
||||
/* Make sure there are no other arguments */
|
||||
if (*p)
|
||||
return 0;
|
||||
|
||||
/* No specified address or network means all IPv4 and IPv6 addresses */
|
||||
if (!*net) {
|
||||
ip->family = IPADDR_UNSPEC;
|
||||
*subnet_bits = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
slash = strchr(net, '/');
|
||||
if (slash) {
|
||||
if (sscanf(slash + 1, "%d%n", &bits, &len) != 1 || slash[len + 1] || bits < 0)
|
||||
return 0;
|
||||
*slash = '\0';
|
||||
} else {
|
||||
bits = -1;
|
||||
}
|
||||
|
||||
if (UTI_StringToIP(net, ip)) {
|
||||
if (bits >= 0)
|
||||
*subnet_bits = bits;
|
||||
else
|
||||
*subnet_bits = ip->family == IPADDR_INET6 ? 128 : 32;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check for a shortened IPv4 network notation using only 1, 2, or 3 decimal
|
||||
numbers. This is different than the numbers-and-dots notation accepted
|
||||
by inet_aton()! */
|
||||
|
||||
a = b = c = 0;
|
||||
n = sscanf(net, "%"PRIu32"%n.%"PRIu32"%n.%"PRIu32"%n", &a, &len, &b, &len, &c, &len);
|
||||
|
||||
if (n > 0 && !net[len]) {
|
||||
if (a > 255 || b > 255 || c > 255)
|
||||
return 0;
|
||||
|
||||
ip->family = IPADDR_INET4;
|
||||
ip->addr.in4 = (a << 24) | (b << 16) | (c << 8);
|
||||
|
||||
if (bits >= 0)
|
||||
*subnet_bits = bits;
|
||||
else
|
||||
*subnet_bits = n * 8;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* The last possibility is a hostname */
|
||||
if (bits < 0 && DNS_Name2IPAddress(net, ip, 1) == DNS_Success) {
|
||||
*subnet_bits = ip->family == IPADDR_INET6 ? 128 : 32;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
CPS_Status
|
||||
CPS_ParseLocal(char *line, int *stratum, int *orphan, double *distance, double *activate,
|
||||
double *wait_synced, double *wait_unsynced)
|
||||
{
|
||||
int n;
|
||||
char *cmd;
|
||||
|
||||
*stratum = 10;
|
||||
*distance = 1.0;
|
||||
*activate = 0.0;
|
||||
*orphan = 0;
|
||||
*wait_synced = 0;
|
||||
*wait_unsynced = -1.0;
|
||||
|
||||
while (*line) {
|
||||
cmd = line;
|
||||
line = CPS_SplitWord(line);
|
||||
|
||||
if (!strcasecmp(cmd, "stratum")) {
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", stratum, &n, 1, NTP_MAX_STRATUM - 1))
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "orphan")) {
|
||||
*orphan = 1;
|
||||
n = 0;
|
||||
} else if (!strcasecmp(cmd, "distance")) {
|
||||
if (sscanf(line, "%lf%n", distance, &n) != 1)
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "activate")) {
|
||||
if (sscanf(line, "%lf%n", activate, &n) != 1)
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "waitsynced")) {
|
||||
if (sscanf(line, "%lf%n", wait_synced, &n) != 1)
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "waitunsynced")) {
|
||||
if (sscanf(line, "%lf%n", wait_unsynced, &n) != 1)
|
||||
return CPS_InvalidValue;
|
||||
} else {
|
||||
return CPS_InvalidOption;
|
||||
}
|
||||
|
||||
line += n;
|
||||
}
|
||||
|
||||
if (*wait_unsynced < 0.0)
|
||||
*wait_unsynced = *orphan ? 300 : 0.0;
|
||||
|
||||
return CPS_Success;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -341,7 +413,7 @@ CPS_SplitWord(char *line)
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
CPS_ParseKey(char *line, uint32_t *id, const char **hash, char **key)
|
||||
CPS_ParseKey(char *line, uint32_t *id, const char **type, char **key)
|
||||
{
|
||||
char *s1, *s2, *s3, *s4;
|
||||
|
||||
@@ -358,12 +430,28 @@ CPS_ParseKey(char *line, uint32_t *id, const char **hash, char **key)
|
||||
return 0;
|
||||
|
||||
if (*s3) {
|
||||
*hash = s2;
|
||||
*type = s2;
|
||||
*key = s3;
|
||||
} else {
|
||||
*hash = "MD5";
|
||||
*type = "MD5";
|
||||
*key = s2;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
CPS_ParseRefid(char *line, uint32_t *ref_id)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = *ref_id = 0; line[i] && !isspace((unsigned char)line[i]); i++) {
|
||||
if (i >= 4)
|
||||
return 0;
|
||||
*ref_id |= (uint32_t)line[i] << (24 - i * 8);
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
38
cmdparse.h
38
cmdparse.h
@@ -32,35 +32,30 @@
|
||||
|
||||
typedef enum {
|
||||
CPS_Success,
|
||||
CPS_BadOption,
|
||||
CPS_BadHost,
|
||||
CPS_BadPort,
|
||||
CPS_BadMinpoll,
|
||||
CPS_BadMaxpoll,
|
||||
CPS_BadPresend,
|
||||
CPS_BadMaxdelaydevratio,
|
||||
CPS_BadMaxdelayratio,
|
||||
CPS_BadMaxdelay,
|
||||
CPS_BadKey,
|
||||
CPS_BadMinstratum,
|
||||
CPS_BadPolltarget,
|
||||
CPS_BadVersion,
|
||||
CPS_BadMaxsources,
|
||||
CPS_BadMinsamples,
|
||||
CPS_BadMaxsamples,
|
||||
CPS_InvalidValue,
|
||||
CPS_InvalidOption,
|
||||
CPS_MissingArgument,
|
||||
} CPS_Status;
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
unsigned short port;
|
||||
int family;
|
||||
int port;
|
||||
SourceParameters params;
|
||||
} CPS_NTP_Source;
|
||||
|
||||
/* Parse a command to add an NTP server or peer */
|
||||
extern CPS_Status CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src);
|
||||
|
||||
/* Get a string describing error status */
|
||||
extern void CPS_StatusToString(CPS_Status status, char *dest, int len);
|
||||
/* Get an NTP/refclock select option */
|
||||
extern int CPS_GetSelectOption(char *option);
|
||||
|
||||
/* Parse a command to allow/deny access */
|
||||
extern int CPS_ParseAllowDeny(char *line, int *all, IPAddr *ip, int *subnet_bits);
|
||||
|
||||
/* Parse a command to enable local reference */
|
||||
extern CPS_Status CPS_ParseLocal(char *line, int *stratum, int *orphan, double *distance,
|
||||
double *activate, double *wait_synced, double *wait_unsynced);
|
||||
|
||||
/* Remove extra white-space and comments */
|
||||
extern void CPS_NormalizeLine(char *line);
|
||||
@@ -69,6 +64,9 @@ extern void CPS_NormalizeLine(char *line);
|
||||
extern char *CPS_SplitWord(char *line);
|
||||
|
||||
/* Parse a key from keyfile */
|
||||
extern int CPS_ParseKey(char *line, uint32_t *id, const char **hash, char **key);
|
||||
extern int CPS_ParseKey(char *line, uint32_t *id, const char **type, char **key);
|
||||
|
||||
/* Parse a refclock reference ID (returns number of characters) */
|
||||
extern int CPS_ParseRefid(char *line, uint32_t *ref_id);
|
||||
|
||||
#endif /* GOT_CMDPARSE_H */
|
||||
|
||||
87
conf.h
87
conf.h
@@ -29,28 +29,39 @@
|
||||
#define GOT_CONF_H
|
||||
|
||||
#include "addressing.h"
|
||||
#include "array.h"
|
||||
#include "reference.h"
|
||||
#include "sources.h"
|
||||
|
||||
extern void CNF_Initialise(int restarted);
|
||||
extern void CNF_Initialise(int restarted, int client_only);
|
||||
extern void CNF_Finalise(void);
|
||||
|
||||
extern void CNF_EnablePrint(void);
|
||||
|
||||
extern char *CNF_GetRtcDevice(void);
|
||||
|
||||
extern void CNF_ReadFile(const char *filename);
|
||||
extern void CNF_ParseLine(const char *filename, int number, char *line);
|
||||
|
||||
extern void CNF_CreateDirs(uid_t uid, gid_t gid);
|
||||
|
||||
extern void CNF_CheckReadOnlyAccess(void);
|
||||
|
||||
extern void CNF_AddInitSources(void);
|
||||
extern void CNF_AddSources(void);
|
||||
extern void CNF_AddBroadcasts(void);
|
||||
extern void CNF_AddRefclocks(void);
|
||||
|
||||
extern void CNF_ReloadSources(void);
|
||||
|
||||
extern int CNF_GetAcquisitionPort(void);
|
||||
extern int CNF_GetNTPPort(void);
|
||||
extern char *CNF_GetDriftFile(void);
|
||||
extern char *CNF_GetDriftFile(int *interval);
|
||||
extern char *CNF_GetLogDir(void);
|
||||
extern char *CNF_GetDumpDir(void);
|
||||
extern int CNF_GetLogBanner(void);
|
||||
extern int CNF_GetLogMeasurements(void);
|
||||
extern int CNF_GetLogMeasurements(int *raw);
|
||||
extern int CNF_GetLogSelection(void);
|
||||
extern int CNF_GetLogStatistics(void);
|
||||
extern int CNF_GetLogTracking(void);
|
||||
extern int CNF_GetLogRtc(void);
|
||||
@@ -58,16 +69,14 @@ extern int CNF_GetLogRefclocks(void);
|
||||
extern int CNF_GetLogTempComp(void);
|
||||
extern char *CNF_GetKeysFile(void);
|
||||
extern char *CNF_GetRtcFile(void);
|
||||
extern uint32_t CNF_GetCommandKey(void);
|
||||
extern int CNF_GetGenerateCommandKey(void);
|
||||
extern int CNF_GetDumpOnExit(void);
|
||||
extern int CNF_GetManualEnabled(void);
|
||||
extern ARR_Instance CNF_GetOpenCommands(void);
|
||||
extern int CNF_GetCommandPort(void);
|
||||
extern int CNF_GetRtcOnUtc(void);
|
||||
extern int CNF_GetRtcSync(void);
|
||||
extern void CNF_GetMakeStep(int *limit, double *threshold);
|
||||
extern void CNF_GetMaxChange(int *delay, int *ignore, double *offset);
|
||||
extern void CNF_GetLogChange(int *enabled, double *threshold);
|
||||
extern double CNF_GetLogChange(void);
|
||||
extern void CNF_GetMailOnChange(int *enabled, double *threshold, char **user);
|
||||
extern int CNF_GetNoClientLog(void);
|
||||
extern unsigned long CNF_GetClientLogLimit(void);
|
||||
@@ -75,28 +84,46 @@ extern void CNF_GetFallbackDrifts(int *min, int *max);
|
||||
extern void CNF_GetBindAddress(int family, IPAddr *addr);
|
||||
extern void CNF_GetBindAcquisitionAddress(int family, IPAddr *addr);
|
||||
extern void CNF_GetBindCommandAddress(int family, IPAddr *addr);
|
||||
extern char *CNF_GetBindNtpInterface(void);
|
||||
extern char *CNF_GetBindAcquisitionInterface(void);
|
||||
extern char *CNF_GetBindCommandInterface(void);
|
||||
extern char *CNF_GetBindCommandPath(void);
|
||||
extern int CNF_GetNtpDscp(void);
|
||||
extern char *CNF_GetNtpSigndSocket(void);
|
||||
extern char *CNF_GetPidFile(void);
|
||||
extern REF_LeapMode CNF_GetLeapSecMode(void);
|
||||
extern char *CNF_GetLeapSecTimezone(void);
|
||||
extern char *CNF_GetLeapSecList(void);
|
||||
|
||||
/* Value returned in ppm, as read from file */
|
||||
extern double CNF_GetMaxUpdateSkew(void);
|
||||
extern double CNF_GetMaxClockError(void);
|
||||
extern double CNF_GetMaxDrift(void);
|
||||
extern double CNF_GetCorrectionTimeRatio(void);
|
||||
extern double CNF_GetMaxSlewRate(void);
|
||||
extern double CNF_GetClockPrecision(void);
|
||||
|
||||
extern SRC_AuthSelectMode CNF_GetAuthSelectMode(void);
|
||||
extern double CNF_GetMaxDistance(void);
|
||||
extern double CNF_GetMaxJitter(void);
|
||||
extern int CNF_GetMaxStratum(void);
|
||||
extern int CNF_GetMinStratum(void);
|
||||
extern double CNF_GetReselectDistance(void);
|
||||
extern double CNF_GetStratumWeight(void);
|
||||
extern double CNF_GetCombineLimit(void);
|
||||
|
||||
extern int CNF_AllowLocalReference(int *stratum);
|
||||
extern int CNF_AllowLocalReference(int *stratum, int *orphan, double *distance, double *activate,
|
||||
double *wait_synced, double *wait_unsynced);
|
||||
|
||||
extern void CNF_SetupAccessRestrictions(void);
|
||||
|
||||
extern int CNF_GetSchedPriority(void);
|
||||
extern int CNF_GetLockMemory(void);
|
||||
|
||||
extern void CNF_GetSmooth(double *max_freq, double *max_wander);
|
||||
extern int CNF_GetNTPRateLimit(int *interval, int *burst, int *leak, int *kod);
|
||||
extern int CNF_GetNtsRateLimit(int *interval, int *burst, int *leak);
|
||||
extern int CNF_GetCommandRateLimit(int *interval, int *burst, int *leak);
|
||||
extern void CNF_GetSmooth(double *max_freq, double *max_wander, int *leap_only);
|
||||
extern void CNF_GetTempComp(char **file, double *interval, char **point_file, double *T0, double *k0, double *k1, double *k2);
|
||||
|
||||
extern char *CNF_GetUser(void);
|
||||
@@ -112,4 +139,46 @@ extern char *CNF_GetHwclockFile(void);
|
||||
extern int CNF_GetInitSources(void);
|
||||
extern double CNF_GetInitStepThreshold(void);
|
||||
|
||||
typedef enum {
|
||||
CNF_HWTS_RXFILTER_ANY,
|
||||
CNF_HWTS_RXFILTER_NONE,
|
||||
CNF_HWTS_RXFILTER_NTP,
|
||||
CNF_HWTS_RXFILTER_PTP,
|
||||
CNF_HWTS_RXFILTER_ALL,
|
||||
} CNF_HwTs_RxFilter;
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
int minpoll;
|
||||
int maxpoll;
|
||||
int min_samples;
|
||||
int max_samples;
|
||||
int nocrossts;
|
||||
CNF_HwTs_RxFilter rxfilter;
|
||||
double precision;
|
||||
double tx_comp;
|
||||
double rx_comp;
|
||||
} CNF_HwTsInterface;
|
||||
|
||||
extern int CNF_GetHwTsInterface(unsigned int index, CNF_HwTsInterface **iface);
|
||||
extern double CNF_GetHwTsTimeout(void);
|
||||
|
||||
extern int CNF_GetPtpPort(void);
|
||||
extern int CNF_GetPtpDomain(void);
|
||||
|
||||
extern int CNF_GetRefresh(void);
|
||||
|
||||
extern ARR_Instance CNF_GetNtsAeads(void);
|
||||
extern char *CNF_GetNtsDumpDir(void);
|
||||
extern char *CNF_GetNtsNtpServer(void);
|
||||
extern int CNF_GetNtsServerCertAndKeyFiles(const char ***certs, const char ***keys);
|
||||
extern int CNF_GetNtsServerPort(void);
|
||||
extern int CNF_GetNtsServerProcesses(void);
|
||||
extern int CNF_GetNtsServerConnections(void);
|
||||
extern int CNF_GetNtsRefresh(void);
|
||||
extern int CNF_GetNtsRotate(void);
|
||||
extern int CNF_GetNtsTrustedCertsPaths(const char ***paths, uint32_t **ids);
|
||||
extern int CNF_GetNoSystemCert(void);
|
||||
extern int CNF_GetNoCertTimeCheck(void);
|
||||
|
||||
#endif /* GOT_CONF_H */
|
||||
|
||||
103
contrib/bryan_christianson_1/README.txt
Normal file
103
contrib/bryan_christianson_1/README.txt
Normal file
@@ -0,0 +1,103 @@
|
||||
Notes for installing chrony on macOS
|
||||
Author: Bryan Christianson (bryan@whatroute.net)
|
||||
------------------------------------------------
|
||||
|
||||
These files are for those admins/users who would prefer to install chrony
|
||||
from the source distribution and are intended as guidelines rather than
|
||||
being definitive. They can be edited with a plain text editor, such as
|
||||
vi, emacs or your favourite IDE (Xcode)
|
||||
|
||||
It is assumed you are comfortable with installing software from the
|
||||
terminal command line and know how to use sudo to acquire root access.
|
||||
|
||||
If you are not familiar with the macOS command line then
|
||||
please consider using ChronyControl from http://whatroute.net/chronycontrol.html
|
||||
|
||||
ChronyControl provides a gui wrapper for installing these files and sets the
|
||||
necessary permissions on each file.
|
||||
|
||||
|
||||
Install the chrony software
|
||||
---------------------------
|
||||
|
||||
You will need xcode and the commandline additions to build and install chrony.
|
||||
These can be obtained from Apple's website via the App Store.
|
||||
|
||||
cd to the chrony directory
|
||||
./configure
|
||||
make
|
||||
sudo make install
|
||||
|
||||
chrony is now installed in default locations (/usr/local/sbin/chronyd,
|
||||
/usr/local/bin/chronyc)
|
||||
|
||||
Create a chrony.conf file - see the chrony website for details
|
||||
|
||||
The support files here assume the following directives are specified in the
|
||||
chrony.conf file
|
||||
|
||||
keyfile /etc/chrony.d/chrony.keys
|
||||
driftfile /var/db/chrony/chrony.drift
|
||||
bindcmdaddress /var/db/chrony/chronyd.sock
|
||||
logdir /var/log/chrony
|
||||
dumpdir /var/db/chrony
|
||||
|
||||
Install this file as /etc/chrony.d/chrony.conf and create
|
||||
the directories specified in the above directives if they don't exist.
|
||||
You will need root permissions to create the directories.
|
||||
|
||||
|
||||
Running chronyd
|
||||
---------------
|
||||
At this point chronyd *could* be run as a daemon. Apple discourage running
|
||||
daemons and their preferred method uses the launchd facility. The
|
||||
support files here provide a launchd configuration file for chronyd and also
|
||||
a shell script and launchd configuration file to rotate the chronyd logs on a daily basis.
|
||||
|
||||
|
||||
Support files
|
||||
-------------
|
||||
Dates and sizes may differ
|
||||
-rw-r--r-- 1 yourname staff 2084 4 Aug 22:54 README.txt
|
||||
-rwxr-xr-x 1 yourname staff 676 4 Aug 21:18 chronylogrotate.sh
|
||||
-rw-r--r-- 1 yourname staff 543 18 Jul 20:10 org.chrony-project.chronyc.plist
|
||||
-rw-r--r-- 1 yourname staff 511 19 Jun 18:30 org.chrony-project.chronyd.plist
|
||||
|
||||
If you have used chrony support directories other than those suggested, you
|
||||
will need to edit each file and make the appropriate changes.
|
||||
|
||||
|
||||
Installing the support files
|
||||
----------------------------
|
||||
|
||||
1. chronylogrotate.sh
|
||||
This is a simple shell script that deletes old log files. Unfortunately because
|
||||
of the need to run chronyc, the standard macOS logrotation does not work with
|
||||
chrony logs.
|
||||
|
||||
This script runs on a daily basis under control of launchd and should be
|
||||
installed in the /usr/local/bin directory
|
||||
|
||||
sudo cp chronylogrotate.sh /usr/local/bin
|
||||
sudo chmod +x /usr/local/bin/chronylogrotate.sh
|
||||
sudo chown root:wheel /usr/local/bin/chronylogrotate.sh
|
||||
|
||||
|
||||
2. org.chrony-project.chronyc.plist
|
||||
This file is the launchd plist that runs logrotation each day. You may
|
||||
wish to edit this file to change the time of day at which the rotation
|
||||
will run, currently 04:05 am
|
||||
|
||||
sudo cp org.chrony-project.chronyc.plist /Library/LaunchDaemons
|
||||
sudo chown root:wheel /Library/LaunchDaemons/org.chrony-project.chronyc.plist
|
||||
sudo chmod 0644 /Library/LaunchDaemons/org.chrony-project.chronyc.plist
|
||||
sudo launchctl load -w /Library/LaunchDaemons/org.chrony-project.chronyc.plist
|
||||
|
||||
|
||||
3. org.chrony-project.chronyd.plist
|
||||
This file is the launchd plist that runs chronyd when the Macintosh starts.
|
||||
|
||||
sudo cp org.chrony-project.chronyd.plist /Library/LaunchDaemons
|
||||
sudo chown root:wheel /Library/LaunchDaemons/org.chrony-project.chronyd.plist
|
||||
sudo chmod 0644 /Library/LaunchDaemons/org.chrony-project.chronyd.plist
|
||||
sudo launchctl load -w /Library/LaunchDaemons/org.chrony-project.chronyd.plist
|
||||
58
contrib/bryan_christianson_1/chronylogrotate.sh
Executable file
58
contrib/bryan_christianson_1/chronylogrotate.sh
Executable file
@@ -0,0 +1,58 @@
|
||||
#!/bin/sh
|
||||
|
||||
# chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
#
|
||||
# **********************************************************************
|
||||
# * Copyright (C) Bryan Christianson 2015
|
||||
# *
|
||||
# * This program is free software; you can redistribute it and/or modify
|
||||
# * it under the terms of version 2 of the GNU General Public License as
|
||||
# * published by the Free Software Foundation.
|
||||
# *
|
||||
# * This program is distributed in the hope that it will be useful, but
|
||||
# * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# * General Public License for more details.
|
||||
# *
|
||||
# * You should have received a copy of the GNU General Public License along
|
||||
# * with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
# *
|
||||
# **********************************************************************
|
||||
|
||||
LOGDIR=/var/log/chrony
|
||||
|
||||
rotate () {
|
||||
prefix=$1
|
||||
|
||||
rm -f $prefix.log.10
|
||||
|
||||
for (( count=9; count>= 0; count-- ))
|
||||
do
|
||||
next=$(( $count+1 ))
|
||||
if [ -f $prefix.log.$count ]; then
|
||||
mv $prefix.log.$count $prefix.log.$next
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -f $prefix.log ]; then
|
||||
mv $prefix.log $prefix.log.0
|
||||
fi
|
||||
}
|
||||
|
||||
if [ ! -e "$LOGDIR" ]; then
|
||||
logger -s "missing directory: $LOGDIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd $LOGDIR
|
||||
|
||||
rotate measurements
|
||||
rotate statistics
|
||||
rotate tracking
|
||||
|
||||
#
|
||||
# signal chronyd via chronyc
|
||||
/usr/local/bin/chronyc cyclelogs > /dev/null
|
||||
|
||||
exit $?
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>org.chrony-project.logrotate</string>
|
||||
<key>KeepAlive</key>
|
||||
<false/>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/bin/sh</string>
|
||||
<string>/usr/local/bin/chronylogrotate.sh</string>
|
||||
</array>
|
||||
<key>StartCalendarInterval</key>
|
||||
<dict>
|
||||
<key>Minute</key>
|
||||
<integer>5</integer>
|
||||
<key>Hour</key>
|
||||
<integer>4</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>org.chrony-project.chronyd</string>
|
||||
<key>Program</key>
|
||||
<string>/usr/local/sbin/chronyd</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>chronyd</string>
|
||||
<string>-n</string>
|
||||
<string>-f</string>
|
||||
<string>/private/etc/chrony.d/chrony.conf</string>
|
||||
</array>
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
78
doc/Makefile.in
Normal file
78
doc/Makefile.in
Normal file
@@ -0,0 +1,78 @@
|
||||
ADOC = asciidoctor
|
||||
ADOC_FLAGS =
|
||||
SED = sed
|
||||
HTML_TO_TXT = w3m -dump -T text/html
|
||||
|
||||
MAN_FILES = chrony.conf.man chronyc.man chronyd.man
|
||||
TXT_FILES = faq.txt installation.txt
|
||||
HTML_FILES = $(MAN_FILES:%.man=%.html) $(TXT_FILES:%.txt=%.html)
|
||||
MAN_IN_FILES = $(MAN_FILES:%.man=%.man.in)
|
||||
|
||||
SYSCONFDIR = @SYSCONFDIR@
|
||||
BINDIR = @BINDIR@
|
||||
SBINDIR = @SBINDIR@
|
||||
MANDIR = @MANDIR@
|
||||
DOCDIR = @DOCDIR@
|
||||
CHRONYRUNDIR = @CHRONYRUNDIR@
|
||||
CHRONYVARDIR = @CHRONYVARDIR@
|
||||
CHRONY_VERSION = @CHRONY_VERSION@
|
||||
DEFAULT_USER = @DEFAULT_USER@
|
||||
DEFAULT_CHRONYC_USER = @DEFAULT_CHRONYC_USER@
|
||||
DEFAULT_HWCLOCK_FILE = @DEFAULT_HWCLOCK_FILE@
|
||||
DEFAULT_PID_FILE = @DEFAULT_PID_FILE@
|
||||
DEFAULT_RTC_DEVICE = @DEFAULT_RTC_DEVICE@
|
||||
|
||||
SED_COMMANDS = "s%\@SYSCONFDIR\@%$(SYSCONFDIR)%g;\
|
||||
s%\@BINDIR\@%$(BINDIR)%g;\
|
||||
s%\@SBINDIR\@%$(SBINDIR)%g;\
|
||||
s%\@CHRONY_VERSION\@%$(CHRONY_VERSION)%g;\
|
||||
s%\@DEFAULT_HWCLOCK_FILE\@%$(DEFAULT_HWCLOCK_FILE)%g;\
|
||||
s%\@DEFAULT_PID_FILE\@%$(DEFAULT_PID_FILE)%g;\
|
||||
s%\@DEFAULT_RTC_DEVICE\@%$(DEFAULT_RTC_DEVICE)%g;\
|
||||
s%\@DEFAULT_USER\@%$(DEFAULT_USER)%g;\
|
||||
s%\@DEFAULT_CHRONYC_USER\@%$(DEFAULT_CHRONYC_USER)%g;\
|
||||
s%\@CHRONYRUNDIR\@%$(CHRONYRUNDIR)%g;\
|
||||
s%\@CHRONYVARDIR\@%$(CHRONYVARDIR)%g;"
|
||||
|
||||
man: $(MAN_FILES) $(MAN_IN_FILES)
|
||||
html: $(HTML_FILES)
|
||||
txt: $(TXT_FILES)
|
||||
docs: man html
|
||||
|
||||
%.html: %.adoc
|
||||
$(ADOC) $(ADOC_FLAGS) -b html -o - $< | $(SED) -e $(SED_COMMANDS) > $@
|
||||
|
||||
%.man.in: %.adoc
|
||||
$(ADOC) $(ADOC_FLAGS) -b manpage -o $@ $<
|
||||
|
||||
%.man: %.man.in
|
||||
$(SED) -e $(SED_COMMANDS) < $< > $@
|
||||
|
||||
%.txt: %.html
|
||||
$(HTML_TO_TXT) < $< > $@
|
||||
|
||||
install: $(MAN_FILES)
|
||||
[ -d $(DESTDIR)$(MANDIR)/man1 ] || mkdir -p $(DESTDIR)$(MANDIR)/man1
|
||||
[ -d $(DESTDIR)$(MANDIR)/man5 ] || mkdir -p $(DESTDIR)$(MANDIR)/man5
|
||||
[ -d $(DESTDIR)$(MANDIR)/man8 ] || mkdir -p $(DESTDIR)$(MANDIR)/man8
|
||||
cp chronyc.man $(DESTDIR)$(MANDIR)/man1/chronyc.1
|
||||
chmod 644 $(DESTDIR)$(MANDIR)/man1/chronyc.1
|
||||
cp chronyd.man $(DESTDIR)$(MANDIR)/man8/chronyd.8
|
||||
chmod 644 $(DESTDIR)$(MANDIR)/man8/chronyd.8
|
||||
cp chrony.conf.man $(DESTDIR)$(MANDIR)/man5/chrony.conf.5
|
||||
chmod 644 $(DESTDIR)$(MANDIR)/man5/chrony.conf.5
|
||||
|
||||
install-docs: $(HTML_FILES)
|
||||
[ -d $(DESTDIR)$(DOCDIR) ] || mkdir -p $(DESTDIR)$(DOCDIR)
|
||||
for f in $(HTML_FILES); do \
|
||||
cp $$f $(DESTDIR)$(DOCDIR); \
|
||||
chmod 644 $(DESTDIR)$(DOCDIR)/$$f; \
|
||||
done
|
||||
|
||||
clean:
|
||||
rm -f $(MAN_FILES) $(TXT_FILES) $(HTML_FILES)
|
||||
rm -f $(MAN_IN_FILES)
|
||||
|
||||
distclean:
|
||||
rm -f $(MAN_FILES) $(TXT_FILES) $(HTML_FILES)
|
||||
rm -f Makefile
|
||||
3394
doc/chrony.conf.adoc
Normal file
3394
doc/chrony.conf.adoc
Normal file
File diff suppressed because it is too large
Load Diff
1606
doc/chronyc.adoc
Normal file
1606
doc/chronyc.adoc
Normal file
File diff suppressed because it is too large
Load Diff
243
doc/chronyd.adoc
Normal file
243
doc/chronyd.adoc
Normal file
@@ -0,0 +1,243 @@
|
||||
// This file is part of chrony
|
||||
//
|
||||
// Copyright (C) Richard P. Curnow 1997-2003
|
||||
// Copyright (C) Miroslav Lichvar 2009-2017
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of version 2 of the GNU General Public License as
|
||||
// published by the Free Software Foundation.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
= chronyd(8)
|
||||
:doctype: manpage
|
||||
:man manual: System Administration
|
||||
:man source: chrony @CHRONY_VERSION@
|
||||
|
||||
== NAME
|
||||
|
||||
chronyd - chrony daemon
|
||||
|
||||
== SYNOPSIS
|
||||
|
||||
*chronyd* [_OPTION_]... [_DIRECTIVE_]...
|
||||
|
||||
== DESCRIPTION
|
||||
|
||||
*chronyd* is a daemon for synchronisation of the system clock. It can
|
||||
synchronise the clock with NTP servers, reference clocks (e.g. a GPS receiver),
|
||||
and manual input using wristwatch and keyboard via *chronyc*. It can also
|
||||
operate as an NTPv4 (RFC 5905) server and peer to provide a time service to
|
||||
other computers in the network.
|
||||
|
||||
If no configuration directives are specified on the command line, *chronyd*
|
||||
will read them from a configuration file. The compiled-in default location of
|
||||
the file is _@SYSCONFDIR@/chrony.conf_.
|
||||
|
||||
Informational messages, warnings, and errors will be logged to syslog.
|
||||
|
||||
== OPTIONS
|
||||
|
||||
*-4*::
|
||||
With this option hostnames will be resolved only to IPv4 addresses and only
|
||||
IPv4 sockets will be created.
|
||||
|
||||
*-6*::
|
||||
With this option hostnames will be resolved only to IPv6 addresses and only
|
||||
IPv6 sockets will be created.
|
||||
|
||||
*-f* _file_::
|
||||
This option can be used to specify an alternate location for the configuration
|
||||
file. The compiled-in default value is _@SYSCONFDIR@/chrony.conf_.
|
||||
|
||||
*-n*::
|
||||
When run in this mode, the program will not detach itself from the terminal.
|
||||
|
||||
*-d*::
|
||||
When run in this mode, the program will not detach itself from the terminal,
|
||||
and all messages will be written to the terminal instead of syslog. If
|
||||
*chronyd* was compiled with enabled support for debugging, this option can be
|
||||
used twice to enable debug messages.
|
||||
|
||||
*-l* _file_::
|
||||
This option enables writing of log messages to a file instead of syslog or the
|
||||
terminal.
|
||||
|
||||
*-L* _level_::
|
||||
This option specifies the minimum severity level of messages to be written to
|
||||
the log file, syslog, or terminal. The following levels can be specified: -1
|
||||
(debug, if compiled with enabled support for debugging), 0 (informational), 1
|
||||
(warning), 2 (non-fatal error), and 3 (fatal error). The default value is 0.
|
||||
|
||||
*-p*::
|
||||
When run in this mode, *chronyd* will print the configuration and exit. It will
|
||||
not detach from the terminal. This option can be used to verify the syntax of
|
||||
the configuration and get the whole configuration, even if it is split into
|
||||
multiple files and read by the *include* or *confdir* directive.
|
||||
|
||||
*-q*::
|
||||
When run in this mode, *chronyd* will set the system clock once and exit. It
|
||||
will not detach from the terminal.
|
||||
|
||||
*-Q*::
|
||||
This option is similar to the *-q* option, except it only prints the offset
|
||||
without making any corrections of the clock and disables server ports to allow
|
||||
*chronyd* to be started without root privileges, assuming the configuration
|
||||
does not have any directives which would require them (e.g. *refclock*,
|
||||
*hwtimestamp*, *rtcfile*, etc).
|
||||
|
||||
*-r*::
|
||||
This option will try to reload and then delete files containing sample
|
||||
histories for each of the servers and reference clocks being used. The
|
||||
files are expected to be in the directory specified by the
|
||||
<<chrony.conf.adoc#dumpdir,*dumpdir*>>
|
||||
directive in the configuration file. This option is useful if you want to stop
|
||||
and restart *chronyd* briefly for any reason, e.g. to install a new version.
|
||||
However, it should be used only on systems where the kernel can maintain clock
|
||||
compensation whilst not under *chronyd*'s control (i.e. Linux, FreeBSD, NetBSD,
|
||||
illumos, and macOS 10.13 or later).
|
||||
|
||||
*-R*::
|
||||
When this option is used, the <<chrony.conf.adoc#initstepslew,*initstepslew*>>
|
||||
directive and the <<chrony.conf.adoc#makestep,*makestep*>> directive used with
|
||||
a positive limit will be ignored. This option is useful when restarting
|
||||
*chronyd* and can be used in conjunction with the *-r* option.
|
||||
|
||||
*-s*::
|
||||
This option will set the system clock from the computer's real-time clock (RTC)
|
||||
or to the last modification time of the file specified by the
|
||||
<<chrony.conf.adoc#driftfile,*driftfile*>> directive. Real-time clocks are
|
||||
supported only on Linux.
|
||||
+
|
||||
If used in conjunction with the *-r* flag, *chronyd* will attempt to preserve
|
||||
the old samples after setting the system clock from the RTC. This can be used
|
||||
to allow *chronyd* to perform long term averaging of the gain or loss rate
|
||||
across system reboots, and is useful for systems with intermittent access to
|
||||
network that are shut down when not in use. For this to work well, it relies
|
||||
on *chronyd* having been able to determine accurate statistics for the
|
||||
difference between the RTC and system clock last time the computer was on.
|
||||
+
|
||||
If the last modification time of the drift file is later than both the current
|
||||
time and the RTC time, the system time will be set to it to restore the time
|
||||
when *chronyd* was previously stopped. This is useful on computers that have no
|
||||
RTC or the RTC is broken (e.g. it has no battery).
|
||||
|
||||
*-t* _timeout_::
|
||||
This option sets a timeout (in seconds) after which *chronyd* will exit. If the
|
||||
clock is not synchronised, it will exit with a non-zero status. This is useful
|
||||
with the *-q* or *-Q* option to shorten the maximum time waiting for
|
||||
measurements, or with the *-r* option to limit the time when *chronyd* is
|
||||
running, but still allow it to adjust the frequency of the system clock.
|
||||
|
||||
*-u* _user_::
|
||||
This option sets the name of the system user to which *chronyd* will switch
|
||||
after start in order to drop root privileges. It overrides the
|
||||
<<chrony.conf.adoc#user,*user*>> directive. The compiled-in default value is
|
||||
_@DEFAULT_USER@_.
|
||||
+
|
||||
On Linux, *chronyd* needs to be compiled with support for the *libcap* library.
|
||||
On macOS, FreeBSD, NetBSD, and illumos *chronyd* forks into two processes.
|
||||
The child process retains root privileges, but can only perform a very limited
|
||||
range of privileged system calls on behalf of the parent.
|
||||
|
||||
*-U*::
|
||||
This option disables a check for root privileges to allow *chronyd* to be
|
||||
started under a non-root user, assuming the process will have all capabilities
|
||||
(e.g. provided by the service manager) and access to all files, directories,
|
||||
and devices, needed to operate correctly in the specified configuration. Note
|
||||
that different capabilities might be needed with different configurations and
|
||||
different Linux kernel versions. Starting *chronyd* under a non-root user is
|
||||
not recommended when the configuration is not known, or at least limited to
|
||||
specific directives.
|
||||
|
||||
*-F* _level_::
|
||||
This option configures system call filters loaded by *chronyd* processes if it
|
||||
was compiled with support for the Linux secure computing (seccomp) facility.
|
||||
Three levels are defined: 0, 1, 2. The filters are disabled at level 0. At
|
||||
levels 1 and 2, *chronyd* will be killed if it makes a system call which is
|
||||
blocked by the filters. The level can be specified as a negative number to
|
||||
trigger the SIGSYS signal instead of SIGKILL, which can be useful for
|
||||
debugging. The default value is 0.
|
||||
+
|
||||
At level 1, the filters allow only selected system calls that are normally
|
||||
expected to be made by *chronyd*. Other system calls are blocked. This level is
|
||||
recommended only if it is known to work on the version of the system where
|
||||
*chrony* is installed. The filters need to allow also system calls made by
|
||||
libraries that *chronyd* is using (e.g. libc), but different versions or
|
||||
implementations of the libraries might make different system calls. If the
|
||||
filters are missing a system call, *chronyd* could be killed even in normal
|
||||
operation.
|
||||
+
|
||||
At level 2, the filters block only a small number of specific system calls
|
||||
(e.g. fork and exec). This approach should avoid false positives, but the
|
||||
protection of the system against a compromised *chronyd* process is much more
|
||||
limited.
|
||||
+
|
||||
The filters cannot be enabled with the *mailonchange* directive.
|
||||
|
||||
*-P* _priority_::
|
||||
On Linux, FreeBSD, NetBSD, and illumos this option will select the SCHED_FIFO
|
||||
real-time scheduler at the specified priority (which must be between 0 and
|
||||
100). On macOS, this option must have either a value of 0 to disable the thread
|
||||
time constraint policy or 1 for the policy to be enabled. Other systems do not
|
||||
support this option. The default value is 0.
|
||||
|
||||
*-m*::
|
||||
This option will lock *chronyd* into RAM so that it will never be paged out.
|
||||
This mode is only supported on Linux, FreeBSD, NetBSD, and illumos.
|
||||
|
||||
*-x*::
|
||||
This option disables the control of the system clock. *chronyd* will not try to
|
||||
make any adjustments of the clock. It will assume the clock is free running and
|
||||
still track its offset and frequency relative to the estimated true time. This
|
||||
option allows *chronyd* to be started without the capability to adjust or set
|
||||
the system clock (e.g. in some containers) to operate as an NTP server.
|
||||
|
||||
*-v*, *--version*::
|
||||
With this option *chronyd* will print version number to the terminal and exit.
|
||||
|
||||
*-h*, *--help*::
|
||||
With this option *chronyd* will print a help message to the terminal and exit.
|
||||
|
||||
== ENVIRONMENT VARIABLES
|
||||
|
||||
*LISTEN_FDS*::
|
||||
On Linux systems, the systemd service manager may pass file descriptors for
|
||||
pre-initialised sockets to *chronyd*. The service manager allocates and binds
|
||||
the file descriptors, and passes a copy to each spawned instance of the
|
||||
service. This allows for zero-downtime service restarts as the sockets buffer
|
||||
client requests until the service is able to handle them. The service manager
|
||||
sets the LISTEN_FDS environment variable to the number of passed file
|
||||
descriptors.
|
||||
|
||||
*NOTIFY_SOCKET*::
|
||||
The systemd service manager sets this variable for services of the *notify*
|
||||
type. *chronyd* sends a message to this socket when it it is fully initialised
|
||||
and ready to accept commands (e.g. from *chronyc*), with the clock already set
|
||||
if using the *-s* option or *initstepslew* directive. It is an alternative to
|
||||
the *forking* service type, which does not need the PID file. *chronyd* needs
|
||||
to be started with the *-n* or *-d* option to not fork.
|
||||
|
||||
== FILES
|
||||
|
||||
_@SYSCONFDIR@/chrony.conf_
|
||||
|
||||
== SEE ALSO
|
||||
|
||||
<<chronyc.adoc#,*chronyc(1)*>>, <<chrony.conf.adoc#,*chrony.conf(5)*>>
|
||||
|
||||
== BUGS
|
||||
|
||||
For instructions on how to report bugs, please visit
|
||||
https://chrony-project.org/.
|
||||
|
||||
== AUTHORS
|
||||
|
||||
chrony was written by Richard Curnow, Miroslav Lichvar, and others.
|
||||
74
doc/contributing.adoc
Normal file
74
doc/contributing.adoc
Normal file
@@ -0,0 +1,74 @@
|
||||
// This file is part of chrony
|
||||
//
|
||||
// Copyright (C) Miroslav Lichvar 2024
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of version 2 of the GNU General Public License as
|
||||
// published by the Free Software Foundation.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
= Contributing
|
||||
|
||||
== Patches
|
||||
|
||||
The source code of `chrony` is maintained in a git repository at
|
||||
https://gitlab.com/chrony/chrony. Patches can be submitted to the `chrony-dev`
|
||||
mailing list, or as a merge request on gitlab. Before spending a lot of time
|
||||
implementing a new major feature, it is recommended to ask on the mailing list
|
||||
for comments about its design and whether such feature fits the goals of the
|
||||
project.
|
||||
|
||||
Each commit should be a self-contained logical change, which does not break
|
||||
the build or tests. New functionality and fixed bugs should be covered by a new
|
||||
test or an extended existing test in the test suite. The test can be included
|
||||
in the same commit or added as a separate commit. The same rule applies to
|
||||
documentation. All command-line options, configuration directives, and
|
||||
`chronyc` commands should be documented.
|
||||
|
||||
The most important tests can be executed by running `make check` or `make
|
||||
quickcheck`. The unit and system tests run on all supported systems. The system
|
||||
tests require root privileges. The simulation tests run only on Linux and
|
||||
require https://gitlab.com/chrony/clknetsim[clknetsim] to be compiled in the
|
||||
directory containing the tests, but they are executed with a merge request on
|
||||
gitlab.
|
||||
|
||||
The commit message should explain any non-trivial changes, e.g. what problem is
|
||||
the commit solving and how. The commit subject (first line of the message)
|
||||
should be written in an imperative form, prefixed with the component name if it
|
||||
is not a more general change, starting in lower case, and no period at the end.
|
||||
See the git log for examples.
|
||||
|
||||
Simpler code is better. Less code is better. Security is a top priority.
|
||||
|
||||
Assertions should catch only bugs in the `chrony` code. Unexpected values in
|
||||
external input (e.g. anything received from network) must be handled correctly
|
||||
without crashing and memory corruption. Fuzzing support is available at
|
||||
https://gitlab.com/chrony/chrony-fuzz. The fuzzing coverage is checked by the
|
||||
project maintainer before each release.
|
||||
|
||||
The code should mostly be self-documenting. Comments should explain the
|
||||
less obvious things.
|
||||
|
||||
== Coding style
|
||||
|
||||
The code uses two spaces for indentation. No tabs. The line length should
|
||||
normally not exceed 95 characters. Too much indentation indicates the code will
|
||||
not be very readable.
|
||||
|
||||
Function names are in an imperative form. Names of static functions use
|
||||
lowercase characters and underscores. Public functions, structures, typedefs
|
||||
are in CamelCase with a prefix specific to the module (e.g. LCL - local, NCR
|
||||
- NTP core, NKS - NTS-KE server, SST - sourcestats).
|
||||
|
||||
Function names are not followed by space, but keywords of the language (e.g.
|
||||
`if`, `for`, `while`, `sizeof`) are followed by space.
|
||||
|
||||
Have a look at the existing code to get a better idea what is expected.
|
||||
1239
doc/faq.adoc
Normal file
1239
doc/faq.adoc
Normal file
File diff suppressed because it is too large
Load Diff
193
doc/installation.adoc
Normal file
193
doc/installation.adoc
Normal file
@@ -0,0 +1,193 @@
|
||||
// This file is part of chrony
|
||||
//
|
||||
// Copyright (C) Richard P. Curnow 1997-2003
|
||||
// Copyright (C) Miroslav Lichvar 2009-2016
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of version 2 of the GNU General Public License as
|
||||
// published by the Free Software Foundation.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
= Installation
|
||||
|
||||
The software is distributed as source code which has to be compiled. The source
|
||||
code is supplied in the form of a gzipped tar file, which unpacks to a
|
||||
subdirectory identifying the name and version of the program.
|
||||
|
||||
A C compiler (e.g. `gcc` or `clang`) and GNU Make are needed to build `chrony`.
|
||||
The following libraries with their development files, and programs, are needed
|
||||
to enable optional features:
|
||||
|
||||
* pkg-config: detection of development libraries
|
||||
* Nettle, GnuTLS, NSS, or LibTomCrypt: secure hash functions (`SECHASH`)
|
||||
* libcap: dropping root privileges on Linux (`DROPROOT`)
|
||||
* libseccomp: system call filter on Linux (`SCFILTER`)
|
||||
* GnuTLS and Nettle: Network Time Security (`NTS`)
|
||||
* Editline: line editing in `chronyc` (`READLINE`)
|
||||
* timepps.h header: PPS reference clock
|
||||
* Asciidoctor: documentation in HTML format
|
||||
* Bash: test suite
|
||||
|
||||
The following programs are needed when building `chrony` from the git
|
||||
repository instead of a released tar file:
|
||||
|
||||
* Asciidoctor: manual pages
|
||||
* Bison: parser for chronyc settime command
|
||||
|
||||
After unpacking the source code, change directory into it, and type
|
||||
|
||||
----
|
||||
./configure
|
||||
----
|
||||
|
||||
This is a shell script that automatically determines the system type. There is
|
||||
an optional parameter `--prefix`, which indicates the directory tree where the
|
||||
software should be installed. For example,
|
||||
|
||||
----
|
||||
./configure --prefix=/opt/free
|
||||
----
|
||||
|
||||
will install the `chronyd` daemon into `/opt/free/sbin` and the `chronyc`
|
||||
control program into `/opt/free/bin`. The default value for the prefix is
|
||||
`/usr/local`.
|
||||
|
||||
The `configure` script assumes you want to use `gcc` as your compiler. If you
|
||||
want to use a different compiler, you can configure this way:
|
||||
|
||||
----
|
||||
CC=cc ./configure --prefix=/opt/free
|
||||
----
|
||||
|
||||
for Bourne-family shells, or
|
||||
|
||||
----
|
||||
setenv CC cc
|
||||
setenv CFLAGS -O
|
||||
./configure --prefix=/opt/free
|
||||
----
|
||||
|
||||
for C-family shells.
|
||||
|
||||
If the software cannot (yet) be built on your system, an error message will be
|
||||
shown. Otherwise, `Makefile` will be generated.
|
||||
|
||||
On Linux, if development files for the libcap library are available, `chronyd`
|
||||
will be built with support for dropping root privileges. On other systems no
|
||||
extra library is needed. The default user which `chronyd` should run as can be
|
||||
specified with the `--with-user` option of the `configure` script.
|
||||
|
||||
If development files for the https://www.lysator.liu.se/~nisse/nettle/[Nettle],
|
||||
https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS[NSS], or
|
||||
https://www.libtom.net/LibTomCrypt/[libtomcrypt] library are available,
|
||||
`chronyd` will be built with support for other cryptographic hash functions
|
||||
than MD5, which can be used for NTP authentication with a symmetric key. If you
|
||||
don't want to enable the support, specify the `--disable-sechash` flag to
|
||||
`configure`.
|
||||
|
||||
If development files for the editline library are available,
|
||||
`chronyc` will be built with line editing support. If you don't want this,
|
||||
specify the `--disable-readline` flag to `configure`.
|
||||
|
||||
If a `timepps.h` header is available (e.g. from the
|
||||
http://linuxpps.org[LinuxPPS project]), `chronyd` will be built with PPS API
|
||||
reference clock driver. If the header is installed in a location that isn't
|
||||
normally searched by the compiler, you can add it to the searched locations by
|
||||
setting the `CPPFLAGS` variable to `-I/path/to/timepps`.
|
||||
|
||||
The `--help` option can be specified to `configure` to print all options
|
||||
supported by the script.
|
||||
|
||||
Now type
|
||||
|
||||
----
|
||||
make
|
||||
----
|
||||
|
||||
to build the programs.
|
||||
|
||||
If you want to build the manual in HTML, type
|
||||
|
||||
----
|
||||
make docs
|
||||
----
|
||||
|
||||
Once the programs have been successfully compiled, they need to be installed in
|
||||
their target locations. This step normally needs to be performed by the
|
||||
superuser, and requires the following command to be entered.
|
||||
|
||||
----
|
||||
make install
|
||||
----
|
||||
|
||||
This will install the binaries and man pages.
|
||||
|
||||
To install the HTML version of the manual, enter the command
|
||||
|
||||
----
|
||||
make install-docs
|
||||
----
|
||||
|
||||
Now that the software is successfully installed, the next step is to set up a
|
||||
configuration file. The default location of the file is _/etc/chrony.conf_.
|
||||
Several examples of configuration with comments are included in the examples
|
||||
directory. Suppose you want to use public NTP servers from the pool.ntp.org
|
||||
project as your time reference. A minimal useful configuration file could be
|
||||
|
||||
----
|
||||
pool pool.ntp.org iburst
|
||||
makestep 1.0 3
|
||||
rtcsync
|
||||
----
|
||||
|
||||
Then, `chronyd` can be run. For security reasons, it's recommended to create an
|
||||
unprivileged user for `chronyd` and specify it with the `-u` command-line
|
||||
option or the `user` directive in the configuration file, or set the default
|
||||
user with the `--with-user` configure option before building.
|
||||
|
||||
== Support for system call filtering
|
||||
|
||||
`chronyd` can be built with support for the Linux secure computing (seccomp)
|
||||
facility. This requires development files for the
|
||||
https://github.com/seccomp/libseccomp[libseccomp] library and the
|
||||
`--enable-scfilter` option specified to `configure`. The `-F` option of
|
||||
`chronyd` will enable a system call filter, which should significantly reduce
|
||||
the kernel attack surface and possibly prevent kernel exploits from `chronyd`
|
||||
if it is compromised.
|
||||
|
||||
== Extra options for package builders
|
||||
|
||||
The `configure` and `make` procedures have some extra options that may be
|
||||
useful if you are building a distribution package for `chrony`.
|
||||
|
||||
The `--mandir=DIR` option to `configure` specifies an installation directory
|
||||
for the man pages. This overrides the `man` subdirectory of the argument to the
|
||||
`--prefix` option.
|
||||
|
||||
----
|
||||
./configure --prefix=/usr --mandir=/usr/share/man
|
||||
----
|
||||
|
||||
to set both options together.
|
||||
|
||||
The final option is the `DESTDIR` option to the `make` command. For example,
|
||||
you could use the commands
|
||||
|
||||
----
|
||||
./configure --prefix=/usr --mandir=/usr/share/man
|
||||
make all docs
|
||||
make install DESTDIR=./tmp
|
||||
cd tmp
|
||||
tar cvf - . | gzip -9 > chrony.tar.gz
|
||||
----
|
||||
|
||||
to build a package. When untarred within the root directory, this will install
|
||||
the files to the intended final locations.
|
||||
@@ -1,5 +1,6 @@
|
||||
[Unit]
|
||||
Description=Wait for chrony to synchronize system clock
|
||||
Documentation=man:chronyc(1)
|
||||
After=chronyd.service
|
||||
Requires=chronyd.service
|
||||
Before=time-sync.target
|
||||
@@ -7,11 +8,39 @@ Wants=time-sync.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
# Wait up to ~10 minutes for chronyd to synchronize and the remaining
|
||||
# clock correction to be less than 0.1 seconds
|
||||
ExecStart=/usr/bin/chronyc waitsync 60 0.1
|
||||
# Wait for chronyd to update the clock and the remaining
|
||||
# correction to be less than 0.1 seconds
|
||||
ExecStart=/usr/bin/chronyc -h 127.0.0.1,::1 waitsync 0 0.1 0.0 1
|
||||
# Wait for at most 3 minutes
|
||||
TimeoutStartSec=180
|
||||
RemainAfterExit=yes
|
||||
StandardOutput=null
|
||||
|
||||
CapabilityBoundingSet=
|
||||
DevicePolicy=closed
|
||||
DynamicUser=yes
|
||||
IPAddressAllow=localhost
|
||||
IPAddressDeny=any
|
||||
LockPersonality=yes
|
||||
MemoryDenyWriteExecute=yes
|
||||
PrivateDevices=yes
|
||||
PrivateUsers=yes
|
||||
ProtectClock=yes
|
||||
ProtectControlGroups=yes
|
||||
ProtectHome=yes
|
||||
ProtectHostname=yes
|
||||
ProtectKernelLogs=yes
|
||||
ProtectKernelModules=yes
|
||||
ProtectKernelTunables=yes
|
||||
ProtectProc=invisible
|
||||
ProtectSystem=strict
|
||||
RestrictAddressFamilies=AF_INET AF_INET6
|
||||
RestrictNamespaces=yes
|
||||
RestrictRealtime=yes
|
||||
SystemCallArchitectures=native
|
||||
SystemCallFilter=@system-service
|
||||
SystemCallFilter=~@privileged @resources
|
||||
UMask=0777
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# Use public NTP servers from the pool.ntp.org project.
|
||||
# Use four public NTP servers from the pool.ntp.org project.
|
||||
pool pool.ntp.org iburst
|
||||
|
||||
# Record the rate at which the system clock gains/losses time.
|
||||
driftfile /var/lib/chrony/drift
|
||||
|
||||
# In first three updates step the system clock instead of slew
|
||||
# if the adjustment is larger than 10 seconds.
|
||||
makestep 10 3
|
||||
# Allow the system clock to be stepped in the first three updates
|
||||
# if its offset is larger than 1 second.
|
||||
makestep 1.0 3
|
||||
|
||||
# Enable kernel synchronization of the real-time clock (RTC).
|
||||
rtcsync
|
||||
|
||||
@@ -1,37 +1,49 @@
|
||||
# Use public servers from the pool.ntp.org project.
|
||||
# Please consider joining the pool (http://www.pool.ntp.org/join.html).
|
||||
# Note: The general recommendation for an NTP client is to have at least
|
||||
# three NTP servers to be able to detect one server providing incorrect
|
||||
# time (falseticker).
|
||||
|
||||
# Use four public NTP servers from the pool.ntp.org project. If this
|
||||
# host has a static public IP address, please consider joining the pool:
|
||||
# https://www.ntppool.org/join.html
|
||||
pool pool.ntp.org iburst
|
||||
|
||||
# Record the rate at which the system clock gains/losses time.
|
||||
driftfile /var/lib/chrony/drift
|
||||
|
||||
# In first three updates step the system clock instead of slew
|
||||
# if the adjustment is larger than 10 seconds.
|
||||
makestep 10 3
|
||||
# Allow the system clock to be stepped in the first three updates
|
||||
# if its offset is larger than 1 second.
|
||||
makestep 1.0 3
|
||||
|
||||
# Enable kernel synchronization of the real-time clock (RTC).
|
||||
rtcsync
|
||||
|
||||
# Allow NTP client access from local network.
|
||||
#allow 192.168/16
|
||||
# Enable hardware timestamping on all interfaces that support it.
|
||||
#hwtimestamp *
|
||||
|
||||
# Serve time even if not synchronized to any NTP server.
|
||||
# Increase the minimum number of selectable sources required to adjust
|
||||
# the system clock.
|
||||
#minsources 2
|
||||
|
||||
# Allow NTP client access from local network.
|
||||
#allow 192.168.0.0/16
|
||||
|
||||
# Serve time even if not synchronized to a time source.
|
||||
#local stratum 10
|
||||
|
||||
# Specify file containing keys for NTP and command authentication.
|
||||
keyfile /etc/chrony.keys
|
||||
# Require authentication (nts or key option) for all NTP sources.
|
||||
#authselectmode require
|
||||
|
||||
# Specify key number for command authentication.
|
||||
commandkey 1
|
||||
# Specify file containing keys for NTP authentication.
|
||||
#keyfile /etc/chrony.keys
|
||||
|
||||
# Generate new command key on start if missing.
|
||||
generatecommandkey
|
||||
# Save NTS keys and cookies.
|
||||
ntsdumpdir /var/lib/chrony
|
||||
|
||||
# Disable logging of client accesses.
|
||||
noclientlog
|
||||
# Insert/delete leap seconds by slewing instead of stepping.
|
||||
#leapsecmode slew
|
||||
|
||||
# Send message to syslog when clock adjustment is larger than 0.5 seconds.
|
||||
logchange 0.5
|
||||
# Set the TAI-UTC offset of the system clock.
|
||||
#leapseclist /usr/share/zoneinfo/leap-seconds.list
|
||||
|
||||
# Specify directory for log files.
|
||||
logdir /var/log/chrony
|
||||
|
||||
@@ -5,22 +5,6 @@
|
||||
# want to enable. The more obscure options are not included. Refer
|
||||
# to the documentation for these.
|
||||
#
|
||||
# Copyright 2002 Richard P. Curnow
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of version 2 of the GNU General Public License as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
#
|
||||
#######################################################################
|
||||
### COMMENTS
|
||||
# Any of the following lines are comments (you have a choice of
|
||||
@@ -37,54 +21,58 @@
|
||||
#######################################################################
|
||||
### SPECIFY YOUR NTP SERVERS
|
||||
# Most computers using chrony will send measurement requests to one or
|
||||
# more 'NTP servers'. You will probably find that your Internet Service
|
||||
# more NTP servers. The general recommendation is to have at least
|
||||
# three NTP servers to be able to detect one server providing incorrect
|
||||
# time (falseticker). You will probably find that your Internet Service
|
||||
# Provider or company have one or more NTP servers that you can specify.
|
||||
# Failing that, there are a lot of public NTP servers. There is a list
|
||||
# you can access at http://support.ntp.org/bin/view/Servers/WebHome or
|
||||
# you can access at https://support.ntp.org/bin/view/Servers/WebHome or
|
||||
# you can use servers from the pool.ntp.org project.
|
||||
|
||||
! server foo.example.net iburst
|
||||
! server bar.example.net iburst
|
||||
! server baz.example.net iburst
|
||||
! server ntp1.example.net iburst
|
||||
! server ntp2.example.net iburst
|
||||
! server ntp3.example.net iburst
|
||||
|
||||
! pool pool.ntp.org iburst
|
||||
|
||||
# However, for dial-up use you probably want these instead. The word
|
||||
# 'offline' means that the server is not visible at boot time. Use
|
||||
# chronyc's 'online' command to tell chronyd that these servers have
|
||||
# become visible after you go on-line.
|
||||
|
||||
! server foo.example.net offline
|
||||
! server bar.example.net offline
|
||||
! server baz.example.net offline
|
||||
|
||||
! pool pool.ntp.org offline
|
||||
|
||||
# You may want to specify NTP 'peers' instead. If you run a network
|
||||
# with a lot of computers and want several computers running chrony to
|
||||
# have the 'front-line' interface to the public NTP servers, you can
|
||||
# 'peer' these machines together to increase robustness.
|
||||
|
||||
! peer foo.example.net
|
||||
|
||||
# There are other options to the 'server' and 'peer' directives that you
|
||||
# might want to use. For example, you can ignore measurements whose
|
||||
# round-trip-time is too large (indicating that the measurement is
|
||||
# probably useless, because you don't know which way the measurement
|
||||
# message got held up.) Consult the full documentation for details.
|
||||
|
||||
#######################################################################
|
||||
### AVOIDING POTENTIALLY BOGUS CHANGES TO YOUR CLOCK
|
||||
#
|
||||
# To avoid changes being made to your computer's gain/loss compensation
|
||||
# when the measurement history is too erratic, you might want to enable
|
||||
# one of the following lines. The first seems good for dial-up (or
|
||||
# other high-latency connections like slow leased lines), the second
|
||||
# seems OK for a LAN environment.
|
||||
# one of the following lines. The first seems good with servers on the
|
||||
# Internet, the second seems OK for a LAN environment.
|
||||
|
||||
! maxupdateskew 100
|
||||
! maxupdateskew 5
|
||||
|
||||
# If you want to increase the minimum number of selectable sources
|
||||
# required to update the system clock in order to make the
|
||||
# synchronisation more reliable, uncomment (and edit) the following
|
||||
# line.
|
||||
|
||||
! minsources 2
|
||||
|
||||
# If your computer has a good stable clock (e.g. it is not a virtual
|
||||
# machine), you might also want to reduce the maximum assumed drift
|
||||
# (frequency error) of the clock (the value is specified in ppm).
|
||||
|
||||
! maxdrift 100
|
||||
|
||||
# By default, chronyd allows synchronisation to an unauthenticated NTP
|
||||
# source (i.e. specified without the nts and key options) if it agrees with
|
||||
# a majority of authenticated NTP sources, or if no authenticated source is
|
||||
# specified. If you don't want chronyd to ever synchronise to an
|
||||
# unauthenticated NTP source, uncomment the first from the following lines.
|
||||
# If you don't want to synchronise to an unauthenticated NTP source only
|
||||
# when an authenticated source is specified, uncomment the second line.
|
||||
# If you want chronyd to ignore authentication in the source selection,
|
||||
# uncomment the third line.
|
||||
|
||||
! authselectmode require
|
||||
! authselectmode prefer
|
||||
! authselectmode ignore
|
||||
|
||||
#######################################################################
|
||||
### FILENAMES ETC
|
||||
# Chrony likes to keep information about your computer's clock in files.
|
||||
@@ -95,41 +83,42 @@
|
||||
|
||||
driftfile /var/lib/chrony/drift
|
||||
|
||||
# If you want to use the program called chronyc to configure aspects of
|
||||
# chronyd's operation once it is running (e.g. tell it the Internet link
|
||||
# has gone up or down), you need a password. This is stored in the
|
||||
# following keys file. (You also need keys to support authenticated NTP
|
||||
# exchanges between cooperating machines.) Again, this option is
|
||||
# assumed by default.
|
||||
# If you want to enable NTP authentication with symmetric keys, you will need
|
||||
# to uncomment the following line and edit the file to set up the keys.
|
||||
|
||||
keyfile /etc/chrony.keys
|
||||
! keyfile /etc/chrony.keys
|
||||
|
||||
# Tell chronyd which numbered key in the file is used as the password
|
||||
# for chronyc. (You can pick any integer up to 2**32-1. '1' is just a
|
||||
# default. Using another value will _NOT_ increase security.)
|
||||
# If you specify an NTP server with the nts option to enable authentication
|
||||
# with the Network Time Security (NTS) mechanism, or enable server NTS with
|
||||
# the ntsservercert and ntsserverkey directives below, the following line will
|
||||
# allow the client/server to save the NTS keys and cookies in order to reduce
|
||||
# the number of key establishments (NTS-KE sessions).
|
||||
|
||||
commandkey 1
|
||||
ntsdumpdir /var/lib/chrony
|
||||
|
||||
# With this directive a random password will be generated automatically.
|
||||
# If chronyd is configured to act as an NTP server and you want to enable NTS
|
||||
# for its clients, you will need a TLS certificate and private key. Uncomment
|
||||
# and edit the following lines to specify the locations of the certificate and
|
||||
# key.
|
||||
|
||||
generatecommandkey
|
||||
! ntsservercert /etc/.../nts-server.crt
|
||||
! ntsserverkey /etc/.../nts-server.key
|
||||
|
||||
# chronyd can save the measurement history for the servers to files when
|
||||
# it it exits. This is useful in 2 situations:
|
||||
# it exits. This is useful in 2 situations:
|
||||
#
|
||||
# 1. On Linux, if you stop chronyd and restart it with '-r' (e.g. after
|
||||
# 1. If you stop chronyd and restart it with the '-r' option (e.g. after
|
||||
# an upgrade), the old measurements will still be relevant when chronyd
|
||||
# is restarted. This will reduce the time needed to get accurate
|
||||
# gain/loss measurements, especially with a dial-up link.
|
||||
# gain/loss measurements.
|
||||
#
|
||||
# 2. Again on Linux, if you use the RTC support and start chronyd with
|
||||
# 2. On Linux, if you use the RTC support and start chronyd with
|
||||
# '-r -s' on bootup, measurements from the last boot will still be
|
||||
# useful (the real time clock is used to 'flywheel' chronyd between
|
||||
# boots).
|
||||
#
|
||||
# Enable these two options to use this.
|
||||
# Uncomment the following line to use this.
|
||||
|
||||
! dumponexit
|
||||
! dumpdir /var/lib/chrony
|
||||
|
||||
# chronyd writes its process ID to a file. If you try to start a second
|
||||
@@ -137,20 +126,38 @@ generatecommandkey
|
||||
# still running and bail out. If you want to change the path to the PID
|
||||
# file, uncomment this line and edit it. The default path is shown.
|
||||
|
||||
! pidfile /var/run/chronyd.pid
|
||||
! pidfile /var/run/chrony/chronyd.pid
|
||||
|
||||
# The system timezone database usually comes with a list of leap seconds and
|
||||
# corresponding TAI-UTC offsets. chronyd can use it to set the offset of the
|
||||
# system TAI clock and have an additional source of leap seconds.
|
||||
|
||||
! leapseclist /usr/share/zoneinfo/leap-seconds.list
|
||||
|
||||
#######################################################################
|
||||
### INITIAL CLOCK CORRECTION
|
||||
# This option is useful to quickly correct the clock on start if it's
|
||||
# off by a large amount. The value '10' means that if the error is less
|
||||
# than 10 seconds, it will be gradually removed by speeding up or
|
||||
# slowing down your computer's clock until it is correct. If the error
|
||||
# is above 10 seconds, an immediate time jump will be applied to correct
|
||||
# it. The value '1' means the step is allowed only on the first update
|
||||
# of the clock. Some software can get upset if the system clock jumps
|
||||
# off by a large amount. The value '1.0' means that if the error is less
|
||||
# than 1 second, it will be gradually removed by speeding up or slowing
|
||||
# down your computer's clock until it is correct. If the error is above
|
||||
# 1 second, an immediate time jump will be applied to correct it. The
|
||||
# value '3' means the step is allowed only in the first three updates of
|
||||
# the clock. Some software can get upset if the system clock jumps
|
||||
# (especially backwards), so be careful!
|
||||
|
||||
! makestep 10 1
|
||||
! makestep 1.0 3
|
||||
|
||||
#######################################################################
|
||||
### LEAP SECONDS
|
||||
# A leap second is an occasional one-second correction of the UTC
|
||||
# time scale. By default, chronyd tells the kernel to insert/delete
|
||||
# the leap second, which makes a backward/forward step to correct the
|
||||
# clock for it. As with the makestep directive, this jump can upset
|
||||
# some applications. If you prefer chronyd to make a gradual
|
||||
# correction, causing the clock to be off for a longer time, uncomment
|
||||
# the following line.
|
||||
|
||||
! leapsecmode slew
|
||||
|
||||
#######################################################################
|
||||
### LOGGING
|
||||
@@ -171,8 +178,6 @@ generatecommandkey
|
||||
#######################################################################
|
||||
### ACTING AS AN NTP SERVER
|
||||
# You might want the computer to be an NTP server for other computers.
|
||||
# e.g. you might be running chronyd on a dial-up machine that has a LAN
|
||||
# sitting behind it with several 'satellite' computers on it.
|
||||
#
|
||||
# By default, chronyd does not allow any clients to access it. You need
|
||||
# to explicitly enable access using 'allow' and 'deny' directives.
|
||||
@@ -188,15 +193,6 @@ generatecommandkey
|
||||
# You can have as many allow and deny directives as you need. The order
|
||||
# is unimportant.
|
||||
|
||||
# If you want chronyd to act as an NTP broadcast server, enable and edit
|
||||
# (and maybe copy) the following line. This means that a broadcast
|
||||
# packet is sent to the address 192.168.1.255 every 60 seconds. The
|
||||
# address MUST correspond to the broadcast address of one of the network
|
||||
# interfaces on your machine. If you have multiple network interfaces,
|
||||
# add a broadcast line for each.
|
||||
|
||||
! broadcast 60 192.168.1.255
|
||||
|
||||
# If you want to present your computer's time for others to synchronise
|
||||
# with, even if you don't seem to be synchronised to any NTP servers
|
||||
# yourself, enable the following line. The value 10 may be varied
|
||||
@@ -211,16 +207,22 @@ generatecommandkey
|
||||
# machine accesses it. The information can be accessed by the 'clients'
|
||||
# command of chronyc. You can disable this facility by uncommenting the
|
||||
# following line. This will save a bit of memory if you have many
|
||||
# clients.
|
||||
# clients and it will also disable support for the interleaved mode.
|
||||
|
||||
! noclientlog
|
||||
|
||||
# The clientlog size is limited to 512KB by default. If you have many
|
||||
# clients, especially in many different subnets, you might want to
|
||||
# increase the limit.
|
||||
# clients, you might want to increase the limit.
|
||||
|
||||
! clientloglimit 4194304
|
||||
|
||||
# By default, chronyd tries to respond to all valid NTP requests from
|
||||
# allowed addresses. If you want to limit the response rate for NTP
|
||||
# clients that are sending requests too frequently, uncomment and edit
|
||||
# the following line.
|
||||
|
||||
! ratelimit interval 3 burst 8
|
||||
|
||||
#######################################################################
|
||||
### REPORTING BIG CLOCK CHANGES
|
||||
# Perhaps you want to know if chronyd suddenly detects any large error
|
||||
@@ -238,7 +240,7 @@ generatecommandkey
|
||||
# several people, you need to set up a mailing list or sendmail alias
|
||||
# for them and use the address of that.)
|
||||
|
||||
! mailonchange wibble@foo.example.net 0.5
|
||||
! mailonchange wibble@example.net 0.5
|
||||
|
||||
#######################################################################
|
||||
### COMMAND ACCESS
|
||||
@@ -247,6 +249,7 @@ generatecommandkey
|
||||
|
||||
# By default chronyd binds to the loopback interface. Uncomment the
|
||||
# following lines to allow receiving command packets from remote hosts.
|
||||
|
||||
! bindcmdaddress 0.0.0.0
|
||||
! bindcmdaddress ::
|
||||
|
||||
@@ -262,10 +265,20 @@ generatecommandkey
|
||||
# syntax and meaning is the same as for 'allow' and 'deny', except that
|
||||
# 'cmdallow' and 'cmddeny' control access to the chronyd's command port.
|
||||
|
||||
# NOTE, even if the host where you run chronyc is granted access, you
|
||||
# still need a command key set up and you have to know the password to
|
||||
# put into chronyc to allow you to modify chronyd's parameters. By
|
||||
# default all you can do is view information about chronyd's operation.
|
||||
# Rate limiting can be enabled also for command packets. (Note,
|
||||
# commands from localhost are never limited.)
|
||||
|
||||
! cmdratelimit interval -4 burst 16
|
||||
|
||||
#######################################################################
|
||||
### HARDWARE TIMESTAMPING
|
||||
# On Linux, if the network interface controller and its driver support
|
||||
# hardware timestamping, it can significantly improve the accuracy of
|
||||
# synchronisation. It can be enabled on specified interfaces only, or it
|
||||
# can be enabled on all interfaces that support it.
|
||||
|
||||
! hwtimestamp eth0
|
||||
! hwtimestamp *
|
||||
|
||||
#######################################################################
|
||||
### REAL TIME CLOCK
|
||||
@@ -296,6 +309,12 @@ generatecommandkey
|
||||
|
||||
! rtcdevice /dev/misc/rtc
|
||||
|
||||
# Alternatively, if not using the -s option, this directive can be used
|
||||
# to enable a mode in which the RTC is periodically set to the system
|
||||
# time, with no tracking of its drift.
|
||||
|
||||
! rtcsync
|
||||
|
||||
#######################################################################
|
||||
### REAL TIME SCHEDULER
|
||||
# This directive tells chronyd to use the real-time FIFO scheduler with the
|
||||
|
||||
@@ -1,29 +1,15 @@
|
||||
#######################################################################
|
||||
# This is an example chrony keys file. It enables authentication of NTP
|
||||
# packets with symmetric keys when its location is specified by the keyfile
|
||||
# directive in chrony.conf(5). It should be readable only by root and the
|
||||
# user under which chronyd is running.
|
||||
#
|
||||
# This is an example chrony keys file. You should copy it to /etc/chrony.keys
|
||||
# after editing it to set up the key(s) you want to use. It should be readable
|
||||
# only by root or the user chronyd drops the root privileges to. In most
|
||||
# situations, you will require a single key (the 'commandkey') so that you can
|
||||
# supply a password to chronyc to enable you to modify chronyd's operation
|
||||
# whilst it is running.
|
||||
#
|
||||
# Copyright 2002 Richard P. Curnow
|
||||
#
|
||||
######################################################################
|
||||
# Don't use the example keys! It's recommended to generate random keys using
|
||||
# the chronyc keygen command.
|
||||
|
||||
# Examples of valid keys:
|
||||
|
||||
#1 ALongAndRandomPassword
|
||||
#2 MD5 HEX:B028F91EA5C38D06C2E140B26C7F41EC
|
||||
#3 SHA1 HEX:1DC764E0791B11FA67EFC7ECBC4B0D73F68A070C
|
||||
|
||||
# The keys should be random for maximum security. If you wanted to use a key
|
||||
# with ID 1 as your commandkey (i.e. chronyc password) you would put
|
||||
# "commandkey 1" into chrony.conf. If no commandkey is present in the keys
|
||||
# file and the generatecommandkey directive is specified in chrony.conf,
|
||||
# a random commandkey will be generated and added to the keys file
|
||||
# automatically on chronyd start.
|
||||
|
||||
# You might want to define more keys if you use the authentication facility
|
||||
# in the network time protocol to authenticate request/response packets between
|
||||
# trusted clients and servers.
|
||||
#1 MD5 AVeryLongAndRandomPassword
|
||||
#2 MD5 HEX:12114855C7931009B4049EF3EFC48A139C3F989F
|
||||
#3 SHA1 HEX:B2159C05D6A219673A3B7E896B6DE07F6A440995
|
||||
#4 AES128 HEX:2DA837C4B6573748CA692B8C828E4891
|
||||
#5 AES256 HEX:2666B8099BFF2D5BA20876121788ED24D2BE59111B8FFB562F0F56AE6EC7246E
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
nocreate
|
||||
sharedscripts
|
||||
postrotate
|
||||
/usr/bin/chronyc -a cyclelogs > /dev/null 2>&1 || true
|
||||
/usr/bin/chronyc cyclelogs > /dev/null 2>&1 || true
|
||||
endscript
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
#!/bin/sh
|
||||
# This is a NetworkManager dispatcher script for chronyd to set its NTP sources
|
||||
# online/offline when a default route is configured/removed on the system.
|
||||
|
||||
export LC_ALL=C
|
||||
|
||||
if [ "$2" = "up" ]; then
|
||||
/sbin/ip route list dev "$1" | grep -q '^default' &&
|
||||
/usr/bin/chronyc -a online > /dev/null 2>&1
|
||||
fi
|
||||
|
||||
if [ "$2" = "down" ]; then
|
||||
/sbin/ip route list | grep -q '^default' ||
|
||||
/usr/bin/chronyc -a offline > /dev/null 2>&1
|
||||
fi
|
||||
|
||||
exit 0
|
||||
49
examples/chrony.nm-dispatcher.dhcp
Normal file
49
examples/chrony.nm-dispatcher.dhcp
Normal file
@@ -0,0 +1,49 @@
|
||||
#!/bin/sh
|
||||
# This is a NetworkManager dispatcher script for chronyd to update
|
||||
# its NTP sources with servers from DHCP options passed by NetworkManager
|
||||
# in the DHCP4_NTP_SERVERS and DHCP6_DHCP6_NTP_SERVERS environment variables.
|
||||
|
||||
export LC_ALL=C
|
||||
|
||||
interface=$1
|
||||
action=$2
|
||||
|
||||
chronyc=/usr/bin/chronyc
|
||||
server_options=iburst
|
||||
server_dir=/var/run/chrony-dhcp
|
||||
|
||||
dhcp_server_file=$server_dir/$interface.sources
|
||||
dhcp_ntp_servers="$DHCP4_NTP_SERVERS $DHCP6_DHCP6_NTP_SERVERS"
|
||||
|
||||
add_servers_from_dhcp() {
|
||||
rm -f "$dhcp_server_file"
|
||||
for server in $dhcp_ntp_servers; do
|
||||
# Check for invalid characters (from the DHCPv6 NTP FQDN suboption)
|
||||
len1=$(printf '%s' "$server" | wc -c)
|
||||
len2=$(printf '%s' "$server" | tr -d -c 'A-Za-z0-9:.-' | wc -c)
|
||||
if [ "$len1" -ne "$len2" ] || [ "$len2" -lt 1 ] || [ "$len2" -gt 255 ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
printf 'server %s %s\n' "$server" "$server_options" >> "$dhcp_server_file"
|
||||
done
|
||||
$chronyc reload sources > /dev/null 2>&1 || :
|
||||
}
|
||||
|
||||
clear_servers_from_dhcp() {
|
||||
if [ -f "$dhcp_server_file" ]; then
|
||||
rm -f "$dhcp_server_file"
|
||||
$chronyc reload sources > /dev/null 2>&1 || :
|
||||
fi
|
||||
}
|
||||
|
||||
mkdir -p $server_dir
|
||||
|
||||
case "$action" in
|
||||
up|dhcp4-change|dhcp6-change)
|
||||
add_servers_from_dhcp;;
|
||||
down)
|
||||
clear_servers_from_dhcp;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
29
examples/chrony.nm-dispatcher.onoffline
Normal file
29
examples/chrony.nm-dispatcher.onoffline
Normal file
@@ -0,0 +1,29 @@
|
||||
#!/bin/sh
|
||||
# This is a NetworkManager dispatcher / networkd-dispatcher script for
|
||||
# chronyd to set its NTP sources online or offline when a network interface
|
||||
# is configured or removed
|
||||
|
||||
export LC_ALL=C
|
||||
|
||||
chronyc=/usr/bin/chronyc
|
||||
|
||||
# For NetworkManager consider only selected events
|
||||
if [ $# -ge 2 ]; then
|
||||
case "$2" in
|
||||
up|down|connectivity-change)
|
||||
;;
|
||||
dhcp4-change|dhcp6-change)
|
||||
# Actions "up" and "connectivity-change" in some cases do not
|
||||
# guarantee that the interface has a route (e.g. a bond).
|
||||
# dhcp(x)-change handles at least cases that use DHCP.
|
||||
;;
|
||||
*)
|
||||
exit 0;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Note: for networkd-dispatcher routable.d ~= on and off.d ~= off
|
||||
|
||||
$chronyc onoffline > /dev/null 2>&1
|
||||
|
||||
exit 0
|
||||
@@ -1,57 +0,0 @@
|
||||
%global chrony_version @@VERSION@@
|
||||
%if 0%(echo %{chrony_version} | grep -q pre && echo 1)
|
||||
%global prerelease %(echo %{chrony_version} | sed 's/.*-//')
|
||||
%endif
|
||||
Summary: An NTP client/server
|
||||
Name: chrony
|
||||
Version: %(echo %{chrony_version} | sed 's/-.*//')
|
||||
Release: %{!?prerelease:1}%{?prerelease:0.1.%{prerelease}}
|
||||
Source: chrony-%{version}%{?prerelease:-%{prerelease}}.tar.gz
|
||||
License: GPLv2
|
||||
Group: Applications/Utilities
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-root-%(id -u -n)
|
||||
Requires: info
|
||||
|
||||
%description
|
||||
chrony is a client and server for the Network Time Protocol (NTP).
|
||||
This program keeps your computer's clock accurate. It was specially
|
||||
designed to support systems with intermittent Internet connections,
|
||||
but it also works well in permanently connected environments. It can
|
||||
also use hardware reference clocks, the system real-time clock, or
|
||||
manual input as time references.
|
||||
|
||||
%prep
|
||||
%setup -q -n %{name}-%{version}%{?prerelease:-%{prerelease}}
|
||||
|
||||
%build
|
||||
./configure \
|
||||
--prefix=%{_prefix} \
|
||||
--bindir=%{_bindir} \
|
||||
--sbindir=%{_sbindir} \
|
||||
--infodir=%{_infodir} \
|
||||
--mandir=%{_mandir}
|
||||
make
|
||||
make chrony.txt
|
||||
make chrony.info
|
||||
|
||||
%install
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
make install DESTDIR=$RPM_BUILD_ROOT
|
||||
rm -rf $RPM_BUILD_ROOT%{_docdir}
|
||||
mkdir -p $RPM_BUILD_ROOT%{_infodir}
|
||||
cp chrony.info* $RPM_BUILD_ROOT%{_infodir}
|
||||
|
||||
%files
|
||||
%{_sbindir}/chronyd
|
||||
%{_bindir}/chronyc
|
||||
%{_infodir}/chrony.info*
|
||||
%{_mandir}/man1/chrony.1.gz
|
||||
%{_mandir}/man1/chronyc.1.gz
|
||||
%{_mandir}/man5/chrony.conf.5.gz
|
||||
%{_mandir}/man8/chronyd.8.gz
|
||||
%doc README
|
||||
%doc chrony.txt
|
||||
%doc COPYING
|
||||
%doc examples/chrony.conf.example*
|
||||
%doc examples/chrony.keys.example
|
||||
|
||||
59
examples/chronyd-restricted.service
Normal file
59
examples/chronyd-restricted.service
Normal file
@@ -0,0 +1,59 @@
|
||||
# This is a more restricted version of the chronyd service intended for
|
||||
# minimal NTP/NTS client configurations. The daemon is started without root
|
||||
# privileges and is allowed to write only to its own runtime, state, and log
|
||||
# directories. It cannot bind to privileged ports in order to operate as an
|
||||
# NTP server, or provide monitoring access over IPv4/IPv6. It cannot use
|
||||
# reference clocks, HW timestamping, RTC tracking, and other features.
|
||||
[Unit]
|
||||
Description=NTP client (restricted)
|
||||
Documentation=man:chronyd(8) man:chrony.conf(5)
|
||||
After=chronyd.service ntpdate.service sntp.service ntpd.service
|
||||
Conflicts=chronyd.service ntpd.service systemd-timesyncd.service
|
||||
ConditionCapability=CAP_SYS_TIME
|
||||
|
||||
[Service]
|
||||
Type=notify
|
||||
PIDFile=/run/chrony/chronyd.pid
|
||||
Environment="OPTIONS="
|
||||
EnvironmentFile=-/etc/sysconfig/chronyd
|
||||
ExecStart=/usr/sbin/chronyd -n -U $OPTIONS
|
||||
|
||||
User=chrony
|
||||
LogsDirectory=chrony
|
||||
LogsDirectoryMode=0750
|
||||
RuntimeDirectory=chrony
|
||||
RuntimeDirectoryMode=0750
|
||||
RuntimeDirectoryPreserve=restart
|
||||
StateDirectory=chrony
|
||||
StateDirectoryMode=0750
|
||||
|
||||
AmbientCapabilities=CAP_SYS_TIME
|
||||
CapabilityBoundingSet=CAP_SYS_TIME
|
||||
DevicePolicy=closed
|
||||
LockPersonality=yes
|
||||
MemoryDenyWriteExecute=yes
|
||||
NoNewPrivileges=yes
|
||||
PrivateDevices=yes
|
||||
PrivateTmp=yes
|
||||
# This breaks adjtimex()
|
||||
#PrivateUsers=yes
|
||||
ProtectControlGroups=yes
|
||||
ProtectHome=yes
|
||||
ProtectHostname=yes
|
||||
ProtectKernelLogs=yes
|
||||
ProtectKernelModules=yes
|
||||
ProtectKernelTunables=yes
|
||||
ProtectProc=invisible
|
||||
ProtectSystem=strict
|
||||
RemoveIPC=yes
|
||||
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
|
||||
RestrictNamespaces=yes
|
||||
RestrictRealtime=yes
|
||||
RestrictSUIDSGID=yes
|
||||
SystemCallArchitectures=native
|
||||
SystemCallFilter=~@cpu-emulation @debug @module @mount @obsolete @raw-io
|
||||
SystemCallFilter=~@reboot @resources @swap
|
||||
UMask=0077
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -1,13 +1,49 @@
|
||||
[Unit]
|
||||
Description=NTP client/server
|
||||
Documentation=man:chronyd(8) man:chrony.conf(5)
|
||||
After=ntpdate.service sntp.service ntpd.service
|
||||
Conflicts=ntpd.service systemd-timesyncd.service
|
||||
ConditionCapability=CAP_SYS_TIME
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
PIDFile=/var/run/chronyd.pid
|
||||
Type=notify
|
||||
PIDFile=/run/chrony/chronyd.pid
|
||||
Environment="OPTIONS="
|
||||
EnvironmentFile=-/etc/sysconfig/chronyd
|
||||
ExecStart=/usr/sbin/chronyd $OPTIONS
|
||||
ExecStart=/usr/sbin/chronyd -n $OPTIONS
|
||||
|
||||
CapabilityBoundingSet=~CAP_AUDIT_CONTROL CAP_AUDIT_READ CAP_AUDIT_WRITE
|
||||
CapabilityBoundingSet=~CAP_BLOCK_SUSPEND CAP_KILL CAP_LEASE CAP_LINUX_IMMUTABLE
|
||||
CapabilityBoundingSet=~CAP_MAC_ADMIN CAP_MAC_OVERRIDE CAP_MKNOD CAP_SYS_ADMIN
|
||||
CapabilityBoundingSet=~CAP_SYS_BOOT CAP_SYS_CHROOT CAP_SYS_MODULE CAP_SYS_PACCT
|
||||
CapabilityBoundingSet=~CAP_SYS_PTRACE CAP_SYS_RAWIO CAP_SYS_TTY_CONFIG CAP_WAKE_ALARM
|
||||
DeviceAllow=char-pps rw
|
||||
DeviceAllow=char-ptp rw
|
||||
DeviceAllow=char-rtc rw
|
||||
DevicePolicy=closed
|
||||
LockPersonality=yes
|
||||
MemoryDenyWriteExecute=yes
|
||||
NoNewPrivileges=yes
|
||||
PrivateTmp=yes
|
||||
ProtectControlGroups=yes
|
||||
ProtectHome=yes
|
||||
ProtectHostname=yes
|
||||
ProtectKernelLogs=yes
|
||||
ProtectKernelModules=yes
|
||||
ProtectKernelTunables=yes
|
||||
ProtectProc=invisible
|
||||
ProtectSystem=strict
|
||||
ReadWritePaths=/run /var/lib/chrony -/var/log
|
||||
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
|
||||
RestrictNamespaces=yes
|
||||
RestrictSUIDSGID=yes
|
||||
SystemCallArchitectures=native
|
||||
SystemCallFilter=~@cpu-emulation @debug @module @mount @obsolete @raw-io @reboot @swap
|
||||
|
||||
# Adjust restrictions for /usr/sbin/sendmail (mailonchange directive)
|
||||
NoNewPrivileges=no
|
||||
ReadWritePaths=-/var/spool
|
||||
RestrictAddressFamilies=AF_NETLINK
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
27
getdate.y
27
getdate.y
@@ -8,12 +8,7 @@
|
||||
** This code is in the public domain and has no copyright.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
# ifdef HAVE_ALLOCA_H
|
||||
# include <alloca.h>
|
||||
# endif
|
||||
#endif
|
||||
#include "config.h"
|
||||
|
||||
/* Since the code of getdate.y is not included in the Emacs executable
|
||||
itself, there is no need to #define static in this file. Even if
|
||||
@@ -453,9 +448,9 @@ o_merid : /* NULL */
|
||||
the same signature as the function definition does. */
|
||||
#include "getdate.h"
|
||||
|
||||
extern struct tm *gmtime ();
|
||||
extern struct tm *localtime ();
|
||||
extern time_t mktime ();
|
||||
extern struct tm *gmtime (const time_t *timep);
|
||||
extern struct tm *localtime (const time_t *timep);
|
||||
extern time_t mktime (struct tm *tm);
|
||||
|
||||
/* Month and day table. */
|
||||
static TABLE const MonthDayTable[] = {
|
||||
@@ -646,16 +641,13 @@ static TABLE const MilitaryTable[] = {
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
yyerror (s)
|
||||
char *s ATTRIBUTE_UNUSED;
|
||||
yyerror (char *s ATTRIBUTE_UNUSED)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ToHour (Hours, Meridian)
|
||||
int Hours;
|
||||
MERIDIAN Meridian;
|
||||
ToHour (int Hours, MERIDIAN Meridian)
|
||||
{
|
||||
switch (Meridian)
|
||||
{
|
||||
@@ -682,8 +674,7 @@ ToHour (Hours, Meridian)
|
||||
}
|
||||
|
||||
static int
|
||||
ToYear (Year)
|
||||
int Year;
|
||||
ToYear (int Year)
|
||||
{
|
||||
if (Year < 0)
|
||||
Year = -Year;
|
||||
@@ -699,8 +690,7 @@ ToYear (Year)
|
||||
}
|
||||
|
||||
static int
|
||||
LookupWord (buff)
|
||||
char *buff;
|
||||
LookupWord (char *buff)
|
||||
{
|
||||
register char *p;
|
||||
register char *q;
|
||||
@@ -917,6 +907,7 @@ get_date (const char *p, const time_t *now)
|
||||
yyHour = tmp->tm_hour;
|
||||
yyMinutes = tmp->tm_min;
|
||||
yySeconds = tmp->tm_sec;
|
||||
memset(&tm, 0, sizeof (tm));
|
||||
tm.tm_isdst = tmp->tm_isdst;
|
||||
yyMeridian = MER24;
|
||||
yyRelSeconds = 0;
|
||||
|
||||
24
hash.h
24
hash.h
@@ -31,12 +31,26 @@
|
||||
/* length of hash values produced by SHA512 */
|
||||
#define MAX_HASH_LENGTH 64
|
||||
|
||||
extern int HSH_GetHashId(const char *name);
|
||||
typedef enum {
|
||||
HSH_INVALID = 0,
|
||||
HSH_MD5 = 1,
|
||||
HSH_SHA1 = 2,
|
||||
HSH_SHA256 = 3,
|
||||
HSH_SHA384 = 4,
|
||||
HSH_SHA512 = 5,
|
||||
HSH_SHA3_224 = 6,
|
||||
HSH_SHA3_256 = 7,
|
||||
HSH_SHA3_384 = 8,
|
||||
HSH_SHA3_512 = 9,
|
||||
HSH_TIGER = 10,
|
||||
HSH_WHIRLPOOL = 11,
|
||||
HSH_MD5_NONCRYPTO = 10000, /* For NTPv4 reference ID */
|
||||
} HSH_Algorithm;
|
||||
|
||||
extern unsigned int HSH_Hash(int id,
|
||||
const unsigned char *in1, unsigned int in1_len,
|
||||
const unsigned char *in2, unsigned int in2_len,
|
||||
unsigned char *out, unsigned int out_len);
|
||||
extern int HSH_GetHashId(HSH_Algorithm algorithm);
|
||||
|
||||
extern int HSH_Hash(int id, const void *in1, int in1_len, const void *in2, int in2_len,
|
||||
unsigned char *out, int out_len);
|
||||
|
||||
extern void HSH_Finalise(void);
|
||||
|
||||
|
||||
145
hash_gnutls.c
Normal file
145
hash_gnutls.c
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2021
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Crypto hashing using the GnuTLS library
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include <gnutls/crypto.h>
|
||||
|
||||
#include "hash.h"
|
||||
#include "logging.h"
|
||||
|
||||
struct hash {
|
||||
const HSH_Algorithm algorithm;
|
||||
const gnutls_digest_algorithm_t type;
|
||||
gnutls_hash_hd_t handle;
|
||||
};
|
||||
|
||||
static struct hash hashes[] = {
|
||||
{ HSH_MD5_NONCRYPTO, GNUTLS_DIG_MD5, NULL },
|
||||
{ HSH_MD5, GNUTLS_DIG_MD5, NULL },
|
||||
{ HSH_SHA1, GNUTLS_DIG_SHA1, NULL },
|
||||
{ HSH_SHA256, GNUTLS_DIG_SHA256, NULL },
|
||||
{ HSH_SHA384, GNUTLS_DIG_SHA384, NULL },
|
||||
{ HSH_SHA512, GNUTLS_DIG_SHA512, NULL },
|
||||
{ HSH_SHA3_224, GNUTLS_DIG_SHA3_224, NULL },
|
||||
{ HSH_SHA3_256, GNUTLS_DIG_SHA3_256, NULL },
|
||||
{ HSH_SHA3_384, GNUTLS_DIG_SHA3_384, NULL },
|
||||
{ HSH_SHA3_512, GNUTLS_DIG_SHA3_512, NULL },
|
||||
{ 0, 0, NULL }
|
||||
};
|
||||
|
||||
static int gnutls_initialised = 0;
|
||||
|
||||
int
|
||||
HSH_GetHashId(HSH_Algorithm algorithm)
|
||||
{
|
||||
int id, r;
|
||||
|
||||
if (!gnutls_initialised) {
|
||||
r = gnutls_global_init();
|
||||
if (r < 0)
|
||||
LOG_FATAL("Could not initialise %s : %s", "gnutls", gnutls_strerror(r));
|
||||
gnutls_initialised = 1;
|
||||
}
|
||||
|
||||
for (id = 0; hashes[id].algorithm != 0; id++) {
|
||||
if (hashes[id].algorithm == algorithm)
|
||||
break;
|
||||
}
|
||||
|
||||
if (hashes[id].algorithm == 0)
|
||||
return -1;
|
||||
|
||||
if (hashes[id].handle)
|
||||
return id;
|
||||
|
||||
if (algorithm == HSH_MD5_NONCRYPTO)
|
||||
GNUTLS_FIPS140_SET_LAX_MODE();
|
||||
|
||||
r = gnutls_hash_init(&hashes[id].handle, hashes[id].type);
|
||||
|
||||
if (algorithm == HSH_MD5_NONCRYPTO)
|
||||
GNUTLS_FIPS140_SET_STRICT_MODE();
|
||||
|
||||
if (r < 0) {
|
||||
DEBUG_LOG("Could not initialise %s : %s", "hash", gnutls_strerror(r));
|
||||
hashes[id].handle = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
int
|
||||
HSH_Hash(int id, const void *in1, int in1_len, const void *in2, int in2_len,
|
||||
unsigned char *out, int out_len)
|
||||
{
|
||||
unsigned char buf[MAX_HASH_LENGTH];
|
||||
gnutls_hash_hd_t handle;
|
||||
int hash_len;
|
||||
|
||||
if (in1_len < 0 || in2_len < 0 || out_len < 0)
|
||||
return 0;
|
||||
|
||||
handle = hashes[id].handle;
|
||||
hash_len = gnutls_hash_get_len(hashes[id].type);
|
||||
|
||||
if (out_len > hash_len)
|
||||
out_len = hash_len;
|
||||
|
||||
if (hash_len > sizeof (buf))
|
||||
return 0;
|
||||
|
||||
if (gnutls_hash(handle, in1, in1_len) < 0 ||
|
||||
(in2 && gnutls_hash(handle, in2, in2_len) < 0)) {
|
||||
/* Reset the state */
|
||||
gnutls_hash_output(handle, buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
gnutls_hash_output(handle, buf);
|
||||
memcpy(out, buf, out_len);
|
||||
|
||||
return out_len;
|
||||
}
|
||||
|
||||
void
|
||||
HSH_Finalise(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!gnutls_initialised)
|
||||
return;
|
||||
|
||||
for (i = 0; hashes[i].algorithm != 0; i++) {
|
||||
if (hashes[i].handle)
|
||||
gnutls_hash_deinit(hashes[i].handle, NULL);
|
||||
}
|
||||
|
||||
gnutls_global_deinit();
|
||||
}
|
||||
@@ -29,27 +29,27 @@
|
||||
#include "sysincl.h"
|
||||
#include "hash.h"
|
||||
#include "memory.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "md5.c"
|
||||
|
||||
static MD5_CTX ctx;
|
||||
|
||||
int
|
||||
HSH_GetHashId(const char *name)
|
||||
HSH_GetHashId(HSH_Algorithm algorithm)
|
||||
{
|
||||
/* only MD5 is supported */
|
||||
if (strcmp(name, "MD5"))
|
||||
if (algorithm != HSH_MD5 && algorithm != HSH_MD5_NONCRYPTO)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
|
||||
const unsigned char *in2, unsigned int in2_len,
|
||||
unsigned char *out, unsigned int out_len)
|
||||
int
|
||||
HSH_Hash(int id, const void *in1, int in1_len, const void *in2, int in2_len,
|
||||
unsigned char *out, int out_len)
|
||||
{
|
||||
if (out_len < 16)
|
||||
if (in1_len < 0 || in2_len < 0 || out_len < 0)
|
||||
return 0;
|
||||
|
||||
MD5Init(&ctx);
|
||||
@@ -58,9 +58,11 @@ HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
|
||||
MD5Update(&ctx, in2, in2_len);
|
||||
MD5Final(&ctx);
|
||||
|
||||
memcpy(out, ctx.digest, 16);
|
||||
out_len = MIN(out_len, 16);
|
||||
|
||||
return 16;
|
||||
memcpy(out, ctx.digest, out_len);
|
||||
|
||||
return out_len;
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
124
hash_nettle.c
Normal file
124
hash_nettle.c
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2018
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Routines implementing crypto hashing using the nettle library.
|
||||
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include <nettle/nettle-meta.h>
|
||||
|
||||
#include "hash.h"
|
||||
#include "memory.h"
|
||||
|
||||
struct hash {
|
||||
const HSH_Algorithm algorithm;
|
||||
const char *int_name;
|
||||
const struct nettle_hash *nettle_hash;
|
||||
void *context;
|
||||
};
|
||||
|
||||
static struct hash hashes[] = {
|
||||
{ HSH_MD5, "md5", NULL, NULL },
|
||||
{ HSH_SHA1, "sha1", NULL, NULL },
|
||||
{ HSH_SHA256, "sha256", NULL, NULL },
|
||||
{ HSH_SHA384, "sha384", NULL, NULL },
|
||||
{ HSH_SHA512, "sha512", NULL, NULL },
|
||||
{ HSH_SHA3_224, "sha3_224", NULL, NULL },
|
||||
{ HSH_SHA3_256, "sha3_256", NULL, NULL },
|
||||
{ HSH_SHA3_384, "sha3_384", NULL, NULL },
|
||||
{ HSH_SHA3_512, "sha3_512", NULL, NULL },
|
||||
{ 0, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
int
|
||||
HSH_GetHashId(HSH_Algorithm algorithm)
|
||||
{
|
||||
int id, nid;
|
||||
|
||||
if (algorithm == HSH_MD5_NONCRYPTO)
|
||||
algorithm = HSH_MD5;
|
||||
|
||||
for (id = 0; hashes[id].algorithm != 0; id++) {
|
||||
if (hashes[id].algorithm == algorithm)
|
||||
break;
|
||||
}
|
||||
|
||||
if (hashes[id].algorithm == 0)
|
||||
return -1;
|
||||
|
||||
if (hashes[id].context)
|
||||
return id;
|
||||
|
||||
for (nid = 0; nettle_hashes[nid]; nid++) {
|
||||
if (!strcmp(hashes[id].int_name, nettle_hashes[nid]->name))
|
||||
break;
|
||||
}
|
||||
|
||||
if (!nettle_hashes[nid] || !nettle_hashes[nid]->context_size || !nettle_hashes[nid]->init)
|
||||
return -1;
|
||||
|
||||
hashes[id].nettle_hash = nettle_hashes[nid];
|
||||
hashes[id].context = Malloc(hashes[id].nettle_hash->context_size);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
int
|
||||
HSH_Hash(int id, const void *in1, int in1_len, const void *in2, int in2_len,
|
||||
unsigned char *out, int out_len)
|
||||
{
|
||||
const struct nettle_hash *hash;
|
||||
void *context;
|
||||
|
||||
if (in1_len < 0 || in2_len < 0 || out_len < 0)
|
||||
return 0;
|
||||
|
||||
hash = hashes[id].nettle_hash;
|
||||
context = hashes[id].context;
|
||||
|
||||
if (out_len > hash->digest_size)
|
||||
out_len = hash->digest_size;
|
||||
|
||||
hash->init(context);
|
||||
hash->update(context, in1_len, in1);
|
||||
if (in2)
|
||||
hash->update(context, in2_len, in2);
|
||||
hash->digest(context, out_len, out);
|
||||
|
||||
return out_len;
|
||||
}
|
||||
|
||||
void
|
||||
HSH_Finalise(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; hashes[i].algorithm != 0; i++) {
|
||||
if (hashes[i].context)
|
||||
Free(hashes[i].context);
|
||||
}
|
||||
}
|
||||
49
hash_nss.c
49
hash_nss.c
@@ -25,41 +25,46 @@
|
||||
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <nss.h>
|
||||
#include <hasht.h>
|
||||
#include <nsslowhash.h>
|
||||
|
||||
/* #include "config.h" */
|
||||
#include "hash.h"
|
||||
#include "util.h"
|
||||
|
||||
static NSSLOWInitContext *ictx;
|
||||
|
||||
struct hash {
|
||||
HASH_HashType type;
|
||||
const char *name;
|
||||
HSH_Algorithm algorithm;
|
||||
NSSLOWHASHContext *context;
|
||||
};
|
||||
|
||||
static struct hash hashes[] = {
|
||||
{ HASH_AlgMD5, "MD5", NULL },
|
||||
{ HASH_AlgSHA1, "SHA1", NULL },
|
||||
{ HASH_AlgSHA256, "SHA256", NULL },
|
||||
{ HASH_AlgSHA384, "SHA384", NULL },
|
||||
{ HASH_AlgSHA512, "SHA512", NULL },
|
||||
{ 0, NULL, NULL }
|
||||
{ HASH_AlgMD5, HSH_MD5, NULL },
|
||||
{ HASH_AlgSHA1, HSH_SHA1, NULL },
|
||||
{ HASH_AlgSHA256, HSH_SHA256, NULL },
|
||||
{ HASH_AlgSHA384, HSH_SHA384, NULL },
|
||||
{ HASH_AlgSHA512, HSH_SHA512, NULL },
|
||||
{ 0, 0, NULL }
|
||||
};
|
||||
|
||||
int
|
||||
HSH_GetHashId(const char *name)
|
||||
HSH_GetHashId(HSH_Algorithm algorithm)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; hashes[i].name; i++) {
|
||||
if (!strcmp(name, hashes[i].name))
|
||||
if (algorithm == HSH_MD5_NONCRYPTO)
|
||||
algorithm = HSH_MD5;
|
||||
|
||||
for (i = 0; hashes[i].algorithm != 0; i++) {
|
||||
if (hashes[i].algorithm == algorithm)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!hashes[i].name)
|
||||
if (hashes[i].algorithm == 0)
|
||||
return -1; /* not found */
|
||||
|
||||
if (!ictx && !(ictx = NSSLOW_Init()))
|
||||
@@ -72,18 +77,24 @@ HSH_GetHashId(const char *name)
|
||||
return i;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
|
||||
const unsigned char *in2, unsigned int in2_len,
|
||||
unsigned char *out, unsigned int out_len)
|
||||
int
|
||||
HSH_Hash(int id, const void *in1, int in1_len, const void *in2, int in2_len,
|
||||
unsigned char *out, int out_len)
|
||||
{
|
||||
unsigned int ret;
|
||||
unsigned char buf[MAX_HASH_LENGTH];
|
||||
unsigned int ret = 0;
|
||||
|
||||
if (in1_len < 0 || in2_len < 0 || out_len < 0)
|
||||
return 0;
|
||||
|
||||
NSSLOWHASH_Begin(hashes[id].context);
|
||||
NSSLOWHASH_Update(hashes[id].context, in1, in1_len);
|
||||
if (in2)
|
||||
NSSLOWHASH_Update(hashes[id].context, in2, in2_len);
|
||||
NSSLOWHASH_End(hashes[id].context, out, &ret, out_len);
|
||||
NSSLOWHASH_End(hashes[id].context, buf, &ret, sizeof (buf));
|
||||
|
||||
ret = MIN(ret, out_len);
|
||||
memcpy(out, buf, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -93,7 +104,7 @@ HSH_Finalise(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; hashes[i].name; i++) {
|
||||
for (i = 0; hashes[i].algorithm != 0; i++) {
|
||||
if (hashes[i].context)
|
||||
NSSLOWHASH_Destroy(hashes[i].context);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2012
|
||||
* Copyright (C) Miroslav Lichvar 2012, 2018
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -29,59 +29,57 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "hash.h"
|
||||
#include "util.h"
|
||||
|
||||
struct hash {
|
||||
const char *name;
|
||||
HSH_Algorithm algorithm;
|
||||
const char *int_name;
|
||||
const struct ltc_hash_descriptor *desc;
|
||||
};
|
||||
|
||||
static const struct hash hashes[] = {
|
||||
{ "MD5", "md5", &md5_desc },
|
||||
#ifdef LTC_RIPEMD128
|
||||
{ "RMD128", "rmd128", &rmd128_desc },
|
||||
#endif
|
||||
#ifdef LTC_RIPEMD160
|
||||
{ "RMD160", "rmd160", &rmd160_desc },
|
||||
#endif
|
||||
#ifdef LTC_RIPEMD256
|
||||
{ "RMD256", "rmd256", &rmd256_desc },
|
||||
#endif
|
||||
#ifdef LTC_RIPEMD320
|
||||
{ "RMD320", "rmd320", &rmd320_desc },
|
||||
#endif
|
||||
{ HSH_MD5, "md5", &md5_desc },
|
||||
#ifdef LTC_SHA1
|
||||
{ "SHA1", "sha1", &sha1_desc },
|
||||
{ HSH_SHA1, "sha1", &sha1_desc },
|
||||
#endif
|
||||
#ifdef LTC_SHA256
|
||||
{ "SHA256", "sha256", &sha256_desc },
|
||||
{ HSH_SHA256, "sha256", &sha256_desc },
|
||||
#endif
|
||||
#ifdef LTC_SHA384
|
||||
{ "SHA384", "sha384", &sha384_desc },
|
||||
{ HSH_SHA384, "sha384", &sha384_desc },
|
||||
#endif
|
||||
#ifdef LTC_SHA512
|
||||
{ "SHA512", "sha512", &sha512_desc },
|
||||
{ HSH_SHA512, "sha512", &sha512_desc },
|
||||
#endif
|
||||
#ifdef LTC_SHA3
|
||||
{ HSH_SHA3_224, "sha3-224", &sha3_224_desc },
|
||||
{ HSH_SHA3_256, "sha3-256", &sha3_256_desc },
|
||||
{ HSH_SHA3_384, "sha3-384", &sha3_384_desc },
|
||||
{ HSH_SHA3_512, "sha3-512", &sha3_512_desc },
|
||||
#endif
|
||||
#ifdef LTC_TIGER
|
||||
{ "TIGER", "tiger", &tiger_desc },
|
||||
{ HSH_TIGER, "tiger", &tiger_desc },
|
||||
#endif
|
||||
#ifdef LTC_WHIRLPOOL
|
||||
{ "WHIRLPOOL", "whirlpool", &whirlpool_desc },
|
||||
{ HSH_WHIRLPOOL, "whirlpool", &whirlpool_desc },
|
||||
#endif
|
||||
{ NULL, NULL, NULL }
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
int
|
||||
HSH_GetHashId(const char *name)
|
||||
HSH_GetHashId(HSH_Algorithm algorithm)
|
||||
{
|
||||
int i, h;
|
||||
|
||||
for (i = 0; hashes[i].name; i++) {
|
||||
if (!strcmp(name, hashes[i].name))
|
||||
if (algorithm == HSH_MD5_NONCRYPTO)
|
||||
algorithm = HSH_MD5;
|
||||
|
||||
for (i = 0; hashes[i].algorithm != 0; i++) {
|
||||
if (hashes[i].algorithm == algorithm)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!hashes[i].name)
|
||||
if (hashes[i].algorithm == 0)
|
||||
return -1; /* not found */
|
||||
|
||||
h = find_hash(hashes[i].int_name);
|
||||
@@ -94,24 +92,31 @@ HSH_GetHashId(const char *name)
|
||||
return find_hash(hashes[i].int_name);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
|
||||
const unsigned char *in2, unsigned int in2_len,
|
||||
unsigned char *out, unsigned int out_len)
|
||||
int
|
||||
HSH_Hash(int id, const void *in1, int in1_len, const void *in2, int in2_len,
|
||||
unsigned char *out, int out_len)
|
||||
{
|
||||
unsigned char buf[MAX_HASH_LENGTH];
|
||||
unsigned long len;
|
||||
int r;
|
||||
|
||||
len = out_len;
|
||||
if (in1_len < 0 || in2_len < 0 || out_len < 0)
|
||||
return 0;
|
||||
|
||||
len = sizeof (buf);
|
||||
if (in2)
|
||||
r = hash_memory_multi(id, out, &len,
|
||||
in1, (unsigned long)in1_len, in2, (unsigned long)in2_len, NULL, 0);
|
||||
r = hash_memory_multi(id, buf, &len,
|
||||
in1, (unsigned long)in1_len,
|
||||
in2, (unsigned long)in2_len, NULL, 0);
|
||||
else
|
||||
r = hash_memory(id, in1, in1_len, out, &len);
|
||||
r = hash_memory(id, in1, in1_len, buf, &len);
|
||||
|
||||
if (r != CRYPT_OK)
|
||||
return 0;
|
||||
|
||||
len = MIN(len, out_len);
|
||||
memcpy(out, buf, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
344
hwclock.c
Normal file
344
hwclock.c
Normal file
@@ -0,0 +1,344 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2016-2018, 2022
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Tracking of hardware clocks (e.g. RTC, PHC)
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "array.h"
|
||||
#include "hwclock.h"
|
||||
#include "local.h"
|
||||
#include "logging.h"
|
||||
#include "memory.h"
|
||||
#include "quantiles.h"
|
||||
#include "regress.h"
|
||||
#include "util.h"
|
||||
|
||||
/* Minimum and maximum number of samples per clock */
|
||||
#define MIN_SAMPLES 2
|
||||
#define MAX_SAMPLES 64
|
||||
|
||||
/* Maximum acceptable frequency offset of the clock */
|
||||
#define MAX_FREQ_OFFSET (2.0 / 3.0)
|
||||
|
||||
/* Quantiles for filtering readings by delay */
|
||||
#define DELAY_QUANT_MIN_K 1
|
||||
#define DELAY_QUANT_MAX_K 2
|
||||
#define DELAY_QUANT_Q 10
|
||||
#define DELAY_QUANT_REPEAT 7
|
||||
#define DELAY_QUANT_LARGE_STEP_DELAY 1000
|
||||
#define DELAY_QUANT_MIN_STEP 1.0e-9
|
||||
|
||||
struct HCL_Instance_Record {
|
||||
/* HW and local reference timestamp */
|
||||
struct timespec hw_ref;
|
||||
struct timespec local_ref;
|
||||
|
||||
/* Samples stored as intervals (uncorrected for frequency error)
|
||||
relative to local_ref and hw_ref */
|
||||
double *x_data;
|
||||
double *y_data;
|
||||
|
||||
/* Minimum, maximum and current number of samples */
|
||||
int min_samples;
|
||||
int max_samples;
|
||||
int n_samples;
|
||||
|
||||
/* Maximum error of the last sample */
|
||||
double last_err;
|
||||
|
||||
/* Minimum interval between samples */
|
||||
double min_separation;
|
||||
|
||||
/* Expected precision of readings */
|
||||
double precision;
|
||||
|
||||
/* Flag indicating the offset and frequency values are valid */
|
||||
int valid_coefs;
|
||||
|
||||
/* Estimated offset and frequency of HW clock relative to local clock */
|
||||
double offset;
|
||||
double frequency;
|
||||
|
||||
/* Estimated quantiles of reading delay */
|
||||
QNT_Instance delay_quants;
|
||||
};
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
handle_slew(struct timespec *raw, struct timespec *cooked, double dfreq,
|
||||
double doffset, LCL_ChangeType change_type, void *anything)
|
||||
{
|
||||
HCL_Instance clock;
|
||||
double delta;
|
||||
|
||||
clock = anything;
|
||||
|
||||
if (clock->n_samples)
|
||||
UTI_AdjustTimespec(&clock->local_ref, cooked, &clock->local_ref, &delta, dfreq, doffset);
|
||||
if (clock->valid_coefs)
|
||||
clock->frequency /= 1.0 - dfreq;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
HCL_Instance
|
||||
HCL_CreateInstance(int min_samples, int max_samples, double min_separation, double precision)
|
||||
{
|
||||
HCL_Instance clock;
|
||||
|
||||
min_samples = CLAMP(MIN_SAMPLES, min_samples, MAX_SAMPLES);
|
||||
max_samples = CLAMP(MIN_SAMPLES, max_samples, MAX_SAMPLES);
|
||||
max_samples = MAX(min_samples, max_samples);
|
||||
|
||||
clock = MallocNew(struct HCL_Instance_Record);
|
||||
clock->x_data = MallocArray(double, max_samples);
|
||||
clock->y_data = MallocArray(double, max_samples);
|
||||
clock->x_data[max_samples - 1] = 0.0;
|
||||
clock->y_data[max_samples - 1] = 0.0;
|
||||
clock->min_samples = min_samples;
|
||||
clock->max_samples = max_samples;
|
||||
clock->n_samples = 0;
|
||||
clock->valid_coefs = 0;
|
||||
clock->min_separation = min_separation;
|
||||
clock->precision = precision;
|
||||
clock->delay_quants = QNT_CreateInstance(DELAY_QUANT_MIN_K, DELAY_QUANT_MAX_K,
|
||||
DELAY_QUANT_Q, DELAY_QUANT_REPEAT,
|
||||
DELAY_QUANT_LARGE_STEP_DELAY,
|
||||
DELAY_QUANT_MIN_STEP);
|
||||
|
||||
LCL_AddParameterChangeHandler(handle_slew, clock);
|
||||
|
||||
return clock;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void HCL_DestroyInstance(HCL_Instance clock)
|
||||
{
|
||||
LCL_RemoveParameterChangeHandler(handle_slew, clock);
|
||||
QNT_DestroyInstance(clock->delay_quants);
|
||||
Free(clock->y_data);
|
||||
Free(clock->x_data);
|
||||
Free(clock);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
HCL_NeedsNewSample(HCL_Instance clock, struct timespec *now)
|
||||
{
|
||||
if (!clock->n_samples ||
|
||||
fabs(UTI_DiffTimespecsToDouble(now, &clock->local_ref)) >= clock->min_separation)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
HCL_ProcessReadings(HCL_Instance clock, int n_readings, struct timespec tss[][3],
|
||||
struct timespec *hw_ts, struct timespec *local_ts, double *err,
|
||||
int *quality)
|
||||
{
|
||||
double delay, raw_delay, min_delay, low_delay, high_delay, e, pred_err;
|
||||
double delay_sum, hw_sum, local_sum, local_prec, freq;
|
||||
int i, min_reading, combined;
|
||||
struct timespec ts1, ts2;
|
||||
|
||||
if (n_readings < 1)
|
||||
return 0;
|
||||
|
||||
/* Work out the current correction multiplier needed to get cooked delays */
|
||||
LCL_CookTime(&tss[0][0], &ts1, NULL);
|
||||
LCL_CookTime(&tss[n_readings - 1][2], &ts2, NULL);
|
||||
if (UTI_CompareTimespecs(&tss[0][0], &tss[n_readings - 1][2]) < 0)
|
||||
freq = UTI_DiffTimespecsToDouble(&ts1, &ts2) /
|
||||
UTI_DiffTimespecsToDouble(&tss[0][0], &tss[n_readings - 1][2]);
|
||||
else
|
||||
freq = 1.0;
|
||||
|
||||
for (i = 0; i < n_readings; i++) {
|
||||
delay = freq * UTI_DiffTimespecsToDouble(&tss[i][2], &tss[i][0]);
|
||||
|
||||
if (delay < 0.0) {
|
||||
/* Step in the middle of a reading? */
|
||||
DEBUG_LOG("Bad reading delay=%e", delay);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (i == 0 || min_delay > delay) {
|
||||
min_delay = delay;
|
||||
min_reading = i;
|
||||
}
|
||||
|
||||
QNT_Accumulate(clock->delay_quants, delay);
|
||||
}
|
||||
|
||||
local_prec = LCL_GetSysPrecisionAsQuantum();
|
||||
|
||||
low_delay = QNT_GetQuantile(clock->delay_quants, QNT_GetMinK(clock->delay_quants)) -
|
||||
QNT_GetMinStep(clock->delay_quants) / 2.0;
|
||||
high_delay = QNT_GetQuantile(clock->delay_quants, QNT_GetMaxK(clock->delay_quants)) +
|
||||
QNT_GetMinStep(clock->delay_quants) / 2.0;
|
||||
low_delay = MIN(low_delay, high_delay);
|
||||
high_delay = MAX(high_delay, low_delay + local_prec);
|
||||
|
||||
/* Combine readings with delay in the expected interval */
|
||||
for (i = combined = 0, delay_sum = hw_sum = local_sum = 0.0; i < n_readings; i++) {
|
||||
raw_delay = UTI_DiffTimespecsToDouble(&tss[i][2], &tss[i][0]);
|
||||
delay = freq * raw_delay;
|
||||
|
||||
if (delay < low_delay || delay > high_delay)
|
||||
continue;
|
||||
|
||||
delay_sum += delay;
|
||||
hw_sum += UTI_DiffTimespecsToDouble(&tss[i][1], &tss[0][1]);
|
||||
local_sum += UTI_DiffTimespecsToDouble(&tss[i][0], &tss[0][0]) + raw_delay / 2.0;
|
||||
combined++;
|
||||
}
|
||||
|
||||
DEBUG_LOG("Combined %d readings lo=%e hi=%e", combined, low_delay, high_delay);
|
||||
|
||||
if (combined > 0) {
|
||||
UTI_AddDoubleToTimespec(&tss[0][1], hw_sum / combined, hw_ts);
|
||||
UTI_AddDoubleToTimespec(&tss[0][0], local_sum / combined, local_ts);
|
||||
*err = MAX(delay_sum / combined / 2.0, clock->precision);
|
||||
*quality = 2;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Indicate acceptable quality of the reading with minimum delay if its
|
||||
interval does not contain the current offset predicted from previous
|
||||
samples, or a new sample is needed to get the tracking working */
|
||||
|
||||
*hw_ts = tss[min_reading][1];
|
||||
UTI_AddDoubleToTimespec(&tss[min_reading][0], min_delay / freq / 2.0, local_ts);
|
||||
*err = MAX(min_delay / 2.0, clock->precision);
|
||||
|
||||
pred_err = 0.0;
|
||||
LCL_CookTime(local_ts, &ts1, NULL);
|
||||
if (!HCL_CookTime(clock, hw_ts, &ts2, &e) ||
|
||||
((pred_err = UTI_DiffTimespecsToDouble(&ts1, &ts2)) > *err)) {
|
||||
*quality = 1;
|
||||
} else {
|
||||
*quality = 0;
|
||||
}
|
||||
|
||||
DEBUG_LOG("Min-delay reading err=%e prerr=%e ql=%d", *err, pred_err, *quality);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
HCL_AccumulateSample(HCL_Instance clock, struct timespec *hw_ts,
|
||||
struct timespec *local_ts, double err)
|
||||
{
|
||||
double hw_delta, local_delta, local_freq, raw_freq;
|
||||
int i, n_runs, best_start;
|
||||
|
||||
local_freq = 1.0 - LCL_ReadAbsoluteFrequency() / 1.0e6;
|
||||
|
||||
/* Shift old samples */
|
||||
if (clock->n_samples) {
|
||||
if (clock->n_samples >= clock->max_samples)
|
||||
clock->n_samples--;
|
||||
|
||||
hw_delta = UTI_DiffTimespecsToDouble(hw_ts, &clock->hw_ref);
|
||||
local_delta = UTI_DiffTimespecsToDouble(local_ts, &clock->local_ref) / local_freq;
|
||||
|
||||
if (hw_delta <= 0.0 || local_delta < clock->min_separation / 2.0) {
|
||||
clock->n_samples = 0;
|
||||
DEBUG_LOG("HW clock reset interval=%f", local_delta);
|
||||
}
|
||||
|
||||
for (i = clock->max_samples - clock->n_samples; i < clock->max_samples; i++) {
|
||||
clock->y_data[i - 1] = clock->y_data[i] - hw_delta;
|
||||
clock->x_data[i - 1] = clock->x_data[i] - local_delta;
|
||||
}
|
||||
}
|
||||
|
||||
clock->n_samples++;
|
||||
clock->hw_ref = *hw_ts;
|
||||
clock->local_ref = *local_ts;
|
||||
clock->last_err = err;
|
||||
|
||||
/* Get new coefficients */
|
||||
clock->valid_coefs =
|
||||
RGR_FindBestRobustRegression(clock->x_data + clock->max_samples - clock->n_samples,
|
||||
clock->y_data + clock->max_samples - clock->n_samples,
|
||||
clock->n_samples, 1.0e-10, &clock->offset, &raw_freq,
|
||||
&n_runs, &best_start);
|
||||
|
||||
if (!clock->valid_coefs) {
|
||||
DEBUG_LOG("HW clock needs more samples");
|
||||
return;
|
||||
}
|
||||
|
||||
clock->frequency = raw_freq / local_freq;
|
||||
|
||||
/* Drop unneeded samples */
|
||||
if (clock->n_samples > clock->min_samples)
|
||||
clock->n_samples -= MIN(best_start, clock->n_samples - clock->min_samples);
|
||||
|
||||
/* If the fit doesn't cross the error interval of the last sample,
|
||||
or the frequency is not sane, drop all samples and start again */
|
||||
if (fabs(clock->offset) > err ||
|
||||
fabs(clock->frequency - 1.0) > MAX_FREQ_OFFSET) {
|
||||
DEBUG_LOG("HW clock reset");
|
||||
clock->n_samples = 0;
|
||||
clock->valid_coefs = 0;
|
||||
}
|
||||
|
||||
DEBUG_LOG("HW clock samples=%d offset=%e freq=%e raw_freq=%e err=%e ref_diff=%e",
|
||||
clock->n_samples, clock->offset, clock->frequency - 1.0, raw_freq - 1.0, err,
|
||||
UTI_DiffTimespecsToDouble(&clock->hw_ref, &clock->local_ref));
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
HCL_CookTime(HCL_Instance clock, struct timespec *raw, struct timespec *cooked, double *err)
|
||||
{
|
||||
double offset, elapsed;
|
||||
|
||||
if (!clock->valid_coefs)
|
||||
return 0;
|
||||
|
||||
elapsed = UTI_DiffTimespecsToDouble(raw, &clock->hw_ref);
|
||||
offset = elapsed / clock->frequency - clock->offset;
|
||||
UTI_AddDoubleToTimespec(&clock->local_ref, offset, cooked);
|
||||
|
||||
/* Fow now, just return the error of the last sample */
|
||||
if (err)
|
||||
*err = clock->last_err;
|
||||
|
||||
return 1;
|
||||
}
|
||||
58
hwclock.h
Normal file
58
hwclock.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2016
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Header for tracking of hardware clocks */
|
||||
|
||||
#ifndef GOT_HWCLOCK_H
|
||||
#define GOT_HWCLOCK_H
|
||||
|
||||
typedef struct HCL_Instance_Record *HCL_Instance;
|
||||
|
||||
/* Create a new HW clock instance */
|
||||
extern HCL_Instance HCL_CreateInstance(int min_samples, int max_samples,
|
||||
double min_separation, double precision);
|
||||
|
||||
/* Destroy a HW clock instance */
|
||||
extern void HCL_DestroyInstance(HCL_Instance clock);
|
||||
|
||||
/* Check if a new sample should be accumulated at this time */
|
||||
extern int HCL_NeedsNewSample(HCL_Instance clock, struct timespec *now);
|
||||
|
||||
/* Process new readings of the HW clock in the form of (sys, hw, sys) triplets
|
||||
and produce a sample which can be accumulated by HCL_AccumulateSample().
|
||||
Indicate the quality of the sample relative to already processed samples as
|
||||
a value of 0, 1, or 2, where a sample of quality 0 should normally be
|
||||
dropped. */
|
||||
extern int HCL_ProcessReadings(HCL_Instance clock, int n_readings, struct timespec tss[][3],
|
||||
struct timespec *hw_ts, struct timespec *local_ts, double *err,
|
||||
int *quality);
|
||||
|
||||
/* Accumulate a new sample */
|
||||
extern void HCL_AccumulateSample(HCL_Instance clock, struct timespec *hw_ts,
|
||||
struct timespec *local_ts, double err);
|
||||
|
||||
/* Convert raw hardware time to cooked local time */
|
||||
extern int HCL_CookTime(HCL_Instance clock, struct timespec *raw, struct timespec *cooked,
|
||||
double *err);
|
||||
|
||||
#endif
|
||||
322
keys.c
322
keys.c
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2012-2014
|
||||
* Copyright (C) Miroslav Lichvar 2012-2016, 2019-2020
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
#include "array.h"
|
||||
#include "keys.h"
|
||||
#include "cmac.h"
|
||||
#include "cmdparse.h"
|
||||
#include "conf.h"
|
||||
#include "memory.h"
|
||||
@@ -39,93 +40,57 @@
|
||||
#include "local.h"
|
||||
#include "logging.h"
|
||||
|
||||
/* Consider 80 bits as the absolute minimum for a secure key */
|
||||
#define MIN_SECURE_KEY_LENGTH 10
|
||||
|
||||
typedef enum {
|
||||
NTP_MAC,
|
||||
CMAC,
|
||||
} KeyClass;
|
||||
|
||||
typedef struct {
|
||||
uint32_t id;
|
||||
char *val;
|
||||
int len;
|
||||
int hash_id;
|
||||
int auth_delay;
|
||||
int type;
|
||||
int length;
|
||||
KeyClass class;
|
||||
union {
|
||||
struct {
|
||||
unsigned char *value;
|
||||
int hash_id;
|
||||
} ntp_mac;
|
||||
CMC_Instance cmac;
|
||||
} data;
|
||||
} Key;
|
||||
|
||||
static ARR_Instance keys;
|
||||
|
||||
static int command_key_valid;
|
||||
static uint32_t command_key_id;
|
||||
static int cache_valid;
|
||||
static uint32_t cache_key_id;
|
||||
static int cache_key_pos;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
generate_key(uint32_t key_id)
|
||||
{
|
||||
#ifdef FEAT_SECHASH
|
||||
unsigned char key[20];
|
||||
const char *hashname = "SHA1";
|
||||
#else
|
||||
unsigned char key[16];
|
||||
const char *hashname = "MD5";
|
||||
#endif
|
||||
const char *key_file, *rand_dev = "/dev/urandom";
|
||||
FILE *f;
|
||||
struct stat st;
|
||||
int i;
|
||||
|
||||
key_file = CNF_GetKeysFile();
|
||||
|
||||
if (!key_file)
|
||||
return 0;
|
||||
|
||||
f = fopen(rand_dev, "r");
|
||||
if (!f || fread(key, sizeof (key), 1, f) != 1) {
|
||||
if (f)
|
||||
fclose(f);
|
||||
LOG_FATAL(LOGF_Keys, "Could not read %s", rand_dev);
|
||||
return 0;
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
f = fopen(key_file, "a");
|
||||
if (!f) {
|
||||
LOG_FATAL(LOGF_Keys, "Could not open keyfile %s for writing", key_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Make sure the keyfile is not world-readable */
|
||||
if (stat(key_file, &st) || chmod(key_file, st.st_mode & 0770)) {
|
||||
fclose(f);
|
||||
LOG_FATAL(LOGF_Keys, "Could not change permissions of keyfile %s", key_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fprintf(f, "\n%"PRIu32" %s HEX:", key_id, hashname);
|
||||
for (i = 0; i < sizeof (key); i++)
|
||||
fprintf(f, "%02hhX", key[i]);
|
||||
fprintf(f, "\n");
|
||||
fclose(f);
|
||||
|
||||
/* Erase the key from stack */
|
||||
memset(key, 0, sizeof (key));
|
||||
|
||||
LOG(LOGS_INFO, LOGF_Keys, "Generated key %"PRIu32, key_id);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
free_keys(void)
|
||||
{
|
||||
unsigned int i;
|
||||
Key *key;
|
||||
|
||||
for (i = 0; i < ARR_GetSize(keys); i++)
|
||||
Free(((Key *)ARR_GetElement(keys, i))->val);
|
||||
for (i = 0; i < ARR_GetSize(keys); i++) {
|
||||
key = ARR_GetElement(keys, i);
|
||||
switch (key->class) {
|
||||
case NTP_MAC:
|
||||
Free(key->data.ntp_mac.value);
|
||||
break;
|
||||
case CMAC:
|
||||
CMC_DestroyInstance(key->data.cmac);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
ARR_SetSize(keys, 0);
|
||||
command_key_valid = 0;
|
||||
cache_valid = 0;
|
||||
}
|
||||
|
||||
@@ -135,14 +100,8 @@ void
|
||||
KEY_Initialise(void)
|
||||
{
|
||||
keys = ARR_CreateInstance(sizeof (Key));
|
||||
command_key_valid = 0;
|
||||
cache_valid = 0;
|
||||
KEY_Reload();
|
||||
|
||||
if (CNF_GetGenerateCommandKey() && !KEY_KeyKnown(KEY_GetCommandKey())) {
|
||||
if (generate_key(KEY_GetCommandKey()))
|
||||
KEY_Reload();
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -163,34 +122,22 @@ get_key(unsigned int index)
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Decode key encoded in ASCII or HEX */
|
||||
|
||||
static int
|
||||
determine_hash_delay(uint32_t key_id)
|
||||
decode_key(char *key)
|
||||
{
|
||||
NTP_Packet pkt;
|
||||
struct timeval before, after;
|
||||
unsigned long usecs, min_usecs=0;
|
||||
int i;
|
||||
int len = strlen(key);
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
LCL_ReadRawTime(&before);
|
||||
KEY_GenerateAuth(key_id, (unsigned char *)&pkt, NTP_NORMAL_PACKET_LENGTH,
|
||||
(unsigned char *)&pkt.auth_data, sizeof (pkt.auth_data));
|
||||
LCL_ReadRawTime(&after);
|
||||
|
||||
usecs = (after.tv_sec - before.tv_sec) * 1000000 + (after.tv_usec - before.tv_usec);
|
||||
|
||||
if (i == 0 || usecs < min_usecs) {
|
||||
min_usecs = usecs;
|
||||
}
|
||||
if (!strncmp(key, "ASCII:", 6)) {
|
||||
memmove(key, key + 6, len - 6);
|
||||
return len - 6;
|
||||
} else if (!strncmp(key, "HEX:", 4)) {
|
||||
return UTI_HexToBytes(key + 4, key, len);
|
||||
} else {
|
||||
/* assume ASCII */
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Add on a bit extra to allow for copying, conversions etc */
|
||||
min_usecs += min_usecs >> 4;
|
||||
|
||||
DEBUG_LOG(LOGF_Keys, "authentication delay for key %"PRIu32": %ld useconds", key_id, min_usecs);
|
||||
|
||||
return min_usecs;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -218,11 +165,13 @@ compare_keys_by_id(const void *a, const void *b)
|
||||
void
|
||||
KEY_Reload(void)
|
||||
{
|
||||
unsigned int i, line_number;
|
||||
unsigned int i, line_number, key_length, cmac_key_length;
|
||||
FILE *in;
|
||||
uint32_t key_id;
|
||||
char line[2048], *keyval, *key_file;
|
||||
const char *hashname;
|
||||
char line[2048], *key_file, *key_value;
|
||||
const char *key_type;
|
||||
HSH_Algorithm hash_algorithm;
|
||||
CMC_Algorithm cmac_algorithm;
|
||||
int hash_id;
|
||||
Key key;
|
||||
|
||||
free_keys();
|
||||
@@ -233,9 +182,12 @@ KEY_Reload(void)
|
||||
if (!key_file)
|
||||
return;
|
||||
|
||||
in = fopen(key_file, "r");
|
||||
if (!UTI_CheckFilePermissions(key_file, 0771))
|
||||
;
|
||||
|
||||
in = UTI_OpenFile(NULL, key_file, NULL, 'r', 0);
|
||||
if (!in) {
|
||||
LOG(LOGS_WARN, LOGF_Keys, "Could not open keyfile %s", key_file);
|
||||
LOG(LOGS_WARN, "Could not open keyfile %s", key_file);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -246,26 +198,56 @@ KEY_Reload(void)
|
||||
if (!*line)
|
||||
continue;
|
||||
|
||||
if (!CPS_ParseKey(line, &key_id, &hashname, &keyval)) {
|
||||
LOG(LOGS_WARN, LOGF_Keys, "Could not parse key at line %d in file %s", line_number, key_file);
|
||||
memset(&key, 0, sizeof (key));
|
||||
|
||||
if (!CPS_ParseKey(line, &key.id, &key_type, &key_value)) {
|
||||
LOG(LOGS_WARN, "Could not parse key at line %u in file %s", line_number, key_file);
|
||||
continue;
|
||||
}
|
||||
|
||||
key.hash_id = HSH_GetHashId(hashname);
|
||||
if (key.hash_id < 0) {
|
||||
LOG(LOGS_WARN, LOGF_Keys, "Unknown hash function in key %"PRIu32, key_id);
|
||||
key_length = decode_key(key_value);
|
||||
if (key_length == 0) {
|
||||
LOG(LOGS_WARN, "Could not decode key %"PRIu32, key.id);
|
||||
continue;
|
||||
}
|
||||
|
||||
key.len = UTI_DecodePasswordFromText(keyval);
|
||||
if (!key.len) {
|
||||
LOG(LOGS_WARN, LOGF_Keys, "Could not decode password in key %"PRIu32, key_id);
|
||||
hash_algorithm = UTI_HashNameToAlgorithm(key_type);
|
||||
cmac_algorithm = UTI_CmacNameToAlgorithm(key_type);
|
||||
|
||||
if (hash_algorithm != 0) {
|
||||
hash_id = HSH_GetHashId(hash_algorithm);
|
||||
if (hash_id < 0) {
|
||||
LOG(LOGS_WARN, "Unsupported %s in key %"PRIu32, "hash function", key.id);
|
||||
continue;
|
||||
}
|
||||
key.class = NTP_MAC;
|
||||
key.type = hash_algorithm;
|
||||
key.length = key_length;
|
||||
key.data.ntp_mac.value = MallocArray(unsigned char, key_length);
|
||||
memcpy(key.data.ntp_mac.value, key_value, key_length);
|
||||
key.data.ntp_mac.hash_id = hash_id;
|
||||
} else if (cmac_algorithm != 0) {
|
||||
cmac_key_length = CMC_GetKeyLength(cmac_algorithm);
|
||||
if (cmac_key_length == 0) {
|
||||
LOG(LOGS_WARN, "Unsupported %s in key %"PRIu32, "cipher", key.id);
|
||||
continue;
|
||||
} else if (cmac_key_length != key_length) {
|
||||
LOG(LOGS_WARN, "Invalid length of %s key %"PRIu32" (expected %u bits)",
|
||||
key_type, key.id, 8 * cmac_key_length);
|
||||
continue;
|
||||
}
|
||||
|
||||
key.class = CMAC;
|
||||
key.type = cmac_algorithm;
|
||||
key.length = key_length;
|
||||
key.data.cmac = CMC_CreateInstance(cmac_algorithm, (unsigned char *)key_value,
|
||||
key_length);
|
||||
assert(key.data.cmac);
|
||||
} else {
|
||||
LOG(LOGS_WARN, "Invalid type in key %"PRIu32, key.id);
|
||||
continue;
|
||||
}
|
||||
|
||||
key.id = key_id;
|
||||
key.val = MallocArray(char, key.len);
|
||||
memcpy(key.val, keyval, key.len);
|
||||
ARR_AppendElement(keys, &key);
|
||||
}
|
||||
|
||||
@@ -276,17 +258,13 @@ KEY_Reload(void)
|
||||
more careful! */
|
||||
qsort(ARR_GetElements(keys), ARR_GetSize(keys), sizeof (Key), compare_keys_by_id);
|
||||
|
||||
LOG(LOGS_INFO, "Loaded %u symmetric keys", ARR_GetSize(keys));
|
||||
|
||||
/* Check for duplicates */
|
||||
for (i = 1; i < ARR_GetSize(keys); i++) {
|
||||
if (get_key(i - 1)->id == get_key(i)->id)
|
||||
LOG(LOGS_WARN, LOGF_Keys, "Detected duplicate key %"PRIu32, get_key(i - 1)->id);
|
||||
LOG(LOGS_WARN, "Detected duplicate key %"PRIu32, get_key(i - 1)->id);
|
||||
}
|
||||
|
||||
/* Erase any passwords from stack */
|
||||
memset(line, 0, sizeof (line));
|
||||
|
||||
for (i = 0; i < ARR_GetSize(keys); i++)
|
||||
get_key(i)->auth_delay = determine_hash_delay(get_key(i)->id);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -334,18 +312,6 @@ get_key_by_id(uint32_t key_id)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
uint32_t
|
||||
KEY_GetCommandKey(void)
|
||||
{
|
||||
if (!command_key_valid) {
|
||||
command_key_id = CNF_GetCommandKey();
|
||||
}
|
||||
|
||||
return command_key_id;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
KEY_KeyKnown(uint32_t key_id)
|
||||
{
|
||||
@@ -355,8 +321,9 @@ KEY_KeyKnown(uint32_t key_id)
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
KEY_GetAuthDelay(uint32_t key_id)
|
||||
KEY_GetAuthLength(uint32_t key_id)
|
||||
{
|
||||
unsigned char buf[MAX_HASH_LENGTH];
|
||||
Key *key;
|
||||
|
||||
key = get_key_by_id(key_id);
|
||||
@@ -364,14 +331,21 @@ KEY_GetAuthDelay(uint32_t key_id)
|
||||
if (!key)
|
||||
return 0;
|
||||
|
||||
return key->auth_delay;
|
||||
switch (key->class) {
|
||||
case NTP_MAC:
|
||||
return HSH_Hash(key->data.ntp_mac.hash_id, buf, 0, buf, 0, buf, sizeof (buf));
|
||||
case CMAC:
|
||||
return CMC_Hash(key->data.cmac, buf, 0, buf, sizeof (buf));
|
||||
default:
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
KEY_GenerateAuth(uint32_t key_id, const unsigned char *data, int data_len,
|
||||
unsigned char *auth, int auth_len)
|
||||
KEY_CheckKeyLength(uint32_t key_id)
|
||||
{
|
||||
Key *key;
|
||||
|
||||
@@ -380,15 +354,13 @@ KEY_GenerateAuth(uint32_t key_id, const unsigned char *data, int data_len,
|
||||
if (!key)
|
||||
return 0;
|
||||
|
||||
return UTI_GenerateNTPAuth(key->hash_id, (unsigned char *)key->val,
|
||||
key->len, data, data_len, auth, auth_len);
|
||||
return key->length >= MIN_SECURE_KEY_LENGTH;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
KEY_CheckAuth(uint32_t key_id, const unsigned char *data, int data_len,
|
||||
const unsigned char *auth, int auth_len)
|
||||
KEY_GetKeyInfo(uint32_t key_id, int *type, int *bits)
|
||||
{
|
||||
Key *key;
|
||||
|
||||
@@ -397,6 +369,70 @@ KEY_CheckAuth(uint32_t key_id, const unsigned char *data, int data_len,
|
||||
if (!key)
|
||||
return 0;
|
||||
|
||||
return UTI_CheckNTPAuth(key->hash_id, (unsigned char *)key->val,
|
||||
key->len, data, data_len, auth, auth_len);
|
||||
*type = key->type;
|
||||
*bits = 8 * key->length;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
generate_auth(Key *key, const void *data, int data_len, unsigned char *auth, int auth_len)
|
||||
{
|
||||
switch (key->class) {
|
||||
case NTP_MAC:
|
||||
return HSH_Hash(key->data.ntp_mac.hash_id, key->data.ntp_mac.value,
|
||||
key->length, data, data_len, auth, auth_len);
|
||||
case CMAC:
|
||||
return CMC_Hash(key->data.cmac, data, data_len, auth, auth_len);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
check_auth(Key *key, const void *data, int data_len,
|
||||
const unsigned char *auth, int auth_len, int trunc_len)
|
||||
{
|
||||
unsigned char buf[MAX_HASH_LENGTH];
|
||||
int hash_len;
|
||||
|
||||
hash_len = generate_auth(key, data, data_len, buf, sizeof (buf));
|
||||
|
||||
return MIN(hash_len, trunc_len) == auth_len && UTI_IsMemoryEqual(buf, auth, auth_len);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
KEY_GenerateAuth(uint32_t key_id, const void *data, int data_len,
|
||||
unsigned char *auth, int auth_len)
|
||||
{
|
||||
Key *key;
|
||||
|
||||
key = get_key_by_id(key_id);
|
||||
|
||||
if (!key)
|
||||
return 0;
|
||||
|
||||
return generate_auth(key, data, data_len, auth, auth_len);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
KEY_CheckAuth(uint32_t key_id, const void *data, int data_len,
|
||||
const unsigned char *auth, int auth_len, int trunc_len)
|
||||
{
|
||||
Key *key;
|
||||
|
||||
key = get_key_by_id(key_id);
|
||||
|
||||
if (!key)
|
||||
return 0;
|
||||
|
||||
return check_auth(key, data, data_len, auth, auth_len, trunc_len);
|
||||
}
|
||||
|
||||
15
keys.h
15
keys.h
@@ -34,15 +34,14 @@ extern void KEY_Finalise(void);
|
||||
|
||||
extern void KEY_Reload(void);
|
||||
|
||||
extern uint32_t KEY_GetCommandKey(void);
|
||||
|
||||
extern int KEY_GetKey(uint32_t key_id, char **key, int *len);
|
||||
extern int KEY_KeyKnown(uint32_t key_id);
|
||||
extern int KEY_GetAuthDelay(uint32_t key_id);
|
||||
extern int KEY_GetAuthLength(uint32_t key_id);
|
||||
extern int KEY_CheckKeyLength(uint32_t key_id);
|
||||
extern int KEY_GetKeyInfo(uint32_t key_id, int *type, int *bits);
|
||||
|
||||
extern int KEY_GenerateAuth(uint32_t key_id, const unsigned char *data,
|
||||
int data_len, unsigned char *auth, int auth_len);
|
||||
extern int KEY_CheckAuth(uint32_t key_id, const unsigned char *data,
|
||||
int data_len, const unsigned char *auth, int auth_len);
|
||||
extern int KEY_GenerateAuth(uint32_t key_id, const void *data, int data_len,
|
||||
unsigned char *auth, int auth_len);
|
||||
extern int KEY_CheckAuth(uint32_t key_id, const void *data, int data_len,
|
||||
const unsigned char *auth, int auth_len, int trunc_len);
|
||||
|
||||
#endif /* GOT_KEYS_H */
|
||||
|
||||
272
leapdb.c
Normal file
272
leapdb.c
Normal file
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2009-2018, 2020, 2022
|
||||
* Copyright (C) Patrick Oppenlander 2023, 2024
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
This module provides leap second information. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "conf.h"
|
||||
#include "leapdb.h"
|
||||
#include "logging.h"
|
||||
#include "util.h"
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Source of leap second data */
|
||||
enum {
|
||||
SRC_NONE,
|
||||
SRC_TIMEZONE,
|
||||
SRC_LIST,
|
||||
} leap_src;
|
||||
|
||||
/* Offset between leap-seconds.list timestamp epoch and Unix epoch.
|
||||
leap-seconds.list epoch is 1 Jan 1900, 00:00:00 */
|
||||
#define LEAP_SEC_LIST_OFFSET 2208988800
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static NTP_Leap
|
||||
get_tz_leap(time_t when, int *tai_offset)
|
||||
{
|
||||
struct tm stm, *tm;
|
||||
time_t t;
|
||||
char *tz_env, tz_orig[128];
|
||||
NTP_Leap tz_leap = LEAP_Normal;
|
||||
|
||||
tm = gmtime(&when);
|
||||
if (!tm)
|
||||
return tz_leap;
|
||||
|
||||
stm = *tm;
|
||||
|
||||
/* Temporarily switch to the timezone containing leap seconds */
|
||||
tz_env = getenv("TZ");
|
||||
if (tz_env) {
|
||||
if (strlen(tz_env) >= sizeof (tz_orig))
|
||||
return tz_leap;
|
||||
strcpy(tz_orig, tz_env);
|
||||
}
|
||||
setenv("TZ", CNF_GetLeapSecTimezone(), 1);
|
||||
tzset();
|
||||
|
||||
/* Get the TAI-UTC offset, which started at the epoch at 10 seconds */
|
||||
t = mktime(&stm);
|
||||
if (t != -1)
|
||||
*tai_offset = t - when + 10;
|
||||
|
||||
/* Set the time to 23:59:60 and see how it overflows in mktime() */
|
||||
stm.tm_sec = 60;
|
||||
stm.tm_min = 59;
|
||||
stm.tm_hour = 23;
|
||||
|
||||
t = mktime(&stm);
|
||||
|
||||
if (tz_env)
|
||||
setenv("TZ", tz_orig, 1);
|
||||
else
|
||||
unsetenv("TZ");
|
||||
tzset();
|
||||
|
||||
if (t == -1)
|
||||
return tz_leap;
|
||||
|
||||
if (stm.tm_sec == 60)
|
||||
tz_leap = LEAP_InsertSecond;
|
||||
else if (stm.tm_sec == 1)
|
||||
tz_leap = LEAP_DeleteSecond;
|
||||
|
||||
return tz_leap;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static NTP_Leap
|
||||
get_list_leap(time_t when, int *tai_offset)
|
||||
{
|
||||
FILE *f;
|
||||
char line[1024];
|
||||
NTP_Leap ret_leap = LEAP_Normal;
|
||||
int ret_tai_offset = 0, prev_lsl_tai_offset = 10;
|
||||
int64_t when1900, lsl_updated = 0, lsl_expiry = 0;
|
||||
const char *leap_sec_list = CNF_GetLeapSecList();
|
||||
|
||||
if (!(f = UTI_OpenFile(NULL, leap_sec_list, NULL, 'r', 0))) {
|
||||
LOG(LOGS_ERR, "Failed to open leap seconds list %s", leap_sec_list);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Leap second happens at midnight */
|
||||
when = (when / (24 * 3600) + 1) * (24 * 3600);
|
||||
|
||||
/* leap-seconds.list timestamps are relative to 1 Jan 1900, 00:00:00 */
|
||||
when1900 = (int64_t)when + LEAP_SEC_LIST_OFFSET;
|
||||
|
||||
while (fgets(line, sizeof line, f)) {
|
||||
int64_t lsl_when;
|
||||
int lsl_tai_offset;
|
||||
char *p;
|
||||
|
||||
/* Ignore blank lines */
|
||||
for (p = line; *p && isspace((unsigned char)*p); ++p)
|
||||
;
|
||||
if (!*p)
|
||||
continue;
|
||||
|
||||
if (*line == '#') {
|
||||
/* Update time line starts with #$ */
|
||||
if (line[1] == '$' && sscanf(line + 2, "%"SCNd64, &lsl_updated) != 1)
|
||||
goto error;
|
||||
/* Expiration time line starts with #@ */
|
||||
if (line[1] == '@' && sscanf(line + 2, "%"SCNd64, &lsl_expiry) != 1)
|
||||
goto error;
|
||||
/* Comment or a special comment we don't care about */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Leap entry */
|
||||
if (sscanf(line, "%"SCNd64" %d", &lsl_when, &lsl_tai_offset) != 2)
|
||||
goto error;
|
||||
|
||||
if (when1900 == lsl_when) {
|
||||
if (lsl_tai_offset > prev_lsl_tai_offset)
|
||||
ret_leap = LEAP_InsertSecond;
|
||||
else if (lsl_tai_offset < prev_lsl_tai_offset)
|
||||
ret_leap = LEAP_DeleteSecond;
|
||||
/* When is rounded to the end of the day, so offset hasn't changed yet! */
|
||||
ret_tai_offset = prev_lsl_tai_offset;
|
||||
} else if (when1900 > lsl_when) {
|
||||
ret_tai_offset = lsl_tai_offset;
|
||||
}
|
||||
|
||||
prev_lsl_tai_offset = lsl_tai_offset;
|
||||
}
|
||||
|
||||
/* Make sure the file looks sensible */
|
||||
if (!feof(f) || !lsl_updated || !lsl_expiry)
|
||||
goto error;
|
||||
|
||||
if (when1900 >= lsl_expiry)
|
||||
LOG(LOGS_WARN, "Leap second list %s needs update", leap_sec_list);
|
||||
|
||||
goto out;
|
||||
|
||||
error:
|
||||
if (f)
|
||||
fclose(f);
|
||||
LOG(LOGS_ERR, "Failed to parse leap seconds list %s", leap_sec_list);
|
||||
return LEAP_Normal;
|
||||
|
||||
out:
|
||||
if (f)
|
||||
fclose(f);
|
||||
*tai_offset = ret_tai_offset;
|
||||
return ret_leap;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
check_leap_source(NTP_Leap (*src)(time_t when, int *tai_offset))
|
||||
{
|
||||
int tai_offset = 0;
|
||||
|
||||
/* Check that the leap second source has good data for Jun 30 2012 and Dec 31 2012 */
|
||||
if (src(1341014400, &tai_offset) == LEAP_InsertSecond && tai_offset == 34 &&
|
||||
src(1356912000, &tai_offset) == LEAP_Normal && tai_offset == 35)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LDB_Initialise(void)
|
||||
{
|
||||
const char *leap_tzname, *leap_sec_list;
|
||||
|
||||
leap_tzname = CNF_GetLeapSecTimezone();
|
||||
if (leap_tzname && !check_leap_source(get_tz_leap)) {
|
||||
LOG(LOGS_WARN, "Timezone %s failed leap second check, ignoring", leap_tzname);
|
||||
leap_tzname = NULL;
|
||||
}
|
||||
|
||||
leap_sec_list = CNF_GetLeapSecList();
|
||||
if (leap_sec_list && !check_leap_source(get_list_leap)) {
|
||||
LOG(LOGS_WARN, "Leap second list %s failed check, ignoring", leap_sec_list);
|
||||
leap_sec_list = NULL;
|
||||
}
|
||||
|
||||
if (leap_sec_list) {
|
||||
LOG(LOGS_INFO, "Using leap second list %s", leap_sec_list);
|
||||
leap_src = SRC_LIST;
|
||||
} else if (leap_tzname) {
|
||||
LOG(LOGS_INFO, "Using %s timezone to obtain leap second data", leap_tzname);
|
||||
leap_src = SRC_TIMEZONE;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
NTP_Leap
|
||||
LDB_GetLeap(time_t when, int *tai_offset)
|
||||
{
|
||||
static time_t last_ldb_leap_check;
|
||||
static NTP_Leap ldb_leap;
|
||||
static int ldb_tai_offset;
|
||||
|
||||
/* Do this check at most twice a day */
|
||||
when = when / (12 * 3600) * (12 * 3600);
|
||||
if (last_ldb_leap_check == when)
|
||||
goto out;
|
||||
|
||||
last_ldb_leap_check = when;
|
||||
ldb_leap = LEAP_Normal;
|
||||
ldb_tai_offset = 0;
|
||||
|
||||
switch (leap_src) {
|
||||
case SRC_NONE:
|
||||
break;
|
||||
case SRC_TIMEZONE:
|
||||
ldb_leap = get_tz_leap(when, &ldb_tai_offset);
|
||||
break;
|
||||
case SRC_LIST:
|
||||
ldb_leap = get_list_leap(when, &ldb_tai_offset);
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
*tai_offset = ldb_tai_offset;
|
||||
return ldb_leap;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LDB_Finalise(void)
|
||||
{
|
||||
/* Nothing to do */
|
||||
}
|
||||
37
leapdb.h
Normal file
37
leapdb.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Patrick Oppenlander 2024
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
This module provides leap second information.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef GOT_LEAPDB_H
|
||||
#define GOT_LEAPDB_H
|
||||
|
||||
#include "ntp.h"
|
||||
|
||||
extern void LDB_Initialise(void);
|
||||
extern NTP_Leap LDB_GetLeap(time_t when, int *tai_offset);
|
||||
extern void LDB_Finalise(void);
|
||||
|
||||
#endif /* GOT_LEAPDB_H */
|
||||
359
local.c
359
local.c
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2011, 2014
|
||||
* Copyright (C) Miroslav Lichvar 2011, 2014-2015
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -42,13 +42,12 @@
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Maximum allowed frequency offset in ppm, the time must not stop
|
||||
or run backwards */
|
||||
#define MAX_FREQ 500000.0
|
||||
|
||||
/* Variable to store the current frequency, in ppm */
|
||||
static double current_freq_ppm;
|
||||
|
||||
/* Maximum allowed frequency, in ppm */
|
||||
static double max_freq_ppm;
|
||||
|
||||
/* Temperature compensation, in ppm */
|
||||
static double temp_comp_ppm;
|
||||
|
||||
@@ -98,8 +97,142 @@ static double precision_quantum;
|
||||
|
||||
static double max_clock_error;
|
||||
|
||||
#define NSEC_PER_SEC 1000000000
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Ask the system for the resolution of the system clock. The Linux
|
||||
clock_getres() is not usable, because it reports the internal timer
|
||||
resolution, which is 1 ns when high-resolution timers are enabled,
|
||||
even when using a lower-resolution clocksource. */
|
||||
|
||||
static int
|
||||
get_clock_resolution(void)
|
||||
{
|
||||
#if defined(HAVE_CLOCK_GETTIME) && !defined(LINUX)
|
||||
struct timespec res;
|
||||
|
||||
if (clock_getres(CLOCK_REALTIME, &res) < 0)
|
||||
return 0;
|
||||
|
||||
return NSEC_PER_SEC * res.tv_sec + res.tv_nsec;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#if defined(LINUX) && defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC_RAW)
|
||||
|
||||
static int
|
||||
compare_ints(const void *a, const void *b)
|
||||
{
|
||||
return *(const int *)a - *(const int *)b;
|
||||
}
|
||||
|
||||
#define READINGS 64
|
||||
|
||||
/* On Linux, try to measure the actual resolution of the system
|
||||
clock by performing a varying amount of busy work between clock
|
||||
readings and finding the minimum change in the measured interval.
|
||||
Require a change of at least two nanoseconds to ignore errors
|
||||
caused by conversion to timespec. Use the raw monotonic clock
|
||||
to avoid the impact of potential frequency changes due to NTP
|
||||
adjustments made by other processes, and the kernel dithering of
|
||||
the 32-bit multiplier. */
|
||||
|
||||
static int
|
||||
measure_clock_resolution(void)
|
||||
{
|
||||
int i, j, b, busy, diffs[READINGS - 1], diff2, min;
|
||||
struct timespec start_ts, ts[READINGS];
|
||||
uint32_t acc;
|
||||
|
||||
if (clock_gettime(CLOCK_MONOTONIC_RAW, &start_ts) < 0)
|
||||
return 0;
|
||||
|
||||
for (acc = 0, busy = 1; busy < 100000; busy = busy * 3 / 2 + 1) {
|
||||
for (i = 0, b = busy * READINGS; i < READINGS; i++, b -= busy) {
|
||||
if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts[i]) < 0)
|
||||
return 0;
|
||||
|
||||
for (j = b; j > 0; j--)
|
||||
acc += (acc & 1) + (uint32_t)ts[i].tv_nsec;
|
||||
}
|
||||
|
||||
/* Give up after 0.1 seconds */
|
||||
if (UTI_DiffTimespecsToDouble(&ts[READINGS - 1], &start_ts) > 0.1) {
|
||||
DEBUG_LOG("Measurement too slow");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < READINGS - 1; i++) {
|
||||
diffs[i] = NSEC_PER_SEC * (ts[i + 1].tv_sec - ts[i].tv_sec) +
|
||||
(ts[i + 1].tv_nsec - ts[i].tv_nsec);
|
||||
|
||||
/* Make sure the differences are sane. A resolution larger than the
|
||||
reading time will be measured in measure_clock_read_delay(). */
|
||||
if (diffs[i] <= 0 || diffs[i] > NSEC_PER_SEC)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Sort the differences and keep values unique within 1 ns from the
|
||||
first half of the array, which are less likely to be impacted by CPU
|
||||
interruptions */
|
||||
qsort(diffs, READINGS - 1, sizeof (diffs[0]), compare_ints);
|
||||
for (i = 1, j = 0; i < READINGS / 2; i++) {
|
||||
if (diffs[j] + 1 < diffs[i])
|
||||
diffs[++j] = diffs[i];
|
||||
}
|
||||
j++;
|
||||
|
||||
#if 0
|
||||
for (i = 0; i < j; i++)
|
||||
DEBUG_LOG("busy %d diff %d %d", busy, i, diffs[i]);
|
||||
#endif
|
||||
|
||||
/* Require at least three unique differences to be more confident
|
||||
with the result */
|
||||
if (j < 3)
|
||||
continue;
|
||||
|
||||
/* Find the smallest difference between the unique differences */
|
||||
for (i = 1, min = 0; i < j; i++) {
|
||||
diff2 = diffs[i] - diffs[i - 1];
|
||||
if (min == 0 || min > diff2)
|
||||
min = diff2;
|
||||
}
|
||||
|
||||
if (min == 0)
|
||||
continue;
|
||||
|
||||
/* Prevent the compiler from optimising the busy work out */
|
||||
if (acc == 0)
|
||||
min += 1;
|
||||
|
||||
return min;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
static int
|
||||
measure_clock_resolution(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* As a fallback, measure how long it takes to read the clock. It
|
||||
typically takes longer than the resolution of the clock (and it
|
||||
depends on the CPU speed), i.e. every reading gives a different
|
||||
value, but handle also low-resolution clocks that might give
|
||||
the same reading multiple times. */
|
||||
|
||||
/* Define the number of increments of the system clock that we want
|
||||
to see to be fairly sure that we've got something approaching
|
||||
the minimum increment. Even on a crummy implementation that can't
|
||||
@@ -107,40 +240,55 @@ static double max_clock_error;
|
||||
under 1s of busy waiting. */
|
||||
#define NITERS 100
|
||||
|
||||
static void
|
||||
calculate_sys_precision(void)
|
||||
static int
|
||||
measure_clock_read_delay(void)
|
||||
{
|
||||
struct timeval tv, old_tv;
|
||||
int dusec, best_dusec;
|
||||
int iters;
|
||||
struct timespec ts, old_ts;
|
||||
int iters, diff, best;
|
||||
|
||||
gettimeofday(&old_tv, NULL);
|
||||
best_dusec = 1000000; /* Assume we must be better than a second */
|
||||
LCL_ReadRawTime(&old_ts);
|
||||
|
||||
/* Assume we must be better than a second */
|
||||
best = NSEC_PER_SEC;
|
||||
iters = 0;
|
||||
|
||||
do {
|
||||
gettimeofday(&tv, NULL);
|
||||
dusec = 1000000*(tv.tv_sec - old_tv.tv_sec) + (tv.tv_usec - old_tv.tv_usec);
|
||||
old_tv = tv;
|
||||
if (dusec > 0) {
|
||||
if (dusec < best_dusec) {
|
||||
best_dusec = dusec;
|
||||
}
|
||||
LCL_ReadRawTime(&ts);
|
||||
|
||||
diff = NSEC_PER_SEC * (ts.tv_sec - old_ts.tv_sec) + (ts.tv_nsec - old_ts.tv_nsec);
|
||||
|
||||
old_ts = ts;
|
||||
if (diff > 0) {
|
||||
if (diff < best)
|
||||
best = diff;
|
||||
iters++;
|
||||
}
|
||||
} while (iters < NITERS);
|
||||
|
||||
assert(best_dusec > 0);
|
||||
assert(best > 0);
|
||||
|
||||
precision_quantum = best_dusec * 1.0e-6;
|
||||
return best;
|
||||
}
|
||||
|
||||
/* Get rounded log2 value of the measured precision */
|
||||
precision_log = 0;
|
||||
while (best_dusec < 707107) {
|
||||
precision_log--;
|
||||
best_dusec *= 2;
|
||||
}
|
||||
/* ================================================== */
|
||||
|
||||
DEBUG_LOG(LOGF_Local, "Clock precision %.9f (%d)", precision_quantum, precision_log);
|
||||
static double
|
||||
measure_clock_precision(void)
|
||||
{
|
||||
int res, delay, prec;
|
||||
|
||||
res = get_clock_resolution();
|
||||
if (res <= 0)
|
||||
res = measure_clock_resolution();
|
||||
|
||||
delay = measure_clock_read_delay();
|
||||
|
||||
if (res > 0)
|
||||
prec = MIN(res, delay);
|
||||
else
|
||||
prec = delay;
|
||||
|
||||
return prec / 1.0e9;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -164,7 +312,21 @@ LCL_Initialise(void)
|
||||
current_freq_ppm = 0.0;
|
||||
temp_comp_ppm = 0.0;
|
||||
|
||||
calculate_sys_precision();
|
||||
precision_quantum = CNF_GetClockPrecision();
|
||||
if (precision_quantum <= 0.0)
|
||||
precision_quantum = measure_clock_precision();
|
||||
|
||||
precision_quantum = CLAMP(1.0e-9, precision_quantum, 1.0);
|
||||
precision_log = round(log(precision_quantum) / log(2.0));
|
||||
/* NTP code doesn't support smaller log than -30 */
|
||||
assert(precision_log >= -30);
|
||||
|
||||
DEBUG_LOG("Clock precision %.9f (%d)", precision_quantum, precision_log);
|
||||
|
||||
/* This is the maximum allowed frequency offset in ppm, the time must
|
||||
never stop or run backwards */
|
||||
max_freq_ppm = CNF_GetMaxDrift();
|
||||
max_freq_ppm = CLAMP(0.0, max_freq_ppm, 500000.0);
|
||||
|
||||
max_clock_error = CNF_GetMaxClockError() * 1e-6;
|
||||
}
|
||||
@@ -174,13 +336,9 @@ LCL_Initialise(void)
|
||||
void
|
||||
LCL_Finalise(void)
|
||||
{
|
||||
while (change_list.next != &change_list)
|
||||
LCL_RemoveParameterChangeHandler(change_list.next->handler,
|
||||
change_list.next->anything);
|
||||
|
||||
while (dispersion_notify_list.next != &dispersion_notify_list)
|
||||
LCL_RemoveDispersionNotifyHandler(dispersion_notify_list.next->handler,
|
||||
dispersion_notify_list.next->anything);
|
||||
/* Make sure all handlers have been removed */
|
||||
BRIEF_ASSERT(change_list.next == &change_list);
|
||||
BRIEF_ASSERT(dispersion_notify_list.next == &dispersion_notify_list);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -218,9 +376,7 @@ LCL_AddParameterChangeHandler(LCL_ParameterChangeHandler handler, void *anything
|
||||
|
||||
/* Check that the handler is not already registered */
|
||||
for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) {
|
||||
if (!(ptr->handler != handler || ptr->anything != anything)) {
|
||||
assert(0);
|
||||
}
|
||||
BRIEF_ASSERT(ptr->handler != handler || ptr->anything != anything);
|
||||
}
|
||||
|
||||
new_entry = MallocNew(ChangeListEntry);
|
||||
@@ -274,7 +430,7 @@ LCL_IsFirstParameterChangeHandler(LCL_ParameterChangeHandler handler)
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
invoke_parameter_change_handlers(struct timeval *raw, struct timeval *cooked,
|
||||
invoke_parameter_change_handlers(struct timespec *raw, struct timespec *cooked,
|
||||
double dfreq, double doffset,
|
||||
LCL_ChangeType change_type)
|
||||
{
|
||||
@@ -294,9 +450,7 @@ LCL_AddDispersionNotifyHandler(LCL_DispersionNotifyHandler handler, void *anythi
|
||||
|
||||
/* Check that the handler is not already registered */
|
||||
for (ptr = dispersion_notify_list.next; ptr != &dispersion_notify_list; ptr = ptr->next) {
|
||||
if (!(ptr->handler != handler || ptr->anything != anything)) {
|
||||
assert(0);
|
||||
}
|
||||
BRIEF_ASSERT(ptr->handler != handler || ptr->anything != anything);
|
||||
}
|
||||
|
||||
new_entry = MallocNew(DispersionNotifyListEntry);
|
||||
@@ -341,23 +495,29 @@ void LCL_RemoveDispersionNotifyHandler(LCL_DispersionNotifyHandler handler, void
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* At the moment, this is just gettimeofday(), because
|
||||
I can't think of a Unix system where it would not be */
|
||||
|
||||
void
|
||||
LCL_ReadRawTime(struct timeval *result)
|
||||
LCL_ReadRawTime(struct timespec *ts)
|
||||
{
|
||||
if (gettimeofday(result, NULL) < 0) {
|
||||
LOG_FATAL(LOGF_Local, "gettimeofday() failed");
|
||||
}
|
||||
#if HAVE_CLOCK_GETTIME
|
||||
if (clock_gettime(CLOCK_REALTIME, ts) < 0)
|
||||
LOG_FATAL("clock_gettime() failed : %s", strerror(errno));
|
||||
#else
|
||||
struct timeval tv;
|
||||
|
||||
if (gettimeofday(&tv, NULL) < 0)
|
||||
LOG_FATAL("gettimeofday() failed : %s", strerror(errno));
|
||||
|
||||
UTI_TimevalToTimespec(&tv, ts);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LCL_ReadCookedTime(struct timeval *result, double *err)
|
||||
LCL_ReadCookedTime(struct timespec *result, double *err)
|
||||
{
|
||||
struct timeval raw;
|
||||
struct timespec raw;
|
||||
|
||||
LCL_ReadRawTime(&raw);
|
||||
LCL_CookTime(&raw, result, err);
|
||||
@@ -366,18 +526,18 @@ LCL_ReadCookedTime(struct timeval *result, double *err)
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LCL_CookTime(struct timeval *raw, struct timeval *cooked, double *err)
|
||||
LCL_CookTime(struct timespec *raw, struct timespec *cooked, double *err)
|
||||
{
|
||||
double correction;
|
||||
|
||||
LCL_GetOffsetCorrection(raw, &correction, err);
|
||||
UTI_AddDoubleToTimeval(raw, correction, cooked);
|
||||
UTI_AddDoubleToTimespec(raw, correction, cooked);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LCL_GetOffsetCorrection(struct timeval *raw, double *correction, double *err)
|
||||
LCL_GetOffsetCorrection(struct timespec *raw, double *correction, double *err)
|
||||
{
|
||||
/* Call system specific driver to get correction */
|
||||
(*drv_offset_convert)(raw, correction, err);
|
||||
@@ -406,24 +566,24 @@ LCL_ReadAbsoluteFrequency(void)
|
||||
static double
|
||||
clamp_freq(double freq)
|
||||
{
|
||||
if (freq <= MAX_FREQ && freq >= -MAX_FREQ)
|
||||
if (freq <= max_freq_ppm && freq >= -max_freq_ppm)
|
||||
return freq;
|
||||
|
||||
LOG(LOGS_WARN, LOGF_Local, "Frequency %.1f ppm exceeds allowed maximum", freq);
|
||||
LOG(LOGS_WARN, "Frequency %.1f ppm exceeds allowed maximum", freq);
|
||||
|
||||
return freq >= MAX_FREQ ? MAX_FREQ : -MAX_FREQ;
|
||||
return CLAMP(-max_freq_ppm, freq, max_freq_ppm);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
check_offset(struct timeval *now, double offset)
|
||||
check_offset(struct timespec *now, double offset)
|
||||
{
|
||||
/* Check if the time will be still sane with accumulated offset */
|
||||
if (UTI_IsTimeOffsetSane(now, -offset))
|
||||
return 1;
|
||||
|
||||
LOG(LOGS_WARN, LOGF_Local, "Adjustment of %.1f seconds is invalid", -offset);
|
||||
LOG(LOGS_WARN, "Adjustment of %.1f seconds is invalid", -offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -435,7 +595,7 @@ check_offset(struct timeval *now, double offset)
|
||||
void
|
||||
LCL_SetAbsoluteFrequency(double afreq_ppm)
|
||||
{
|
||||
struct timeval raw, cooked;
|
||||
struct timespec raw, cooked;
|
||||
double dfreq;
|
||||
|
||||
afreq_ppm = clamp_freq(afreq_ppm);
|
||||
@@ -466,7 +626,7 @@ LCL_SetAbsoluteFrequency(double afreq_ppm)
|
||||
void
|
||||
LCL_AccumulateDeltaFrequency(double dfreq)
|
||||
{
|
||||
struct timeval raw, cooked;
|
||||
struct timespec raw, cooked;
|
||||
double old_freq_ppm;
|
||||
|
||||
old_freq_ppm = current_freq_ppm;
|
||||
@@ -492,10 +652,10 @@ LCL_AccumulateDeltaFrequency(double dfreq)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
int
|
||||
LCL_AccumulateOffset(double offset, double corr_rate)
|
||||
{
|
||||
struct timeval raw, cooked;
|
||||
struct timespec raw, cooked;
|
||||
|
||||
/* In this case, the cooked time to be passed to the notify clients
|
||||
has to be the cooked time BEFORE the change was made */
|
||||
@@ -504,12 +664,14 @@ LCL_AccumulateOffset(double offset, double corr_rate)
|
||||
LCL_CookTime(&raw, &cooked, NULL);
|
||||
|
||||
if (!check_offset(&cooked, offset))
|
||||
return;
|
||||
return 0;
|
||||
|
||||
(*drv_accrue_offset)(offset, corr_rate);
|
||||
|
||||
/* Dispatch to all handlers */
|
||||
invoke_parameter_change_handlers(&raw, &cooked, 0.0, offset, LCL_ChangeAdjust);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -517,7 +679,7 @@ LCL_AccumulateOffset(double offset, double corr_rate)
|
||||
int
|
||||
LCL_ApplyStepOffset(double offset)
|
||||
{
|
||||
struct timeval raw, cooked;
|
||||
struct timespec raw, cooked;
|
||||
|
||||
/* In this case, the cooked time to be passed to the notify clients
|
||||
has to be the cooked time BEFORE the change was made */
|
||||
@@ -529,7 +691,7 @@ LCL_ApplyStepOffset(double offset)
|
||||
return 0;
|
||||
|
||||
if (!(*drv_apply_step_offset)(offset)) {
|
||||
LOG(LOGS_ERR, LOGF_Local, "Could not step clock");
|
||||
LOG(LOGS_ERR, "Could not step system clock");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -545,9 +707,11 @@ LCL_ApplyStepOffset(double offset)
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LCL_NotifyExternalTimeStep(struct timeval *raw, struct timeval *cooked,
|
||||
LCL_NotifyExternalTimeStep(struct timespec *raw, struct timespec *cooked,
|
||||
double offset, double dispersion)
|
||||
{
|
||||
LCL_CancelOffsetCorrection();
|
||||
|
||||
/* Dispatch to all handlers */
|
||||
invoke_parameter_change_handlers(raw, cooked, 0.0, offset, LCL_ChangeUnknownStep);
|
||||
|
||||
@@ -559,21 +723,24 @@ LCL_NotifyExternalTimeStep(struct timeval *raw, struct timeval *cooked,
|
||||
void
|
||||
LCL_NotifyLeap(int leap)
|
||||
{
|
||||
struct timeval raw, cooked;
|
||||
struct timespec raw, cooked;
|
||||
|
||||
LCL_ReadRawTime(&raw);
|
||||
LCL_CookTime(&raw, &cooked, NULL);
|
||||
|
||||
/* Smooth the leap second out */
|
||||
SMT_Leap(&cooked, leap);
|
||||
|
||||
/* Dispatch to all handlers as if the clock was stepped */
|
||||
invoke_parameter_change_handlers(&raw, &cooked, 0.0, -leap, LCL_ChangeStep);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
int
|
||||
LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
|
||||
{
|
||||
struct timeval raw, cooked;
|
||||
struct timespec raw, cooked;
|
||||
double old_freq_ppm;
|
||||
|
||||
LCL_ReadRawTime(&raw);
|
||||
@@ -582,7 +749,7 @@ LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
|
||||
LCL_CookTime(&raw, &cooked, NULL);
|
||||
|
||||
if (!check_offset(&cooked, doffset))
|
||||
return;
|
||||
return 0;
|
||||
|
||||
old_freq_ppm = current_freq_ppm;
|
||||
|
||||
@@ -593,7 +760,7 @@ LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
|
||||
|
||||
current_freq_ppm = clamp_freq(current_freq_ppm);
|
||||
|
||||
DEBUG_LOG(LOGF_Local, "old_freq=%.3fppm new_freq=%.3fppm offset=%.6fsec",
|
||||
DEBUG_LOG("old_freq=%.3fppm new_freq=%.3fppm offset=%.6fsec",
|
||||
old_freq_ppm, current_freq_ppm, doffset);
|
||||
|
||||
/* Call the system-specific driver for setting the frequency */
|
||||
@@ -604,6 +771,26 @@ LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
|
||||
|
||||
/* Dispatch to all handlers */
|
||||
invoke_parameter_change_handlers(&raw, &cooked, dfreq, doffset, LCL_ChangeAdjust);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
LCL_AccumulateFrequencyAndOffsetNoHandlers(double dfreq, double doffset, double corr_rate)
|
||||
{
|
||||
ChangeListEntry *first_handler;
|
||||
int r;
|
||||
|
||||
first_handler = change_list.next;
|
||||
change_list.next = &change_list;
|
||||
|
||||
r = LCL_AccumulateFrequencyAndOffset(dfreq, doffset, corr_rate);
|
||||
|
||||
change_list.next = first_handler;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -640,7 +827,7 @@ lcl_RegisterSystemDrivers(lcl_ReadFrequencyDriver read_freq,
|
||||
|
||||
current_freq_ppm = (*drv_read_freq)();
|
||||
|
||||
DEBUG_LOG(LOGF_Local, "Local freq=%.3fppm", current_freq_ppm);
|
||||
DEBUG_LOG("Local freq=%.3fppm", current_freq_ppm);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -650,7 +837,7 @@ lcl_RegisterSystemDrivers(lcl_ReadFrequencyDriver read_freq,
|
||||
int
|
||||
LCL_MakeStep(void)
|
||||
{
|
||||
struct timeval raw;
|
||||
struct timespec raw;
|
||||
double correction;
|
||||
|
||||
LCL_ReadRawTime(&raw);
|
||||
@@ -661,16 +848,32 @@ LCL_MakeStep(void)
|
||||
|
||||
/* Cancel remaining slew and make the step */
|
||||
LCL_AccumulateOffset(correction, 0.0);
|
||||
if (!LCL_ApplyStepOffset(-correction))
|
||||
if (!LCL_ApplyStepOffset(-correction)) {
|
||||
/* Revert the correction */
|
||||
LCL_AccumulateOffset(-correction, 0.0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOG(LOGS_WARN, LOGF_Local, "System clock was stepped by %.6f seconds", correction);
|
||||
LOG(LOGS_WARN, "System clock was stepped by %.6f seconds", correction);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LCL_CancelOffsetCorrection(void)
|
||||
{
|
||||
struct timespec raw;
|
||||
double correction;
|
||||
|
||||
LCL_ReadRawTime(&raw);
|
||||
LCL_GetOffsetCorrection(&raw, &correction, NULL);
|
||||
LCL_AccumulateOffset(correction, 0.0);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
LCL_CanSystemLeap(void)
|
||||
{
|
||||
@@ -680,10 +883,10 @@ LCL_CanSystemLeap(void)
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LCL_SetSystemLeap(int leap)
|
||||
LCL_SetSystemLeap(int leap, int tai_offset)
|
||||
{
|
||||
if (drv_set_leap) {
|
||||
(drv_set_leap)(leap);
|
||||
(drv_set_leap)(leap, tai_offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
36
local.h
36
local.h
@@ -31,9 +31,8 @@
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
/* Read the system clock. This is analogous to gettimeofday(),
|
||||
but with the timezone information ignored */
|
||||
extern void LCL_ReadRawTime(struct timeval *);
|
||||
/* Read the system clock */
|
||||
extern void LCL_ReadRawTime(struct timespec *ts);
|
||||
|
||||
/* Read the system clock, corrected according to all accumulated
|
||||
drifts and uncompensated offsets.
|
||||
@@ -44,15 +43,15 @@ extern void LCL_ReadRawTime(struct timeval *);
|
||||
adjtime()-like interface to correct offsets, and to adjust the
|
||||
frequency), we must correct the raw time to get this value */
|
||||
|
||||
extern void LCL_ReadCookedTime(struct timeval *t, double *err);
|
||||
extern void LCL_ReadCookedTime(struct timespec *ts, double *err);
|
||||
|
||||
/* Convert raw time to cooked. */
|
||||
extern void LCL_CookTime(struct timeval *raw, struct timeval *cooked, double *err);
|
||||
extern void LCL_CookTime(struct timespec *raw, struct timespec *cooked, double *err);
|
||||
|
||||
/* Read the current offset between the system clock and true time
|
||||
(i.e. 'cooked' - 'raw') (in seconds). */
|
||||
|
||||
extern void LCL_GetOffsetCorrection(struct timeval *raw, double *correction, double *err);
|
||||
extern void LCL_GetOffsetCorrection(struct timespec *raw, double *correction, double *err);
|
||||
|
||||
/* Type of routines that may be invoked as callbacks when there is a
|
||||
change to the frequency or offset.
|
||||
@@ -79,7 +78,7 @@ typedef enum {
|
||||
} LCL_ChangeType;
|
||||
|
||||
typedef void (*LCL_ParameterChangeHandler)
|
||||
(struct timeval *raw, struct timeval *cooked,
|
||||
(struct timespec *raw, struct timespec *cooked,
|
||||
double dfreq,
|
||||
double doffset,
|
||||
LCL_ChangeType change_type,
|
||||
@@ -150,7 +149,7 @@ extern void LCL_AccumulateDeltaFrequency(double dfreq);
|
||||
forwards (i.e. it is currently slow of true time). Provided is also
|
||||
a suggested correction rate (correction time * offset). */
|
||||
|
||||
extern void LCL_AccumulateOffset(double offset, double corr_rate);
|
||||
extern int LCL_AccumulateOffset(double offset, double corr_rate);
|
||||
|
||||
/* Routine to apply an immediate offset by doing a sudden step if
|
||||
possible. (Intended for use after an initial estimate of offset has
|
||||
@@ -163,7 +162,7 @@ extern int LCL_ApplyStepOffset(double offset);
|
||||
|
||||
/* Routine to invoke notify handlers on an unexpected time jump
|
||||
in system clock */
|
||||
extern void LCL_NotifyExternalTimeStep(struct timeval *raw, struct timeval *cooked,
|
||||
extern void LCL_NotifyExternalTimeStep(struct timespec *raw, struct timespec *cooked,
|
||||
double offset, double dispersion);
|
||||
|
||||
/* Routine to invoke notify handlers on leap second when the system clock
|
||||
@@ -172,7 +171,12 @@ extern void LCL_NotifyLeap(int leap);
|
||||
|
||||
/* Perform the combination of modifying the frequency and applying
|
||||
a slew, in one easy step */
|
||||
extern void LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate);
|
||||
extern int LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate);
|
||||
|
||||
/* Same as the routine above, except it does not call the registered
|
||||
parameter change handlers */
|
||||
extern int LCL_AccumulateFrequencyAndOffsetNoHandlers(double dfreq, double doffset,
|
||||
double corr_rate);
|
||||
|
||||
/* Routine to read the system precision as a log to base 2 value. */
|
||||
extern int LCL_GetSysPrecisionAsLog(void);
|
||||
@@ -198,14 +202,18 @@ extern void LCL_Finalise(void);
|
||||
to a timezone problem. */
|
||||
extern int LCL_MakeStep(void);
|
||||
|
||||
/* Routine to cancel the outstanding system clock correction */
|
||||
extern void LCL_CancelOffsetCorrection(void);
|
||||
|
||||
/* Check if the system driver supports leap seconds, i.e. LCL_SetSystemLeap
|
||||
does something */
|
||||
extern int LCL_CanSystemLeap(void);
|
||||
|
||||
/* Routine to set the system clock to correct itself for a leap second if
|
||||
supported. Leap second will be inserted at the end of the day if the
|
||||
argument is positive, deleted if negative, and zero resets the setting. */
|
||||
extern void LCL_SetSystemLeap(int leap);
|
||||
/* Routine to set the system clock to correct itself for a leap second and also
|
||||
set its TAI-UTC offset. If supported, leap second will be inserted at the
|
||||
end of the day if the argument is positive, deleted if negative, and zero
|
||||
resets the setting. */
|
||||
extern void LCL_SetSystemLeap(int leap, int tai_offset);
|
||||
|
||||
/* Routine to set a frequency correction (in ppm) that should be applied
|
||||
to local clock to compensate for temperature changes. A positive
|
||||
|
||||
6
localp.h
6
localp.h
@@ -52,10 +52,10 @@ typedef int (*lcl_ApplyStepOffsetDriver)(double offset);
|
||||
/* System driver to convert a raw time to an adjusted (cooked) time.
|
||||
The number of seconds returned in 'corr' have to be added to the
|
||||
raw time to get the corrected time */
|
||||
typedef void (*lcl_OffsetCorrectionDriver)(struct timeval *raw, double *corr, double *err);
|
||||
typedef void (*lcl_OffsetCorrectionDriver)(struct timespec *raw, double *corr, double *err);
|
||||
|
||||
/* System driver to schedule leap second */
|
||||
typedef void (*lcl_SetLeapDriver)(int leap);
|
||||
/* System driver to schedule leap seconds and set TAI-UTC offset */
|
||||
typedef void (*lcl_SetLeapDriver)(int leap, int tai_offset);
|
||||
|
||||
/* System driver to set the synchronisation status */
|
||||
typedef void (*lcl_SetSyncStatusDriver)(int synchronised, double est_error, double max_error);
|
||||
|
||||
284
logging.c
284
logging.c
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2011-2014
|
||||
* Copyright (C) Miroslav Lichvar 2011-2014, 2018-2020
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -29,30 +29,29 @@
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
#include "conf.h"
|
||||
#include "logging.h"
|
||||
#include "mkdirpp.h"
|
||||
#include "memory.h"
|
||||
#include "util.h"
|
||||
|
||||
/* This is used by DEBUG_LOG macro */
|
||||
int log_debug_enabled = 0;
|
||||
LOG_Severity log_min_severity = LOGS_INFO;
|
||||
|
||||
/* Current logging contexts */
|
||||
static LOG_Context log_contexts;
|
||||
|
||||
/* ================================================== */
|
||||
/* Flag indicating we have initialised */
|
||||
static int initialised = 0;
|
||||
|
||||
static char *file_log_path = NULL;
|
||||
static FILE *file_log = NULL;
|
||||
static int system_log = 0;
|
||||
|
||||
static int parent_fd = 0;
|
||||
|
||||
#define DEBUG_LEVEL_PRINT_FUNCTION 2
|
||||
#define DEBUG_LEVEL_PRINT_DEBUG 2
|
||||
static int debug_level = 0;
|
||||
|
||||
#ifdef WINNT
|
||||
static FILE *logfile;
|
||||
#endif
|
||||
|
||||
struct LogFile {
|
||||
const char *name;
|
||||
const char *banner;
|
||||
@@ -67,17 +66,20 @@ static int n_filelogs = 0;
|
||||
|
||||
static struct LogFile logfiles[MAX_FILELOGS];
|
||||
|
||||
/* Global prefix for debug messages */
|
||||
static char *debug_prefix;
|
||||
|
||||
/* ================================================== */
|
||||
/* Init function */
|
||||
|
||||
void
|
||||
LOG_Initialise(void)
|
||||
{
|
||||
initialised = 1;
|
||||
debug_prefix = Strdup("");
|
||||
log_contexts = 0;
|
||||
|
||||
#ifdef WINNT
|
||||
logfile = fopen("./chronyd.err", "a");
|
||||
#endif
|
||||
initialised = 1;
|
||||
LOG_OpenFileLog(NULL);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -86,18 +88,19 @@ LOG_Initialise(void)
|
||||
void
|
||||
LOG_Finalise(void)
|
||||
{
|
||||
#ifdef WINNT
|
||||
if (logfile) {
|
||||
fclose(logfile);
|
||||
}
|
||||
#else
|
||||
if (system_log) {
|
||||
if (system_log)
|
||||
closelog();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (file_log && file_log != stderr)
|
||||
fclose(file_log);
|
||||
file_log = NULL;
|
||||
Free(file_log_path);
|
||||
file_log_path = NULL;
|
||||
|
||||
LOG_CycleLogFiles();
|
||||
|
||||
Free(debug_prefix);
|
||||
|
||||
initialised = 0;
|
||||
}
|
||||
|
||||
@@ -105,11 +108,6 @@ LOG_Finalise(void)
|
||||
|
||||
static void log_message(int fatal, LOG_Severity severity, const char *message)
|
||||
{
|
||||
#ifdef WINNT
|
||||
if (logfile) {
|
||||
fprintf(logfile, fatal ? "Fatal error : %s\n" : "%s\n", message);
|
||||
}
|
||||
#else
|
||||
if (system_log) {
|
||||
int priority;
|
||||
switch (severity) {
|
||||
@@ -132,35 +130,45 @@ static void log_message(int fatal, LOG_Severity severity, const char *message)
|
||||
assert(0);
|
||||
}
|
||||
syslog(priority, fatal ? "Fatal error : %s" : "%s", message);
|
||||
} else {
|
||||
fprintf(stderr, fatal ? "Fatal error : %s\n" : "%s\n", message);
|
||||
} else if (file_log) {
|
||||
fprintf(file_log, fatal ? "Fatal error : %s\n" : "%s\n", message);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void LOG_Message(LOG_Severity severity, LOG_Facility facility,
|
||||
int line_number, const char *filename,
|
||||
const char *function_name, const char *format, ...)
|
||||
void LOG_Message(LOG_Severity severity,
|
||||
#if DEBUG > 0
|
||||
int line_number, const char *filename, const char *function_name,
|
||||
#endif
|
||||
const char *format, ...)
|
||||
{
|
||||
char buf[2048];
|
||||
va_list other_args;
|
||||
time_t t;
|
||||
struct tm stm;
|
||||
struct tm *tm;
|
||||
|
||||
#ifdef WINNT
|
||||
#else
|
||||
if (!system_log) {
|
||||
assert(initialised);
|
||||
severity = CLAMP(LOGS_DEBUG, severity, LOGS_FATAL);
|
||||
|
||||
if (!system_log && file_log && severity >= log_min_severity) {
|
||||
/* Don't clutter up syslog with timestamps and internal debugging info */
|
||||
time(&t);
|
||||
stm = *gmtime(&t);
|
||||
strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%SZ", &stm);
|
||||
fprintf(stderr, "%s ", buf);
|
||||
if (debug_level >= DEBUG_LEVEL_PRINT_FUNCTION)
|
||||
fprintf(stderr, "%s:%d:(%s) ", filename, line_number, function_name);
|
||||
}
|
||||
tm = gmtime(&t);
|
||||
if (tm) {
|
||||
strftime(buf, sizeof (buf), "%Y-%m-%dT%H:%M:%SZ", tm);
|
||||
fprintf(file_log, "%s ", buf);
|
||||
}
|
||||
#if DEBUG > 0
|
||||
if (log_min_severity <= LOGS_DEBUG) {
|
||||
/* Log severity to character mapping (debug, info, warn, err, fatal) */
|
||||
const char severity_chars[LOGS_FATAL - LOGS_DEBUG + 1] = {'D', 'I', 'W', 'E', 'F'};
|
||||
|
||||
fprintf(file_log, "%c:%s%s:%d:(%s) ", severity_chars[severity - LOGS_DEBUG],
|
||||
debug_prefix, filename, line_number, function_name);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
va_start(other_args, format);
|
||||
vsnprintf(buf, sizeof(buf), format, other_args);
|
||||
@@ -171,22 +179,23 @@ void LOG_Message(LOG_Severity severity, LOG_Facility facility,
|
||||
case LOGS_INFO:
|
||||
case LOGS_WARN:
|
||||
case LOGS_ERR:
|
||||
log_message(0, severity, buf);
|
||||
if (severity >= log_min_severity)
|
||||
log_message(0, severity, buf);
|
||||
break;
|
||||
case LOGS_FATAL:
|
||||
log_message(1, severity, buf);
|
||||
if (severity >= log_min_severity)
|
||||
log_message(1, severity, buf);
|
||||
|
||||
/* With syslog, send the message also to the grandparent
|
||||
process or write it to stderr if not detached */
|
||||
if (system_log) {
|
||||
if (parent_fd > 0) {
|
||||
if (write(parent_fd, buf, strlen(buf) + 1) < 0)
|
||||
; /* Not much we can do here */
|
||||
} else if (parent_fd == 0) {
|
||||
system_log = 0;
|
||||
log_message(1, severity, buf);
|
||||
}
|
||||
/* Send the message also to the foreground process if it is
|
||||
still running, or stderr if it is still open */
|
||||
if (parent_fd > 0) {
|
||||
if (!LOG_NotifyParent(buf))
|
||||
; /* Not much we can do here */
|
||||
} else if (system_log && parent_fd == 0) {
|
||||
system_log = 0;
|
||||
log_message(1, severity, buf);
|
||||
}
|
||||
exit(1);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
@@ -195,24 +204,98 @@ void LOG_Message(LOG_Severity severity, LOG_Facility facility,
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LOG_OpenSystemLog(void)
|
||||
static FILE *
|
||||
open_file_log(const char *log_file, char mode)
|
||||
{
|
||||
#ifdef WINNT
|
||||
#else
|
||||
system_log = 1;
|
||||
openlog("chronyd", LOG_PID, LOG_DAEMON);
|
||||
#endif
|
||||
FILE *f;
|
||||
|
||||
if (log_file) {
|
||||
f = UTI_OpenFile(NULL, log_file, NULL, mode, 0640);
|
||||
} else {
|
||||
f = stderr;
|
||||
}
|
||||
|
||||
/* Enable line buffering */
|
||||
if (f)
|
||||
setvbuf(f, NULL, _IOLBF, BUFSIZ);
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void LOG_SetDebugLevel(int level)
|
||||
void
|
||||
LOG_OpenFileLog(const char *log_file)
|
||||
{
|
||||
debug_level = level;
|
||||
if (level >= DEBUG_LEVEL_PRINT_DEBUG) {
|
||||
log_debug_enabled = 1;
|
||||
}
|
||||
if (file_log_path)
|
||||
Free(file_log_path);
|
||||
if (log_file)
|
||||
file_log_path = Strdup(log_file);
|
||||
else
|
||||
file_log_path = NULL;
|
||||
|
||||
if (file_log && file_log != stderr)
|
||||
fclose(file_log);
|
||||
|
||||
file_log = open_file_log(file_log_path, 'A');
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LOG_OpenSystemLog(void)
|
||||
{
|
||||
system_log = 1;
|
||||
openlog("chronyd", LOG_PID, LOG_DAEMON);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void LOG_SetMinSeverity(LOG_Severity severity)
|
||||
{
|
||||
/* Don't print any debug messages in a non-debug build */
|
||||
log_min_severity = CLAMP(DEBUG > 0 ? LOGS_DEBUG : LOGS_INFO, severity, LOGS_FATAL);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
LOG_Severity
|
||||
LOG_GetMinSeverity(void)
|
||||
{
|
||||
return log_min_severity;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LOG_SetContext(LOG_Context context)
|
||||
{
|
||||
log_contexts |= context;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LOG_UnsetContext(LOG_Context context)
|
||||
{
|
||||
log_contexts &= ~context;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
LOG_Severity
|
||||
LOG_GetContextSeverity(LOG_Context contexts)
|
||||
{
|
||||
return log_contexts & contexts ? LOGS_INFO : LOGS_DEBUG;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LOG_SetDebugPrefix(const char *prefix)
|
||||
{
|
||||
Free(debug_prefix);
|
||||
debug_prefix = Strdup(prefix);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -221,6 +304,19 @@ void
|
||||
LOG_SetParentFd(int fd)
|
||||
{
|
||||
parent_fd = fd;
|
||||
if (file_log == stderr)
|
||||
file_log = NULL;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
LOG_NotifyParent(const char *message)
|
||||
{
|
||||
if (parent_fd <= 0)
|
||||
return 1;
|
||||
|
||||
return write(parent_fd, message, strlen(message) + 1) > 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -238,7 +334,10 @@ LOG_CloseParentFd()
|
||||
LOG_FileID
|
||||
LOG_FileOpen(const char *name, const char *banner)
|
||||
{
|
||||
assert(n_filelogs < MAX_FILELOGS);
|
||||
if (n_filelogs >= MAX_FILELOGS) {
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
logfiles[n_filelogs].name = name;
|
||||
logfiles[n_filelogs].banner = banner;
|
||||
@@ -260,18 +359,20 @@ LOG_FileWrite(LOG_FileID id, const char *format, ...)
|
||||
return;
|
||||
|
||||
if (!logfiles[id].file) {
|
||||
char filename[512];
|
||||
char *logdir = CNF_GetLogDir();
|
||||
|
||||
if (snprintf(filename, sizeof(filename), "%s/%s.log",
|
||||
CNF_GetLogDir(), logfiles[id].name) >= sizeof(filename) ||
|
||||
!(logfiles[id].file = fopen(filename, "a"))) {
|
||||
LOG(LOGS_WARN, LOGF_Refclock, "Couldn't open logfile %s for update", filename);
|
||||
if (!logdir) {
|
||||
LOG(LOGS_WARN, "logdir not specified");
|
||||
logfiles[id].name = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Close on exec */
|
||||
UTI_FdSetCloexec(fileno(logfiles[id].file));
|
||||
logfiles[id].file = UTI_OpenFile(logdir, logfiles[id].name, ".log", 'a', 0644);
|
||||
if (!logfiles[id].file) {
|
||||
/* Disable the log */
|
||||
logfiles[id].name = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
banner = CNF_GetLogBanner();
|
||||
@@ -279,7 +380,7 @@ LOG_FileWrite(LOG_FileID id, const char *format, ...)
|
||||
char bannerline[256];
|
||||
int i, bannerlen;
|
||||
|
||||
bannerlen = strlen(logfiles[id].banner);
|
||||
bannerlen = MIN(strlen(logfiles[id].banner), sizeof (bannerline) - 1);
|
||||
|
||||
for (i = 0; i < bannerlen; i++)
|
||||
bannerline[i] = '=';
|
||||
@@ -300,31 +401,32 @@ LOG_FileWrite(LOG_FileID id, const char *format, ...)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LOG_CreateLogFileDir(void)
|
||||
{
|
||||
const char *logdir;
|
||||
|
||||
logdir = CNF_GetLogDir();
|
||||
|
||||
if (!mkdir_and_parents(logdir)) {
|
||||
LOG(LOGS_ERR, LOGF_Logging, "Could not create directory %s", logdir);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LOG_CycleLogFiles(void)
|
||||
{
|
||||
struct stat st;
|
||||
LOG_FileID i;
|
||||
FILE *f;
|
||||
|
||||
/* The log will be opened later when an entry is logged */
|
||||
for (i = 0; i < n_filelogs; i++) {
|
||||
if (logfiles[i].file)
|
||||
fclose(logfiles[i].file);
|
||||
logfiles[i].file = NULL;
|
||||
logfiles[i].writes = 0;
|
||||
}
|
||||
|
||||
/* Try to open the log specified by the -l option, but only if nothing is
|
||||
present at its path to avoid unnecessary error messages. Keep the
|
||||
original file if that fails (the process might no longer have the
|
||||
necessary privileges to write in the directory). */
|
||||
if (file_log && file_log != stderr && stat(file_log_path, &st) < 0 && errno == ENOENT) {
|
||||
f = open_file_log(file_log_path, 'a');
|
||||
if (f) {
|
||||
fclose(file_log);
|
||||
file_log = f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
121
logging.h
121
logging.h
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
* Copyright (C) Miroslav Lichvar 2013-2014
|
||||
* Copyright (C) Miroslav Lichvar 2013-2015
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -31,9 +31,6 @@
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
/* Flag indicating whether debug messages are logged */
|
||||
extern int log_debug_enabled;
|
||||
|
||||
/* Line logging macros. If the compiler is GNU C, we take advantage of
|
||||
being able to get the function name also. */
|
||||
|
||||
@@ -45,64 +42,39 @@ extern int log_debug_enabled;
|
||||
#define FORMAT_ATTRIBUTE_PRINTF(str, first)
|
||||
#endif
|
||||
|
||||
#define DEBUG_LOG(facility, ...) \
|
||||
#if DEBUG > 0
|
||||
#define LOG_MESSAGE(severity, ...) \
|
||||
LOG_Message(severity, __LINE__, __FILE__, FUNCTION_NAME, __VA_ARGS__)
|
||||
#else
|
||||
#define LOG_MESSAGE(severity, ...) \
|
||||
LOG_Message(severity, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#define DEBUG_LOG(...) \
|
||||
do { \
|
||||
if (DEBUG && log_debug_enabled) \
|
||||
LOG_Message(LOGS_DEBUG, facility, __LINE__, __FILE__, FUNCTION_NAME, __VA_ARGS__); \
|
||||
if (DEBUG && log_min_severity == LOGS_DEBUG) \
|
||||
LOG_MESSAGE(LOGS_DEBUG, __VA_ARGS__); \
|
||||
} while (0)
|
||||
#define LOG(severity, facility, ...) LOG_Message(severity, facility, __LINE__, __FILE__, FUNCTION_NAME, __VA_ARGS__)
|
||||
#define LOG_FATAL(facility, ...) \
|
||||
|
||||
#define LOG_FATAL(...) \
|
||||
do { \
|
||||
LOG_Message(LOGS_FATAL, facility, __LINE__, __FILE__, FUNCTION_NAME, __VA_ARGS__); \
|
||||
LOG_MESSAGE(LOGS_FATAL, __VA_ARGS__); \
|
||||
exit(1); \
|
||||
} while (0)
|
||||
|
||||
#define LOG(severity, ...) LOG_MESSAGE(severity, __VA_ARGS__)
|
||||
|
||||
/* Definition of severity */
|
||||
typedef enum {
|
||||
LOGS_INFO,
|
||||
LOGS_DEBUG = -1,
|
||||
LOGS_INFO = 0,
|
||||
LOGS_WARN,
|
||||
LOGS_ERR,
|
||||
LOGS_FATAL,
|
||||
LOGS_DEBUG
|
||||
} LOG_Severity;
|
||||
|
||||
/* Definition of facility. Each message is tagged with who generated
|
||||
it, so that the user can customise what level of reporting he gets
|
||||
for each area of the software */
|
||||
typedef enum {
|
||||
LOGF_Reference,
|
||||
LOGF_NtpIO,
|
||||
LOGF_NtpCore,
|
||||
LOGF_NtpSources,
|
||||
LOGF_Scheduler,
|
||||
LOGF_SourceStats,
|
||||
LOGF_Sources,
|
||||
LOGF_Local,
|
||||
LOGF_Util,
|
||||
LOGF_Main,
|
||||
LOGF_Memory,
|
||||
LOGF_ClientLog,
|
||||
LOGF_Configure,
|
||||
LOGF_CmdMon,
|
||||
LOGF_Acquire,
|
||||
LOGF_Manual,
|
||||
LOGF_Keys,
|
||||
LOGF_Logging,
|
||||
LOGF_Nameserv,
|
||||
LOGF_Rtc,
|
||||
LOGF_Regress,
|
||||
LOGF_Sys,
|
||||
LOGF_SysGeneric,
|
||||
LOGF_SysLinux,
|
||||
LOGF_SysNetBSD,
|
||||
LOGF_SysSolaris,
|
||||
LOGF_SysSunOS,
|
||||
LOGF_SysWinnt,
|
||||
LOGF_TempComp,
|
||||
LOGF_RtcLinux,
|
||||
LOGF_Refclock,
|
||||
LOGF_Smooth,
|
||||
} LOG_Facility;
|
||||
/* Minimum severity of messages to be logged */
|
||||
extern LOG_Severity log_min_severity;
|
||||
|
||||
/* Init function */
|
||||
extern void LOG_Initialise(void);
|
||||
@@ -111,25 +83,53 @@ extern void LOG_Initialise(void);
|
||||
extern void LOG_Finalise(void);
|
||||
|
||||
/* Line logging function */
|
||||
FORMAT_ATTRIBUTE_PRINTF(6, 7)
|
||||
extern void LOG_Message(LOG_Severity severity, LOG_Facility facility,
|
||||
int line_number, const char *filename,
|
||||
#if DEBUG > 0
|
||||
FORMAT_ATTRIBUTE_PRINTF(5, 6)
|
||||
extern void LOG_Message(LOG_Severity severity, int line_number, const char *filename,
|
||||
const char *function_name, const char *format, ...);
|
||||
#else
|
||||
FORMAT_ATTRIBUTE_PRINTF(2, 3)
|
||||
extern void LOG_Message(LOG_Severity severity, const char *format, ...);
|
||||
#endif
|
||||
|
||||
/* Set debug level:
|
||||
0, 1 - only non-debug messages are logged
|
||||
2 - debug messages are logged too, all messages are prefixed with
|
||||
filename, line, and function name
|
||||
*/
|
||||
extern void LOG_SetDebugLevel(int level);
|
||||
/* Set the minimum severity of a message to be logged or printed to terminal.
|
||||
If the severity is LOGS_DEBUG and DEBUG is enabled, all messages will be
|
||||
prefixed with the filename, line number, and function name. */
|
||||
extern void LOG_SetMinSeverity(LOG_Severity severity);
|
||||
|
||||
/* Get the minimum severity */
|
||||
extern LOG_Severity LOG_GetMinSeverity(void);
|
||||
|
||||
/* Flags for info messages that should be logged only in specific contexts */
|
||||
typedef enum {
|
||||
LOGC_Command = 1,
|
||||
LOGC_SourceFile = 2,
|
||||
} LOG_Context;
|
||||
|
||||
/* Modify current contexts */
|
||||
extern void LOG_SetContext(LOG_Context context);
|
||||
extern void LOG_UnsetContext(LOG_Context context);
|
||||
|
||||
/* Get severity depending on the current active contexts: INFO if they contain
|
||||
at least one of the specified contexts, DEBUG otherwise */
|
||||
extern LOG_Severity LOG_GetContextSeverity(LOG_Context contexts);
|
||||
|
||||
/* Set a prefix for debug messages */
|
||||
extern void LOG_SetDebugPrefix(const char *prefix);
|
||||
|
||||
/* Log messages to a file instead of stderr, or stderr again if NULL */
|
||||
extern void LOG_OpenFileLog(const char *log_file);
|
||||
|
||||
/* Log messages to syslog instead of stderr */
|
||||
extern void LOG_OpenSystemLog(void);
|
||||
|
||||
/* Send fatal message also to the foreground process */
|
||||
/* Stop using stderr and send fatal message to the foreground process */
|
||||
extern void LOG_SetParentFd(int fd);
|
||||
|
||||
/* Close the pipe to the foreground process so it can exit */
|
||||
/* Send a message to the foreground process */
|
||||
extern int LOG_NotifyParent(const char *message);
|
||||
|
||||
/* Close the pipe to the foreground process */
|
||||
extern void LOG_CloseParentFd(void);
|
||||
|
||||
/* File logging functions */
|
||||
@@ -141,7 +141,6 @@ extern LOG_FileID LOG_FileOpen(const char *name, const char *banner);
|
||||
FORMAT_ATTRIBUTE_PRINTF(2, 3)
|
||||
extern void LOG_FileWrite(LOG_FileID id, const char *format, ...);
|
||||
|
||||
extern void LOG_CreateLogFileDir(void);
|
||||
extern void LOG_CycleLogFiles(void);
|
||||
|
||||
#endif /* GOT_LOGGING_H */
|
||||
|
||||
537
main.c
537
main.c
@@ -4,7 +4,7 @@
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) John G. Hasler 2009
|
||||
* Copyright (C) Miroslav Lichvar 2012-2014
|
||||
* Copyright (C) Miroslav Lichvar 2012-2020
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -32,11 +32,16 @@
|
||||
|
||||
#include "main.h"
|
||||
#include "sched.h"
|
||||
#include "leapdb.h"
|
||||
#include "local.h"
|
||||
#include "sys.h"
|
||||
#include "ntp_io.h"
|
||||
#include "ntp_signd.h"
|
||||
#include "ntp_sources.h"
|
||||
#include "ntp_core.h"
|
||||
#include "nts_ke_server.h"
|
||||
#include "nts_ntp_server.h"
|
||||
#include "socket.h"
|
||||
#include "sources.h"
|
||||
#include "sourcestats.h"
|
||||
#include "reference.h"
|
||||
@@ -49,8 +54,10 @@
|
||||
#include "refclock.h"
|
||||
#include "clientlog.h"
|
||||
#include "nameserv.h"
|
||||
#include "privops.h"
|
||||
#include "smooth.h"
|
||||
#include "tempcomp.h"
|
||||
#include "util.h"
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
@@ -67,12 +74,62 @@ static REF_Mode ref_mode = REF_ModeNormal;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
do_platform_checks(void)
|
||||
{
|
||||
struct timespec ts;
|
||||
|
||||
/* Require at least 32-bit integers, two's complement representation and
|
||||
the usual implementation of conversion of unsigned integers */
|
||||
assert(sizeof (int) >= 4);
|
||||
assert(-1 == ~0);
|
||||
assert((int32_t)4294967295U == (int32_t)-1);
|
||||
|
||||
/* Require time_t and tv_nsec in timespec to be signed */
|
||||
ts.tv_sec = -1;
|
||||
ts.tv_nsec = -1;
|
||||
assert(ts.tv_sec < 0 && ts.tv_nsec < 0);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
delete_pidfile(void)
|
||||
{
|
||||
const char *pidfile = CNF_GetPidFile();
|
||||
/* Don't care if this fails, there's not a lot we can do */
|
||||
unlink(pidfile);
|
||||
|
||||
if (!pidfile)
|
||||
return;
|
||||
|
||||
if (!UTI_RemoveFile(NULL, pidfile, NULL))
|
||||
;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
notify_system_manager(int start)
|
||||
{
|
||||
#ifdef LINUX
|
||||
/* The systemd protocol is documented in the sd_notify(3) man page */
|
||||
const char *message, *path = getenv("NOTIFY_SOCKET");
|
||||
int sock_fd;
|
||||
|
||||
if (!path)
|
||||
return;
|
||||
|
||||
if (path[0] != '/')
|
||||
LOG_FATAL("Unsupported notification socket");
|
||||
|
||||
message = start ? "READY=1" : "STOPPING=1";
|
||||
|
||||
sock_fd = SCK_OpenUnixDatagramSocket(path, NULL, 0);
|
||||
|
||||
if (sock_fd < 0 || SCK_Send(sock_fd, message, strlen(message), 0) != strlen(message))
|
||||
LOG_FATAL("Could not send notification to $NOTIFY_SOCKET");
|
||||
|
||||
SCK_CloseSocket(sock_fd);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -82,9 +139,10 @@ MAI_CleanupAndExit(void)
|
||||
{
|
||||
if (!initialised) exit(exit_status);
|
||||
|
||||
if (CNF_GetDumpOnExit()) {
|
||||
SRC_DumpSources();
|
||||
}
|
||||
notify_system_manager(0);
|
||||
|
||||
LCL_CancelOffsetCorrection();
|
||||
SRC_DumpSources();
|
||||
|
||||
/* Don't update clock when removing sources */
|
||||
REF_SetMode(REF_ModeIgnore);
|
||||
@@ -93,26 +151,35 @@ MAI_CleanupAndExit(void)
|
||||
TMC_Finalise();
|
||||
MNL_Finalise();
|
||||
CLG_Finalise();
|
||||
NKS_Finalise();
|
||||
NNS_Finalise();
|
||||
NSD_Finalise();
|
||||
NSR_Finalise();
|
||||
NCR_Finalise();
|
||||
CAM_Finalise();
|
||||
NIO_Finalise();
|
||||
SST_Finalise();
|
||||
NCR_Finalise();
|
||||
NIO_Finalise();
|
||||
CAM_Finalise();
|
||||
|
||||
KEY_Finalise();
|
||||
RCL_Finalise();
|
||||
SRC_Finalise();
|
||||
REF_Finalise();
|
||||
LDB_Finalise();
|
||||
RTC_Finalise();
|
||||
SYS_Finalise();
|
||||
|
||||
SCK_Finalise();
|
||||
SCH_Finalise();
|
||||
LCL_Finalise();
|
||||
PRV_Finalise();
|
||||
|
||||
delete_pidfile();
|
||||
|
||||
CNF_Finalise();
|
||||
HSH_Finalise();
|
||||
LOG_Finalise();
|
||||
|
||||
HSH_Finalise();
|
||||
UTI_ResetGetRandomFunctions();
|
||||
|
||||
exit(exit_status);
|
||||
}
|
||||
@@ -122,7 +189,18 @@ MAI_CleanupAndExit(void)
|
||||
static void
|
||||
signal_cleanup(int x)
|
||||
{
|
||||
if (!initialised) exit(0);
|
||||
SCH_QuitProgram();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
quit_timeout(void *arg)
|
||||
{
|
||||
LOG(LOGS_INFO, "Timeout reached");
|
||||
|
||||
/* Return with non-zero status if the clock is not synchronised */
|
||||
exit_status = REF_GetOurStratum() >= NTP_MAX_STRATUM;
|
||||
SCH_QuitProgram();
|
||||
}
|
||||
|
||||
@@ -141,13 +219,14 @@ ntp_source_resolving_end(void)
|
||||
SRC_ReloadSources();
|
||||
}
|
||||
|
||||
SRC_RemoveDumpFiles();
|
||||
RTC_StartMeasurements();
|
||||
RCL_StartRefclocks();
|
||||
NSR_StartSources();
|
||||
NSR_AutoStartSources();
|
||||
|
||||
/* Special modes can end only when sources update their reachability.
|
||||
Give up immediatelly if there are no active sources. */
|
||||
Give up immediately if there are no active sources. */
|
||||
if (ref_mode != REF_ModeNormal && !SRC_ActiveSources()) {
|
||||
REF_SetUnsynchronised();
|
||||
}
|
||||
@@ -165,7 +244,12 @@ post_init_ntp_hook(void *anything)
|
||||
REF_SetMode(ref_mode);
|
||||
}
|
||||
|
||||
/* Close the pipe to the foreground process so it can exit */
|
||||
notify_system_manager(1);
|
||||
|
||||
/* Send an empty message to the foreground process so it can exit.
|
||||
If that fails, indicating the process was killed, exit too. */
|
||||
if (!LOG_NotifyParent(""))
|
||||
SCH_QuitProgram();
|
||||
LOG_CloseParentFd();
|
||||
|
||||
CNF_AddSources();
|
||||
@@ -214,131 +298,185 @@ post_init_rtc_hook(void *anything)
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Return 1 if the process exists on the system. */
|
||||
|
||||
static int
|
||||
does_process_exist(int pid)
|
||||
{
|
||||
int status;
|
||||
status = getsid(pid);
|
||||
if (status >= 0) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
maybe_another_chronyd_running(int *other_pid)
|
||||
static void
|
||||
check_pidfile(void)
|
||||
{
|
||||
const char *pidfile = CNF_GetPidFile();
|
||||
FILE *in;
|
||||
int pid, count;
|
||||
|
||||
*other_pid = 0;
|
||||
if (!pidfile)
|
||||
return;
|
||||
|
||||
in = fopen(pidfile, "r");
|
||||
if (!in) return 0;
|
||||
in = UTI_OpenFile(NULL, pidfile, NULL, 'r', 0);
|
||||
if (!in)
|
||||
return;
|
||||
|
||||
count = fscanf(in, "%d", &pid);
|
||||
fclose(in);
|
||||
|
||||
if (count != 1) return 0;
|
||||
if (count != 1)
|
||||
return;
|
||||
|
||||
*other_pid = pid;
|
||||
return does_process_exist(pid);
|
||||
|
||||
if (getsid(pid) < 0)
|
||||
return;
|
||||
|
||||
LOG_FATAL("Another chronyd may already be running (pid=%d), check %s",
|
||||
pid, pidfile);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
write_lockfile(void)
|
||||
write_pidfile(void)
|
||||
{
|
||||
const char *pidfile = CNF_GetPidFile();
|
||||
FILE *out;
|
||||
|
||||
out = fopen(pidfile, "w");
|
||||
if (!out) {
|
||||
LOG_FATAL(LOGF_Main, "could not open lockfile %s for writing", pidfile);
|
||||
} else {
|
||||
fprintf(out, "%d\n", getpid());
|
||||
fclose(out);
|
||||
}
|
||||
if (!pidfile)
|
||||
return;
|
||||
|
||||
out = UTI_OpenFile(NULL, pidfile, NULL, 'W', 0644);
|
||||
fprintf(out, "%d\n", (int)getpid());
|
||||
fclose(out);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#define DEV_NULL "/dev/null"
|
||||
|
||||
static void
|
||||
go_daemon(void)
|
||||
{
|
||||
#ifdef WINNT
|
||||
|
||||
|
||||
#else
|
||||
|
||||
int pid, fd, pipefd[2];
|
||||
|
||||
/* Create pipe which will the daemon use to notify the grandparent
|
||||
when it's initialised or send an error message */
|
||||
if (pipe(pipefd)) {
|
||||
LOG_FATAL(LOGF_Logging, "Could not detach, pipe failed : %s", strerror(errno));
|
||||
LOG_FATAL("pipe() failed : %s", strerror(errno));
|
||||
}
|
||||
|
||||
/* Does this preserve existing signal handlers? */
|
||||
pid = fork();
|
||||
|
||||
if (pid < 0) {
|
||||
LOG_FATAL(LOGF_Logging, "Could not detach, fork failed : %s", strerror(errno));
|
||||
LOG_FATAL("fork() failed : %s", strerror(errno));
|
||||
} else if (pid > 0) {
|
||||
/* In the 'grandparent' */
|
||||
char message[1024];
|
||||
int r;
|
||||
|
||||
close(pipefd[1]);
|
||||
/* Don't exit before the 'parent' */
|
||||
waitpid(pid, NULL, 0);
|
||||
|
||||
r = read(pipefd[0], message, sizeof (message));
|
||||
if (r) {
|
||||
if (r > 0) {
|
||||
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
|
||||
if (r != 1 || message[0] != '\0') {
|
||||
if (r > 1) {
|
||||
/* Print the error message from the child */
|
||||
fprintf(stderr, "%.1024s\n", message);
|
||||
message[sizeof (message) - 1] = '\0';
|
||||
fprintf(stderr, "%s\n", message);
|
||||
}
|
||||
exit(1);
|
||||
} else
|
||||
exit(0);
|
||||
} else {
|
||||
close(pipefd[0]);
|
||||
|
||||
setsid();
|
||||
|
||||
/* Do 2nd fork, as-per recommended practice for launching daemons. */
|
||||
pid = fork();
|
||||
|
||||
if (pid < 0) {
|
||||
LOG_FATAL(LOGF_Logging, "Could not detach, fork failed : %s", strerror(errno));
|
||||
LOG_FATAL("fork() failed : %s", strerror(errno));
|
||||
} else if (pid > 0) {
|
||||
exit(0); /* In the 'parent' */
|
||||
/* In the 'parent' */
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
exit(0);
|
||||
} else {
|
||||
/* In the child we want to leave running as the daemon */
|
||||
|
||||
/* Change current directory to / */
|
||||
if (chdir("/") < 0) {
|
||||
LOG_FATAL(LOGF_Logging, "Could not chdir to / : %s", strerror(errno));
|
||||
LOG_FATAL("chdir() failed : %s", strerror(errno));
|
||||
}
|
||||
|
||||
/* Don't keep stdin/out/err from before. But don't close
|
||||
the parent pipe yet. */
|
||||
the parent pipe yet, or reusable file descriptors. */
|
||||
for (fd=0; fd<1024; fd++) {
|
||||
if (fd != pipefd[1])
|
||||
if (fd != pipefd[1] && !SCK_IsReusable(fd))
|
||||
close(fd);
|
||||
}
|
||||
|
||||
LOG_SetParentFd(pipefd[1]);
|
||||
|
||||
/* Open /dev/null as new stdin/out/err */
|
||||
errno = 0;
|
||||
if (open(DEV_NULL, O_RDONLY) != STDIN_FILENO ||
|
||||
open(DEV_NULL, O_WRONLY) != STDOUT_FILENO ||
|
||||
open(DEV_NULL, O_RDWR) != STDERR_FILENO)
|
||||
LOG_FATAL("Could not open %s : %s", DEV_NULL, strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
print_help(const char *progname)
|
||||
{
|
||||
printf("Usage: %s [OPTION]... [DIRECTIVE]...\n\n"
|
||||
"Options:\n"
|
||||
" -4\t\tUse IPv4 addresses only\n"
|
||||
" -6\t\tUse IPv6 addresses only\n"
|
||||
" -f FILE\tSpecify configuration file (%s)\n"
|
||||
" -n\t\tDon't run as daemon\n"
|
||||
" -d\t\tDon't run as daemon and log to stderr\n"
|
||||
#if DEBUG > 0
|
||||
" -d -d\t\tEnable debug messages\n"
|
||||
#endif
|
||||
" -l FILE\tLog to file\n"
|
||||
" -L LEVEL\tSet logging threshold (0)\n"
|
||||
" -p\t\tPrint configuration and exit\n"
|
||||
" -q\t\tSet clock and exit\n"
|
||||
" -Q\t\tLog offset and exit\n"
|
||||
" -r\t\tReload dump files\n"
|
||||
" -R\t\tAdapt configuration for restart\n"
|
||||
" -s\t\tSet clock from RTC\n"
|
||||
" -t SECONDS\tExit after elapsed time\n"
|
||||
" -u USER\tSpecify user (%s)\n"
|
||||
" -U\t\tDon't check for root\n"
|
||||
" -F LEVEL\tSet system call filter level (0)\n"
|
||||
" -P PRIORITY\tSet process priority (0)\n"
|
||||
" -m\t\tLock memory\n"
|
||||
" -x\t\tDon't control clock\n"
|
||||
" -v, --version\tPrint version and exit\n"
|
||||
" -h, --help\tPrint usage and exit\n",
|
||||
progname, DEFAULT_CONF_FILE, DEFAULT_USER);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
print_version(void)
|
||||
{
|
||||
printf("chronyd (chrony) version %s (%s)\n", CHRONY_VERSION, CHRONYD_FEATURES);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
parse_int_arg(const char *arg)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (sscanf(arg, "%d", &i) != 1)
|
||||
LOG_FATAL("Invalid argument %s", arg);
|
||||
return i;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -347,126 +485,191 @@ int main
|
||||
(int argc, char **argv)
|
||||
{
|
||||
const char *conf_file = DEFAULT_CONF_FILE;
|
||||
char *user = NULL;
|
||||
int debug = 0, nofork = 0, address_family = IPADDR_UNSPEC;
|
||||
int do_init_rtc = 0, restarted = 0;
|
||||
int other_pid;
|
||||
int lock_memory = 0, sched_priority = 0;
|
||||
int system_log = 1;
|
||||
int config_args = 0;
|
||||
const char *progname = argv[0];
|
||||
char *user = NULL, *log_file = NULL;
|
||||
struct passwd *pw;
|
||||
int opt, debug = 0, nofork = 0, address_family = IPADDR_UNSPEC;
|
||||
int do_init_rtc = 0, restarted = 0, client_only = 0, timeout = -1;
|
||||
int scfilter_level = 0, lock_memory = 0, sched_priority = 0;
|
||||
int clock_control = 1, system_log = 1, log_severity = LOGS_INFO;
|
||||
int user_check = 1, config_args = 0, print_config = 0;
|
||||
|
||||
do_platform_checks();
|
||||
|
||||
LOG_Initialise();
|
||||
|
||||
/* Parse command line options */
|
||||
while (++argv, (--argc)>0) {
|
||||
|
||||
if (!strcmp("-f", *argv)) {
|
||||
++argv, --argc;
|
||||
conf_file = *argv;
|
||||
} else if (!strcmp("-P", *argv)) {
|
||||
++argv, --argc;
|
||||
if (argc == 0 || sscanf(*argv, "%d", &sched_priority) != 1) {
|
||||
LOG_FATAL(LOGF_Main, "Bad scheduler priority");
|
||||
}
|
||||
} else if (!strcmp("-m", *argv)) {
|
||||
lock_memory = 1;
|
||||
} else if (!strcmp("-r", *argv)) {
|
||||
reload = 1;
|
||||
} else if (!strcmp("-R", *argv)) {
|
||||
restarted = 1;
|
||||
} else if (!strcmp("-u", *argv)) {
|
||||
++argv, --argc;
|
||||
if (argc == 0) {
|
||||
LOG_FATAL(LOGF_Main, "Missing user name");
|
||||
} else {
|
||||
user = *argv;
|
||||
}
|
||||
} else if (!strcmp("-s", *argv)) {
|
||||
do_init_rtc = 1;
|
||||
} else if (!strcmp("-v", *argv) || !strcmp("--version",*argv)) {
|
||||
/* This write to the terminal is OK, it comes before we turn into a daemon */
|
||||
printf("chronyd (chrony) version %s (%s)\n", CHRONY_VERSION, CHRONYD_FEATURES);
|
||||
exit(0);
|
||||
} else if (!strcmp("-n", *argv)) {
|
||||
nofork = 1;
|
||||
} else if (!strcmp("-d", *argv)) {
|
||||
debug++;
|
||||
nofork = 1;
|
||||
system_log = 0;
|
||||
} else if (!strcmp("-q", *argv)) {
|
||||
ref_mode = REF_ModeUpdateOnce;
|
||||
nofork = 1;
|
||||
system_log = 0;
|
||||
} else if (!strcmp("-Q", *argv)) {
|
||||
ref_mode = REF_ModePrintOnce;
|
||||
nofork = 1;
|
||||
system_log = 0;
|
||||
} else if (!strcmp("-4", *argv)) {
|
||||
address_family = IPADDR_INET4;
|
||||
} else if (!strcmp("-6", *argv)) {
|
||||
address_family = IPADDR_INET6;
|
||||
} else if (*argv[0] == '-') {
|
||||
LOG_FATAL(LOGF_Main, "Unrecognized command line option [%s]", *argv);
|
||||
} else {
|
||||
/* Process remaining arguments and configuration lines */
|
||||
config_args = argc;
|
||||
break;
|
||||
/* Parse long command-line options */
|
||||
for (optind = 1; optind < argc; optind++) {
|
||||
if (!strcmp("--help", argv[optind])) {
|
||||
print_help(progname);
|
||||
return 0;
|
||||
} else if (!strcmp("--version", argv[optind])) {
|
||||
print_version();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (getuid() != 0) {
|
||||
/* This write to the terminal is OK, it comes before we turn into a daemon */
|
||||
fprintf(stderr,"Not superuser\n");
|
||||
exit(1);
|
||||
optind = 1;
|
||||
|
||||
/* Parse short command-line options */
|
||||
while ((opt = getopt(argc, argv, "46df:F:hl:L:mnpP:qQrRst:u:Uvx")) != -1) {
|
||||
switch (opt) {
|
||||
case '4':
|
||||
case '6':
|
||||
address_family = opt == '4' ? IPADDR_INET4 : IPADDR_INET6;
|
||||
break;
|
||||
case 'd':
|
||||
debug++;
|
||||
nofork = 1;
|
||||
system_log = 0;
|
||||
break;
|
||||
case 'f':
|
||||
conf_file = optarg;
|
||||
break;
|
||||
case 'F':
|
||||
scfilter_level = parse_int_arg(optarg);
|
||||
break;
|
||||
case 'l':
|
||||
log_file = optarg;
|
||||
break;
|
||||
case 'L':
|
||||
log_severity = parse_int_arg(optarg);
|
||||
break;
|
||||
case 'm':
|
||||
lock_memory = 1;
|
||||
break;
|
||||
case 'n':
|
||||
nofork = 1;
|
||||
break;
|
||||
case 'p':
|
||||
print_config = 1;
|
||||
user_check = 0;
|
||||
nofork = 1;
|
||||
system_log = 0;
|
||||
log_severity = LOGS_WARN;
|
||||
break;
|
||||
case 'P':
|
||||
sched_priority = parse_int_arg(optarg);
|
||||
break;
|
||||
case 'q':
|
||||
ref_mode = REF_ModeUpdateOnce;
|
||||
nofork = 1;
|
||||
client_only = 0;
|
||||
system_log = 0;
|
||||
break;
|
||||
case 'Q':
|
||||
ref_mode = REF_ModePrintOnce;
|
||||
nofork = 1;
|
||||
client_only = 1;
|
||||
user_check = 0;
|
||||
clock_control = 0;
|
||||
system_log = 0;
|
||||
break;
|
||||
case 'r':
|
||||
reload = 1;
|
||||
break;
|
||||
case 'R':
|
||||
restarted = 1;
|
||||
break;
|
||||
case 's':
|
||||
do_init_rtc = 1;
|
||||
break;
|
||||
case 't':
|
||||
timeout = parse_int_arg(optarg);
|
||||
break;
|
||||
case 'u':
|
||||
user = optarg;
|
||||
break;
|
||||
case 'U':
|
||||
user_check = 0;
|
||||
break;
|
||||
case 'v':
|
||||
print_version();
|
||||
return 0;
|
||||
case 'x':
|
||||
clock_control = 0;
|
||||
break;
|
||||
default:
|
||||
print_help(progname);
|
||||
return opt != 'h';
|
||||
}
|
||||
}
|
||||
|
||||
if (user_check && getuid() != 0)
|
||||
LOG_FATAL("Not superuser");
|
||||
|
||||
/* Initialise reusable file descriptors before fork */
|
||||
SCK_PreInitialise();
|
||||
|
||||
/* Turn into a daemon */
|
||||
if (!nofork) {
|
||||
go_daemon();
|
||||
}
|
||||
|
||||
if (system_log) {
|
||||
if (log_file) {
|
||||
LOG_OpenFileLog(log_file);
|
||||
} else if (system_log) {
|
||||
LOG_OpenSystemLog();
|
||||
}
|
||||
|
||||
LOG_SetDebugLevel(debug);
|
||||
LOG_SetMinSeverity(debug >= 2 ? LOGS_DEBUG : log_severity);
|
||||
|
||||
LOG(LOGS_INFO, LOGF_Main, "chronyd version %s starting (%s)",
|
||||
CHRONY_VERSION, CHRONYD_FEATURES);
|
||||
LOG(LOGS_INFO, "chronyd version %s starting (%s)", CHRONY_VERSION, CHRONYD_FEATURES);
|
||||
|
||||
DNS_SetAddressFamily(address_family);
|
||||
|
||||
CNF_Initialise(restarted);
|
||||
CNF_Initialise(restarted, client_only);
|
||||
if (print_config)
|
||||
CNF_EnablePrint();
|
||||
|
||||
/* Parse the config file or the remaining command line arguments */
|
||||
config_args = argc - optind;
|
||||
if (!config_args) {
|
||||
CNF_ReadFile(conf_file);
|
||||
} else {
|
||||
do {
|
||||
CNF_ParseLine(NULL, config_args - argc + 1, *argv);
|
||||
} while (++argv, --argc);
|
||||
for (; optind < argc; optind++)
|
||||
CNF_ParseLine(NULL, config_args + optind - argc + 1, argv[optind]);
|
||||
}
|
||||
|
||||
/* Check whether another chronyd may already be running. Do this after
|
||||
* forking, so that message logging goes to the right place (i.e. syslog), in
|
||||
* case this chronyd is being run from a boot script. */
|
||||
if (maybe_another_chronyd_running(&other_pid)) {
|
||||
LOG_FATAL(LOGF_Main, "Another chronyd may already be running (pid=%d), check lockfile (%s)",
|
||||
other_pid, CNF_GetPidFile());
|
||||
}
|
||||
if (print_config)
|
||||
return 0;
|
||||
|
||||
/* Write our lockfile to prevent other chronyds running. This has *GOT* to
|
||||
* be done *AFTER* the daemon-creation fork() */
|
||||
write_lockfile();
|
||||
/* Check whether another chronyd may already be running */
|
||||
check_pidfile();
|
||||
|
||||
if (!user)
|
||||
user = CNF_GetUser();
|
||||
|
||||
pw = getpwnam(user);
|
||||
if (!pw)
|
||||
LOG_FATAL("Could not get user/group ID of %s", user);
|
||||
|
||||
/* Create directories for sockets, log files, and dump files */
|
||||
CNF_CreateDirs(pw->pw_uid, pw->pw_gid);
|
||||
|
||||
/* Write our pidfile to prevent other instances from running */
|
||||
write_pidfile();
|
||||
|
||||
PRV_Initialise();
|
||||
LCL_Initialise();
|
||||
SCH_Initialise();
|
||||
SYS_Initialise();
|
||||
SCK_Initialise(address_family);
|
||||
|
||||
/* Start helper processes if needed */
|
||||
NKS_PreInitialise(pw->pw_uid, pw->pw_gid, scfilter_level);
|
||||
|
||||
SYS_Initialise(clock_control);
|
||||
RTC_Initialise(do_init_rtc);
|
||||
SRC_Initialise();
|
||||
RCL_Initialise();
|
||||
KEY_Initialise();
|
||||
|
||||
/* Open privileged ports before dropping root */
|
||||
CAM_Initialise();
|
||||
NIO_Initialise();
|
||||
NCR_Initialise();
|
||||
CNF_SetupAccessRestrictions();
|
||||
|
||||
/* Command-line switch must have priority */
|
||||
if (!sched_priority) {
|
||||
sched_priority = CNF_GetSchedPriority();
|
||||
@@ -479,21 +682,24 @@ int main
|
||||
SYS_LockMemory();
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
user = CNF_GetUser();
|
||||
}
|
||||
if (user && strcmp(user, "root")) {
|
||||
SYS_DropRoot(user);
|
||||
/* Drop root privileges if the specified user has a non-zero UID */
|
||||
if (!geteuid() && (pw->pw_uid || pw->pw_gid)) {
|
||||
SYS_DropRoot(pw->pw_uid, pw->pw_gid, SYS_MAIN_PROCESS);
|
||||
|
||||
/* Warn if missing read access or having write access to keys */
|
||||
CNF_CheckReadOnlyAccess();
|
||||
}
|
||||
|
||||
LOG_CreateLogFileDir();
|
||||
if (!geteuid())
|
||||
LOG(LOGS_WARN, "Running with root privileges");
|
||||
|
||||
LDB_Initialise();
|
||||
REF_Initialise();
|
||||
SST_Initialise();
|
||||
NIO_Initialise(address_family);
|
||||
CAM_Initialise(address_family);
|
||||
NCR_Initialise();
|
||||
NSR_Initialise();
|
||||
NSD_Initialise();
|
||||
NNS_Initialise();
|
||||
NKS_Initialise();
|
||||
CLG_Initialise();
|
||||
MNL_Initialise();
|
||||
TMC_Initialise();
|
||||
@@ -502,7 +708,12 @@ int main
|
||||
/* From now on, it is safe to do finalisation on exit */
|
||||
initialised = 1;
|
||||
|
||||
CNF_SetupAccessRestrictions();
|
||||
UTI_SetQuitSignalsHandler(signal_cleanup, 1);
|
||||
|
||||
CAM_OpenUnixSocket();
|
||||
|
||||
if (scfilter_level)
|
||||
SYS_EnableSystemCallFilter(scfilter_level, SYS_MAIN_PROCESS);
|
||||
|
||||
if (ref_mode == REF_ModeNormal && CNF_GetInitSources() > 0) {
|
||||
ref_mode = REF_ModeInitStepSlew;
|
||||
@@ -511,24 +722,20 @@ int main
|
||||
REF_SetModeEndHandler(reference_mode_end);
|
||||
REF_SetMode(ref_mode);
|
||||
|
||||
if (timeout >= 0)
|
||||
SCH_AddTimeoutByDelay(timeout, quit_timeout, NULL);
|
||||
|
||||
if (do_init_rtc) {
|
||||
RTC_TimeInit(post_init_rtc_hook, NULL);
|
||||
} else {
|
||||
post_init_rtc_hook(NULL);
|
||||
}
|
||||
|
||||
signal(SIGINT, signal_cleanup);
|
||||
signal(SIGTERM, signal_cleanup);
|
||||
#if !defined(WINNT)
|
||||
signal(SIGQUIT, signal_cleanup);
|
||||
signal(SIGHUP, signal_cleanup);
|
||||
#endif /* WINNT */
|
||||
|
||||
/* The program normally runs under control of the main loop in
|
||||
the scheduler. */
|
||||
SCH_MainLoop();
|
||||
|
||||
LOG(LOGS_INFO, LOGF_Main, "chronyd exiting");
|
||||
LOG(LOGS_INFO, "chronyd exiting");
|
||||
|
||||
MAI_CleanupAndExit();
|
||||
|
||||
|
||||
37
make_release
37
make_release
@@ -1,6 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
LANG=C
|
||||
LANG=C.UTF-8
|
||||
export LANG
|
||||
|
||||
if [ $# -ne 1 ]; then
|
||||
@@ -11,7 +11,6 @@ fi
|
||||
version=$1
|
||||
tag=$version
|
||||
subdir=chrony-${version}
|
||||
mandate=$(date +'%B %Y')
|
||||
|
||||
umask 022
|
||||
|
||||
@@ -37,39 +36,13 @@ cd RELEASES/$subdir || exit 1
|
||||
|
||||
echo $version > version.txt
|
||||
|
||||
sed -i -e "s%@@VERSION@@%${version}%" examples/chrony.spec
|
||||
./configure && make -C doc man txt || exit 1
|
||||
|
||||
for m in chrony.1 chronyc.1.in chrony.conf.5.in chronyd.8.in; do
|
||||
sed -e "s%@VERSION@%${version}%;s%@MAN_DATE@%${mandate}%" \
|
||||
< $m > ${m}_
|
||||
mv -f ${m}_ $m
|
||||
done
|
||||
iconv -f utf-8 -t ascii//TRANSLIT < doc/installation.txt > INSTALL
|
||||
iconv -f utf-8 -t ascii//TRANSLIT < doc/faq.txt > FAQ
|
||||
|
||||
./configure && make chrony.txt || exit 1
|
||||
mv chrony.txt chrony.txt_
|
||||
make distclean
|
||||
mv chrony.txt_ chrony.txt
|
||||
|
||||
awk '/^[1-9] Installation$/{p=1}
|
||||
/^[1-9]\.. Support for line editing/{exit}; p' chrony.txt | \
|
||||
tail -n +4 > INSTALL
|
||||
|
||||
if [ $(wc -l < INSTALL) -gt 100 -o $(wc -l < INSTALL) -lt 85 ]; then
|
||||
echo "INSTALL generated incorrectly?"
|
||||
exit 3
|
||||
fi
|
||||
|
||||
awk '/^[1-9] Frequently asked questions$/{p=1}
|
||||
/^Appendix A GNU General Public License$/{exit}; p' chrony.txt | \
|
||||
tail -n +4 | sed 's/^[1-9]\.\([1-9]\)/\1/' | sed 's/^----/--/' | \
|
||||
sed 's/^====/==/' > FAQ
|
||||
|
||||
if [ $(wc -l < FAQ) -gt 400 -o $(wc -l < FAQ) -lt 200 ]; then
|
||||
echo "FAQ generated incorrectly?"
|
||||
exit 3
|
||||
fi
|
||||
|
||||
rm -f config.h config.log make_release .gitignore
|
||||
rm -f make_release .gitignore
|
||||
|
||||
cd ..
|
||||
tar cv --owner root --group root $subdir | gzip -9 > ${subdir}.tar.gz
|
||||
|
||||
69
manual.c
69
manual.c
@@ -47,7 +47,7 @@ static int enabled = 0;
|
||||
|
||||
/* More recent samples at highest indices */
|
||||
typedef struct {
|
||||
struct timeval when; /* This is our 'cooked' time */
|
||||
struct timespec when; /* This is our 'cooked' time */
|
||||
double orig_offset; /*+ Not modified by slew samples */
|
||||
double offset; /*+ if we are fast of the supplied reference */
|
||||
double residual; /*+ regression residual (sign convention given by
|
||||
@@ -64,8 +64,8 @@ static int n_samples;
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
slew_samples(struct timeval *raw,
|
||||
struct timeval *cooked,
|
||||
slew_samples(struct timespec *raw,
|
||||
struct timespec *cooked,
|
||||
double dfreq,
|
||||
double doffset,
|
||||
LCL_ChangeType change_type,
|
||||
@@ -92,12 +92,14 @@ MNL_Initialise(void)
|
||||
void
|
||||
MNL_Finalise(void)
|
||||
{
|
||||
LCL_RemoveParameterChangeHandler(slew_samples, NULL);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
estimate_and_set_system(struct timeval *now, int offset_provided, double offset, long *offset_cs, double *dfreq_ppm, double *new_afreq_ppm)
|
||||
estimate_and_set_system(struct timespec *now, int offset_provided, double offset,
|
||||
double *reg_offset, double *dfreq_ppm, double *new_afreq_ppm)
|
||||
{
|
||||
double agos[MAX_SAMPLES], offsets[MAX_SAMPLES];
|
||||
double b0, b1;
|
||||
@@ -108,32 +110,26 @@ estimate_and_set_system(struct timeval *now, int offset_provided, double offset,
|
||||
int found_freq;
|
||||
double slew_by;
|
||||
|
||||
b0 = offset_provided ? offset : 0.0;
|
||||
b1 = freq = 0.0;
|
||||
found_freq = 0;
|
||||
|
||||
if (n_samples > 1) {
|
||||
for (i=0; i<n_samples; i++) {
|
||||
UTI_DiffTimevalsToDouble(&agos[i], &samples[n_samples-1].when, &samples[i].when);
|
||||
agos[i] = UTI_DiffTimespecsToDouble(&samples[n_samples - 1].when, &samples[i].when);
|
||||
offsets[i] = samples[i].offset;
|
||||
}
|
||||
|
||||
RGR_FindBestRobustRegression(agos, offsets, n_samples,
|
||||
1.0e-8, /* 0.01ppm easily good enough for this! */
|
||||
&b0, &b1, &n_runs, &best_start);
|
||||
|
||||
|
||||
/* Ignore b0 from regression; treat offset as being the most
|
||||
recently entered value. (If the administrator knows he's put
|
||||
an outlier in, he will rerun the settime operation.) However,
|
||||
the frequency estimate comes from the regression. */
|
||||
|
||||
freq = -b1;
|
||||
found_freq = 1;
|
||||
} else {
|
||||
if (offset_provided) {
|
||||
b0 = offset;
|
||||
} else {
|
||||
b0 = 0.0;
|
||||
if (RGR_FindBestRobustRegression(agos, offsets, n_samples, 1.0e-8,
|
||||
&b0, &b1, &n_runs, &best_start)) {
|
||||
/* Ignore b0 from regression; treat offset as being the most
|
||||
recently entered value. (If the administrator knows he's put
|
||||
an outlier in, he will rerun the settime operation.) However,
|
||||
the frequency estimate comes from the regression. */
|
||||
freq = -b1;
|
||||
found_freq = 1;
|
||||
}
|
||||
b1 = freq = 0.0;
|
||||
found_freq = 0;
|
||||
} else {
|
||||
agos[0] = 0.0;
|
||||
offsets[0] = b0;
|
||||
}
|
||||
@@ -145,21 +141,20 @@ estimate_and_set_system(struct timeval *now, int offset_provided, double offset,
|
||||
}
|
||||
|
||||
if (found_freq) {
|
||||
LOG(LOGS_INFO, LOGF_Manual,
|
||||
"Making a frequency change of %.3f ppm and a slew of %.6f",
|
||||
LOG(LOGS_INFO, "Making a frequency change of %.3f ppm and a slew of %.6f",
|
||||
1.0e6 * freq, slew_by);
|
||||
|
||||
REF_SetManualReference(now,
|
||||
slew_by,
|
||||
freq, skew);
|
||||
} else {
|
||||
LOG(LOGS_INFO, LOGF_Manual, "Making a slew of %.6f", slew_by);
|
||||
LOG(LOGS_INFO, "Making a slew of %.6f", slew_by);
|
||||
REF_SetManualReference(now,
|
||||
slew_by,
|
||||
0.0, skew);
|
||||
}
|
||||
|
||||
if (offset_cs) *offset_cs = (long)(0.5 + 100.0 * b0);
|
||||
if (reg_offset) *reg_offset = b0;
|
||||
if (dfreq_ppm) *dfreq_ppm = 1.0e6 * freq;
|
||||
if (new_afreq_ppm) *new_afreq_ppm = LCL_ReadAbsoluteFrequency();
|
||||
|
||||
@@ -173,9 +168,9 @@ estimate_and_set_system(struct timeval *now, int offset_provided, double offset,
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
MNL_AcceptTimestamp(struct timeval *ts, long *offset_cs, double *dfreq_ppm, double *new_afreq_ppm)
|
||||
MNL_AcceptTimestamp(struct timespec *ts, double *reg_offset, double *dfreq_ppm, double *new_afreq_ppm)
|
||||
{
|
||||
struct timeval now;
|
||||
struct timespec now;
|
||||
double offset, diff;
|
||||
int i;
|
||||
|
||||
@@ -189,12 +184,12 @@ MNL_AcceptTimestamp(struct timeval *ts, long *offset_cs, double *dfreq_ppm, doub
|
||||
return 0;
|
||||
|
||||
if (n_samples) {
|
||||
UTI_DiffTimevalsToDouble(&diff, &now, &samples[n_samples - 1].when);
|
||||
diff = UTI_DiffTimespecsToDouble(&now, &samples[n_samples - 1].when);
|
||||
if (diff < MIN_SAMPLE_SEPARATION)
|
||||
return 0;
|
||||
}
|
||||
|
||||
UTI_DiffTimevalsToDouble(&offset, &now, ts);
|
||||
offset = UTI_DiffTimespecsToDouble(&now, ts);
|
||||
|
||||
/* Check if buffer full up */
|
||||
if (n_samples == MAX_SAMPLES) {
|
||||
@@ -210,7 +205,7 @@ MNL_AcceptTimestamp(struct timeval *ts, long *offset_cs, double *dfreq_ppm, doub
|
||||
samples[n_samples].orig_offset = offset;
|
||||
++n_samples;
|
||||
|
||||
estimate_and_set_system(&now, 1, offset, offset_cs, dfreq_ppm, new_afreq_ppm);
|
||||
estimate_and_set_system(&now, 1, offset, reg_offset, dfreq_ppm, new_afreq_ppm);
|
||||
|
||||
return 1;
|
||||
|
||||
@@ -224,8 +219,8 @@ MNL_AcceptTimestamp(struct timeval *ts, long *offset_cs, double *dfreq_ppm, doub
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
slew_samples(struct timeval *raw,
|
||||
struct timeval *cooked,
|
||||
slew_samples(struct timespec *raw,
|
||||
struct timespec *cooked,
|
||||
double dfreq,
|
||||
double doffset,
|
||||
LCL_ChangeType change_type,
|
||||
@@ -239,7 +234,7 @@ slew_samples(struct timeval *raw,
|
||||
}
|
||||
|
||||
for (i=0; i<n_samples; i++) {
|
||||
UTI_AdjustTimeval(&samples[i].when, cooked, &samples[i].when, &delta_time,
|
||||
UTI_AdjustTimespec(&samples[i].when, cooked, &samples[i].when, &delta_time,
|
||||
dfreq, doffset);
|
||||
samples[i].offset += delta_time;
|
||||
}
|
||||
@@ -309,7 +304,7 @@ int
|
||||
MNL_DeleteSample(int index)
|
||||
{
|
||||
int i;
|
||||
struct timeval now;
|
||||
struct timespec now;
|
||||
|
||||
if ((index < 0) || (index >= n_samples)) {
|
||||
return 0;
|
||||
|
||||
2
manual.h
2
manual.h
@@ -33,7 +33,7 @@
|
||||
|
||||
extern void MNL_Initialise(void);
|
||||
extern void MNL_Finalise(void);
|
||||
extern int MNL_AcceptTimestamp(struct timeval *ts, long *offset_cs, double *dfreq_ppm, double *new_afreq_ppm);
|
||||
extern int MNL_AcceptTimestamp(struct timespec *ts, double *reg_offset, double *dfreq_ppm, double *new_afreq_ppm);
|
||||
|
||||
extern void MNL_Enable(void);
|
||||
extern void MNL_Disable(void);
|
||||
|
||||
15
md5.c
15
md5.c
@@ -117,8 +117,7 @@ inline UINT4 ROTATE_LEFT(UINT4 x, int n)
|
||||
/* The routine MD5Init initializes the message-digest context
|
||||
mdContext. All fields are set to zero.
|
||||
*/
|
||||
void MD5Init (mdContext)
|
||||
MD5_CTX *mdContext;
|
||||
void MD5Init (MD5_CTX *mdContext)
|
||||
{
|
||||
mdContext->i[0] = mdContext->i[1] = (UINT4)0;
|
||||
|
||||
@@ -134,10 +133,7 @@ MD5_CTX *mdContext;
|
||||
account for the presence of each of the characters inBuf[0..inLen-1]
|
||||
in the message whose digest is being computed.
|
||||
*/
|
||||
void MD5Update (mdContext, inBuf, inLen)
|
||||
MD5_CTX *mdContext;
|
||||
unsigned const char *inBuf;
|
||||
unsigned int inLen;
|
||||
void MD5Update (MD5_CTX *mdContext, unsigned const char *inBuf, unsigned int inLen)
|
||||
{
|
||||
UINT4 in[16];
|
||||
int mdi;
|
||||
@@ -173,8 +169,7 @@ unsigned int inLen;
|
||||
ends with the desired message digest in mdContext->digest[0...15].
|
||||
*/
|
||||
|
||||
void MD5Final (mdContext)
|
||||
MD5_CTX *mdContext;
|
||||
void MD5Final (MD5_CTX *mdContext)
|
||||
{
|
||||
UINT4 in[16];
|
||||
int mdi;
|
||||
@@ -214,9 +209,7 @@ MD5_CTX *mdContext;
|
||||
|
||||
/* Basic MD5 step. Transforms buf based on in.
|
||||
*/
|
||||
static void Transform (buf, in)
|
||||
UINT4 *buf;
|
||||
UINT4 *in;
|
||||
static void Transform (UINT4 *buf, UINT4 *in)
|
||||
{
|
||||
UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
|
||||
|
||||
|
||||
41
memory.c
41
memory.c
@@ -2,7 +2,7 @@
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2014
|
||||
* Copyright (C) Miroslav Lichvar 2014, 2017
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -37,7 +37,7 @@ Malloc(size_t size)
|
||||
|
||||
r = malloc(size);
|
||||
if (!r && size)
|
||||
LOG_FATAL(LOGF_Memory, "Could not allocate memory");
|
||||
LOG_FATAL("Could not allocate memory");
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -47,13 +47,44 @@ Realloc(void *ptr, size_t size)
|
||||
{
|
||||
void *r;
|
||||
|
||||
if (size == 0) {
|
||||
Free(ptr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
r = realloc(ptr, size);
|
||||
if (!r && size)
|
||||
LOG_FATAL(LOGF_Memory, "Could not allocate memory");
|
||||
if (!r)
|
||||
LOG_FATAL("Could not allocate memory");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static size_t
|
||||
get_array_size(size_t nmemb, size_t size)
|
||||
{
|
||||
size_t array_size;
|
||||
|
||||
array_size = nmemb * size;
|
||||
|
||||
/* Check for overflow */
|
||||
if (nmemb > 0 && array_size / nmemb != size)
|
||||
LOG_FATAL("Could not allocate memory");
|
||||
|
||||
return array_size;
|
||||
}
|
||||
|
||||
void *
|
||||
Malloc2(size_t nmemb, size_t size)
|
||||
{
|
||||
return Malloc(get_array_size(nmemb, size));
|
||||
}
|
||||
|
||||
void *
|
||||
Realloc2(void *ptr, size_t nmemb, size_t size)
|
||||
{
|
||||
return Realloc(ptr, get_array_size(nmemb, size));
|
||||
}
|
||||
|
||||
char *
|
||||
Strdup(const char *s)
|
||||
{
|
||||
@@ -61,7 +92,7 @@ Strdup(const char *s)
|
||||
|
||||
r = strdup(s);
|
||||
if (!r)
|
||||
LOG_FATAL(LOGF_Memory, "Could not allocate memory");
|
||||
LOG_FATAL("Could not allocate memory");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
8
memory.h
8
memory.h
@@ -27,15 +27,19 @@
|
||||
#ifndef GOT_MEMORY_H
|
||||
#define GOT_MEMORY_H
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
/* Wrappers checking for errors */
|
||||
extern void *Malloc(size_t size);
|
||||
extern void *Realloc(void *ptr, size_t size);
|
||||
extern void *Malloc2(size_t nmemb, size_t size);
|
||||
extern void *Realloc2(void *ptr, size_t nmemb, size_t size);
|
||||
extern char *Strdup(const char *s);
|
||||
|
||||
/* Convenient macros */
|
||||
#define MallocNew(T) ((T *) Malloc(sizeof(T)))
|
||||
#define MallocArray(T, n) ((T *) Malloc((n) * sizeof(T)))
|
||||
#define ReallocArray(T,n,x) ((T *) Realloc((void *)(x), (n)*sizeof(T)))
|
||||
#define MallocArray(T, n) ((T *) Malloc2(n, sizeof(T)))
|
||||
#define ReallocArray(T, n, x) ((T *) Realloc2((void *)(x), n, sizeof(T)))
|
||||
#define Free(x) free(x)
|
||||
|
||||
#endif /* GOT_MEMORY_H */
|
||||
|
||||
135
mkdirpp.c
135
mkdirpp.c
@@ -1,135 +0,0 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
A function for creating a directory and any parent directories that
|
||||
don't exist.
|
||||
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "memory.h"
|
||||
#include "mkdirpp.h"
|
||||
|
||||
static int
|
||||
do_dir(char *p)
|
||||
{
|
||||
int status;
|
||||
struct stat buf;
|
||||
|
||||
#if defined(TEST)
|
||||
fprintf(stderr, "do_dir(%s)\n", p);
|
||||
#endif
|
||||
|
||||
/* See if directory exists */
|
||||
status = stat(p, &buf);
|
||||
|
||||
if (status < 0) {
|
||||
if (errno == ENOENT) {
|
||||
/* Try to create directory */
|
||||
status = mkdir(p, 0755);
|
||||
return status;
|
||||
} else {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
if (!S_ISDIR(buf.st_mode)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Return 0 if the directory couldn't be created, 1 if it could (or
|
||||
already existed) */
|
||||
|
||||
int
|
||||
mkdir_and_parents(const char *path)
|
||||
{
|
||||
char *p;
|
||||
int len;
|
||||
int i, j, k, last;
|
||||
len = strlen(path);
|
||||
|
||||
p = (char *)Malloc(1 + len);
|
||||
|
||||
i = k = 0;
|
||||
while (1) {
|
||||
p[i++] = path[k++];
|
||||
|
||||
if (path[k] == '/' || !path[k]) {
|
||||
p[i] = 0;
|
||||
|
||||
if (do_dir(p) < 0) {
|
||||
Free(p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!path[k]) {
|
||||
/* End of the string */
|
||||
break;
|
||||
}
|
||||
|
||||
/* check whether its a trailing / or group of / */
|
||||
last = 1;
|
||||
j = k+1;
|
||||
while (path[j]) {
|
||||
if (path[j] != '/') {
|
||||
k = j - 1; /* Pick up a / into p[] thru the assignment at the top of the loop */
|
||||
last = 0;
|
||||
break;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
|
||||
if (last) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!path[k]) break;
|
||||
|
||||
}
|
||||
|
||||
Free(p);
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#if defined(TEST)
|
||||
int main(int argc, char **argv) {
|
||||
if (argc > 1) {
|
||||
/* Invert sense of result */
|
||||
return mkdir_and_parents(argv[1]) ? 0 : 1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
112
nameserv.c
112
nameserv.c
@@ -30,7 +30,11 @@
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include <netdb.h>
|
||||
#include <resolv.h>
|
||||
|
||||
#include "nameserv.h"
|
||||
#include "socket.h"
|
||||
#include "util.h"
|
||||
|
||||
/* ================================================== */
|
||||
@@ -46,13 +50,39 @@ DNS_SetAddressFamily(int family)
|
||||
DNS_Status
|
||||
DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs)
|
||||
{
|
||||
#ifdef HAVE_GETADDRINFO
|
||||
struct addrinfo hints, *res, *ai;
|
||||
int i, result;
|
||||
|
||||
IPAddr ip;
|
||||
|
||||
max_addrs = MIN(max_addrs, DNS_MAX_ADDRESSES);
|
||||
|
||||
for (i = 0; i < max_addrs; i++)
|
||||
ip_addrs[i].family = IPADDR_UNSPEC;
|
||||
|
||||
/* Avoid calling getaddrinfo() if the name is an IP address */
|
||||
if (UTI_StringToIP(name, &ip)) {
|
||||
if (address_family != IPADDR_UNSPEC && ip.family != address_family)
|
||||
return DNS_Failure;
|
||||
if (max_addrs >= 1)
|
||||
ip_addrs[0] = ip;
|
||||
return DNS_Success;
|
||||
}
|
||||
|
||||
memset(&hints, 0, sizeof (hints));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
switch (address_family) {
|
||||
case IPADDR_INET4:
|
||||
hints.ai_family = AF_INET;
|
||||
break;
|
||||
#ifdef FEAT_IPV6
|
||||
case IPADDR_INET6:
|
||||
hints.ai_family = AF_INET6;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
}
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
|
||||
result = getaddrinfo(name, NULL, &hints, &res);
|
||||
|
||||
@@ -77,6 +107,9 @@ DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs)
|
||||
case AF_INET6:
|
||||
if (address_family != IPADDR_UNSPEC && address_family != IPADDR_INET6)
|
||||
continue;
|
||||
/* Don't return an address that would lose a scope ID */
|
||||
if (((struct sockaddr_in6 *)ai->ai_addr)->sin6_scope_id != 0)
|
||||
continue;
|
||||
ip_addrs[i].family = IPADDR_INET6;
|
||||
memcpy(&ip_addrs[i].addr.in6, &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr.s6_addr,
|
||||
sizeof (ip_addrs->addr.in6));
|
||||
@@ -86,46 +119,9 @@ DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs)
|
||||
}
|
||||
}
|
||||
|
||||
for (; i < max_addrs; i++)
|
||||
ip_addrs[i].family = IPADDR_UNSPEC;
|
||||
|
||||
freeaddrinfo(res);
|
||||
|
||||
return !max_addrs || ip_addrs[0].family != IPADDR_UNSPEC ? DNS_Success : DNS_Failure;
|
||||
#else
|
||||
struct hostent *host;
|
||||
int i;
|
||||
|
||||
if (address_family != IPADDR_UNSPEC && address_family != IPADDR_INET4)
|
||||
return DNS_Failure;
|
||||
|
||||
host = gethostbyname(name);
|
||||
|
||||
if (host == NULL) {
|
||||
if (h_errno == TRY_AGAIN)
|
||||
return DNS_TryAgain;
|
||||
} else {
|
||||
if (host->h_addrtype != AF_INET || !host->h_addr_list[0])
|
||||
return DNS_Failure;
|
||||
|
||||
for (i = 0; host->h_addr_list[i] && i < max_addrs; i++) {
|
||||
ip_addrs[i].family = IPADDR_INET4;
|
||||
ip_addrs[i].addr.in4 = ntohl(*(uint32_t *)host->h_addr_list[i]);
|
||||
}
|
||||
|
||||
for (; i < max_addrs; i++)
|
||||
ip_addrs[i].family = IPADDR_UNSPEC;
|
||||
|
||||
return DNS_Success;
|
||||
}
|
||||
|
||||
#ifdef FORCE_DNSRETRY
|
||||
return DNS_TryAgain;
|
||||
#else
|
||||
return DNS_Failure;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -134,35 +130,21 @@ int
|
||||
DNS_IPAddress2Name(IPAddr *ip_addr, char *name, int len)
|
||||
{
|
||||
char *result = NULL;
|
||||
|
||||
#ifdef FEAT_IPV6
|
||||
struct sockaddr_in6 in6;
|
||||
struct sockaddr_in6 saddr;
|
||||
#else
|
||||
struct sockaddr_in saddr;
|
||||
#endif
|
||||
IPSockAddr ip_saddr;
|
||||
socklen_t slen;
|
||||
char hbuf[NI_MAXHOST];
|
||||
|
||||
slen = UTI_IPAndPortToSockaddr(ip_addr, 0, (struct sockaddr *)&in6);
|
||||
if (!getnameinfo((struct sockaddr *)&in6, slen, hbuf, sizeof (hbuf), NULL, 0, 0))
|
||||
result = hbuf;
|
||||
#else
|
||||
struct hostent *host;
|
||||
uint32_t addr;
|
||||
ip_saddr.ip_addr = *ip_addr;
|
||||
ip_saddr.port = 0;
|
||||
|
||||
switch (ip_addr->family) {
|
||||
case IPADDR_INET4:
|
||||
addr = htonl(ip_addr->addr.in4);
|
||||
host = gethostbyaddr((const char *) &addr, sizeof (ip_addr), AF_INET);
|
||||
break;
|
||||
#ifdef FEAT_IPV6
|
||||
case IPADDR_INET6:
|
||||
host = gethostbyaddr((const void *) ip_addr->addr.in6, sizeof (ip_addr->addr.in6), AF_INET6);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
host = NULL;
|
||||
}
|
||||
if (host)
|
||||
result = host->h_name;
|
||||
#endif
|
||||
slen = SCK_IPSockAddrToSockaddr(&ip_saddr, (struct sockaddr *)&saddr, sizeof (saddr));
|
||||
if (!getnameinfo((struct sockaddr *)&saddr, slen, hbuf, sizeof (hbuf), NULL, 0, 0))
|
||||
result = hbuf;
|
||||
|
||||
if (result == NULL)
|
||||
result = UTI_IPToString(ip_addr);
|
||||
|
||||
@@ -39,6 +39,9 @@ typedef enum {
|
||||
/* Resolve names only to selected address family */
|
||||
extern void DNS_SetAddressFamily(int family);
|
||||
|
||||
/* Maximum number of addresses returned by DNS_Name2IPAddress */
|
||||
#define DNS_MAX_ADDRESSES 16
|
||||
|
||||
extern DNS_Status DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs);
|
||||
|
||||
extern int DNS_IPAddress2Name(IPAddr *ip_addr, char *name, int len);
|
||||
|
||||
@@ -31,20 +31,19 @@
|
||||
#include "nameserv_async.h"
|
||||
#include "logging.h"
|
||||
#include "memory.h"
|
||||
#include "privops.h"
|
||||
#include "sched.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifdef USE_PTHREAD_ASYNCDNS
|
||||
#include <pthread.h>
|
||||
|
||||
#define MAX_ADDRESSES 16
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
struct DNS_Async_Instance {
|
||||
const char *name;
|
||||
DNS_Status status;
|
||||
IPAddr addresses[MAX_ADDRESSES];
|
||||
IPAddr addresses[DNS_MAX_ADDRESSES];
|
||||
DNS_NameResolveHandler handler;
|
||||
void *arg;
|
||||
|
||||
@@ -52,7 +51,7 @@ struct DNS_Async_Instance {
|
||||
int pipe[2];
|
||||
};
|
||||
|
||||
static int resolving_threads = 0;
|
||||
static pthread_mutex_t privops_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
@@ -61,7 +60,9 @@ start_resolving(void *anything)
|
||||
{
|
||||
struct DNS_Async_Instance *inst = (struct DNS_Async_Instance *)anything;
|
||||
|
||||
inst->status = DNS_Name2IPAddress(inst->name, inst->addresses, MAX_ADDRESSES);
|
||||
pthread_mutex_lock(&privops_lock);
|
||||
inst->status = PRV_Name2IPAddress(inst->name, inst->addresses, DNS_MAX_ADDRESSES);
|
||||
pthread_mutex_unlock(&privops_lock);
|
||||
|
||||
/* Notify the main thread that the result is ready */
|
||||
if (write(inst->pipe[1], "", 1) < 0)
|
||||
@@ -73,22 +74,20 @@ start_resolving(void *anything)
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
end_resolving(void *anything)
|
||||
end_resolving(int fd, int event, void *anything)
|
||||
{
|
||||
struct DNS_Async_Instance *inst = (struct DNS_Async_Instance *)anything;
|
||||
int i;
|
||||
|
||||
if (pthread_join(inst->thread, NULL)) {
|
||||
LOG_FATAL(LOGF_Nameserv, "pthread_join() failed");
|
||||
LOG_FATAL("pthread_join() failed");
|
||||
}
|
||||
|
||||
resolving_threads--;
|
||||
|
||||
SCH_RemoveInputFileHandler(inst->pipe[0]);
|
||||
SCH_RemoveFileHandler(inst->pipe[0]);
|
||||
close(inst->pipe[0]);
|
||||
close(inst->pipe[1]);
|
||||
|
||||
for (i = 0; inst->status == DNS_Success && i < MAX_ADDRESSES &&
|
||||
for (i = 0; inst->status == DNS_Success && i < DNS_MAX_ADDRESSES &&
|
||||
inst->addresses[i].family != IPADDR_UNSPEC; i++)
|
||||
;
|
||||
|
||||
@@ -111,17 +110,17 @@ DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *
|
||||
inst->status = DNS_Failure;
|
||||
|
||||
if (pipe(inst->pipe)) {
|
||||
LOG_FATAL(LOGF_Nameserv, "pipe() failed");
|
||||
LOG_FATAL("pipe() failed");
|
||||
}
|
||||
|
||||
resolving_threads++;
|
||||
assert(resolving_threads <= 1);
|
||||
UTI_FdSetCloexec(inst->pipe[0]);
|
||||
UTI_FdSetCloexec(inst->pipe[1]);
|
||||
|
||||
if (pthread_create(&inst->thread, NULL, start_resolving, inst)) {
|
||||
LOG_FATAL(LOGF_Nameserv, "pthread_create() failed");
|
||||
LOG_FATAL("pthread_create() failed");
|
||||
}
|
||||
|
||||
SCH_AddInputFileHandler(inst->pipe[0], end_resolving, inst);
|
||||
SCH_AddFileHandler(inst->pipe[0], SCH_FILE_INPUT, end_resolving, inst);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
@@ -34,8 +34,7 @@
|
||||
typedef void (*DNS_NameResolveHandler)(DNS_Status status, int n_addrs, IPAddr *ip_addrs, void *anything);
|
||||
|
||||
/* Request resolving of a name to IP address. The handler will be
|
||||
called when the result is available, but it may be also called
|
||||
directly from this function call. */
|
||||
called when the result is available. */
|
||||
extern void DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *anything);
|
||||
|
||||
#endif
|
||||
|
||||
132
ntp.h
132
ntp.h
@@ -38,23 +38,33 @@ typedef struct {
|
||||
|
||||
typedef uint32_t NTP_int32;
|
||||
|
||||
/* The UDP port number used by NTP */
|
||||
#define NTP_PORT 123
|
||||
|
||||
/* The NTP protocol version that we support */
|
||||
#define NTP_VERSION 4
|
||||
|
||||
/* Maximum stratum number (infinity) */
|
||||
#define NTP_MAX_STRATUM 16
|
||||
|
||||
/* The minimum valid length of an extension field */
|
||||
#define NTP_MIN_EXTENSION_LENGTH 16
|
||||
|
||||
/* The maximum assumed length of all extension fields in received
|
||||
packets (RFC 5905 doesn't specify a limit on length or number of
|
||||
extension fields in one packet) */
|
||||
#define NTP_MAX_EXTENSIONS_LENGTH 1024
|
||||
/* Invalid stratum number */
|
||||
#define NTP_INVALID_STRATUM 0
|
||||
|
||||
/* The minimum and maximum supported length of MAC */
|
||||
#define NTP_MIN_MAC_LENGTH 16
|
||||
#define NTP_MAX_MAC_LENGTH MAX_HASH_LENGTH
|
||||
#define NTP_MIN_MAC_LENGTH (4 + 16)
|
||||
#define NTP_MAX_MAC_LENGTH (4 + MAX_HASH_LENGTH)
|
||||
|
||||
/* The minimum valid length of an extension field */
|
||||
#define NTP_MIN_EF_LENGTH 16
|
||||
|
||||
/* The maximum assumed length of all extension fields in an NTP packet,
|
||||
including a MAC (RFC 5905 doesn't specify a limit on length or number of
|
||||
extension fields in one packet) */
|
||||
#define NTP_MAX_EXTENSIONS_LENGTH (1024 + NTP_MAX_MAC_LENGTH)
|
||||
|
||||
/* The maximum length of MAC in NTPv4 packets which allows deterministic
|
||||
parsing of extension fields (RFC 7822) */
|
||||
#define NTP_MAX_V4_MAC_LENGTH (4 + 20)
|
||||
|
||||
/* Type definition for leap bits */
|
||||
typedef enum {
|
||||
@@ -86,21 +96,10 @@ typedef struct {
|
||||
NTP_int64 receive_ts;
|
||||
NTP_int64 transmit_ts;
|
||||
|
||||
/* Optional extension fields, we don't send packets with them yet */
|
||||
/* uint8_t extensions[] */
|
||||
|
||||
/* Optional message authentication code (MAC) */
|
||||
NTP_int32 auth_keyid;
|
||||
uint8_t auth_data[NTP_MAX_MAC_LENGTH];
|
||||
uint8_t extensions[NTP_MAX_EXTENSIONS_LENGTH];
|
||||
} NTP_Packet;
|
||||
|
||||
#define NTP_NORMAL_PACKET_LENGTH (int)offsetof(NTP_Packet, auth_keyid)
|
||||
|
||||
/* The buffer used to hold a datagram read from the network */
|
||||
typedef struct {
|
||||
NTP_Packet ntp_pkt;
|
||||
uint8_t extensions[NTP_MAX_EXTENSIONS_LENGTH];
|
||||
} NTP_Receive_Buffer;
|
||||
#define NTP_HEADER_LENGTH (int)offsetof(NTP_Packet, extensions)
|
||||
|
||||
/* Macros to work with the lvm field */
|
||||
#define NTP_LVM_TO_LEAP(lvm) (((lvm) >> 6) & 0x3)
|
||||
@@ -109,4 +108,93 @@ typedef struct {
|
||||
#define NTP_LVM(leap, version, mode) \
|
||||
((((leap) << 6) & 0xc0) | (((version) << 3) & 0x38) | ((mode) & 0x07))
|
||||
|
||||
/* Special NTP reference IDs */
|
||||
#define NTP_REFID_UNSYNC 0x0UL
|
||||
#define NTP_REFID_LOCAL 0x7F7F0101UL /* 127.127.1.1 */
|
||||
#define NTP_REFID_SMOOTH 0x7F7F01FFUL /* 127.127.1.255 */
|
||||
|
||||
/* Non-authentication extension fields and corresponding internal flags */
|
||||
|
||||
#define NTP_EF_EXP_MONO_ROOT 0xF323
|
||||
#define NTP_EF_EXP_NET_CORRECTION 0xF324
|
||||
|
||||
#define NTP_EF_FLAG_EXP_MONO_ROOT 0x1
|
||||
#define NTP_EF_FLAG_EXP_NET_CORRECTION 0x2
|
||||
|
||||
/* Pre-NTPv5 experimental extension field */
|
||||
typedef struct {
|
||||
uint32_t magic;
|
||||
NTP_int32 root_delay;
|
||||
NTP_int32 root_dispersion;
|
||||
NTP_int64 mono_receive_ts;
|
||||
uint32_t mono_epoch;
|
||||
} NTP_EFExpMonoRoot;
|
||||
|
||||
#define NTP_EF_EXP_MONO_ROOT_MAGIC 0xF5BEDD9AU
|
||||
|
||||
/* Experimental extension field to provide PTP corrections */
|
||||
typedef struct {
|
||||
uint32_t magic;
|
||||
NTP_int64 correction;
|
||||
uint32_t reserved[3];
|
||||
} NTP_EFExpNetCorrection;
|
||||
|
||||
#define NTP_EF_EXP_NET_CORRECTION_MAGIC 0x07AC2CEBU
|
||||
|
||||
/* Authentication extension fields */
|
||||
|
||||
#define NTP_EF_NTS_UNIQUE_IDENTIFIER 0x0104
|
||||
#define NTP_EF_NTS_COOKIE 0x0204
|
||||
#define NTP_EF_NTS_COOKIE_PLACEHOLDER 0x0304
|
||||
#define NTP_EF_NTS_AUTH_AND_EEF 0x0404
|
||||
|
||||
/* Enumeration for authentication modes of NTP packets */
|
||||
typedef enum {
|
||||
NTP_AUTH_NONE = 0, /* No authentication */
|
||||
NTP_AUTH_SYMMETRIC, /* NTP MAC or CMAC using a symmetric key
|
||||
(RFC 1305, RFC 5905, RFC 8573) */
|
||||
NTP_AUTH_MSSNTP, /* MS-SNTP authenticator field */
|
||||
NTP_AUTH_MSSNTP_EXT, /* MS-SNTP extended authenticator field */
|
||||
NTP_AUTH_NTS, /* Network Time Security (RFC 8915) */
|
||||
} NTP_AuthMode;
|
||||
|
||||
/* Structure describing an NTP packet */
|
||||
typedef struct {
|
||||
int length;
|
||||
int version;
|
||||
NTP_Mode mode;
|
||||
|
||||
int ext_fields;
|
||||
int ext_field_flags;
|
||||
|
||||
struct {
|
||||
NTP_AuthMode mode;
|
||||
struct {
|
||||
int start;
|
||||
int length;
|
||||
uint32_t key_id;
|
||||
} mac;
|
||||
} auth;
|
||||
} NTP_PacketInfo;
|
||||
|
||||
/* Structure used to save NTP measurements. time is the local time at which
|
||||
the sample is to be considered to have been made and offset is the offset at
|
||||
the time (positive indicates that the local clock is slow relative to the
|
||||
source). root_delay/root_dispersion include peer_delay/peer_dispersion. */
|
||||
typedef struct {
|
||||
struct timespec time;
|
||||
double offset;
|
||||
double peer_delay;
|
||||
double peer_dispersion;
|
||||
double root_delay;
|
||||
double root_dispersion;
|
||||
} NTP_Sample;
|
||||
|
||||
/* Possible sources of timestamps */
|
||||
typedef enum {
|
||||
NTP_TS_DAEMON = 0,
|
||||
NTP_TS_KERNEL,
|
||||
NTP_TS_HARDWARE
|
||||
} NTP_Timestamp_Source;
|
||||
|
||||
#endif /* GOT_NTP_H */
|
||||
|
||||
386
ntp_auth.c
Normal file
386
ntp_auth.c
Normal file
@@ -0,0 +1,386 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2019-2020
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
NTP authentication
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "keys.h"
|
||||
#include "logging.h"
|
||||
#include "memory.h"
|
||||
#include "ntp_auth.h"
|
||||
#include "ntp_signd.h"
|
||||
#include "nts_ntp.h"
|
||||
#include "nts_ntp_client.h"
|
||||
#include "nts_ntp_server.h"
|
||||
#include "srcparams.h"
|
||||
#include "util.h"
|
||||
|
||||
/* Structure to hold authentication configuration and state */
|
||||
|
||||
struct NAU_Instance_Record {
|
||||
NTP_AuthMode mode; /* Authentication mode of NTP packets */
|
||||
uint32_t key_id; /* Identifier of a symmetric key */
|
||||
NNC_Instance nts; /* Client NTS state */
|
||||
};
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
generate_symmetric_auth(uint32_t key_id, NTP_Packet *packet, NTP_PacketInfo *info)
|
||||
{
|
||||
int auth_len, max_auth_len;
|
||||
|
||||
if (info->length + NTP_MIN_MAC_LENGTH > sizeof (*packet)) {
|
||||
DEBUG_LOG("Packet too long");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Truncate long MACs in NTPv4 packets to allow deterministic parsing
|
||||
of extension fields (RFC 7822) */
|
||||
max_auth_len = (info->version == 4 ? NTP_MAX_V4_MAC_LENGTH : NTP_MAX_MAC_LENGTH) - 4;
|
||||
max_auth_len = MIN(max_auth_len, sizeof (*packet) - info->length - 4);
|
||||
|
||||
auth_len = KEY_GenerateAuth(key_id, packet, info->length,
|
||||
(unsigned char *)packet + info->length + 4, max_auth_len);
|
||||
if (auth_len < NTP_MIN_MAC_LENGTH - 4) {
|
||||
DEBUG_LOG("Could not generate auth data with key %"PRIu32, key_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*(uint32_t *)((unsigned char *)packet + info->length) = htonl(key_id);
|
||||
|
||||
info->auth.mac.start = info->length;
|
||||
info->auth.mac.length = 4 + auth_len;
|
||||
info->auth.mac.key_id = key_id;
|
||||
info->length += info->auth.mac.length;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
check_symmetric_auth(NTP_Packet *packet, NTP_PacketInfo *info)
|
||||
{
|
||||
int trunc_len;
|
||||
|
||||
if (info->auth.mac.length < NTP_MIN_MAC_LENGTH)
|
||||
return 0;
|
||||
|
||||
trunc_len = info->version == 4 && info->auth.mac.length <= NTP_MAX_V4_MAC_LENGTH ?
|
||||
NTP_MAX_V4_MAC_LENGTH : NTP_MAX_MAC_LENGTH;
|
||||
|
||||
if (!KEY_CheckAuth(info->auth.mac.key_id, packet, info->auth.mac.start,
|
||||
(unsigned char *)packet + info->auth.mac.start + 4,
|
||||
info->auth.mac.length - 4, trunc_len - 4))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static NAU_Instance
|
||||
create_instance(NTP_AuthMode mode)
|
||||
{
|
||||
NAU_Instance instance;
|
||||
|
||||
instance = MallocNew(struct NAU_Instance_Record);
|
||||
instance->mode = mode;
|
||||
instance->key_id = INACTIVE_AUTHKEY;
|
||||
instance->nts = NULL;
|
||||
|
||||
assert(sizeof (instance->key_id) == 4);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
NAU_Instance
|
||||
NAU_CreateNoneInstance(void)
|
||||
{
|
||||
return create_instance(NTP_AUTH_NONE);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
NAU_Instance
|
||||
NAU_CreateSymmetricInstance(uint32_t key_id)
|
||||
{
|
||||
NAU_Instance instance = create_instance(NTP_AUTH_SYMMETRIC);
|
||||
|
||||
instance->key_id = key_id;
|
||||
|
||||
if (!KEY_KeyKnown(key_id))
|
||||
LOG(LOGS_WARN, "Key %"PRIu32" is %s", key_id, "missing");
|
||||
else if (!KEY_CheckKeyLength(key_id))
|
||||
LOG(LOGS_WARN, "Key %"PRIu32" is %s", key_id, "too short");
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
NAU_Instance
|
||||
NAU_CreateNtsInstance(IPSockAddr *nts_address, const char *name, uint32_t cert_set,
|
||||
uint16_t ntp_port)
|
||||
{
|
||||
NAU_Instance instance = create_instance(NTP_AUTH_NTS);
|
||||
|
||||
instance->nts = NNC_CreateInstance(nts_address, name, cert_set, ntp_port);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NAU_DestroyInstance(NAU_Instance instance)
|
||||
{
|
||||
if (instance->mode == NTP_AUTH_NTS)
|
||||
NNC_DestroyInstance(instance->nts);
|
||||
Free(instance);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NAU_IsAuthEnabled(NAU_Instance instance)
|
||||
{
|
||||
return instance->mode != NTP_AUTH_NONE;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NAU_GetSuggestedNtpVersion(NAU_Instance instance)
|
||||
{
|
||||
/* If the MAC in NTPv4 packets would be truncated, prefer NTPv3 for
|
||||
compatibility with older chronyd servers */
|
||||
if (instance->mode == NTP_AUTH_SYMMETRIC &&
|
||||
KEY_GetAuthLength(instance->key_id) + sizeof (instance->key_id) > NTP_MAX_V4_MAC_LENGTH)
|
||||
return 3;
|
||||
|
||||
return NTP_VERSION;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NAU_PrepareRequestAuth(NAU_Instance instance)
|
||||
{
|
||||
switch (instance->mode) {
|
||||
case NTP_AUTH_NTS:
|
||||
if (!NNC_PrepareForAuth(instance->nts))
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NAU_GenerateRequestAuth(NAU_Instance instance, NTP_Packet *request, NTP_PacketInfo *info)
|
||||
{
|
||||
switch (instance->mode) {
|
||||
case NTP_AUTH_NONE:
|
||||
break;
|
||||
case NTP_AUTH_SYMMETRIC:
|
||||
if (!generate_symmetric_auth(instance->key_id, request, info))
|
||||
return 0;
|
||||
break;
|
||||
case NTP_AUTH_NTS:
|
||||
if (!NNC_GenerateRequestAuth(instance->nts, request, info))
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
info->auth.mode = instance->mode;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NAU_CheckRequestAuth(NTP_Packet *request, NTP_PacketInfo *info, uint32_t *kod)
|
||||
{
|
||||
*kod = 0;
|
||||
|
||||
switch (info->auth.mode) {
|
||||
case NTP_AUTH_NONE:
|
||||
break;
|
||||
case NTP_AUTH_SYMMETRIC:
|
||||
if (!check_symmetric_auth(request, info))
|
||||
return 0;
|
||||
break;
|
||||
case NTP_AUTH_MSSNTP:
|
||||
/* MS-SNTP requests are not authenticated */
|
||||
break;
|
||||
case NTP_AUTH_MSSNTP_EXT:
|
||||
/* Not supported yet */
|
||||
return 0;
|
||||
case NTP_AUTH_NTS:
|
||||
if (!NNS_CheckRequestAuth(request, info, kod))
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NAU_GenerateResponseAuth(NTP_Packet *request, NTP_PacketInfo *request_info,
|
||||
NTP_Packet *response, NTP_PacketInfo *response_info,
|
||||
NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
|
||||
uint32_t kod)
|
||||
{
|
||||
switch (request_info->auth.mode) {
|
||||
case NTP_AUTH_NONE:
|
||||
break;
|
||||
case NTP_AUTH_SYMMETRIC:
|
||||
if (!generate_symmetric_auth(request_info->auth.mac.key_id, response, response_info))
|
||||
return 0;
|
||||
break;
|
||||
case NTP_AUTH_MSSNTP:
|
||||
/* Sign the packet asynchronously by ntp_signd */
|
||||
if (!NSD_SignAndSendPacket(request_info->auth.mac.key_id, response, response_info,
|
||||
remote_addr, local_addr))
|
||||
return 0;
|
||||
/* Don't send the original packet */
|
||||
return 0;
|
||||
case NTP_AUTH_NTS:
|
||||
if (!NNS_GenerateResponseAuth(request, request_info, response, response_info, kod))
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
DEBUG_LOG("Could not authenticate response auth_mode=%d", (int)request_info->auth.mode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
response_info->auth.mode = request_info->auth.mode;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NAU_CheckResponseAuth(NAU_Instance instance, NTP_Packet *response, NTP_PacketInfo *info)
|
||||
{
|
||||
/* The authentication must match the expected mode */
|
||||
if (info->auth.mode != instance->mode)
|
||||
return 0;
|
||||
|
||||
switch (info->auth.mode) {
|
||||
case NTP_AUTH_NONE:
|
||||
break;
|
||||
case NTP_AUTH_SYMMETRIC:
|
||||
/* Check if it is authenticated with the specified key */
|
||||
if (info->auth.mac.key_id != instance->key_id)
|
||||
return 0;
|
||||
/* and that the MAC is valid */
|
||||
if (!check_symmetric_auth(response, info))
|
||||
return 0;
|
||||
break;
|
||||
case NTP_AUTH_NTS:
|
||||
if (!NNC_CheckResponseAuth(instance->nts, response, info))
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NAU_ChangeAddress(NAU_Instance instance, IPAddr *address)
|
||||
{
|
||||
switch (instance->mode) {
|
||||
case NTP_AUTH_NONE:
|
||||
case NTP_AUTH_SYMMETRIC:
|
||||
break;
|
||||
case NTP_AUTH_NTS:
|
||||
NNC_ChangeAddress(instance->nts, address);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NAU_DumpData(NAU_Instance instance)
|
||||
{
|
||||
switch (instance->mode) {
|
||||
case NTP_AUTH_NTS:
|
||||
NNC_DumpData(instance->nts);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NAU_GetReport(NAU_Instance instance, RPT_AuthReport *report)
|
||||
{
|
||||
memset(report, 0, sizeof (*report));
|
||||
|
||||
report->mode = instance->mode;
|
||||
report->last_ke_ago = -1;
|
||||
|
||||
switch (instance->mode) {
|
||||
case NTP_AUTH_NONE:
|
||||
break;
|
||||
case NTP_AUTH_SYMMETRIC:
|
||||
report->key_id = instance->key_id;
|
||||
KEY_GetKeyInfo(instance->key_id, &report->key_type, &report->key_length);
|
||||
break;
|
||||
case NTP_AUTH_NTS:
|
||||
NNC_GetReport(instance->nts, report);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
84
ntp_auth.h
Normal file
84
ntp_auth.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2019
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Header file for NTP authentication
|
||||
*/
|
||||
|
||||
#ifndef GOT_NTP_AUTH_H
|
||||
#define GOT_NTP_AUTH_H
|
||||
|
||||
#include "addressing.h"
|
||||
#include "ntp.h"
|
||||
#include "reports.h"
|
||||
|
||||
typedef struct NAU_Instance_Record *NAU_Instance;
|
||||
|
||||
/* Create an authenticator instance in a specific mode */
|
||||
extern NAU_Instance NAU_CreateNoneInstance(void);
|
||||
extern NAU_Instance NAU_CreateSymmetricInstance(uint32_t key_id);
|
||||
extern NAU_Instance NAU_CreateNtsInstance(IPSockAddr *nts_address, const char *name,
|
||||
uint32_t cert_set, uint16_t ntp_port);
|
||||
|
||||
/* Destroy an instance */
|
||||
extern void NAU_DestroyInstance(NAU_Instance instance);
|
||||
|
||||
/* Check if an instance is not in the None mode */
|
||||
extern int NAU_IsAuthEnabled(NAU_Instance instance);
|
||||
|
||||
/* Get NTP version recommended for better compatibility */
|
||||
extern int NAU_GetSuggestedNtpVersion(NAU_Instance instance);
|
||||
|
||||
/* Perform operations necessary for NAU_GenerateRequestAuth() */
|
||||
extern int NAU_PrepareRequestAuth(NAU_Instance instance);
|
||||
|
||||
/* Extend a request with data required by the authentication mode */
|
||||
extern int NAU_GenerateRequestAuth(NAU_Instance instance, NTP_Packet *request,
|
||||
NTP_PacketInfo *info);
|
||||
|
||||
/* Verify that a request is authentic. If it is not authentic and a non-zero
|
||||
kod code is returned, a KoD response should be sent back. */
|
||||
extern int NAU_CheckRequestAuth(NTP_Packet *request, NTP_PacketInfo *info, uint32_t *kod);
|
||||
|
||||
/* Extend a response with data required by the authentication mode. This
|
||||
function can be called only if the previous call of NAU_CheckRequestAuth()
|
||||
was on the same request. */
|
||||
extern int NAU_GenerateResponseAuth(NTP_Packet *request, NTP_PacketInfo *request_info,
|
||||
NTP_Packet *response, NTP_PacketInfo *response_info,
|
||||
NTP_Remote_Address *remote_addr,
|
||||
NTP_Local_Address *local_addr,
|
||||
uint32_t kod);
|
||||
|
||||
/* Verify that a response is authentic */
|
||||
extern int NAU_CheckResponseAuth(NAU_Instance instance, NTP_Packet *response,
|
||||
NTP_PacketInfo *info);
|
||||
|
||||
/* Change an authentication-specific address (e.g. after replacing a source) */
|
||||
extern void NAU_ChangeAddress(NAU_Instance instance, IPAddr *address);
|
||||
|
||||
/* Save authentication-specific data to speed up the next start */
|
||||
extern void NAU_DumpData(NAU_Instance instance);
|
||||
|
||||
/* Provide a report about the current authentication state */
|
||||
extern void NAU_GetReport(NAU_Instance instance, RPT_AuthReport *report);
|
||||
|
||||
#endif
|
||||
2706
ntp_core.c
2706
ntp_core.c
File diff suppressed because it is too large
Load Diff
56
ntp_core.h
56
ntp_core.h
@@ -38,6 +38,14 @@ typedef enum {
|
||||
NTP_SERVER, NTP_PEER
|
||||
} NTP_Source_Type;
|
||||
|
||||
typedef struct {
|
||||
struct timespec ts;
|
||||
double err;
|
||||
NTP_Timestamp_Source source;
|
||||
double rx_duration;
|
||||
double net_correction;
|
||||
} NTP_Local_Timestamp;
|
||||
|
||||
/* This is a private data type used for storing the instance record for
|
||||
each source that we are chiming with */
|
||||
typedef struct NCR_Instance_Record *NCR_Instance;
|
||||
@@ -47,7 +55,8 @@ extern void NCR_Initialise(void);
|
||||
extern void NCR_Finalise(void);
|
||||
|
||||
/* Get a new instance for a server or peer */
|
||||
extern NCR_Instance NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params);
|
||||
extern NCR_Instance NCR_CreateInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type,
|
||||
SourceParameters *params, const char *name);
|
||||
|
||||
/* Destroy an instance */
|
||||
extern void NCR_DestroyInstance(NCR_Instance instance);
|
||||
@@ -58,26 +67,39 @@ extern void NCR_StartInstance(NCR_Instance instance);
|
||||
/* Reset an instance */
|
||||
extern void NCR_ResetInstance(NCR_Instance inst);
|
||||
|
||||
/* Reset polling interval of an instance */
|
||||
extern void NCR_ResetPoll(NCR_Instance instance);
|
||||
|
||||
/* Change the remote address of an instance */
|
||||
extern void NCR_ChangeRemoteAddress(NCR_Instance inst, NTP_Remote_Address *remote_addr);
|
||||
extern void NCR_ChangeRemoteAddress(NCR_Instance inst, NTP_Remote_Address *remote_addr,
|
||||
int ntp_only);
|
||||
|
||||
/* This routine is called when a new packet arrives off the network,
|
||||
and it relates to a source we have an ongoing protocol exchange with */
|
||||
extern int NCR_ProcessKnown(NTP_Packet *message, struct timeval *now, double now_err, NCR_Instance data, NTP_Local_Address *local_addr, int length);
|
||||
extern int NCR_ProcessRxKnown(NCR_Instance inst, NTP_Local_Address *local_addr,
|
||||
NTP_Local_Timestamp *rx_ts, NTP_Packet *message, int length);
|
||||
|
||||
/* This routine is called when a new packet arrives off the network,
|
||||
and we do not recognize its source */
|
||||
extern void NCR_ProcessUnknown(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int length);
|
||||
extern void NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
|
||||
NTP_Local_Timestamp *rx_ts, NTP_Packet *message, int length);
|
||||
|
||||
/* This routine is called when a packet is sent to a source we have
|
||||
an ongoing protocol exchange with */
|
||||
extern void NCR_ProcessTxKnown(NCR_Instance inst, NTP_Local_Address *local_addr,
|
||||
NTP_Local_Timestamp *tx_ts, NTP_Packet *message, int length);
|
||||
|
||||
/* This routine is called when a packet is sent to a destination we
|
||||
do not recognize */
|
||||
extern void NCR_ProcessTxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
|
||||
NTP_Local_Timestamp *tx_ts, NTP_Packet *message, int length);
|
||||
|
||||
/* Slew receive and transmit times in instance records */
|
||||
extern void NCR_SlewTimes(NCR_Instance inst, struct timeval *when, double dfreq, double doffset);
|
||||
extern void NCR_SlewTimes(NCR_Instance inst, struct timespec *when, double dfreq, double doffset);
|
||||
|
||||
/* Take a particular source online (i.e. start sampling it) */
|
||||
extern void NCR_TakeSourceOnline(NCR_Instance inst);
|
||||
|
||||
/* Take a particular source offline (i.e. stop sampling it, without
|
||||
marking it unreachable in the source selection stuff) */
|
||||
extern void NCR_TakeSourceOffline(NCR_Instance inst);
|
||||
/* Take a particular source online (i.e. start sampling it) or offline
|
||||
(i.e. stop sampling it) */
|
||||
extern void NCR_SetConnectivity(NCR_Instance inst, SRC_Connectivity connectivity);
|
||||
|
||||
extern void NCR_ModifyMinpoll(NCR_Instance inst, int new_minpoll);
|
||||
|
||||
@@ -91,11 +113,15 @@ extern void NCR_ModifyMaxdelaydevratio(NCR_Instance inst, double new_max_delay_d
|
||||
|
||||
extern void NCR_ModifyMinstratum(NCR_Instance inst, int new_min_stratum);
|
||||
|
||||
extern void NCR_ModifyOffset(NCR_Instance inst, double new_offset);
|
||||
|
||||
extern void NCR_ModifyPolltarget(NCR_Instance inst, int new_poll_target);
|
||||
|
||||
extern void NCR_InitiateSampleBurst(NCR_Instance inst, int n_good_samples, int n_total_samples);
|
||||
|
||||
extern void NCR_ReportSource(NCR_Instance inst, RPT_SourceReport *report, struct timeval *now);
|
||||
extern void NCR_ReportSource(NCR_Instance inst, RPT_SourceReport *report, struct timespec *now);
|
||||
extern void NCR_GetAuthReport(NCR_Instance inst, RPT_AuthReport *report);
|
||||
extern void NCR_GetNTPReport(NCR_Instance inst, RPT_NTPReport *report);
|
||||
|
||||
extern int NCR_AddAccessRestriction(IPAddr *ip_addr, int subnet_bits, int allow, int all);
|
||||
extern int NCR_CheckAccessRestriction(IPAddr *ip_addr);
|
||||
@@ -105,8 +131,12 @@ extern void NCR_IncrementActivityCounters(NCR_Instance inst, int *online, int *o
|
||||
|
||||
extern NTP_Remote_Address *NCR_GetRemoteAddress(NCR_Instance instance);
|
||||
|
||||
extern uint32_t NCR_GetLocalRefid(NCR_Instance inst);
|
||||
|
||||
extern int NCR_IsSyncPeer(NCR_Instance instance);
|
||||
|
||||
extern void NCR_AddBroadcastDestination(IPAddr *addr, unsigned short port, int interval);
|
||||
extern void NCR_DumpAuthData(NCR_Instance inst);
|
||||
|
||||
extern void NCR_AddBroadcastDestination(NTP_Remote_Address *addr, int interval);
|
||||
|
||||
#endif /* GOT_NTP_CORE_H */
|
||||
|
||||
192
ntp_ext.c
Normal file
192
ntp_ext.c
Normal file
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2019-2020
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Functions for adding and parsing NTPv4 extension fields
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "ntp_ext.h"
|
||||
|
||||
struct ExtFieldHeader {
|
||||
uint16_t type;
|
||||
uint16_t length;
|
||||
};
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
format_field(unsigned char *buffer, int buffer_length, int start,
|
||||
int type, int body_length, int *length, void **body)
|
||||
{
|
||||
struct ExtFieldHeader *header;
|
||||
|
||||
if (buffer_length < 0 || start < 0 || buffer_length <= start ||
|
||||
buffer_length - start < sizeof (*header) || start % 4 != 0)
|
||||
return 0;
|
||||
|
||||
header = (struct ExtFieldHeader *)(buffer + start);
|
||||
|
||||
if (body_length < 0 || sizeof (*header) + body_length > 0xffff ||
|
||||
start + sizeof (*header) + body_length > buffer_length || body_length % 4 != 0)
|
||||
return 0;
|
||||
|
||||
header->type = htons(type);
|
||||
header->length = htons(sizeof (*header) + body_length);
|
||||
*length = sizeof (*header) + body_length;
|
||||
*body = header + 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NEF_SetField(unsigned char *buffer, int buffer_length, int start,
|
||||
int type, void *body, int body_length, int *length)
|
||||
{
|
||||
void *ef_body;
|
||||
|
||||
if (!format_field(buffer, buffer_length, start, type, body_length, length, &ef_body))
|
||||
return 0;
|
||||
|
||||
memcpy(ef_body, body, body_length);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NEF_AddBlankField(NTP_Packet *packet, NTP_PacketInfo *info, int type, int body_length, void **body)
|
||||
{
|
||||
int ef_length, length = info->length;
|
||||
|
||||
if (length < NTP_HEADER_LENGTH || length >= sizeof (*packet) || length % 4 != 0)
|
||||
return 0;
|
||||
|
||||
/* Only NTPv4 packets can have extension fields */
|
||||
if (info->version != 4)
|
||||
return 0;
|
||||
|
||||
if (!format_field((unsigned char *)packet, sizeof (*packet), length,
|
||||
type, body_length, &ef_length, body))
|
||||
return 0;
|
||||
|
||||
if (ef_length < NTP_MIN_EF_LENGTH)
|
||||
return 0;
|
||||
|
||||
info->length += ef_length;
|
||||
info->ext_fields++;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NEF_AddField(NTP_Packet *packet, NTP_PacketInfo *info,
|
||||
int type, void *body, int body_length)
|
||||
{
|
||||
void *ef_body;
|
||||
|
||||
if (!NEF_AddBlankField(packet, info, type, body_length, &ef_body))
|
||||
return 0;
|
||||
|
||||
memcpy(ef_body, body, body_length);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NEF_ParseSingleField(unsigned char *buffer, int buffer_length, int start,
|
||||
int *length, int *type, void **body, int *body_length)
|
||||
{
|
||||
struct ExtFieldHeader *header;
|
||||
int ef_length;
|
||||
|
||||
if (buffer_length < 0 || start < 0 || buffer_length <= start ||
|
||||
buffer_length - start < sizeof (*header))
|
||||
return 0;
|
||||
|
||||
header = (struct ExtFieldHeader *)(buffer + start);
|
||||
|
||||
assert(sizeof (*header) == 4);
|
||||
|
||||
ef_length = ntohs(header->length);
|
||||
|
||||
if (ef_length < (int)(sizeof (*header)) || start + ef_length > buffer_length ||
|
||||
ef_length % 4 != 0)
|
||||
return 0;
|
||||
|
||||
if (length)
|
||||
*length = ef_length;
|
||||
if (type)
|
||||
*type = ntohs(header->type);
|
||||
if (body)
|
||||
*body = header + 1;
|
||||
if (body_length)
|
||||
*body_length = ef_length - sizeof (*header);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NEF_ParseField(NTP_Packet *packet, int packet_length, int start,
|
||||
int *length, int *type, void **body, int *body_length)
|
||||
{
|
||||
int ef_length;
|
||||
|
||||
if (packet_length <= NTP_HEADER_LENGTH || packet_length > sizeof (*packet) ||
|
||||
packet_length <= start || packet_length % 4 != 0 ||
|
||||
start < NTP_HEADER_LENGTH || start % 4 != 0)
|
||||
return 0;
|
||||
|
||||
/* Only NTPv4 packets have extension fields */
|
||||
if (NTP_LVM_TO_VERSION(packet->lvm) != 4)
|
||||
return 0;
|
||||
|
||||
/* Check if the remaining data is a MAC. RFC 7822 specifies the maximum
|
||||
length of a MAC in NTPv4 packets in order to enable deterministic
|
||||
parsing. */
|
||||
if (packet_length - start <= NTP_MAX_V4_MAC_LENGTH)
|
||||
return 0;
|
||||
|
||||
if (!NEF_ParseSingleField((unsigned char *)packet, packet_length, start,
|
||||
&ef_length, type, body, body_length))
|
||||
return 0;
|
||||
|
||||
if (ef_length < NTP_MIN_EF_LENGTH)
|
||||
return 0;
|
||||
|
||||
if (length)
|
||||
*length = ef_length;
|
||||
|
||||
return 1;
|
||||
}
|
||||
43
ntp_ext.h
Normal file
43
ntp_ext.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2019
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Header file for NTP extension fields
|
||||
*/
|
||||
|
||||
#ifndef GOT_NTP_EXT_H
|
||||
#define GOT_NTP_EXT_H
|
||||
|
||||
#include "ntp.h"
|
||||
|
||||
extern int NEF_SetField(unsigned char *buffer, int buffer_length, int start,
|
||||
int type, void *body, int body_length, int *length);
|
||||
extern int NEF_AddBlankField(NTP_Packet *packet, NTP_PacketInfo *info, int type,
|
||||
int body_length, void **body);
|
||||
extern int NEF_AddField(NTP_Packet *packet, NTP_PacketInfo *info,
|
||||
int type, void *body, int body_length);
|
||||
extern int NEF_ParseSingleField(unsigned char *buffer, int buffer_length, int start,
|
||||
int *length, int *type, void **body, int *body_length);
|
||||
extern int NEF_ParseField(NTP_Packet *packet, int packet_length, int start,
|
||||
int *length, int *type, void **body, int *body_length);
|
||||
|
||||
#endif
|
||||
18
ntp_io.h
18
ntp_io.h
@@ -31,13 +31,17 @@
|
||||
|
||||
#include "ntp.h"
|
||||
#include "addressing.h"
|
||||
#include "socket.h"
|
||||
|
||||
/* Function to initialise the module. */
|
||||
extern void NIO_Initialise(int family);
|
||||
extern void NIO_Initialise(void);
|
||||
|
||||
/* Function to finalise the module */
|
||||
extern void NIO_Finalise(void);
|
||||
|
||||
/* Function to check if HW timestamping is enabled on any interface */
|
||||
extern int NIO_IsHwTsEnabled(void);
|
||||
|
||||
/* Function to obtain a socket for sending client packets */
|
||||
extern int NIO_OpenClientSocket(NTP_Remote_Address *remote_addr);
|
||||
|
||||
@@ -53,7 +57,17 @@ extern void NIO_CloseServerSocket(int sock_fd);
|
||||
/* Function to check if socket is a server socket */
|
||||
extern int NIO_IsServerSocket(int sock_fd);
|
||||
|
||||
/* Function to check if a server socket is currently open */
|
||||
extern int NIO_IsServerSocketOpen(void);
|
||||
|
||||
/* Function to check if client packets can be sent to a server */
|
||||
extern int NIO_IsServerConnectable(NTP_Remote_Address *remote_addr);
|
||||
|
||||
/* Function to unwrap an NTP message from non-native transport (e.g. PTP) */
|
||||
extern int NIO_UnwrapMessage(SCK_Message *message, int sock_fd, double *net_correction);
|
||||
|
||||
/* Function to transmit a packet */
|
||||
extern int NIO_SendPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int length);
|
||||
extern int NIO_SendPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr,
|
||||
NTP_Local_Address *local_addr, int length, int process_tx);
|
||||
|
||||
#endif /* GOT_NTP_IO_H */
|
||||
|
||||
816
ntp_io_linux.c
Normal file
816
ntp_io_linux.c
Normal file
@@ -0,0 +1,816 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2016-2019, 2021-2023
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Functions for NTP I/O specific to Linux
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include <ifaddrs.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/net_tstamp.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include "array.h"
|
||||
#include "conf.h"
|
||||
#include "hwclock.h"
|
||||
#include "local.h"
|
||||
#include "logging.h"
|
||||
#include "memory.h"
|
||||
#include "ntp_core.h"
|
||||
#include "ntp_io.h"
|
||||
#include "ntp_io_linux.h"
|
||||
#include "ntp_sources.h"
|
||||
#include "sched.h"
|
||||
#include "socket.h"
|
||||
#include "sys_linux.h"
|
||||
#include "util.h"
|
||||
|
||||
struct Interface {
|
||||
char name[IF_NAMESIZE];
|
||||
int if_index;
|
||||
int phc_fd;
|
||||
int phc_mode;
|
||||
int phc_nocrossts;
|
||||
/* Link speed in mbit/s */
|
||||
int link_speed;
|
||||
/* Start of UDP data at layer 2 for IPv4 and IPv6 */
|
||||
int l2_udp4_ntp_start;
|
||||
int l2_udp6_ntp_start;
|
||||
/* Compensation of errors in TX and RX timestamping */
|
||||
double tx_comp;
|
||||
double rx_comp;
|
||||
HCL_Instance clock;
|
||||
int maxpoll;
|
||||
SCH_TimeoutID poll_timeout_id;
|
||||
};
|
||||
|
||||
/* Number of PHC readings per HW clock sample */
|
||||
#define PHC_READINGS 25
|
||||
|
||||
/* Minimum and maximum interval between PHC readings */
|
||||
#define MIN_PHC_POLL -6
|
||||
#define MAX_PHC_POLL 20
|
||||
|
||||
/* Maximum acceptable offset between SW/HW and daemon timestamp */
|
||||
#define MAX_TS_DELAY 1.0
|
||||
|
||||
/* Array of Interfaces */
|
||||
static ARR_Instance interfaces;
|
||||
|
||||
/* RX/TX and TX-specific timestamping socket options */
|
||||
static int ts_flags;
|
||||
static int ts_tx_flags;
|
||||
|
||||
/* Flag indicating the socket options can't be changed in control messages */
|
||||
static int permanent_ts_options;
|
||||
|
||||
/* Unbound socket keeping the kernel RX timestamping permanently enabled
|
||||
in order to avoid a race condition between receiving a server response
|
||||
and the kernel actually starting to timestamp received packets after
|
||||
enabling the timestamping and sending a request */
|
||||
static int dummy_rxts_socket;
|
||||
|
||||
#define INVALID_SOCK_FD -3
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void poll_phc(struct Interface *iface, struct timespec *now);
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
add_interface(CNF_HwTsInterface *conf_iface)
|
||||
{
|
||||
int sock_fd, if_index, minpoll, phc_fd, req_hwts_flags, rx_filter;
|
||||
struct ethtool_ts_info ts_info;
|
||||
struct hwtstamp_config ts_config;
|
||||
struct ifreq req;
|
||||
unsigned int i;
|
||||
struct Interface *iface;
|
||||
|
||||
/* Check if the interface was not already added */
|
||||
for (i = 0; i < ARR_GetSize(interfaces); i++) {
|
||||
if (!strcmp(conf_iface->name, ((struct Interface *)ARR_GetElement(interfaces, i))->name))
|
||||
return 1;
|
||||
}
|
||||
|
||||
sock_fd = SCK_OpenUdpSocket(NULL, NULL, NULL, 0);
|
||||
if (sock_fd < 0)
|
||||
return 0;
|
||||
|
||||
memset(&req, 0, sizeof (req));
|
||||
memset(&ts_info, 0, sizeof (ts_info));
|
||||
|
||||
if (snprintf(req.ifr_name, sizeof (req.ifr_name), "%s", conf_iface->name) >=
|
||||
sizeof (req.ifr_name)) {
|
||||
SCK_CloseSocket(sock_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ioctl(sock_fd, SIOCGIFINDEX, &req)) {
|
||||
DEBUG_LOG("ioctl(%s) failed : %s", "SIOCGIFINDEX", strerror(errno));
|
||||
SCK_CloseSocket(sock_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if_index = req.ifr_ifindex;
|
||||
|
||||
ts_info.cmd = ETHTOOL_GET_TS_INFO;
|
||||
req.ifr_data = (char *)&ts_info;
|
||||
|
||||
if (ioctl(sock_fd, SIOCETHTOOL, &req)) {
|
||||
DEBUG_LOG("ioctl(%s) failed : %s", "SIOCETHTOOL", strerror(errno));
|
||||
SCK_CloseSocket(sock_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
req_hwts_flags = SOF_TIMESTAMPING_RX_HARDWARE | SOF_TIMESTAMPING_TX_HARDWARE |
|
||||
SOF_TIMESTAMPING_RAW_HARDWARE;
|
||||
if ((ts_info.so_timestamping & req_hwts_flags) != req_hwts_flags) {
|
||||
DEBUG_LOG("HW timestamping not supported on %s", req.ifr_name);
|
||||
SCK_CloseSocket(sock_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ts_info.phc_index < 0) {
|
||||
DEBUG_LOG("PHC missing on %s", req.ifr_name);
|
||||
SCK_CloseSocket(sock_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (conf_iface->rxfilter) {
|
||||
case CNF_HWTS_RXFILTER_ANY:
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING_RXFILTER_NTP
|
||||
if (ts_info.rx_filters & (1 << HWTSTAMP_FILTER_NTP_ALL))
|
||||
rx_filter = HWTSTAMP_FILTER_NTP_ALL;
|
||||
else
|
||||
#endif
|
||||
if (ts_info.rx_filters & (1 << HWTSTAMP_FILTER_ALL))
|
||||
rx_filter = HWTSTAMP_FILTER_ALL;
|
||||
else
|
||||
rx_filter = HWTSTAMP_FILTER_NONE;
|
||||
break;
|
||||
case CNF_HWTS_RXFILTER_NONE:
|
||||
rx_filter = HWTSTAMP_FILTER_NONE;
|
||||
break;
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING_RXFILTER_NTP
|
||||
case CNF_HWTS_RXFILTER_NTP:
|
||||
rx_filter = HWTSTAMP_FILTER_NTP_ALL;
|
||||
break;
|
||||
#endif
|
||||
case CNF_HWTS_RXFILTER_PTP:
|
||||
if (ts_info.rx_filters & (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT))
|
||||
rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT;
|
||||
else if (ts_info.rx_filters & (1 << HWTSTAMP_FILTER_PTP_V2_EVENT))
|
||||
rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
|
||||
else
|
||||
rx_filter = HWTSTAMP_FILTER_NONE;
|
||||
break;
|
||||
default:
|
||||
rx_filter = HWTSTAMP_FILTER_ALL;
|
||||
break;
|
||||
}
|
||||
|
||||
ts_config.flags = 0;
|
||||
ts_config.tx_type = HWTSTAMP_TX_ON;
|
||||
ts_config.rx_filter = rx_filter;
|
||||
req.ifr_data = (char *)&ts_config;
|
||||
|
||||
if (ioctl(sock_fd, SIOCSHWTSTAMP, &req)) {
|
||||
LOG(errno == EPERM ? LOGS_ERR : LOGS_DEBUG,
|
||||
"ioctl(%s) failed : %s", "SIOCSHWTSTAMP", strerror(errno));
|
||||
|
||||
/* Check the current timestamping configuration in case this interface
|
||||
allows only reading of the configuration and it was already configured
|
||||
as requested */
|
||||
req.ifr_data = (char *)&ts_config;
|
||||
#ifdef SIOCGHWTSTAMP
|
||||
if (ioctl(sock_fd, SIOCGHWTSTAMP, &req) ||
|
||||
ts_config.tx_type != HWTSTAMP_TX_ON || ts_config.rx_filter != rx_filter)
|
||||
#endif
|
||||
{
|
||||
SCK_CloseSocket(sock_fd);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
SCK_CloseSocket(sock_fd);
|
||||
|
||||
phc_fd = SYS_Linux_OpenPHC(req.ifr_name, O_RDONLY);
|
||||
if (phc_fd < 0)
|
||||
return 0;
|
||||
|
||||
iface = ARR_GetNewElement(interfaces);
|
||||
|
||||
snprintf(iface->name, sizeof (iface->name), "%s", conf_iface->name);
|
||||
iface->if_index = if_index;
|
||||
iface->phc_fd = phc_fd;
|
||||
iface->phc_mode = 0;
|
||||
iface->phc_nocrossts = conf_iface->nocrossts;
|
||||
|
||||
/* Start with 1 gbit and no VLANs or IPv4/IPv6 options */
|
||||
iface->link_speed = 1000;
|
||||
iface->l2_udp4_ntp_start = 42;
|
||||
iface->l2_udp6_ntp_start = 62;
|
||||
|
||||
iface->tx_comp = conf_iface->tx_comp;
|
||||
iface->rx_comp = conf_iface->rx_comp;
|
||||
|
||||
minpoll = CLAMP(MIN_PHC_POLL, conf_iface->minpoll, MAX_PHC_POLL);
|
||||
iface->clock = HCL_CreateInstance(conf_iface->min_samples, conf_iface->max_samples,
|
||||
UTI_Log2ToDouble(minpoll), conf_iface->precision);
|
||||
|
||||
iface->maxpoll = CLAMP(minpoll, conf_iface->maxpoll, MAX_PHC_POLL);
|
||||
|
||||
/* Do not schedule the first poll timeout here! The argument (interface) can
|
||||
move until all interfaces are added. Wait for the first HW timestamp. */
|
||||
iface->poll_timeout_id = 0;
|
||||
|
||||
LOG(LOGS_INFO, "Enabled HW timestamping %son %s",
|
||||
ts_config.rx_filter == HWTSTAMP_FILTER_NONE ? "(TX only) " : "", iface->name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
add_all_interfaces(CNF_HwTsInterface *conf_iface_all)
|
||||
{
|
||||
CNF_HwTsInterface conf_iface;
|
||||
struct ifaddrs *ifaddr, *ifa;
|
||||
int r;
|
||||
|
||||
conf_iface = *conf_iface_all;
|
||||
|
||||
if (getifaddrs(&ifaddr)) {
|
||||
DEBUG_LOG("getifaddrs() failed : %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (r = 0, ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
|
||||
conf_iface.name = ifa->ifa_name;
|
||||
if (add_interface(&conf_iface))
|
||||
r = 1;
|
||||
}
|
||||
|
||||
freeifaddrs(ifaddr);
|
||||
|
||||
/* Return success if at least one interface was added */
|
||||
return r;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
update_interface_speed(struct Interface *iface)
|
||||
{
|
||||
struct ethtool_cmd cmd;
|
||||
struct ifreq req;
|
||||
int sock_fd, link_speed;
|
||||
|
||||
sock_fd = SCK_OpenUdpSocket(NULL, NULL, NULL, 0);
|
||||
if (sock_fd < 0)
|
||||
return;
|
||||
|
||||
memset(&req, 0, sizeof (req));
|
||||
memset(&cmd, 0, sizeof (cmd));
|
||||
|
||||
snprintf(req.ifr_name, sizeof (req.ifr_name), "%s", iface->name);
|
||||
cmd.cmd = ETHTOOL_GSET;
|
||||
req.ifr_data = (char *)&cmd;
|
||||
|
||||
if (ioctl(sock_fd, SIOCETHTOOL, &req)) {
|
||||
DEBUG_LOG("ioctl(%s) failed : %s", "SIOCETHTOOL", strerror(errno));
|
||||
SCK_CloseSocket(sock_fd);
|
||||
return;
|
||||
}
|
||||
|
||||
SCK_CloseSocket(sock_fd);
|
||||
|
||||
link_speed = ethtool_cmd_speed(&cmd);
|
||||
|
||||
if (iface->link_speed != link_speed) {
|
||||
iface->link_speed = link_speed;
|
||||
DEBUG_LOG("Updated speed of %s to %d Mb/s", iface->name, link_speed);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#if defined(HAVE_LINUX_TIMESTAMPING_OPT_PKTINFO) || defined(HAVE_LINUX_TIMESTAMPING_OPT_TX_SWHW)
|
||||
static int
|
||||
check_timestamping_option(int option)
|
||||
{
|
||||
int sock_fd;
|
||||
|
||||
sock_fd = SCK_OpenUdpSocket(NULL, NULL, NULL, 0);
|
||||
if (sock_fd < 0)
|
||||
return 0;
|
||||
|
||||
if (!SCK_SetIntOption(sock_fd, SOL_SOCKET, SO_TIMESTAMPING, option)) {
|
||||
SCK_CloseSocket(sock_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SCK_CloseSocket(sock_fd);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
open_dummy_socket(void)
|
||||
{
|
||||
int sock_fd, events = 0;
|
||||
|
||||
sock_fd = SCK_OpenUdpSocket(NULL, NULL, NULL, 0);
|
||||
if (sock_fd < 0)
|
||||
return INVALID_SOCK_FD;
|
||||
|
||||
if (!NIO_Linux_SetTimestampSocketOptions(sock_fd, 1, &events)) {
|
||||
SCK_CloseSocket(sock_fd);
|
||||
return INVALID_SOCK_FD;
|
||||
}
|
||||
|
||||
return sock_fd;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NIO_Linux_Initialise(void)
|
||||
{
|
||||
CNF_HwTsInterface *conf_iface;
|
||||
unsigned int i;
|
||||
int hwts;
|
||||
|
||||
interfaces = ARR_CreateInstance(sizeof (struct Interface));
|
||||
|
||||
/* Enable HW timestamping on specified interfaces. If "*" was specified, try
|
||||
all interfaces. If no interface was specified, enable SW timestamping. */
|
||||
|
||||
for (i = hwts = 0; CNF_GetHwTsInterface(i, &conf_iface); i++) {
|
||||
if (!strcmp("*", conf_iface->name))
|
||||
continue;
|
||||
if (!add_interface(conf_iface))
|
||||
LOG_FATAL("Could not enable HW timestamping on %s", conf_iface->name);
|
||||
hwts = 1;
|
||||
}
|
||||
|
||||
for (i = 0; CNF_GetHwTsInterface(i, &conf_iface); i++) {
|
||||
if (strcmp("*", conf_iface->name))
|
||||
continue;
|
||||
if (add_all_interfaces(conf_iface))
|
||||
hwts = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
ts_flags = SOF_TIMESTAMPING_SOFTWARE | SOF_TIMESTAMPING_RX_SOFTWARE;
|
||||
ts_tx_flags = SOF_TIMESTAMPING_TX_SOFTWARE;
|
||||
|
||||
if (hwts) {
|
||||
ts_flags |= SOF_TIMESTAMPING_RAW_HARDWARE | SOF_TIMESTAMPING_RX_HARDWARE;
|
||||
ts_tx_flags |= SOF_TIMESTAMPING_TX_HARDWARE;
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING_OPT_PKTINFO
|
||||
if (check_timestamping_option(SOF_TIMESTAMPING_OPT_PKTINFO))
|
||||
ts_flags |= SOF_TIMESTAMPING_OPT_PKTINFO;
|
||||
#endif
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING_OPT_TX_SWHW
|
||||
if (check_timestamping_option(SOF_TIMESTAMPING_OPT_TX_SWHW))
|
||||
ts_flags |= SOF_TIMESTAMPING_OPT_TX_SWHW;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Enable IP_PKTINFO in messages looped back to the error queue */
|
||||
ts_flags |= SOF_TIMESTAMPING_OPT_CMSG;
|
||||
|
||||
/* Kernels before 4.7 ignore timestamping flags set in control messages */
|
||||
permanent_ts_options = !SYS_Linux_CheckKernelVersion(4, 7);
|
||||
|
||||
dummy_rxts_socket = INVALID_SOCK_FD;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NIO_Linux_Finalise(void)
|
||||
{
|
||||
struct Interface *iface;
|
||||
unsigned int i;
|
||||
|
||||
if (dummy_rxts_socket != INVALID_SOCK_FD)
|
||||
SCK_CloseSocket(dummy_rxts_socket);
|
||||
|
||||
for (i = 0; i < ARR_GetSize(interfaces); i++) {
|
||||
iface = ARR_GetElement(interfaces, i);
|
||||
SCH_RemoveTimeout(iface->poll_timeout_id);
|
||||
HCL_DestroyInstance(iface->clock);
|
||||
close(iface->phc_fd);
|
||||
}
|
||||
|
||||
ARR_DestroyInstance(interfaces);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NIO_Linux_IsHwTsEnabled(void)
|
||||
{
|
||||
return ARR_GetSize(interfaces) > 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NIO_Linux_SetTimestampSocketOptions(int sock_fd, int client_only, int *events)
|
||||
{
|
||||
int val, flags;
|
||||
|
||||
if (!ts_flags)
|
||||
return 0;
|
||||
|
||||
/* Enable SCM_TIMESTAMPING control messages and the socket's error queue in
|
||||
order to receive our transmitted packets with more accurate timestamps */
|
||||
|
||||
val = 1;
|
||||
flags = ts_flags;
|
||||
|
||||
if (client_only || permanent_ts_options)
|
||||
flags |= ts_tx_flags;
|
||||
|
||||
if (!SCK_SetIntOption(sock_fd, SOL_SOCKET, SO_SELECT_ERR_QUEUE, val)) {
|
||||
ts_flags = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!SCK_SetIntOption(sock_fd, SOL_SOCKET, SO_TIMESTAMPING, flags)) {
|
||||
ts_flags = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*events |= SCH_FILE_EXCEPTION;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static struct Interface *
|
||||
get_interface(int if_index)
|
||||
{
|
||||
struct Interface *iface;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARR_GetSize(interfaces); i++) {
|
||||
iface = ARR_GetElement(interfaces, i);
|
||||
if (iface->if_index != if_index)
|
||||
continue;
|
||||
|
||||
return iface;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
poll_timeout(void *arg)
|
||||
{
|
||||
struct Interface *iface = arg;
|
||||
struct timespec now;
|
||||
|
||||
iface->poll_timeout_id = 0;
|
||||
|
||||
SCH_GetLastEventTime(&now, NULL, NULL);
|
||||
poll_phc(iface, &now);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
poll_phc(struct Interface *iface, struct timespec *now)
|
||||
{
|
||||
struct timespec sample_phc_ts, sample_sys_ts, sample_local_ts;
|
||||
struct timespec phc_readings[PHC_READINGS][3];
|
||||
double phc_err, local_err, interval;
|
||||
int n_readings, quality;
|
||||
|
||||
if (!HCL_NeedsNewSample(iface->clock, now))
|
||||
return;
|
||||
|
||||
DEBUG_LOG("Polling PHC on %s%s",
|
||||
iface->name, iface->poll_timeout_id != 0 ? " before timeout" : "");
|
||||
|
||||
n_readings = SYS_Linux_GetPHCReadings(iface->phc_fd, iface->phc_nocrossts,
|
||||
&iface->phc_mode, PHC_READINGS, phc_readings);
|
||||
|
||||
/* Add timeout for the next poll in case no HW timestamp will be captured
|
||||
between the minpoll and maxpoll. Separate reading of different PHCs to
|
||||
avoid long intervals between handling I/O events. */
|
||||
SCH_RemoveTimeout(iface->poll_timeout_id);
|
||||
interval = UTI_Log2ToDouble(iface->maxpoll);
|
||||
iface->poll_timeout_id = SCH_AddTimeoutInClass(interval, interval /
|
||||
ARR_GetSize(interfaces) / 4, 0.1,
|
||||
SCH_PhcPollClass, poll_timeout, iface);
|
||||
|
||||
if (n_readings <= 0)
|
||||
return;
|
||||
|
||||
if (!HCL_ProcessReadings(iface->clock, n_readings, phc_readings,
|
||||
&sample_phc_ts, &sample_sys_ts, &phc_err, &quality) ||
|
||||
quality <= 0)
|
||||
return;
|
||||
|
||||
LCL_CookTime(&sample_sys_ts, &sample_local_ts, &local_err);
|
||||
HCL_AccumulateSample(iface->clock, &sample_phc_ts, &sample_local_ts, phc_err + local_err);
|
||||
|
||||
update_interface_speed(iface);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
process_hw_timestamp(struct Interface *iface, struct timespec *hw_ts,
|
||||
NTP_Local_Timestamp *local_ts, int rx_ntp_length, int family,
|
||||
int l2_length)
|
||||
{
|
||||
double rx_correction = 0.0, ts_delay, local_err;
|
||||
struct timespec ts;
|
||||
|
||||
poll_phc(iface, &local_ts->ts);
|
||||
|
||||
/* We need to transpose RX timestamps as hardware timestamps are normally
|
||||
preamble timestamps and RX timestamps in NTP are supposed to be trailer
|
||||
timestamps. If we don't know the length of the packet at layer 2, we
|
||||
make an assumption that UDP data start at the same position as in the
|
||||
last transmitted packet which had a HW TX timestamp. */
|
||||
if (rx_ntp_length && iface->link_speed) {
|
||||
if (!l2_length)
|
||||
l2_length = (family == IPADDR_INET4 ? iface->l2_udp4_ntp_start :
|
||||
iface->l2_udp6_ntp_start) + rx_ntp_length;
|
||||
|
||||
/* Include the frame check sequence (FCS) */
|
||||
l2_length += 4;
|
||||
|
||||
rx_correction = l2_length / (1.0e6 / 8 * iface->link_speed);
|
||||
|
||||
UTI_AddDoubleToTimespec(hw_ts, rx_correction, hw_ts);
|
||||
}
|
||||
|
||||
if (!HCL_CookTime(iface->clock, hw_ts, &ts, &local_err))
|
||||
return;
|
||||
|
||||
if (!rx_ntp_length && iface->tx_comp)
|
||||
UTI_AddDoubleToTimespec(&ts, iface->tx_comp, &ts);
|
||||
else if (rx_ntp_length && iface->rx_comp)
|
||||
UTI_AddDoubleToTimespec(&ts, -iface->rx_comp, &ts);
|
||||
|
||||
ts_delay = UTI_DiffTimespecsToDouble(&local_ts->ts, &ts);
|
||||
|
||||
if (fabs(ts_delay) > MAX_TS_DELAY) {
|
||||
DEBUG_LOG("Unacceptable timestamp delay %.9f", ts_delay);
|
||||
return;
|
||||
}
|
||||
|
||||
local_ts->ts = ts;
|
||||
local_ts->err = local_err;
|
||||
local_ts->source = NTP_TS_HARDWARE;
|
||||
local_ts->rx_duration = rx_correction;
|
||||
/* Network correction needs to include the RX duration to avoid
|
||||
asymmetric correction with asymmetric link speeds */
|
||||
local_ts->net_correction = rx_correction;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
process_sw_timestamp(struct timespec *sw_ts, NTP_Local_Timestamp *local_ts)
|
||||
{
|
||||
double ts_delay, local_err;
|
||||
struct timespec ts;
|
||||
|
||||
LCL_CookTime(sw_ts, &ts, &local_err);
|
||||
|
||||
ts_delay = UTI_DiffTimespecsToDouble(&local_ts->ts, &ts);
|
||||
|
||||
if (fabs(ts_delay) > MAX_TS_DELAY) {
|
||||
DEBUG_LOG("Unacceptable timestamp delay %.9f", ts_delay);
|
||||
return;
|
||||
}
|
||||
|
||||
local_ts->ts = ts;
|
||||
local_ts->err = local_err;
|
||||
local_ts->source = NTP_TS_KERNEL;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Extract UDP data from a layer 2 message. Supported is Ethernet
|
||||
with optional VLAN tags. */
|
||||
|
||||
static int
|
||||
extract_udp_data(unsigned char *msg, NTP_Remote_Address *remote_addr, int len)
|
||||
{
|
||||
unsigned char *msg_start = msg;
|
||||
|
||||
remote_addr->ip_addr.family = IPADDR_UNSPEC;
|
||||
remote_addr->port = 0;
|
||||
|
||||
/* Skip MACs */
|
||||
if (len < 12)
|
||||
return 0;
|
||||
len -= 12, msg += 12;
|
||||
|
||||
/* Skip VLAN tag(s) if present */
|
||||
while (len >= 4 && msg[0] == 0x81 && msg[1] == 0x00)
|
||||
len -= 4, msg += 4;
|
||||
|
||||
/* Skip IPv4 or IPv6 ethertype */
|
||||
if (len < 2 || !((msg[0] == 0x08 && msg[1] == 0x00) ||
|
||||
(msg[0] == 0x86 && msg[1] == 0xdd)))
|
||||
return 0;
|
||||
len -= 2, msg += 2;
|
||||
|
||||
/* Parse destination address and port from IPv4/IPv6 and UDP headers */
|
||||
if (len >= 20 && msg[0] >> 4 == 4) {
|
||||
int ihl = (msg[0] & 0xf) * 4;
|
||||
uint32_t addr;
|
||||
|
||||
if (len < ihl + 8 || msg[9] != 17)
|
||||
return 0;
|
||||
|
||||
memcpy(&addr, msg + 16, sizeof (addr));
|
||||
remote_addr->ip_addr.addr.in4 = ntohl(addr);
|
||||
remote_addr->port = ntohs(*(uint16_t *)(msg + ihl + 2));
|
||||
remote_addr->ip_addr.family = IPADDR_INET4;
|
||||
len -= ihl + 8, msg += ihl + 8;
|
||||
#ifdef FEAT_IPV6
|
||||
} else if (len >= 48 && msg[0] >> 4 == 6) {
|
||||
int eh_len, next_header = msg[6];
|
||||
|
||||
memcpy(&remote_addr->ip_addr.addr.in6, msg + 24, sizeof (remote_addr->ip_addr.addr.in6));
|
||||
len -= 40, msg += 40;
|
||||
|
||||
/* Skip IPv6 extension headers if present */
|
||||
while (next_header != 17) {
|
||||
switch (next_header) {
|
||||
case 44: /* Fragment Header */
|
||||
/* Process only the first fragment */
|
||||
if (ntohs(*(uint16_t *)(msg + 2)) >> 3 != 0)
|
||||
return 0;
|
||||
eh_len = 8;
|
||||
break;
|
||||
case 0: /* Hop-by-Hop Options */
|
||||
case 43: /* Routing Header */
|
||||
case 60: /* Destination Options */
|
||||
case 135: /* Mobility Header */
|
||||
eh_len = 8 * (msg[1] + 1);
|
||||
break;
|
||||
case 51: /* Authentication Header */
|
||||
eh_len = 4 * (msg[1] + 2);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (eh_len < 8 || len < eh_len + 8)
|
||||
return 0;
|
||||
|
||||
next_header = msg[0];
|
||||
len -= eh_len, msg += eh_len;
|
||||
}
|
||||
|
||||
remote_addr->port = ntohs(*(uint16_t *)(msg + 2));
|
||||
remote_addr->ip_addr.family = IPADDR_INET6;
|
||||
len -= 8, msg += 8;
|
||||
#endif
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Move the message to fix alignment of its fields */
|
||||
if (len > 0)
|
||||
memmove(msg_start, msg, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NIO_Linux_ProcessMessage(SCK_Message *message, NTP_Local_Address *local_addr,
|
||||
NTP_Local_Timestamp *local_ts, int event)
|
||||
{
|
||||
struct Interface *iface;
|
||||
int is_tx, ts_if_index, l2_length;
|
||||
double c = 0.0;
|
||||
|
||||
is_tx = event == SCH_FILE_EXCEPTION;
|
||||
iface = NULL;
|
||||
|
||||
ts_if_index = message->timestamp.if_index;
|
||||
if (ts_if_index == INVALID_IF_INDEX)
|
||||
ts_if_index = message->if_index;
|
||||
l2_length = message->timestamp.l2_length;
|
||||
|
||||
if (!UTI_IsZeroTimespec(&message->timestamp.hw)) {
|
||||
iface = get_interface(ts_if_index);
|
||||
if (iface) {
|
||||
process_hw_timestamp(iface, &message->timestamp.hw, local_ts, !is_tx ? message->length : 0,
|
||||
message->remote_addr.ip.ip_addr.family, l2_length);
|
||||
} else {
|
||||
DEBUG_LOG("HW clock not found for interface %d", ts_if_index);
|
||||
}
|
||||
}
|
||||
|
||||
if (local_ts->source == NTP_TS_DAEMON && !UTI_IsZeroTimespec(&message->timestamp.kernel) &&
|
||||
(!is_tx || UTI_IsZeroTimespec(&message->timestamp.hw))) {
|
||||
process_sw_timestamp(&message->timestamp.kernel, local_ts);
|
||||
}
|
||||
|
||||
/* If the kernel is slow with enabling RX timestamping, open a dummy
|
||||
socket to keep the kernel RX timestamping permanently enabled */
|
||||
if (!is_tx && local_ts->source == NTP_TS_DAEMON && ts_flags) {
|
||||
DEBUG_LOG("Missing kernel RX timestamp");
|
||||
if (dummy_rxts_socket == INVALID_SOCK_FD)
|
||||
dummy_rxts_socket = open_dummy_socket();
|
||||
}
|
||||
|
||||
/* Return the message if it's not received from the error queue */
|
||||
if (!is_tx)
|
||||
return 0;
|
||||
|
||||
/* The data from the error queue includes all layers up to UDP. We have to
|
||||
extract the UDP data and also the destination address with port as there
|
||||
currently doesn't seem to be a better way to get them both. */
|
||||
l2_length = message->length;
|
||||
message->length = extract_udp_data(message->data, &message->remote_addr.ip, message->length);
|
||||
|
||||
DEBUG_LOG("Extracted message for %s fd=%d len=%d",
|
||||
UTI_IPSockAddrToString(&message->remote_addr.ip),
|
||||
local_addr->sock_fd, message->length);
|
||||
|
||||
/* Update assumed position of UDP data at layer 2 for next received packet */
|
||||
if (iface && message->length) {
|
||||
if (message->remote_addr.ip.ip_addr.family == IPADDR_INET4)
|
||||
iface->l2_udp4_ntp_start = l2_length - message->length;
|
||||
else if (message->remote_addr.ip.ip_addr.family == IPADDR_INET6)
|
||||
iface->l2_udp6_ntp_start = l2_length - message->length;
|
||||
}
|
||||
|
||||
/* Drop the message if it has no timestamp or its processing failed */
|
||||
if (local_ts->source == NTP_TS_DAEMON) {
|
||||
DEBUG_LOG("Missing TX timestamp");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!NIO_UnwrapMessage(message, local_addr->sock_fd, &c))
|
||||
return 1;
|
||||
|
||||
if (message->length < NTP_HEADER_LENGTH || message->length > sizeof (NTP_Packet))
|
||||
return 1;
|
||||
|
||||
NSR_ProcessTx(&message->remote_addr.ip, local_addr, local_ts, message->data, message->length);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NIO_Linux_RequestTxTimestamp(SCK_Message *message, int sock_fd)
|
||||
{
|
||||
if (!ts_flags)
|
||||
return;
|
||||
|
||||
/* Check if TX timestamping is disabled on this socket */
|
||||
if (permanent_ts_options || !NIO_IsServerSocket(sock_fd))
|
||||
return;
|
||||
|
||||
message->timestamp.tx_flags = ts_tx_flags;
|
||||
}
|
||||
45
ntp_io_linux.h
Normal file
45
ntp_io_linux.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2016
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
This is the header file for the Linux-specific NTP socket I/O bits.
|
||||
*/
|
||||
|
||||
#ifndef GOT_NTP_IO_LINUX_H
|
||||
#define GOT_NTP_IO_LINUX_H
|
||||
|
||||
#include "socket.h"
|
||||
|
||||
extern void NIO_Linux_Initialise(void);
|
||||
|
||||
extern void NIO_Linux_Finalise(void);
|
||||
|
||||
extern int NIO_Linux_IsHwTsEnabled(void);
|
||||
|
||||
extern int NIO_Linux_SetTimestampSocketOptions(int sock_fd, int client_only, int *events);
|
||||
|
||||
extern int NIO_Linux_ProcessMessage(SCK_Message *message, NTP_Local_Address *local_addr,
|
||||
NTP_Local_Timestamp *local_ts, int event);
|
||||
|
||||
extern void NIO_Linux_RequestTxTimestamp(SCK_Message *message, int sock_fd);
|
||||
|
||||
#endif
|
||||
354
ntp_signd.c
Normal file
354
ntp_signd.c
Normal file
@@ -0,0 +1,354 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2016
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Support for MS-SNTP authentication in Samba (ntp_signd)
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "array.h"
|
||||
#include "conf.h"
|
||||
#include "logging.h"
|
||||
#include "ntp_io.h"
|
||||
#include "ntp_signd.h"
|
||||
#include "sched.h"
|
||||
#include "socket.h"
|
||||
#include "util.h"
|
||||
|
||||
/* Declarations per samba/source4/librpc/idl/ntp_signd.idl */
|
||||
|
||||
#define SIGND_VERSION 0
|
||||
|
||||
typedef enum {
|
||||
SIGN_TO_CLIENT = 0,
|
||||
ASK_SERVER_TO_SIGN = 1,
|
||||
CHECK_SERVER_SIGNATURE = 2,
|
||||
SIGNING_SUCCESS = 3,
|
||||
SIGNING_FAILURE = 4,
|
||||
} SigndOp;
|
||||
|
||||
typedef struct {
|
||||
uint32_t length;
|
||||
uint32_t version;
|
||||
uint32_t op;
|
||||
uint16_t packet_id;
|
||||
uint16_t _pad;
|
||||
uint32_t key_id;
|
||||
NTP_Packet packet_to_sign;
|
||||
} SigndRequest;
|
||||
|
||||
typedef struct {
|
||||
uint32_t length;
|
||||
uint32_t version;
|
||||
uint32_t op;
|
||||
uint32_t packet_id;
|
||||
NTP_Packet signed_packet;
|
||||
} SigndResponse;
|
||||
|
||||
typedef struct {
|
||||
NTP_Remote_Address remote_addr;
|
||||
NTP_Local_Address local_addr;
|
||||
|
||||
int sent;
|
||||
int received;
|
||||
int request_length;
|
||||
struct timespec request_ts;
|
||||
SigndRequest request;
|
||||
SigndResponse response;
|
||||
} SignInstance;
|
||||
|
||||
/* As the communication with ntp_signd is asynchronous, incoming packets are
|
||||
saved in a queue in order to avoid loss when they come in bursts */
|
||||
|
||||
#define MAX_QUEUE_LENGTH 16U
|
||||
#define NEXT_QUEUE_INDEX(index) (((index) + 1) % MAX_QUEUE_LENGTH)
|
||||
#define IS_QUEUE_EMPTY() (queue_head == queue_tail)
|
||||
|
||||
/* Fixed-size array of SignInstance */
|
||||
static ARR_Instance queue;
|
||||
static unsigned int queue_head;
|
||||
static unsigned int queue_tail;
|
||||
|
||||
#define INVALID_SOCK_FD (-6)
|
||||
|
||||
/* Unix domain socket connected to ntp_signd */
|
||||
static int sock_fd;
|
||||
|
||||
/* Flag indicating if the MS-SNTP authentication is enabled */
|
||||
static int enabled;
|
||||
|
||||
/* Flag limiting logging of connection error messages */
|
||||
static int logged_connection_error;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void read_write_socket(int sock_fd, int event, void *anything);
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
close_socket(void)
|
||||
{
|
||||
SCH_RemoveFileHandler(sock_fd);
|
||||
SCK_CloseSocket(sock_fd);
|
||||
sock_fd = INVALID_SOCK_FD;
|
||||
|
||||
/* Empty the queue */
|
||||
queue_head = queue_tail = 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
open_socket(void)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
|
||||
if (sock_fd != INVALID_SOCK_FD)
|
||||
return 1;
|
||||
|
||||
if (snprintf(path, sizeof (path), "%s/socket", CNF_GetNtpSigndSocket()) >= sizeof (path)) {
|
||||
DEBUG_LOG("signd socket path too long");
|
||||
return 0;
|
||||
}
|
||||
|
||||
sock_fd = SCK_OpenUnixStreamSocket(path, NULL, 0);
|
||||
if (sock_fd < 0) {
|
||||
sock_fd = INVALID_SOCK_FD;
|
||||
|
||||
/* Log an error only once before a successful exchange to avoid
|
||||
flooding the system log */
|
||||
if (!logged_connection_error) {
|
||||
LOG(LOGS_ERR, "Could not connect to signd socket %s : %s", path, strerror(errno));
|
||||
logged_connection_error = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SCH_AddFileHandler(sock_fd, SCH_FILE_INPUT, read_write_socket, NULL);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
process_response(SignInstance *inst)
|
||||
{
|
||||
struct timespec ts;
|
||||
double delay;
|
||||
|
||||
if (ntohs(inst->request.packet_id) != ntohl(inst->response.packet_id)) {
|
||||
DEBUG_LOG("Invalid response ID");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ntohl(inst->response.op) != SIGNING_SUCCESS) {
|
||||
DEBUG_LOG("Signing failed");
|
||||
return;
|
||||
}
|
||||
|
||||
logged_connection_error = 0;
|
||||
|
||||
/* Check if the file descriptor is still valid */
|
||||
if (!NIO_IsServerSocket(inst->local_addr.sock_fd)) {
|
||||
DEBUG_LOG("Invalid NTP socket");
|
||||
return;
|
||||
}
|
||||
|
||||
SCH_GetLastEventTime(NULL, NULL, &ts);
|
||||
delay = UTI_DiffTimespecsToDouble(&ts, &inst->request_ts);
|
||||
|
||||
DEBUG_LOG("Signing succeeded (delay %f)", delay);
|
||||
|
||||
/* Send the signed NTP packet */
|
||||
NIO_SendPacket(&inst->response.signed_packet, &inst->remote_addr, &inst->local_addr,
|
||||
ntohl(inst->response.length) + sizeof (inst->response.length) -
|
||||
offsetof(SigndResponse, signed_packet), 0);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
read_write_socket(int sock_fd, int event, void *anything)
|
||||
{
|
||||
SignInstance *inst;
|
||||
uint32_t response_length;
|
||||
int s;
|
||||
|
||||
inst = ARR_GetElement(queue, queue_head);
|
||||
|
||||
if (event == SCH_FILE_OUTPUT) {
|
||||
assert(!IS_QUEUE_EMPTY());
|
||||
assert(inst->sent < inst->request_length);
|
||||
|
||||
if (!inst->sent)
|
||||
SCH_GetLastEventTime(NULL, NULL, &inst->request_ts);
|
||||
|
||||
s = SCK_Send(sock_fd, (char *)&inst->request + inst->sent,
|
||||
inst->request_length - inst->sent, 0);
|
||||
|
||||
if (s < 0) {
|
||||
close_socket();
|
||||
return;
|
||||
}
|
||||
|
||||
inst->sent += s;
|
||||
|
||||
/* Try again later if the request is not complete yet */
|
||||
if (inst->sent < inst->request_length)
|
||||
return;
|
||||
|
||||
/* Disable output and wait for a response */
|
||||
SCH_SetFileHandlerEvent(sock_fd, SCH_FILE_OUTPUT, 0);
|
||||
}
|
||||
|
||||
if (event == SCH_FILE_INPUT) {
|
||||
if (IS_QUEUE_EMPTY()) {
|
||||
DEBUG_LOG("Unexpected signd response");
|
||||
close_socket();
|
||||
return;
|
||||
}
|
||||
|
||||
assert(inst->received < sizeof (inst->response));
|
||||
s = SCK_Receive(sock_fd, (char *)&inst->response + inst->received,
|
||||
sizeof (inst->response) - inst->received, 0);
|
||||
|
||||
if (s <= 0) {
|
||||
close_socket();
|
||||
return;
|
||||
}
|
||||
|
||||
inst->received += s;
|
||||
|
||||
if (inst->received < sizeof (inst->response.length))
|
||||
return;
|
||||
|
||||
response_length = ntohl(inst->response.length) + sizeof (inst->response.length);
|
||||
|
||||
if (response_length < offsetof(SigndResponse, signed_packet) ||
|
||||
response_length > sizeof (SigndResponse)) {
|
||||
DEBUG_LOG("Invalid response length");
|
||||
close_socket();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Wait for more data if not complete yet */
|
||||
if (inst->received < response_length)
|
||||
return;
|
||||
|
||||
process_response(inst);
|
||||
|
||||
/* Move the head and enable output for the next packet */
|
||||
queue_head = NEXT_QUEUE_INDEX(queue_head);
|
||||
if (!IS_QUEUE_EMPTY())
|
||||
SCH_SetFileHandlerEvent(sock_fd, SCH_FILE_OUTPUT, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NSD_Initialise()
|
||||
{
|
||||
sock_fd = INVALID_SOCK_FD;
|
||||
enabled = CNF_GetNtpSigndSocket() && CNF_GetNtpSigndSocket()[0];
|
||||
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
queue = ARR_CreateInstance(sizeof (SignInstance));
|
||||
ARR_SetSize(queue, MAX_QUEUE_LENGTH);
|
||||
queue_head = queue_tail = 0;
|
||||
|
||||
LOG(LOGS_INFO, "MS-SNTP authentication enabled");
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NSD_Finalise()
|
||||
{
|
||||
if (!enabled)
|
||||
return;
|
||||
if (sock_fd != INVALID_SOCK_FD)
|
||||
close_socket();
|
||||
ARR_DestroyInstance(queue);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NSD_SignAndSendPacket(uint32_t key_id, NTP_Packet *packet, NTP_PacketInfo *info,
|
||||
NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr)
|
||||
{
|
||||
SignInstance *inst;
|
||||
|
||||
if (!enabled) {
|
||||
DEBUG_LOG("signd disabled");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (queue_head == NEXT_QUEUE_INDEX(queue_tail)) {
|
||||
DEBUG_LOG("signd queue full");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (info->length != NTP_HEADER_LENGTH) {
|
||||
DEBUG_LOG("Invalid packet length");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!open_socket())
|
||||
return 0;
|
||||
|
||||
inst = ARR_GetElement(queue, queue_tail);
|
||||
inst->remote_addr = *remote_addr;
|
||||
inst->local_addr = *local_addr;
|
||||
inst->sent = 0;
|
||||
inst->received = 0;
|
||||
inst->request_length = offsetof(SigndRequest, packet_to_sign) + info->length;
|
||||
|
||||
/* The length field doesn't include itself */
|
||||
inst->request.length = htonl(inst->request_length - sizeof (inst->request.length));
|
||||
inst->request.version = htonl(SIGND_VERSION);
|
||||
inst->request.op = htonl(SIGN_TO_CLIENT);
|
||||
inst->request.packet_id = htons(queue_tail);
|
||||
inst->request._pad = 0;
|
||||
inst->request.key_id = htonl(key_id);
|
||||
|
||||
memcpy(&inst->request.packet_to_sign, packet, info->length);
|
||||
|
||||
/* Enable output if there was no pending request */
|
||||
if (IS_QUEUE_EMPTY())
|
||||
SCH_SetFileHandlerEvent(sock_fd, SCH_FILE_OUTPUT, 1);
|
||||
|
||||
queue_tail = NEXT_QUEUE_INDEX(queue_tail);
|
||||
|
||||
DEBUG_LOG("Packet added to signd queue (%u:%u)", queue_head, queue_tail);
|
||||
|
||||
return 1;
|
||||
}
|
||||
42
ntp_signd.h
Normal file
42
ntp_signd.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2016
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Header for MS-SNTP authentication via Samba (ntp_signd) */
|
||||
|
||||
#ifndef GOT_NTP_SIGND_H
|
||||
#define GOT_NTP_SIGND_H
|
||||
|
||||
#include "addressing.h"
|
||||
#include "ntp.h"
|
||||
|
||||
/* Initialisation function */
|
||||
extern void NSD_Initialise(void);
|
||||
|
||||
/* Finalisation function */
|
||||
extern void NSD_Finalise(void);
|
||||
|
||||
/* Function to sign an NTP packet and send it */
|
||||
extern int NSD_SignAndSendPacket(uint32_t key_id, NTP_Packet *packet, NTP_PacketInfo *info,
|
||||
NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr);
|
||||
|
||||
#endif
|
||||
1273
ntp_sources.c
1273
ntp_sources.c
File diff suppressed because it is too large
Load Diff
@@ -44,16 +44,26 @@ typedef enum {
|
||||
NSR_NoSuchSource, /* Remove - attempt to remove a source that is not known */
|
||||
NSR_AlreadyInUse, /* AddSource - attempt to add a source that is already known */
|
||||
NSR_TooManySources, /* AddSource - too many sources already present */
|
||||
NSR_InvalidAF /* AddSource - attempt to add a source with invalid address family */
|
||||
NSR_InvalidAF, /* AddSource - attempt to add a source with invalid address family */
|
||||
NSR_InvalidName, /* AddSourceByName - attempt to add a source with invalid name */
|
||||
NSR_UnresolvedName, /* AddSourceByName - name will be resolved later */
|
||||
} NSR_Status;
|
||||
|
||||
/* Procedure to add a new server or peer source. */
|
||||
extern NSR_Status NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params);
|
||||
extern NSR_Status NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type,
|
||||
SourceParameters *params, uint32_t *conf_id);
|
||||
|
||||
/* Procedure to add a new server, peer source, or pool of servers specified by
|
||||
name instead of address. The name is resolved in exponentially increasing
|
||||
intervals until it succeeds or fails with a non-temporary error. */
|
||||
extern void NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type, SourceParameters *params);
|
||||
intervals until it succeeds or fails with a non-temporary error. The
|
||||
specified family filters resolved addresses. If the name is an address
|
||||
and its family does not conflict with the specified family, it is equivalent
|
||||
to NSR_AddSource(). */
|
||||
extern NSR_Status NSR_AddSourceByName(char *name, int family, int port, int pool,
|
||||
NTP_Source_Type type,
|
||||
SourceParameters *params, uint32_t *conf_id);
|
||||
|
||||
extern const char *NSR_StatusToString(NSR_Status status);
|
||||
|
||||
/* Function type for handlers to be called back when an attempt
|
||||
* (possibly unsuccessful) to resolve unresolved sources ends */
|
||||
@@ -72,7 +82,10 @@ extern void NSR_StartSources(void);
|
||||
extern void NSR_AutoStartSources(void);
|
||||
|
||||
/* Procedure to remove a source */
|
||||
extern NSR_Status NSR_RemoveSource(NTP_Remote_Address *remote_addr);
|
||||
extern NSR_Status NSR_RemoveSource(IPAddr *address);
|
||||
|
||||
/* Procedure to remove all sources matching a configuration ID */
|
||||
extern void NSR_RemoveSourcesById(uint32_t conf_id);
|
||||
|
||||
/* Procedure to remove all sources */
|
||||
extern void NSR_RemoveAllSources(void);
|
||||
@@ -80,8 +93,29 @@ extern void NSR_RemoveAllSources(void);
|
||||
/* Procedure to try to find a replacement for a bad source */
|
||||
extern void NSR_HandleBadSource(IPAddr *address);
|
||||
|
||||
/* Procedure to resolve all names again */
|
||||
extern void NSR_RefreshAddresses(void);
|
||||
|
||||
/* Procedure to update the address of a source. The update may be
|
||||
postponed. */
|
||||
extern NSR_Status NSR_UpdateSourceNtpAddress(NTP_Remote_Address *old_addr,
|
||||
NTP_Remote_Address *new_addr);
|
||||
|
||||
/* Procedure to get local reference ID corresponding to a source */
|
||||
extern uint32_t NSR_GetLocalRefid(IPAddr *address);
|
||||
|
||||
/* Procedure to get the name of a source as it was specified (it may be
|
||||
an IP address) */
|
||||
extern char *NSR_GetName(IPAddr *address);
|
||||
|
||||
/* This routine is called by ntp_io when a new packet arrives off the network */
|
||||
extern void NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int length);
|
||||
extern void NSR_ProcessRx(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
|
||||
NTP_Local_Timestamp *rx_ts, NTP_Packet *message, int length);
|
||||
|
||||
/* This routine is called by ntp_io when a packet was sent to the network and
|
||||
an accurate transmit timestamp was captured */
|
||||
extern void NSR_ProcessTx(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
|
||||
NTP_Local_Timestamp *tx_ts, NTP_Packet *message, int length);
|
||||
|
||||
/* Initialisation function */
|
||||
extern void NSR_Initialise(void);
|
||||
@@ -90,14 +124,9 @@ extern void NSR_Initialise(void);
|
||||
extern void NSR_Finalise(void);
|
||||
|
||||
/* This routine is used to indicate that sources whose IP addresses
|
||||
match a particular subnet should be set online again. Returns a
|
||||
flag indicating whether any hosts matched the address */
|
||||
extern int NSR_TakeSourcesOnline(IPAddr *mask, IPAddr *address);
|
||||
|
||||
/* This routine is used to indicate that sources whose IP addresses
|
||||
match a particular subnet should be set offline. Returns a flag
|
||||
indicating whether any hosts matched the address */
|
||||
extern int NSR_TakeSourcesOffline(IPAddr *mask, IPAddr *address);
|
||||
match a particular subnet should be set online or offline. It returns
|
||||
a flag indicating whether any hosts matched the address. */
|
||||
extern int NSR_SetConnectivity(IPAddr *mask, IPAddr *address, SRC_Connectivity connectivity);
|
||||
|
||||
extern int NSR_ModifyMinpoll(IPAddr *address, int new_minpoll);
|
||||
|
||||
@@ -111,12 +140,20 @@ extern int NSR_ModifyMaxdelaydevratio(IPAddr *address, double new_max_delay_rati
|
||||
|
||||
extern int NSR_ModifyMinstratum(IPAddr *address, int new_min_stratum);
|
||||
|
||||
extern int NSR_ModifyOffset(IPAddr *address, double new_offset);
|
||||
|
||||
extern int NSR_ModifyPolltarget(IPAddr *address, int new_poll_target);
|
||||
|
||||
extern int NSR_InitiateSampleBurst(int n_good_samples, int n_total_samples, IPAddr *mask, IPAddr *address);
|
||||
|
||||
extern void NSR_ReportSource(RPT_SourceReport *report, struct timeval *now);
|
||||
extern void NSR_ReportSource(RPT_SourceReport *report, struct timespec *now);
|
||||
|
||||
extern int NSR_GetAuthReport(IPAddr *address, RPT_AuthReport *report);
|
||||
|
||||
extern int NSR_GetNTPReport(RPT_NTPReport *report);
|
||||
|
||||
extern void NSR_GetActivityReport(RPT_ActivityReport *report);
|
||||
|
||||
extern void NSR_DumpAuthData(void);
|
||||
|
||||
#endif /* GOT_NTP_SOURCES_H */
|
||||
|
||||
80
nts_ke.h
Normal file
80
nts_ke.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2020
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Header file for the NTS Key Establishment protocol
|
||||
*/
|
||||
|
||||
#ifndef GOT_NTS_KE_H
|
||||
#define GOT_NTS_KE_H
|
||||
|
||||
#include "siv.h"
|
||||
|
||||
#define NKE_PORT 4460
|
||||
|
||||
#define NKE_RECORD_CRITICAL_BIT (1U << 15)
|
||||
#define NKE_RECORD_END_OF_MESSAGE 0
|
||||
#define NKE_RECORD_NEXT_PROTOCOL 1
|
||||
#define NKE_RECORD_ERROR 2
|
||||
#define NKE_RECORD_WARNING 3
|
||||
#define NKE_RECORD_AEAD_ALGORITHM 4
|
||||
#define NKE_RECORD_COOKIE 5
|
||||
#define NKE_RECORD_NTPV4_SERVER_NEGOTIATION 6
|
||||
#define NKE_RECORD_NTPV4_PORT_NEGOTIATION 7
|
||||
#define NKE_RECORD_COMPLIANT_128GCM_EXPORT 1024
|
||||
|
||||
#define NKE_NEXT_PROTOCOL_NTPV4 0
|
||||
|
||||
#define NKE_ERROR_UNRECOGNIZED_CRITICAL_RECORD 0
|
||||
#define NKE_ERROR_BAD_REQUEST 1
|
||||
#define NKE_ERROR_INTERNAL_SERVER_ERROR 2
|
||||
|
||||
#define NKE_ALPN_NAME "ntske/1"
|
||||
#define NKE_EXPORTER_LABEL "EXPORTER-network-time-security"
|
||||
|
||||
#define NKE_MAX_MESSAGE_LENGTH 16384
|
||||
#define NKE_MAX_RECORD_BODY_LENGTH 256
|
||||
#define NKE_MAX_COOKIE_LENGTH 256
|
||||
#define NKE_MAX_COOKIES 8
|
||||
#define NKE_MAX_KEY_LENGTH SIV_MAX_KEY_LENGTH
|
||||
|
||||
#define NKE_RETRY_FACTOR2_CONNECT 4
|
||||
#define NKE_RETRY_FACTOR2_TLS 10
|
||||
#define NKE_MAX_RETRY_INTERVAL2 19
|
||||
|
||||
typedef struct {
|
||||
int length;
|
||||
unsigned char key[NKE_MAX_KEY_LENGTH];
|
||||
} NKE_Key;
|
||||
|
||||
typedef struct {
|
||||
SIV_Algorithm algorithm;
|
||||
NKE_Key c2s;
|
||||
NKE_Key s2c;
|
||||
} NKE_Context;
|
||||
|
||||
typedef struct {
|
||||
int length;
|
||||
unsigned char cookie[NKE_MAX_COOKIE_LENGTH];
|
||||
} NKE_Cookie;
|
||||
|
||||
#endif
|
||||
507
nts_ke_client.c
Normal file
507
nts_ke_client.c
Normal file
@@ -0,0 +1,507 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2020-2021, 2024
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
NTS-KE client
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "nts_ke_client.h"
|
||||
|
||||
#include "conf.h"
|
||||
#include "logging.h"
|
||||
#include "memory.h"
|
||||
#include "nameserv_async.h"
|
||||
#include "nts_ke_session.h"
|
||||
#include "siv.h"
|
||||
#include "socket.h"
|
||||
#include "util.h"
|
||||
|
||||
#define CLIENT_TIMEOUT 16.0
|
||||
|
||||
struct NKC_Instance_Record {
|
||||
char *name;
|
||||
IPSockAddr address;
|
||||
NKSN_Credentials credentials;
|
||||
NKSN_Instance session;
|
||||
int destroying;
|
||||
int got_response;
|
||||
int resolving_name;
|
||||
|
||||
int compliant_128gcm;
|
||||
NKE_Context context;
|
||||
NKE_Context alt_context;
|
||||
NKE_Cookie cookies[NKE_MAX_COOKIES];
|
||||
int num_cookies;
|
||||
char server_name[NKE_MAX_RECORD_BODY_LENGTH + 2];
|
||||
IPSockAddr ntp_address;
|
||||
};
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static NKSN_Credentials default_credentials = NULL;
|
||||
static int default_credentials_refs = 0;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
name_resolve_handler(DNS_Status status, int n_addrs, IPAddr *ip_addrs, void *arg)
|
||||
{
|
||||
NKC_Instance inst = arg;
|
||||
int i;
|
||||
|
||||
inst->resolving_name = 0;
|
||||
|
||||
if (inst->destroying) {
|
||||
Free(inst);
|
||||
return;
|
||||
}
|
||||
|
||||
if (status != DNS_Success || n_addrs < 1) {
|
||||
LOG(LOGS_ERR, "Could not resolve NTP server %s from %s", inst->server_name, inst->name);
|
||||
/* Force restart */
|
||||
inst->got_response = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
inst->ntp_address.ip_addr = ip_addrs[0];
|
||||
|
||||
/* Prefer an address in the same family as the NTS-KE server */
|
||||
for (i = 0; i < n_addrs; i++) {
|
||||
DEBUG_LOG("%s resolved to %s", inst->server_name, UTI_IPToString(&ip_addrs[i]));
|
||||
if (ip_addrs[i].family == inst->address.ip_addr.family) {
|
||||
inst->ntp_address.ip_addr = ip_addrs[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#define MAX_AEAD_ALGORITHMS 4
|
||||
|
||||
static int
|
||||
prepare_request(NKC_Instance inst)
|
||||
{
|
||||
NKSN_Instance session = inst->session;
|
||||
uint16_t data[MAX_AEAD_ALGORITHMS];
|
||||
int i, aead_algorithm, length;
|
||||
|
||||
NKSN_BeginMessage(session);
|
||||
|
||||
data[0] = htons(NKE_NEXT_PROTOCOL_NTPV4);
|
||||
if (!NKSN_AddRecord(session, 1, NKE_RECORD_NEXT_PROTOCOL, data, sizeof (data[0])))
|
||||
return 0;
|
||||
|
||||
for (i = length = 0; i < ARR_GetSize(CNF_GetNtsAeads()) && length < MAX_AEAD_ALGORITHMS;
|
||||
i++) {
|
||||
aead_algorithm = *(int *)ARR_GetElement(CNF_GetNtsAeads(), i);
|
||||
if (SIV_GetKeyLength(aead_algorithm) > 0)
|
||||
data[length++] = htons(aead_algorithm);
|
||||
}
|
||||
if (!NKSN_AddRecord(session, 1, NKE_RECORD_AEAD_ALGORITHM, data,
|
||||
length * sizeof (data[0])))
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
if (data[i] == htons(AEAD_AES_128_GCM_SIV)) {
|
||||
if (!NKSN_AddRecord(session, 0, NKE_RECORD_COMPLIANT_128GCM_EXPORT, NULL, 0))
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!NKSN_EndMessage(session))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
process_response(NKC_Instance inst)
|
||||
{
|
||||
int next_protocol = -1, aead_algorithm = -1, error = 0;
|
||||
int i, critical, type, length;
|
||||
uint16_t data[NKE_MAX_RECORD_BODY_LENGTH / sizeof (uint16_t)];
|
||||
|
||||
assert(NKE_MAX_COOKIE_LENGTH <= NKE_MAX_RECORD_BODY_LENGTH);
|
||||
assert(sizeof (data) % sizeof (uint16_t) == 0);
|
||||
assert(sizeof (uint16_t) == 2);
|
||||
|
||||
inst->compliant_128gcm = 0;
|
||||
inst->alt_context.algorithm = AEAD_SIV_INVALID;
|
||||
inst->num_cookies = 0;
|
||||
inst->ntp_address.ip_addr.family = IPADDR_UNSPEC;
|
||||
inst->ntp_address.port = 0;
|
||||
inst->server_name[0] = '\0';
|
||||
|
||||
while (!error) {
|
||||
if (!NKSN_GetRecord(inst->session, &critical, &type, &length, &data, sizeof (data)))
|
||||
break;
|
||||
|
||||
if (length > sizeof (data)) {
|
||||
DEBUG_LOG("Record too long type=%d length=%d critical=%d", type, length, critical);
|
||||
if (critical)
|
||||
error = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case NKE_RECORD_NEXT_PROTOCOL:
|
||||
if (!critical || length != 2 || ntohs(data[0]) != NKE_NEXT_PROTOCOL_NTPV4) {
|
||||
DEBUG_LOG("Unexpected NTS-KE next protocol");
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
next_protocol = NKE_NEXT_PROTOCOL_NTPV4;
|
||||
break;
|
||||
case NKE_RECORD_AEAD_ALGORITHM:
|
||||
if (length != 2) {
|
||||
DEBUG_LOG("Unexpected AEAD algorithm");
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < ARR_GetSize(CNF_GetNtsAeads()); i++) {
|
||||
if (ntohs(data[0]) == *(int *)ARR_GetElement(CNF_GetNtsAeads(), i) &&
|
||||
SIV_GetKeyLength(ntohs(data[0])) > 0) {
|
||||
aead_algorithm = ntohs(data[0]);
|
||||
inst->context.algorithm = aead_algorithm;
|
||||
}
|
||||
}
|
||||
if (aead_algorithm < 0) {
|
||||
DEBUG_LOG("Unexpected AEAD algorithm");
|
||||
error = 1;
|
||||
}
|
||||
break;
|
||||
case NKE_RECORD_COMPLIANT_128GCM_EXPORT:
|
||||
if (length != 0) {
|
||||
DEBUG_LOG("Non-empty compliant-128gcm record");
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
DEBUG_LOG("Compliant AES-128-GCM-SIV export");
|
||||
inst->compliant_128gcm = 1;
|
||||
break;
|
||||
case NKE_RECORD_ERROR:
|
||||
if (length == 2)
|
||||
DEBUG_LOG("NTS-KE error %d", ntohs(data[0]));
|
||||
error = 1;
|
||||
break;
|
||||
case NKE_RECORD_WARNING:
|
||||
if (length == 2)
|
||||
DEBUG_LOG("NTS-KE warning %d", ntohs(data[0]));
|
||||
error = 1;
|
||||
break;
|
||||
case NKE_RECORD_COOKIE:
|
||||
DEBUG_LOG("Got cookie length=%d", length);
|
||||
|
||||
if (length < 1 || length > NKE_MAX_COOKIE_LENGTH || length % 4 != 0 ||
|
||||
inst->num_cookies >= NKE_MAX_COOKIES) {
|
||||
DEBUG_LOG("Unexpected length/cookie");
|
||||
break;
|
||||
}
|
||||
|
||||
assert(NKE_MAX_COOKIE_LENGTH == sizeof (inst->cookies[inst->num_cookies].cookie));
|
||||
assert(NKE_MAX_COOKIES == sizeof (inst->cookies) /
|
||||
sizeof (inst->cookies[inst->num_cookies]));
|
||||
inst->cookies[inst->num_cookies].length = length;
|
||||
memcpy(inst->cookies[inst->num_cookies].cookie, data, length);
|
||||
|
||||
inst->num_cookies++;
|
||||
break;
|
||||
case NKE_RECORD_NTPV4_SERVER_NEGOTIATION:
|
||||
if (length < 1 || length >= sizeof (inst->server_name)) {
|
||||
DEBUG_LOG("Invalid server name");
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(inst->server_name, data, length);
|
||||
inst->server_name[length] = '\0';
|
||||
|
||||
/* Make sure the name is printable and has no spaces */
|
||||
for (i = 0; i < length && isgraph((unsigned char)inst->server_name[i]); i++)
|
||||
;
|
||||
if (i != length) {
|
||||
DEBUG_LOG("Invalid server name");
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
DEBUG_LOG("Negotiated server %s", inst->server_name);
|
||||
break;
|
||||
case NKE_RECORD_NTPV4_PORT_NEGOTIATION:
|
||||
if (length != 2) {
|
||||
DEBUG_LOG("Invalid port");
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
inst->ntp_address.port = ntohs(data[0]);
|
||||
DEBUG_LOG("Negotiated port %d", inst->ntp_address.port);
|
||||
break;
|
||||
default:
|
||||
DEBUG_LOG("Unknown record type=%d length=%d critical=%d", type, length, critical);
|
||||
if (critical)
|
||||
error = 1;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_LOG("NTS-KE response: error=%d next=%d aead=%d",
|
||||
error, next_protocol, aead_algorithm);
|
||||
|
||||
if (error || inst->num_cookies == 0 ||
|
||||
next_protocol != NKE_NEXT_PROTOCOL_NTPV4 ||
|
||||
aead_algorithm < 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
handle_message(void *arg)
|
||||
{
|
||||
SIV_Algorithm exporter_algorithm;
|
||||
NKC_Instance inst = arg;
|
||||
|
||||
if (!process_response(inst)) {
|
||||
LOG(LOGS_ERR, "Received invalid NTS-KE response from %s", inst->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
exporter_algorithm = inst->context.algorithm;
|
||||
|
||||
/* With AES-128-GCM-SIV, set the algorithm ID in the RFC5705 key exporter
|
||||
context incorrectly for compatibility with older chrony servers unless
|
||||
the server confirmed support for the compliant context. Generate both
|
||||
sets of keys in case the server uses the compliant context, but does not
|
||||
support the negotiation record, assuming it will respond with an NTS NAK
|
||||
to a request authenticated with the noncompliant key. */
|
||||
if (exporter_algorithm == AEAD_AES_128_GCM_SIV && !inst->compliant_128gcm) {
|
||||
inst->alt_context.algorithm = inst->context.algorithm;
|
||||
if (!NKSN_GetKeys(inst->session, inst->alt_context.algorithm, exporter_algorithm,
|
||||
NKE_NEXT_PROTOCOL_NTPV4, &inst->alt_context.c2s, &inst->alt_context.s2c))
|
||||
return 0;
|
||||
|
||||
exporter_algorithm = AEAD_AES_SIV_CMAC_256;
|
||||
}
|
||||
|
||||
if (!NKSN_GetKeys(inst->session, inst->context.algorithm, exporter_algorithm,
|
||||
NKE_NEXT_PROTOCOL_NTPV4, &inst->context.c2s, &inst->context.s2c))
|
||||
return 0;
|
||||
|
||||
if (inst->server_name[0] != '\0') {
|
||||
if (inst->resolving_name)
|
||||
return 0;
|
||||
if (!UTI_StringToIP(inst->server_name, &inst->ntp_address.ip_addr)) {
|
||||
int length = strlen(inst->server_name);
|
||||
|
||||
/* Add a trailing dot if not present to force the name to be
|
||||
resolved as a fully qualified domain name */
|
||||
if (length < 1 || length + 1 >= sizeof (inst->server_name))
|
||||
return 0;
|
||||
if (inst->server_name[length - 1] != '.') {
|
||||
inst->server_name[length] = '.';
|
||||
inst->server_name[length + 1] = '\0';
|
||||
}
|
||||
|
||||
DNS_Name2IPAddressAsync(inst->server_name, name_resolve_handler, inst);
|
||||
inst->resolving_name = 1;
|
||||
}
|
||||
}
|
||||
|
||||
inst->got_response = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
NKC_Instance
|
||||
NKC_CreateInstance(IPSockAddr *address, const char *name, uint32_t cert_set)
|
||||
{
|
||||
const char **trusted_certs;
|
||||
uint32_t *certs_ids;
|
||||
NKC_Instance inst;
|
||||
int n_certs;
|
||||
|
||||
inst = MallocNew(struct NKC_Instance_Record);
|
||||
|
||||
inst->address = *address;
|
||||
inst->name = Strdup(name);
|
||||
inst->session = NKSN_CreateInstance(0, inst->name, handle_message, inst);
|
||||
inst->resolving_name = 0;
|
||||
inst->destroying = 0;
|
||||
inst->got_response = 0;
|
||||
|
||||
n_certs = CNF_GetNtsTrustedCertsPaths(&trusted_certs, &certs_ids);
|
||||
|
||||
/* Share the credentials among clients using the default set of trusted
|
||||
certificates, which likely contains most certificates */
|
||||
if (cert_set == 0) {
|
||||
if (!default_credentials)
|
||||
default_credentials = NKSN_CreateClientCertCredentials(trusted_certs, certs_ids,
|
||||
n_certs, cert_set);
|
||||
inst->credentials = default_credentials;
|
||||
if (default_credentials)
|
||||
default_credentials_refs++;
|
||||
} else {
|
||||
inst->credentials = NKSN_CreateClientCertCredentials(trusted_certs, certs_ids,
|
||||
n_certs, cert_set);
|
||||
}
|
||||
|
||||
return inst;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NKC_DestroyInstance(NKC_Instance inst)
|
||||
{
|
||||
NKSN_DestroyInstance(inst->session);
|
||||
|
||||
Free(inst->name);
|
||||
|
||||
if (inst->credentials) {
|
||||
if (inst->credentials == default_credentials) {
|
||||
default_credentials_refs--;
|
||||
if (default_credentials_refs <= 0) {
|
||||
NKSN_DestroyCertCredentials(default_credentials);
|
||||
default_credentials = NULL;
|
||||
}
|
||||
} else {
|
||||
NKSN_DestroyCertCredentials(inst->credentials);
|
||||
}
|
||||
}
|
||||
|
||||
/* If the asynchronous resolver is running, let the handler free
|
||||
the instance later */
|
||||
if (inst->resolving_name) {
|
||||
inst->destroying = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
Free(inst);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NKC_Start(NKC_Instance inst)
|
||||
{
|
||||
IPSockAddr local_addr;
|
||||
char label[512], *iface;
|
||||
int sock_fd;
|
||||
|
||||
assert(!NKC_IsActive(inst));
|
||||
|
||||
inst->got_response = 0;
|
||||
|
||||
if (!inst->credentials) {
|
||||
DEBUG_LOG("Missing client credentials");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Don't try to connect if missing the algorithm which all servers
|
||||
are required to support */
|
||||
if (SIV_GetKeyLength(AEAD_AES_SIV_CMAC_256) <= 0) {
|
||||
LOG(LOGS_ERR, "Missing AES-SIV-CMAC-256");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Follow the bindacqaddress and bindacqdevice settings */
|
||||
CNF_GetBindAcquisitionAddress(inst->address.ip_addr.family, &local_addr.ip_addr);
|
||||
local_addr.port = 0;
|
||||
iface = CNF_GetBindAcquisitionInterface();
|
||||
|
||||
/* Make a label containing both the address and name of the server */
|
||||
if (snprintf(label, sizeof (label), "%s (%s)",
|
||||
UTI_IPSockAddrToString(&inst->address), inst->name) >= sizeof (label))
|
||||
;
|
||||
|
||||
sock_fd = SCK_OpenTcpSocket(&inst->address, &local_addr, iface, 0);
|
||||
if (sock_fd < 0) {
|
||||
LOG(LOGS_ERR, "Could not connect to %s", label);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Start an NTS-KE session */
|
||||
if (!NKSN_StartSession(inst->session, sock_fd, label, inst->credentials, CLIENT_TIMEOUT)) {
|
||||
SCK_CloseSocket(sock_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Send a request */
|
||||
if (!prepare_request(inst)) {
|
||||
DEBUG_LOG("Could not prepare NTS-KE request");
|
||||
NKSN_StopSession(inst->session);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NKC_IsActive(NKC_Instance inst)
|
||||
{
|
||||
return !NKSN_IsStopped(inst->session) || inst->resolving_name;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NKC_GetNtsData(NKC_Instance inst, NKE_Context *context, NKE_Context *alt_context,
|
||||
NKE_Cookie *cookies, int *num_cookies, int max_cookies,
|
||||
IPSockAddr *ntp_address)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!inst->got_response || inst->resolving_name)
|
||||
return 0;
|
||||
|
||||
*context = inst->context;
|
||||
*alt_context = inst->alt_context;
|
||||
|
||||
for (i = 0; i < inst->num_cookies && i < max_cookies; i++)
|
||||
cookies[i] = inst->cookies[i];
|
||||
*num_cookies = i;
|
||||
|
||||
*ntp_address = inst->ntp_address;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NKC_GetRetryFactor(NKC_Instance inst)
|
||||
{
|
||||
return NKSN_GetRetryFactor(inst->session);
|
||||
}
|
||||
56
nts_ke_client.h
Normal file
56
nts_ke_client.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2020
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Header file for the NTS-KE client
|
||||
*/
|
||||
|
||||
#ifndef GOT_NTS_KE_CLIENT_H
|
||||
#define GOT_NTS_KE_CLIENT_H
|
||||
|
||||
#include "addressing.h"
|
||||
#include "nts_ke.h"
|
||||
|
||||
typedef struct NKC_Instance_Record *NKC_Instance;
|
||||
|
||||
/* Create a client NTS-KE instance */
|
||||
extern NKC_Instance NKC_CreateInstance(IPSockAddr *address, const char *name, uint32_t cert_set);
|
||||
|
||||
/* Destroy an instance */
|
||||
extern void NKC_DestroyInstance(NKC_Instance inst);
|
||||
|
||||
/* Connect to the server, start an NTS-KE session, send an NTS-KE request, and
|
||||
process the response (asynchronously) */
|
||||
extern int NKC_Start(NKC_Instance inst);
|
||||
|
||||
/* Check if the client is still running */
|
||||
extern int NKC_IsActive(NKC_Instance inst);
|
||||
|
||||
/* Get the NTS data if the session was successful */
|
||||
extern int NKC_GetNtsData(NKC_Instance inst, NKE_Context *context, NKE_Context *alt_context,
|
||||
NKE_Cookie *cookies, int *num_cookies, int max_cookies,
|
||||
IPSockAddr *ntp_address);
|
||||
|
||||
/* Get a factor to calculate retry interval (in log2 seconds) */
|
||||
extern int NKC_GetRetryFactor(NKC_Instance inst);
|
||||
|
||||
#endif
|
||||
1064
nts_ke_server.c
Normal file
1064
nts_ke_server.c
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user