diff --git a/README.md b/README.md
index 43a868d..ce4b440 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@ NTPal is an in-development, incomplete, and rough around the edges implementatio
## Code Credits
-The code for NTPal is _very_ similar to pseudocode provided in the [NTPv4 RFC](https://datatracker.ietf.org/doc/html/rfc5905), which is nicely documented and made for a good rewriting experience. Certain changes were made based on more recent additions to projects such as [ntpd](https://github.com/ntp-project/ntp), [chrony](https://github.com/mlichvar/chrony), and others. Additionally, some care was taken to map the program's requirements into better-fit Golang structures, but there's still some room for improvement (especially regarding race conditions).
+The code for NTPal is _very_ similar to pseudocode provided in the [NTPv4 RFC](https://datatracker.ietf.org/doc/html/rfc5905), which is nicely documented and made for a good rewriting experience. Certain changes were made based on more recent additions to projects such as [ntpd](https://github.com/ntp-project/ntp), [chrony](https://github.com/mlichvar/chrony), and others. Additionally, some care was taken to map the program's requirements into better-fit Golang structures, but there's room for improvement (especially regarding race conditions).
## Usage
@@ -25,6 +25,12 @@ NTPal uses a configuration format similar to the [standard `ntpd` config](https:
- `server
[key _key_] [burst] [iburst] [version _version_] [prefer] [minpoll _minpoll_] [maxpoll _maxpoll_]`
- `driftfile `
+Some environment variables are also available to configure the application's runtime and logging:
+
+- `SYMMETRIC`: Set to "1" to allow symmetric active servers to connect.
+- `INFO`: Set to "1" to print periodic system information logs.
+- `DEBUG`: Set to "1" to print timeseries clock statistics meant for graphing.
+
### NTPal — Query
NTPal supports a simpler "query" flag to simply obtain your device's time offset from an NTP server. Accessible via `--query` or `-q`, 5 messages are sent in an attempt to obtain the best measurement possible. This command functions almost identically to the `sntp` command shipped with OSX, though NTPal has far less functionality.
diff --git a/fly.toml b/fly.toml
index f701718..96f046e 100644
--- a/fly.toml
+++ b/fly.toml
@@ -8,7 +8,6 @@ kill_timeout = 5
NTP_PORT = "123"
NTP_HOST = "fly-global-services"
REPORT_PORT = "8080"
- ENABLED = "1"
INFO = "1"
[[mounts]]
diff --git a/internal/templates/templates/index.tmpl.html b/internal/templates/templates/index.tmpl.html
index 03b6e0d..1de905b 100644
--- a/internal/templates/templates/index.tmpl.html
+++ b/internal/templates/templates/index.tmpl.html
@@ -289,18 +289,16 @@ According to this server,
}
const { offset } = minDelayAttempt;
- let serverTime = new Date((Date.now() / 1e3 + offset) * 1e3);
+ let serverTime = new Date(Date.now() + offset / 1e3);
// Wait for the second to hit
await sleep(1e3 - (serverTime % 1e3));
setInterval(() => {
- const serverTime = new Date(
- (Date.now() / 1e3 + offset) * 1e3
- );
+ const serverTime = new Date(Date.now() + offset / 1e3);
displayTime(serverTime);
}, 1000);
- serverTime = new Date((Date.now() / 1e3 + offset) * 1e3);
+ serverTime = new Date(Date.now() + offset / 1e3);
displayTime(serverTime);
const offsetMessage = offset < 0 ? 'ahead' : 'behind';
@@ -308,7 +306,6 @@ According to this server,
offset
).toFixed(3)} seconds`; // We do have up to microsecond precision, but it's not great...
elems.offset.classList.add('done');
-
elems.time.classList.add('done');
}
diff --git a/pkg/ntp/ntp.go b/pkg/ntp/ntp.go
index 3eb5fa8..8adb95d 100644
--- a/pkg/ntp/ntp.go
+++ b/pkg/ntp/ntp.go
@@ -18,7 +18,7 @@ const PORT = 123 // NTP port number
const VERSION byte = 4 // NTP version number
const TOLERANCE = 15e-6 //frequency tolerance PHI (s/s)
const MINPOLL int8 = 6 //minimum poll exponent (64 s)
-const MAXPOLL int8 = 17 // maximum poll exponent (36 h)
+const MAXPOLL int8 = 16 // maximum poll exponent (36 h)
const MAXDISP float64 = 16 // maximum dispersion (16 s)
const MINDISP = 0.005 // minimum dispersion increment (s)
const NOSYNC byte = 0x3 // leap unsync
@@ -696,8 +696,10 @@ func (system *NTPSystem) sendPoll(association *Association) {
if err != nil {
log.Fatal("Invalid address: ", association.hostname)
}
+ if association.srcaddr == addr {
+ hpoll++
+ }
association.srcaddr = addr
- hpoll++
association.unreach = -1
}
association.unreach++
@@ -768,9 +770,20 @@ func (system *NTPSystem) receive(packet ReceivePacket) *TransmitPacket {
// else if (auth == A_ERROR)
// fast_xmit(r, M_SERV, A_CRYPTO);
// return; /* M_SERV packet sent */
+ case NEWPS:
+ if !isSymmetricEnabled() {
+ return nil
+ }
+
+ association = &Association{
+ ReceivePacket: packet,
+ hmode: SYMMETRIC_PASSIVE,
+ ephemeral: true,
+ }
+ system.clear(association, INIT)
+ system.associations = append(system.associations, association)
case PROC:
- break
- case DSCRD:
+ default:
return nil
}
@@ -1086,6 +1099,9 @@ func (system *NTPSystem) clockFilter(association *Association, offset float64, d
for i := NSTAGE - 1; i > 0; i-- {
association.f[i] = association.f[i-1]
association.f[i].disp += PHI * (float64(system.clock.t) - association.t)
+ if association.f[i].disp > MAXDISP {
+ association.f[i].disp = MAXDISP
+ }
f[i] = association.f[i]
}
association.f[0].t = system.clock.t
@@ -1107,7 +1123,7 @@ func (system *NTPSystem) clockFilter(association *Association, offset float64, d
association.disp = 0
association.jitter = 0
for i := NSTAGE - 1; i >= 0; i-- {
- association.disp += f[i].disp / math.Pow(2, float64(i+1))
+ association.disp = 0.5 * (association.disp + f[i].disp)
if i < m {
association.jitter += math.Pow((f[0].offset - f[i].offset), 2)
}
@@ -1443,8 +1459,7 @@ func (system *NTPSystem) clockUpdate(association *Association) {
}
system.reftime = association.Reftime
system.rootdelay = association.Rootdelay + association.delay
- dtemp := math.Sqrt(math.Pow(association.jitter, 2) + math.Pow(system.jitter, 2))
- dtemp += math.Max(association.disp+PHI*(float64(system.clock.t)-association.t)+
+ dtemp := math.Max(association.disp+system.jitter+PHI*(float64(system.clock.t)-association.t)+
math.Abs(association.offset), MINDISP)
system.rootdisp = association.Rootdisp + dtemp
/*
diff --git a/pkg/ntp/system.go b/pkg/ntp/system.go
index 6f29305..113953e 100644
--- a/pkg/ntp/system.go
+++ b/pkg/ntp/system.go
@@ -24,11 +24,10 @@ func stepTime(offset float64) {
Sec -= unixEraOffset
info("CURRENT:", NTPTimestampToTime(systemTime), "STEPPING TO:", NTPTimestampToTime(ntpTime), "OFFSET WAS:", offset)
- if shouldSetTime() {
- err := settimeofday.Settimeofday(Sec, Usec)
- if err != nil {
- info("SETTIMEOFDAYERR:", err)
- }
+
+ err := settimeofday.Settimeofday(Sec, Usec)
+ if err != nil {
+ info("SETTIMEOFDAYERR:", err)
}
}
@@ -50,10 +49,8 @@ func adjustTime(offset float64) {
Usec += 1e6
}
- if shouldSetTime() {
- err := adjtime.Adjtime(Sec, Usec)
- if err != nil {
- info("ADJTIME ERROR:", err, "offset:", offset)
- }
+ err := adjtime.Adjtime(Sec, Usec)
+ if err != nil {
+ info("ADJTIME ERROR:", err, "offset:", offset)
}
}
diff --git a/pkg/ntp/utils.go b/pkg/ntp/utils.go
index f662550..2ef5eef 100644
--- a/pkg/ntp/utils.go
+++ b/pkg/ntp/utils.go
@@ -5,10 +5,6 @@ import (
"os"
)
-func shouldSetTime() bool {
- return os.Getenv("ENABLED") == "1"
-}
-
func info(args ...any) {
if isInfo() {
fmt.Println(args...)
@@ -28,3 +24,7 @@ func isInfo() bool {
func isDebug() bool {
return os.Getenv("DEBUG") == "1"
}
+
+func isSymmetricEnabled() bool {
+ return os.Getenv("SYMMETRIC") == "1"
+}