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  }