github.com/coyove/sdss@v0.0.0-20231129015646-c2ec58cca6a2/future/chrony/helpers.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 "fmt" 21 "math" 22 "net" 23 "time" 24 "unicode" 25 ) 26 27 // ChronySocketPath is the default path to chronyd socket 28 const ChronySocketPath = "/var/run/chrony/chronyd.sock" 29 30 // ChronyPortV6Regexp is a regexp to find anything that listens on port 323 31 // hex(323) = '0x143' 32 const ChronyPortV6Regexp = "[0-9]+: [0-9A-Z]+:0143 .*" 33 34 // This is used in timeSpec.SecHigh for 32-bit timestamps 35 const noHighSec uint32 = 0x7fffffff 36 37 // ip stuff 38 const ( 39 ipAddrInet4 uint16 = 1 40 ipAddrInet6 uint16 = 2 41 ) 42 43 // magic numbers to convert chronyFloat to normal float 44 const ( 45 floatExpBits = 7 46 floatCoefBits = (4*8 - floatExpBits) 47 ) 48 49 type ipAddr struct { 50 IP [16]uint8 51 Family uint16 52 Pad uint16 53 } 54 55 func (ip *ipAddr) ToNetIP() net.IP { 56 if ip.Family == ipAddrInet4 { 57 return net.IP(ip.IP[:4]) 58 } 59 return net.IP(ip.IP[:]) 60 } 61 62 func newIPAddr(ip net.IP) *ipAddr { 63 family := ipAddrInet6 64 if ip.To4() != nil { 65 family = ipAddrInet4 66 } 67 var nIP [16]byte 68 copy(nIP[:], ip) 69 return &ipAddr{ 70 IP: nIP, 71 Family: family, 72 } 73 } 74 75 type timeSpec struct { 76 SecHigh uint32 77 SecLow uint32 78 Nsec uint32 79 } 80 81 func (t *timeSpec) ToTime() time.Time { 82 highU64 := uint64(t.SecHigh) 83 if t.SecHigh == noHighSec { 84 highU64 = 0 85 } 86 lowU64 := uint64(t.SecLow) 87 return time.Unix(int64(highU64<<32|lowU64), int64(t.Nsec)) 88 } 89 90 /* 91 32-bit floating-point format consisting of 7-bit signed exponent 92 and 25-bit signed coefficient without hidden bit. 93 The result is calculated as: 2^(exp - 25) * coef 94 */ 95 type chronyFloat int32 96 97 // ToFloat does magic to decode float from int32. 98 // Code is copied and translated to Go from original C sources. 99 func (f chronyFloat) ToFloat() float64 { 100 var exp, coef int32 101 102 x := uint32(f) 103 104 exp = int32(x >> floatCoefBits) 105 if exp >= 1<<(floatExpBits-1) { 106 exp -= 1 << floatExpBits 107 } 108 exp -= floatCoefBits 109 110 coef = int32(x % (1 << floatCoefBits)) 111 if coef >= 1<<(floatCoefBits-1) { 112 coef -= 1 << floatCoefBits 113 } 114 115 return float64(coef) * math.Pow(2.0, float64(exp)) 116 } 117 118 // RefidAsHEX prints ref id as hex 119 func RefidAsHEX(refID uint32) string { 120 return fmt.Sprintf("%08X", refID) 121 } 122 123 // RefidToString decodes ASCII string encoded as uint32 124 func RefidToString(refID uint32) string { 125 result := []rune{} 126 127 for i := 0; i < 4 && i < 64-1; i++ { 128 c := rune((refID >> (24 - uint(i)*8)) & 0xff) 129 if unicode.IsPrint(c) { 130 result = append(result, c) 131 } 132 } 133 134 return string(result) 135 } 136 137 /* NTP tests from RFC 5905: 138 +--------------------------+----------------------------------------+ 139 | Packet Type | Description | 140 +--------------------------+----------------------------------------+ 141 | 1 duplicate packet | The packet is at best an old duplicate | 142 | | or at worst a replay by a hacker. | 143 | | This can happen in symmetric modes if | 144 | | the poll intervals are uneven. | 145 | 2 bogus packet | | 146 | 3 invalid | One or more timestamp fields are | 147 | | invalid. This normally happens in | 148 | | symmetric modes when one peer sends | 149 | | the first packet to the other and | 150 | | before the other has received its | 151 | | first reply. | 152 | 4 access denied | The access controls have blacklisted | 153 | | the source. | 154 | 5 authentication failure | The cryptographic message digest does | 155 | | not match the MAC. | 156 | 6 unsynchronized | The server is not synchronized to a | 157 | | valid source. | 158 | 7 bad header data | One or more header fields are invalid. | 159 +--------------------------+----------------------------------------+ 160 161 chrony doesn't do test #4, but adds four extra tests: 162 * maximum delay 163 * delay ratio 164 * delay dev ratio 165 * synchronisation loop. 166 167 Those tests are roughly equivalent to ntpd 'flashers' 168 */ 169 170 // NTPTestDescMap maps bit mask with corresponding flash status 171 var NTPTestDescMap = map[uint16]string{ 172 0x0001: "pkt_dup", 173 0x0002: "pkt_bogus", 174 0x0004: "pkt_invalid", 175 0x0008: "pkt_auth", 176 0x0010: "pkt_stratum", 177 0x0020: "pkt_header", 178 0x0040: "tst_max_delay", 179 0x0080: "tst_delay_ratio", 180 0x0100: "tst_delay_dev_ration", 181 0x0200: "tst_sync_loop", 182 } 183 184 // ReadNTPTestFlags returns list of failed ntp test flags (as strings) 185 func ReadNTPTestFlags(flags uint16) []string { 186 testFlags := flags & NTPFlagsTests 187 results := []string{} 188 for mask, message := range NTPTestDescMap { 189 if testFlags&mask == 0 { 190 results = append(results, message) 191 } 192 } 193 return results 194 }