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  }