4 Copyright (C) 2006-2009 Jonathan Zarate
6 Licensed under GNU GPL v2 or later.
13 #include <sys/socket.h>
15 #include <arpa/inet.h>
31 #define TIMEFIX 2208988800UL
34 static void add_word(char *buffer
, const char *word
, int max
)
36 if ((*buffer
!= 0) && (buffer
[strlen(buffer
) - 1] != ' '))
37 strlcat(buffer
, " ", max
);
38 strlcat(buffer
, word
, max
);
41 // 0 = ok, 1 = failed, 2 = permanent failure
42 static int ntpc(struct in_addr addr
)
45 struct timeval txtime
;
46 struct timeval rxtime
;
53 struct sockaddr_in sa
;
59 memset(&sa
, 0, sizeof(sa
));
61 sa
.sin_port
= htons(123);
62 sa
.sin_family
= AF_INET
;
64 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
)) == -1) {
65 printf("Unable to create a socket\n");
69 if (connect(fd
, (struct sockaddr
*)&sa
, sizeof(sa
)) == -1) {
70 printf("Unable to connect\n");
73 memset(&packet
, 0, sizeof(packet
));
74 packet
[I_MISC
] = htonl((4 << 27) | (3 << 24)); // VN=v4 | mode=3 (client)
75 // packet[I_MISC] = htonl((3 << 27) | (3 << 24)); // VN=v3 | mode=3 (client)
76 gettimeofday(&txtime
, NULL
);
77 packet
[I_TXTIME
] = txn
= htonl(txtime
.tv_sec
+ TIMEFIX
);
78 send(fd
, packet
, sizeof(packet
), 0);
82 tv
.tv_sec
= 3; // no more than 3 seconds
84 if (select(fd
+ 1, &fds
, NULL
, NULL
, &tv
) != 1) {
88 len
= recv(fd
, packet
, sizeof(packet
), 0);
89 if (len
!= sizeof(packet
)) {
90 printf("Invalid packet size\n");
93 gettimeofday(&rxtime
, NULL
);
97 _dprintf("u = 0x%08x\n", u
);
98 _dprintf("LI = %u\n", u
>> 30);
99 _dprintf("VN = %u\n", (u
>> 27) & 0x07);
100 _dprintf("mode = %u\n", (u
>> 24) & 0x07);
101 _dprintf("stratum = %u\n", (u
>> 16) & 0xFF);
102 _dprintf("poll interval = %u\n", (u
>> 8) & 0xFF);
103 _dprintf("precision = %u\n", u
& 0xFF);
105 if ((u
& 0x07000000) != 0x04000000) { // mode != 4 (server)
106 printf("Invalid response\n");
112 // - Windows' ntpd returns vn=3, stratum=0
114 if ((u
& 0x00FF0000) == 0) { // stratum == 0
115 printf("Received stratum=0\n");
116 if (!nvram_match("ntp_kiss_ignore", "1")) {
121 ntpt
= ntohl(packet
[I_TXTIME
]) - TIMEFIX
;
122 t
= (rxtime
.tv_sec
- txtime
.tv_sec
) >> 1;
123 diff
= (ntpt
- rxtime
.tv_sec
) + t
;
125 _dprintf("txtime = %ld\n", txtime
.tv_sec
);
126 _dprintf("rxtime = %ld\n", rxtime
.tv_sec
);
127 _dprintf("ntpt = %ld\n", ntpt
);
128 _dprintf("rtt/2 = %ld\n", t
);
129 _dprintf("diff = %ld\n", diff
);
132 gettimeofday(&tv
, NULL
);
134 // tv.tv_usec = 0;// sorry, I'm not a time geek :P
135 settimeofday(&tv
, NULL
);
137 _dprintf("new = %lu\n", tv
.tv_sec
);
139 strftime(s
, sizeof(s
), "%a, %d %b %Y %H:%M:%S %z", localtime(&tv
.tv_sec
));
140 sprintf(q
, "Time Updated: %s [%s%lds]", s
, diff
> 0 ? "+" : "", diff
);
144 strftime(s
, sizeof(s
), "%a, %d %b %Y %H:%M:%S %z", localtime(&t
));
145 sprintf(q
, "Time: %s, no change was needed.", s
);
147 printf("\n\n%s\n", q
);
160 // -----------------------------------------------------------------------------
163 static int ntpc_main(int argc
, char **argv
)
170 for (i
= 1; i
< argc
; ++i
) {
171 if ((he
= gethostbyname(argv
[i
])) != NULL
) {
172 memcpy(&ia
, he
->h_addr_list
[0], sizeof(ia
));
174 if (strcmp(s
, argv
[i
]) == 0) printf("Trying %s: ", s
);
175 else printf("Trying %s [%s]:", argv
[i
], s
);
176 if (ntpc(ia
) == 0) return 0;
179 printf("Unable to resolve: %s\n", argv
[i
]);
184 printf("Usage: ntpc <server>\n");
191 // -----------------------------------------------------------------------------
194 static int ntpsync_main(int argc
, char **argv
)
196 char *servers
, *t
, *p
;
209 enum { USER
, INIT
, CRON
} mode
;
211 nu
= nvram_get_int("ntp_updates");
215 if (strcmp(argv
[1], "--cron") == 0) { // try for a few minutes
217 eval("cru", "d", "ntpsync");
222 else if (strcmp(argv
[1], "--init") == 0) { // try forever, schedule cron job
223 if (fork() != 0) return 0;
230 else if (argc
!= 1) {
234 _dprintf("[ntpsync %ld] start\n", get_uptime());
236 if ((get_wan_proto() != WP_DISABLED
) && (mode
!= INIT
) &&
237 (!check_wanup()) && (nvram_match("ntp_tdod", "0"))) {
238 _dprintf("WAN is down, not updating.");
246 _dprintf("[ntpsync %ld] while\n", get_uptime());
250 servers
= p
= strdup(nvram_safe_get("ntp_server"));
253 printf("Not enough memory\n");
256 while ((count
< 10) && ((t
= strsep(&p
, " ")) != NULL
)) {
257 if (*t
!= 0) addr
[count
++] = t
;
259 if (count
== 0) addr
[count
++] = "pool.ntp.org";
262 i
= (rand() % count
);
263 _dprintf("[ntpsync] i=%d addr=%s\n", i
, addr
[i
]);
265 if ((he
= gethostbyname(addr
[i
])) != NULL
) {
266 memcpy(&ia
, he
->h_addr_list
[0], sizeof(ia
));
268 _dprintf("ip = %s\n", ips
);
270 nvkiss
= nvram_safe_get("ntp_kiss");
271 if (find_word(nvkiss
, ips
)) {
272 _dprintf("kiss: %s\n", ips
);
277 _dprintf("[ntpsync] %ld OK\n", get_uptime());
280 if ((nu
> 0) && ((tms
= localtime(&tt
)) != NULL
)) {
282 // add some randomness to make the servers happier / avoid the xx:00 rush
283 sprintf(s
, "%d ", (tms
->tm_min
+ 20 + (rand() % 20)) % 60);
285 // schedule every nu hours
286 for (i
= 0; i
< 24; ++i
) {
287 if ((i
% nu
) == 0) sprintf(s
+ strlen(s
), "%s%d", i
? "," : "", (i
+ tms
->tm_hour
+ 1) % 24);
289 strcat(s
, " * * * ntpsync --cron");
290 eval("cru", "a", "ntpsync", s
);
294 // make sure access restriction is ok
296 _dprintf("[ntpsync] %ld exit\n", get_uptime());
299 while ((nvkiss
) && (strlen(nvkiss
) > 128)) nvkiss
= strchr(nvkiss
+ 1, ' ');
300 if (nvkiss
) strlcpy(s
, nvkiss
, sizeof(s
));
302 add_word(s
, ips
, sizeof(s
));
303 nvram_set("ntp_kiss", s
);
304 syslog(LOG_WARNING
, "Received a kiss of death packet from %s (%s).", addr
[i
], ips
);
310 addr
[i
] = addr
[--count
];
314 if (mode
== USER
) break;
315 if ((mode
== CRON
) && (retries
== 5)) break;
317 if (++retries
> 300) retries
= 300; // 5m
318 _dprintf("[ntpsync %ld] sleep=%d\n", get_uptime(), retries
);
322 _dprintf("[ntpsync] %ld exit\n", get_uptime());
326 // -----------------------------------------------------------------------------
329 static int ntpstep_main(int argc
, char **argv
)
335 printf("Usage: ntpstep <seconds>\n");
339 gettimeofday(&tv
, NULL
);
340 tv
.tv_sec
+= atol(argv
[1]);
341 settimeofday(&tv
, NULL
);
343 strftime(s
, sizeof(s
), "%a, %d %b %Y %H:%M:%S %z", localtime(&tv
.tv_sec
));
349 // -----------------------------------------------------------------------------
351 int main(int argc
, char **argv
)
353 openlog("ntpc", LOG_PID
, LOG_USER
);
354 if (!nvram_contains_word("log_events", "ntp")) {
355 setlogmask(LOG_MASK(LOG_EMERG
)); // can't set to 0
358 if (strstr(argv
[0], "ntpsync") != NULL
) return ntpsync_main(argc
, argv
);
359 if (strstr(argv
[0], "ntpstep") != NULL
) return ntpstep_main(argc
, argv
);
361 return ntpc_main(argc
, argv
);
368 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
369 +---+-----+-----+---------------+---------------+----------------+
370 |LI | VN |Mode | Stratum | Poll | Precision | 0
371 +---+-----+-----+---------------+---------------+----------------+
373 +----------------------------------------------------------------+
374 | Root Dispersion | 2
375 +----------------------------------------------------------------+
376 | Reference Identifier | 3
377 +----------------------------------------------------------------+
378 | Reference Timestamp (64) | 4
379 +----------------------------------------------------------------+
380 | Originate Timestamp (64) | 6
381 +----------------------------------------------------------------+
382 | Receive Timestamp (64) | 8
383 +----------------------------------------------------------------+
384 | Transmit Timestamp (64) | 10
385 +----------------------------------------------------------------+
386 | Key Identifier (optional) (32) | 12
387 +----------------------------------------------------------------+
388 | Message Digest (optional) (128) | 13+
389 +----------------------------------------------------------------+
395 25,567 days can be converted to one of these units:
396 * 2,208,988,800 seconds
399 * 3652 weeks (rounded down)
402 http://www.faqs.org/rfcs/rfc2030.html
403 http://www.ntp.org/ntpfaq/NTP-s-algo.htm