1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
|
use std::fs;
use std::io;
use std::net::{self, IpAddr, SocketAddr};
use std::path::Path;
use std::thread;
use std::time::Duration;
use chrono::DateTime;
use nix::sys::time::TimeSpec;
use nix::time::ClockId;
use thiserror::Error;
use trust_dns_resolver::config::{NameServerConfig, Protocol, ResolverConfig, ResolverOpts};
use trust_dns_resolver::Resolver;
const EPOCH_OFFSET: i64 = 2208988800;
const NTP_SERVER: &str = "2.pool.ntp.org";
const NTP_PORT: u16 = 123;
const DNS_SERVER: &str = "[2620:fe::fe]:53";
const INTERVAL: Duration = Duration::from_secs(3600);
#[derive(Debug, Error)]
enum Error {
#[error("can't find ntp server hostname")]
NoHostname,
#[error("io: {0}")]
Io(#[from] io::Error),
#[error("can't parse network address: {0}")]
ParseAddr(#[from] net::AddrParseError),
#[error("chrono parse: {0}")]
ChronoParse(#[from] chrono::ParseError),
#[error("nix errno: {0}")]
NixErrno(#[from] nix::errno::Errno),
#[error("ntp: {0}")]
Ntp(#[from] ntp::errors::Error),
#[error("trust_dns_resolver resolve error: {0}")]
TrustDnsResolve(#[from] trust_dns_resolver::error::ResolveError),
}
type Result<T> = std::result::Result<T, Error>;
fn main() -> Result<()> {
let ds_config = Path::new(rsdsl_ip_config::LOCATION);
while !ds_config.exists() {
println!("wait for pppoe");
thread::sleep(Duration::from_secs(8));
}
loop {
match sync_time(NTP_SERVER) {
Ok(_) => {}
Err(e) => eprintln!("can't synchronize system time: {}", e),
}
thread::sleep(INTERVAL);
}
}
fn last_time_unix() -> Option<i64> {
Some(i64::from_be_bytes(
fs::read("/data/ntp.last_unix").ok()?[..8].try_into().ok()?,
))
}
fn sync_time(server: &str) -> Result<()> {
let last = last_time_unix()
.unwrap_or(DateTime::parse_from_rfc3339(env!("SOURCE_TIMESTAMP"))?.timestamp());
let dns = DNS_SERVER.parse()?;
let server_resolved = SocketAddr::new(resolve_custom_dns(server, dns)?, NTP_PORT);
let time = ntp::request(server_resolved)?.transmit_time;
let mut t = time.sec as i64 - EPOCH_OFFSET;
while t < last {
t += 2_i64.pow(32); // NTP era duration.
}
let timespec = TimeSpec::new(t, 0);
nix::time::clock_settime(ClockId::CLOCK_REALTIME, timespec)?;
fs::write("/data/ntp.last_unix", t.to_be_bytes())?;
println!("set system time");
Ok(())
}
fn resolve_custom_dns(hostname: &str, custom_dns: SocketAddr) -> Result<IpAddr> {
let mut cfg = ResolverConfig::new();
cfg.add_name_server(NameServerConfig::new(custom_dns, Protocol::Udp));
let resolver = Resolver::new(cfg, ResolverOpts::default())?;
let response = resolver.lookup_ip(hostname)?;
let ip_addr = response.iter().next().ok_or(Error::NoHostname)?;
Ok(ip_addr)
}
|