aboutsummaryrefslogtreecommitdiff
path: root/getter/time-app.go
diff options
context:
space:
mode:
Diffstat (limited to 'getter/time-app.go')
-rw-r--r--getter/time-app.go185
1 files changed, 185 insertions, 0 deletions
diff --git a/getter/time-app.go b/getter/time-app.go
new file mode 100644
index 0000000..cd91751
--- /dev/null
+++ b/getter/time-app.go
@@ -0,0 +1,185 @@
+package getter
+
+import (
+ "encoding/binary"
+ "errors"
+ "log"
+ "net"
+ "time"
+)
+
+const (
+ InfoColor = "\033[1;34m%s\033[0m"
+ NoticeColor = "\033[1;36m%s\033[0m"
+ WarningColor = "\033[1;33m%s\033[0m"
+ ErrorColor = "\033[1;31m%s\033[0m"
+ DebugColor = "\033[0;36m%s\033[0m"
+)
+const (
+ LI_NO_WARNING = 0
+ LI_ALARM_CONDITION = 3
+ VN_FIRST = 1
+ VN_LAST = 4
+ MODE_CLIENT = 3
+ FROM_1900_TO_1970 = 2208988800
+)
+
+func Serve(req []byte, addr net.Addr) ([]byte, error) {
+ if validFormat(req) {
+ res := generate(req, addr)
+ return res, nil
+ }
+ return []byte{}, errors.New("invalid format.")
+}
+
+func validFormat(req []byte) bool {
+ var l = req[0] >> 6
+ var v = (req[0] << 2) >> 5
+ var m = (req[0] << 5) >> 5
+ if (l == LI_NO_WARNING) || (l == LI_ALARM_CONDITION) {
+ if (v >= VN_FIRST) && (v <= VN_LAST) {
+ if m == MODE_CLIENT {
+ return true
+ }
+ }
+ }
+ return false
+}
+func unix2ntp(u int64) int64 {
+ return u + FROM_1900_TO_1970
+}
+
+func ntp2unix(n int64) int64 {
+ return n - FROM_1900_TO_1970
+}
+
+func int2bytes(i int64) []byte {
+ var b = make([]byte, 4)
+ h1 := i >> 24
+ h2 := (i >> 16) - (h1 << 8)
+ h3 := (i >> 8) - (h1 << 16) - (h2 << 8)
+ h4 := byte(i)
+ b[0] = byte(h1)
+ b[1] = byte(h2)
+ b[2] = byte(h3)
+ b[3] = byte(h4)
+ return b
+}
+
+func NTPPickup(upntp []string, ClientIP net.Addr) time.Time {
+ for _, addr := range upntp {
+ log.Println("\033[1;34mrequest\033[0m ---> asking for time from", ClientIP)
+ log.Println("\033[1;36maccess\033[0m ----> trying to ntp server:", addr)
+ custom, err := ntpaccessclient(addr)
+ if err == nil {
+ log.Println("\033[1;32msuccess\033[0m ---> time received from:", addr)
+ log.Println("\033[1;32mresponse\033[0m --> answering to the client", ClientIP)
+ return custom
+ }
+ log.Printf("\033[1;31merror\033[0m -----> ntp address: %v (%v)\n", addr, err)
+
+ }
+ log.Println("\033[1;31merror\033[0m -----> can not get anything from ntp servers!")
+ log.Println("\033[1;33mwarining\033[0m --> passing system time to client (might be wrong!)")
+ return time.Now()
+}
+
+var ArgNTP []string
+
+func generate(req []byte, addr net.Addr) []byte {
+ custom := NTPPickup(ArgNTP, addr)
+ var second = unix2ntp(custom.Unix())
+ var fraction = unix2ntp(int64(custom.Nanosecond()))
+ var res = make([]byte, 48)
+ var vn = req[0] & 0x38
+ res[0] = vn + 4
+ res[1] = 1
+ res[2] = req[2]
+ res[3] = 0xEC
+ res[12] = 0x4E
+ res[13] = 0x49
+ res[14] = 0x43
+ res[15] = 0x54
+ copy(res[16:20], int2bytes(second)[0:])
+ copy(res[24:32], req[40:48])
+ copy(res[32:36], int2bytes(second)[0:])
+ copy(res[36:40], int2bytes(fraction)[0:])
+ copy(res[40:48], res[32:40])
+ return res
+}
+
+type mode byte
+
+const (
+ reserved mode = 0 + iota
+ symmetricActive
+ symmetricPassive
+ client
+ server
+ broadcast
+ controlMessage
+ reservedPrivate
+)
+
+type ntpTime struct {
+ Seconds uint32
+ Fraction uint32
+}
+
+func (t ntpTime) UTC() time.Time {
+ nsec := uint64(t.Seconds)*1e9 + (uint64(t.Fraction) * 1e9 >> 32)
+ return time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC).Add(time.Duration(nsec))
+}
+
+type msg struct {
+ LiVnMode byte
+ Stratum byte
+ Poll byte
+ Precision byte
+ RootDelay uint32
+ RootDispersion uint32
+ ReferenceId uint32
+ ReferenceTime ntpTime
+ OriginTime ntpTime
+ ReceiveTime ntpTime
+ TransmitTime ntpTime
+}
+
+func (m *msg) SetVersion(v byte) {
+ m.LiVnMode = (m.LiVnMode & 0xc7) | v<<3
+}
+
+func (m *msg) SetMode(md mode) {
+ m.LiVnMode = (m.LiVnMode & 0xf8) | byte(md)
+}
+
+func ntpaccessclient(host string) (time.Time, error) {
+ raddr, err := net.ResolveUDPAddr("udp", host)
+ if err != nil {
+ return time.Now(), err
+ }
+
+ con, err := net.DialUDP("udp", nil, raddr)
+ if err != nil {
+ return time.Now(), err
+ }
+ defer con.Close()
+ con.SetDeadline(time.Now().Add(5 * time.Second))
+
+ m := new(msg)
+ m.SetMode(client)
+ m.SetVersion(4)
+
+ err = binary.Write(con, binary.BigEndian, m)
+ if err != nil {
+ return time.Now(), err
+ }
+
+ err = binary.Read(con, binary.BigEndian, m)
+ if err != nil {
+ return time.Now(), err
+ }
+
+ t := m.ReceiveTime.UTC().Local()
+ return t, nil
+}

Snix LLC Git Repository Holder Copyright(C) 2022 All Rights Reserved Email To Snix.IR