github.com/coyove/sdss@v0.0.0-20231129015646-c2ec58cca6a2/future/chrony/packet_test.go (about) 1 /* 2 Copyright (c) Facebook, Inc. and its affiliates. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package chrony 18 19 import ( 20 "net" 21 "testing" 22 "time" 23 24 "github.com/stretchr/testify/require" 25 ) 26 27 /* 28 The unittests here contain packets in binary form. 29 The easiest way to obtain those is using tcpdump/tshark. 30 31 For example, running `tshark -i any -T fields -e data.data udp and port 323` in one shell and 32 using `chronyc` cli in another allows to capture all the bytes sent and received. 33 34 Alternatively, strace can be used: 35 `strace -xx -e sendto,recvfrom -v -s 10000 chronyc sources` will print sent and received bytes. 36 Using strace is the only option when working with private parts of the 37 chrony protocol (commands that only work over the unix socket), like `chronyc ntpdata`. 38 */ 39 40 func TestDecodeUnauthorized(t *testing.T) { 41 raw := []uint8{ 42 0x06, 0x02, 0x00, 0x00, 0x00, 0x39, 0x00, 0x01, 0x00, 0x02, 43 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa3, 0xa8, 0xc8, 0x40, 44 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 45 } 46 _, err := decodePacket(raw) 47 require.Error(t, err) 48 } 49 50 func TestDecodeSources(t *testing.T) { 51 raw := []uint8{ 52 0x06, 0x02, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x02, 0x00, 0x00, 53 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x3a, 0xb1, 0x23, 54 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 55 0x00, 0x12, 56 } 57 packet, err := decodePacket(raw) 58 require.Nil(t, err) 59 want := &ReplySources{ 60 ReplyHead: ReplyHead{ 61 Version: protoVersionNumber, 62 PKTType: pktTypeCmdReply, 63 Command: reqNSources, 64 Reply: rpyNSources, 65 Status: sttSuccess, 66 Sequence: 960147747, 67 }, 68 NSources: 18, 69 } 70 require.Equal(t, want, packet) 71 } 72 73 func TestDecodeSourceData(t *testing.T) { 74 raw := []uint8{ 75 0x06, 0x02, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x03, 0x00, 0x00, 76 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x83, 0xbf, 0x73, 77 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x01, 78 0xdb, 0x00, 0x31, 0x10, 0x20, 0xc0, 0xfa, 0xce, 0x00, 0x00, 79 0x00, 0x48, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0a, 80 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 81 0x00, 0x00, 0x06, 0xa9, 0xe6, 0xc5, 0xee, 0xf3, 0xe6, 0xd1, 82 0x4f, 0xbe, 0xea, 0xbb, 0x92, 0x3b, 83 } 84 packet, err := decodePacket(raw) 85 require.Nil(t, err) 86 want := &ReplySourceData{ 87 ReplyHead: ReplyHead{ 88 Version: protoVersionNumber, 89 PKTType: pktTypeCmdReply, 90 Command: reqSourceData, 91 Reply: rpySourceData, 92 Status: sttSuccess, 93 Sequence: 209960819, 94 }, 95 SourceData: SourceData{ 96 IPAddr: net.IP{0x24, 0x01, 0xdb, 0x00, 0x31, 0x10, 0x20, 0xc0, 0xfa, 0xce, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00}, 97 Poll: 10, 98 Stratum: 2, 99 State: 4, 100 Mode: 0, 101 Flags: 0, 102 Reachability: 255, 103 SinceSample: 1705, 104 OrigLatestMeas: 4.719099888461642e-05, 105 LatestMeas: 4.990374873159453e-05, 106 LatestMeasErr: 0.00017888184811454266, 107 }, 108 } 109 require.Equal(t, want, packet) 110 } 111 112 func TestDecodeSourceStats(t *testing.T) { 113 raw := []uint8{ 114 0x06, 0x02, 0x00, 0x00, 0x00, 0x22, 0x00, 0x06, 0x00, 0x00, 115 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x95, 0xd8, 0xfa, 116 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbf, 0x8b, 117 0xe5, 0xe9, 0x24, 0x01, 0xdb, 0x00, 0x31, 0x10, 0x20, 0xc0, 118 0xfa, 0xce, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x02, 119 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x05, 120 0x00, 0x00, 0x1a, 0x27, 0xe4, 0x94, 0x84, 0x99, 0xed, 0x34, 121 0xe0, 0x09, 0xf6, 0xc0, 0x64, 0x94, 0xdf, 0x18, 0xb4, 0x76, 122 0xea, 0xb9, 0xc0, 0xa1, 123 } 124 packet, err := decodePacket(raw) 125 require.Nil(t, err) 126 want := &ReplySourceStats{ 127 ReplyHead: ReplyHead{ 128 Version: protoVersionNumber, 129 PKTType: pktTypeCmdReply, 130 Command: reqSourceStats, 131 Reply: rpySourceStats, 132 Status: sttSuccess, 133 Sequence: 1502992634, 134 }, 135 SourceStats: SourceStats{ 136 RefID: 3213616617, 137 IPAddr: net.IP{0x24, 0x01, 0xdb, 0x00, 0x31, 0x10, 0x20, 0xc0, 0xfa, 0xce, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00}, 138 NSamples: 12, 139 NRuns: 5, 140 SpanSeconds: 6695, 141 StandardDeviation: 1.770472044881899e-05, 142 ResidFreqPPM: -0.00038742992910556495, 143 SkewPPM: 0.0117427296936512, 144 EstimatedOffset: -3.44656518791453e-06, 145 EstimatedOffsetErr: 0.0001771473471308127, 146 }, 147 } 148 require.Equal(t, want, packet) 149 } 150 151 func TestDecodeTracking(t *testing.T) { 152 raw := []uint8{ 153 0x06, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x05, 0x00, 0x00, 154 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 155 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0x25, 156 0xc6, 0x6e, 0x24, 0x01, 0xdb, 0x00, 0x31, 0x10, 0x21, 0x32, 157 0xfa, 0xce, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x02, 158 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 159 0x61, 0x38, 0xe1, 0x81, 0x36, 0x94, 0x8d, 0xd5, 0xdf, 0x19, 160 0x2d, 0xb7, 0xdf, 0x42, 0x83, 0xf5, 0xe2, 0xeb, 0xca, 0x12, 161 0x05, 0x39, 0xe1, 0x11, 0xeb, 0x7b, 0x3e, 0x5d, 0xf4, 0xb0, 162 0x75, 0x12, 0xea, 0xe7, 0x5b, 0x0c, 0xf0, 0x88, 0x1d, 0x4e, 163 0x16, 0x82, 0x1f, 0x69, 164 } 165 packet, err := decodePacket(raw) 166 require.Nil(t, err) 167 want := &ReplyTracking{ 168 ReplyHead: ReplyHead{ 169 Version: protoVersionNumber, 170 PKTType: pktTypeCmdReply, 171 Res1: 0, 172 Res2: 0, 173 Command: reqTracking, 174 Reply: rpyTracking, 175 Status: sttSuccess, 176 Sequence: 2, 177 }, 178 Tracking: Tracking{ 179 RefID: 3861235310, 180 IPAddr: net.IP{36, 1, 219, 0, 49, 16, 33, 50, 250, 206, 0, 0, 0, 142, 0, 0}, 181 Stratum: 3, 182 LeapStatus: 0, 183 RefTime: time.Unix(0, 1631117697915705301), 184 CurrentCorrection: -3.4395072816550964e-06, 185 LastOffset: -2.823539716700907e-06, 186 RMSOffset: 1.405413968313951e-05, 187 FreqPPM: -1.5478190183639526, 188 ResidFreqPPM: -0.00012660636275541037, 189 SkewPPM: 0.005385049618780613, 190 RootDelay: 0.00022063794312998652, 191 RootDispersion: 0.0010384710039943457, 192 LastUpdateInterval: 520.4907836914062, 193 }, 194 } 195 require.Equal(t, want, packet) 196 } 197 198 /* private part of the protocol */ 199 200 func TestDecodeServerStats(t *testing.T) { 201 raw := []uint8{ 202 0x06, 0x02, 0x00, 0x00, 0x00, 0x36, 0x00, 0x0e, 0x00, 0x00, 203 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x07, 0x16, 0xff, 204 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 205 0x00, 0x00, 0x00, 0x10, 0x03, 0xcd, 0x00, 0x00, 0x00, 0x00, 206 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 207 } 208 packet, err := decodePacket(raw) 209 require.Nil(t, err) 210 want := &ReplyServerStats{ 211 ReplyHead: ReplyHead{ 212 Version: protoVersionNumber, 213 PKTType: pktTypeCmdReply, 214 Res1: 0, 215 Res2: 0, 216 Command: reqServerStats, 217 Reply: rpyServerStats, 218 Status: sttSuccess, 219 Sequence: 50796287, 220 }, 221 ServerStats: ServerStats{ 222 NTPHits: 0, 223 CMDHits: 1049549, 224 NTPDrops: 0, 225 CMDDrops: 0, 226 LogDrops: 0, 227 }, 228 } 229 require.Equal(t, want, packet) 230 } 231 232 func TestDecodeServerStats2(t *testing.T) { 233 raw := []uint8{ 234 0x06, 0x02, 0x00, 0x00, 0x00, 0x36, 0x00, 0x16, 0x00, 0x00, 235 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x07, 0x16, 0xff, 236 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 237 0x00, 0x00, 0x00, 0x10, 0x03, 0xcd, 0x00, 0x00, 0x00, 0x00, 238 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 239 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 240 } 241 packet, err := decodePacket(raw) 242 require.Nil(t, err) 243 want := &ReplyServerStats2{ 244 ReplyHead: ReplyHead{ 245 Version: protoVersionNumber, 246 PKTType: pktTypeCmdReply, 247 Res1: 0, 248 Res2: 0, 249 Command: reqServerStats, 250 Reply: rpyServerStats2, 251 Status: sttSuccess, 252 Sequence: 50796287, 253 }, 254 ServerStats2: ServerStats2{ 255 NTPHits: 0, 256 NKEHits: 1049549, 257 CMDHits: 0, 258 NTPDrops: 0, 259 NKEDrops: 0, 260 CMDDrops: 553648383, 261 LogDrops: 0, 262 NTPAuthHits: 0, 263 }, 264 } 265 require.Equal(t, want, packet) 266 } 267 268 func TestDecodeNTPData(t *testing.T) { 269 raw := []uint8{ 270 0x06, 0x02, 0x00, 0x00, 0x00, 0x39, 0x00, 0x10, 0x00, 0x00, 271 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe9, 0xb2, 0x80, 0xdb, 272 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x01, 273 0xdb, 0x00, 0x23, 0x1c, 0x28, 0x12, 0xfa, 0xce, 0x00, 0x00, 274 0x01, 0x7b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x24, 0x01, 275 0xdb, 0x00, 0xee, 0xf0, 0x11, 0x20, 0x35, 0x20, 0x00, 0x00, 276 0x20, 0x08, 0x0f, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x7b, 277 0x00, 0x04, 0x04, 0x02, 0x0a, 0xe8, 0xe4, 0x80, 0x00, 0x00, 278 0xe4, 0x80, 0x00, 0x00, 0x23, 0xe1, 0x0b, 0x36, 0x00, 0x00, 279 0x00, 0x00, 0x61, 0x3a, 0x39, 0xf0, 0x06, 0x6a, 0xe1, 0xf8, 280 0xf3, 0x50, 0x79, 0x73, 0xfc, 0xa1, 0x7d, 0x6e, 0xd4, 0xb6, 281 0x81, 0xb7, 0xe6, 0xd1, 0xb9, 0x3d, 0x01, 0x04, 0xb6, 0xad, 282 0x43, 0xfd, 0x4b, 0x4b, 0x00, 0x00, 0x11, 0x2f, 0x00, 0x00, 283 0x11, 0x2c, 0x00, 0x00, 0x11, 0x2c, 0xff, 0xff, 0xff, 0xff, 284 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 285 0xff, 0xff, 286 } 287 packet, err := decodePacket(raw) 288 require.Nil(t, err) 289 want := &ReplyNTPData{ 290 ReplyHead: ReplyHead{ 291 Version: protoVersionNumber, 292 PKTType: pktTypeCmdReply, 293 Res1: 0, 294 Res2: 0, 295 Command: reqNTPData, 296 Reply: rpyNTPData, 297 Status: sttSuccess, 298 Sequence: 3920789723, 299 }, 300 NTPData: NTPData{ 301 RemoteAddr: net.IP{0x24, 0x01, 0xdb, 0x00, 0x23, 0x1c, 0x28, 0x12, 0xfa, 0xce, 0x00, 0x00, 0x01, 0x7b, 0x00, 0x00}, 302 RemotePort: 123, 303 LocalAddr: net.IP{0x24, 0x01, 0xdb, 0x00, 0xee, 0xf0, 0x11, 0x20, 0x35, 0x20, 0x00, 0x00, 0x20, 0x08, 0x0f, 0x06}, 304 Leap: 0, 305 Version: 4, 306 Mode: 4, 307 Stratum: 2, 308 Poll: 10, 309 Precision: -24, 310 RootDelay: 1.52587890625e-05, 311 RootDispersion: 1.52587890625e-05, 312 RefID: 601951030, 313 RefTime: time.Unix(0, 1631205872107667960), 314 Offset: -0.0026783079374581575, 315 PeerDelay: 0.07885251939296722, 316 PeerDispersion: 8.49863042162724e-08, 317 ResponseTime: 5.000199962523766e-05, 318 JitterAsymmetry: -0.49079379439353943, 319 Flags: 17405, 320 TXTssChar: 75, 321 RXTssChar: 75, 322 TotalTXCount: 4399, 323 TotalRXCount: 4396, 324 TotalValidCount: 4396, 325 }, 326 } 327 require.Equal(t, want, packet) 328 } 329 330 func TestDecodeActivity(t *testing.T) { 331 raw := []uint8{ 332 0x06, 0x02, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x0c, 0x00, 0x00, 333 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa7, 0xa8, 0x73, 0x83, 334 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 335 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 336 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 337 } 338 packet, err := decodePacket(raw) 339 require.Nil(t, err) 340 want := &ReplyActivity{ 341 ReplyHead: ReplyHead{ 342 Version: protoVersionNumber, 343 PKTType: pktTypeCmdReply, 344 Res1: 0, 345 Res2: 0, 346 Command: reqActivity, 347 Reply: rpyActivity, 348 Status: sttSuccess, 349 Sequence: 2812834691, 350 }, 351 Activity: Activity{ 352 Online: 4, 353 Offline: 0, 354 BurstOnline: 0, 355 BurstOffline: 0, 356 Unresolved: 0, 357 }, 358 } 359 require.Equal(t, want, packet) 360 } 361 362 func TestSourceStateTypeToString(t *testing.T) { 363 v := SourceStateUnreach 364 got := v.String() 365 want := "unreach" 366 require.Equal(t, want, got) 367 368 v = SourceStateType(10) 369 got = v.String() 370 want = "unknown (10)" 371 require.Equal(t, want, got) 372 } 373 374 func TestModeTypeToString(t *testing.T) { 375 v := SourceModeRef 376 got := v.String() 377 want := "reference clock" 378 require.Equal(t, want, got) 379 380 v = ModeType(10) 381 got = v.String() 382 want = "unknown (10)" 383 require.Equal(t, want, got) 384 } 385 386 func FuzzDecodePacket(f *testing.F) { 387 tracking := []uint8{ 388 0x06, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x05, 0x00, 0x00, 389 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 390 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0x25, 391 0xc6, 0x6e, 0x24, 0x01, 0xdb, 0x00, 0x31, 0x10, 0x21, 0x32, 392 0xfa, 0xce, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x02, 393 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 394 0x61, 0x38, 0xe1, 0x81, 0x36, 0x94, 0x8d, 0xd5, 0xdf, 0x19, 395 0x2d, 0xb7, 0xdf, 0x42, 0x83, 0xf5, 0xe2, 0xeb, 0xca, 0x12, 396 0x05, 0x39, 0xe1, 0x11, 0xeb, 0x7b, 0x3e, 0x5d, 0xf4, 0xb0, 397 0x75, 0x12, 0xea, 0xe7, 0x5b, 0x0c, 0xf0, 0x88, 0x1d, 0x4e, 398 0x16, 0x82, 0x1f, 0x69, 399 } 400 for _, seed := range [][]byte{{}, {0}, {9}, tracking} { 401 f.Add(seed) 402 } 403 f.Fuzz(func(t *testing.T, b []byte) { 404 packet, err := decodePacket(b) 405 if err != nil { 406 require.Nil(t, packet) 407 } 408 }) 409 }