github.com/sagernet/sing@v0.4.0-beta.19.0.20240518125136-f67a0988a636/common/ntp/ntp.go (about) 1 package ntp 2 3 import ( 4 "context" 5 "crypto/rand" 6 "encoding/binary" 7 "time" 8 9 M "github.com/sagernet/sing/common/metadata" 10 N "github.com/sagernet/sing/common/network" 11 ) 12 13 func Exchange(ctx context.Context, dialer N.Dialer, serverAddress M.Socksaddr) (*Response, error) { 14 conn, err := dialer.DialContext(ctx, N.NetworkUDP, serverAddress) 15 if err != nil { 16 return nil, err 17 } 18 defer conn.Close() 19 conn.SetDeadline(time.Now().Add(defaultTimeout)) 20 21 var request msg 22 request.setMode(client) 23 request.setVersion(defaultNtpVersion) 24 request.setLeap(LeapNotInSync) 25 26 bits := make([]byte, 8) 27 _, err = rand.Read(bits) 28 var xmitTime time.Time 29 if err == nil { 30 request.TransmitTime = ntpTime(binary.BigEndian.Uint64(bits)) 31 xmitTime = time.Now() 32 } else { 33 xmitTime = time.Now() 34 request.TransmitTime = toNtpTime(xmitTime) 35 } 36 37 err = binary.Write(conn, binary.BigEndian, request) 38 if err != nil { 39 return nil, err 40 } 41 42 var response msg 43 err = binary.Read(conn, binary.BigEndian, &response) 44 if err != nil { 45 return nil, err 46 } 47 48 recvTime := toNtpTime(xmitTime.Add(time.Since(xmitTime))) 49 response.OriginTime = toNtpTime(xmitTime) 50 return parseTime(&response, recvTime), nil 51 }