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>
27 #define _dprintf(args...) do { } while (0);
28 // #define _dprintf(args...) cprintf(args)
35 #define TIMEFIX 2208988800UL
38 static void add_word(char *buffer
, const char *word
, int max
)
40 if ((*buffer
!= 0) && (buffer
[strlen(buffer
) - 1] != ' '))
41 strlcat(buffer
, " ", max
);
42 strlcat(buffer
, word
, max
);
45 // 0 = ok, 1 = failed, 2 = permanent failure
46 static int ntpc(struct in_addr addr
)
49 struct timeval txtime
;
50 struct timeval rxtime
;
57 struct sockaddr_in sa
;
63 memset(&sa
, 0, sizeof(sa
));
65 sa
.sin_port
= htons(123);
66 sa
.sin_family
= AF_INET
;
68 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
)) == -1) {
69 printf("Unable to create a socket\n");
73 if (connect(fd
, (struct sockaddr
*)&sa
, sizeof(sa
)) == -1) {
74 printf("Unable to connect\n");
77 memset(&packet
, 0, sizeof(packet
));
78 packet
[I_MISC
] = htonl((4 << 27) | (3 << 24)); // VN=v4 | mode=3 (client)
79 // packet[I_MISC] = htonl((3 << 27) | (3 << 24)); // VN=v3 | mode=3 (client)
80 gettimeofday(&txtime
, NULL
);
81 packet
[I_TXTIME
] = txn
= htonl(txtime
.tv_sec
+ TIMEFIX
);
82 send(fd
, packet
, sizeof(packet
), 0);
86 tv
.tv_sec
= 3; // no more than 3 seconds
88 if (select(fd
+ 1, &fds
, NULL
, NULL
, &tv
) != 1) {
92 len
= recv(fd
, packet
, sizeof(packet
), 0);
93 if (len
!= sizeof(packet
)) {
94 printf("Invalid packet size\n");
97 gettimeofday(&rxtime
, NULL
);
101 _dprintf("u = 0x%08x\n", u
);
102 _dprintf("LI = %u\n", u
>> 30);
103 _dprintf("VN = %u\n", (u
>> 27) & 0x07);
104 _dprintf("mode = %u\n", (u
>> 24) & 0x07);
105 _dprintf("stratum = %u\n", (u
>> 16) & 0xFF);
106 _dprintf("poll interval = %u\n", (u
>> 8) & 0xFF);
107 _dprintf("precision = %u\n", u
& 0xFF);
109 if ((u
& 0x07000000) != 0x04000000) { // mode != 4 (server)
110 printf("Invalid response\n");
116 // - Windows' ntpd returns vn=3, stratum=0
118 if ((u
& 0x00FF0000) == 0) { // stratum == 0
119 printf("Received stratum=0\n");
120 if (!nvram_match("ntp_kiss_ignore", "1")) {
125 ntpt
= ntohl(packet
[I_TXTIME
]) - TIMEFIX
;
126 t
= (rxtime
.tv_sec
- txtime
.tv_sec
) >> 1;
127 diff
= (ntpt
- rxtime
.tv_sec
) + t
;
129 _dprintf("txtime = %ld\n", txtime
.tv_sec
);
130 _dprintf("rxtime = %ld\n", rxtime
.tv_sec
);
131 _dprintf("ntpt = %ld\n", ntpt
);
132 _dprintf("rtt/2 = %ld\n", t
);
133 _dprintf("diff = %ld\n", diff
);
136 gettimeofday(&tv
, NULL
);
138 // tv.tv_usec = 0;// sorry, I'm not a time geek :P
139 settimeofday(&tv
, NULL
);
141 _dprintf("new = %lu\n", tv
.tv_sec
);
143 strftime(s
, sizeof(s
), "%a, %d %b %Y %H:%M:%S %z", localtime(&tv
.tv_sec
));
144 sprintf(q
, "Time Updated: %s [%s%lds]", s
, diff
> 0 ? "+" : "", diff
);
145 printf("\n\n%s\n", q
);
150 strftime(s
, sizeof(s
), "%a, %d %b %Y %H:%M:%S %z", localtime(&t
));
151 printf("\n\n%s\nNo change was needed.\n", s
);
164 // -----------------------------------------------------------------------------
167 static int ntpc_main(int argc
, char **argv
)
174 for (i
= 1; i
< argc
; ++i
) {
175 if ((he
= gethostbyname(argv
[i
])) != NULL
) {
176 memcpy(&ia
, he
->h_addr_list
[0], sizeof(ia
));
178 if (strcmp(s
, argv
[i
]) == 0) printf("Trying %s: ", s
);
179 else printf("Trying %s [%s]:", argv
[i
], s
);
180 if (ntpc(ia
) == 0) return 0;
183 printf("Unable to resolve: %s\n", argv
[i
]);
188 printf("Usage: ntpc <server>\n");
195 // -----------------------------------------------------------------------------
198 static int ntpsync_main(int argc
, char **argv
)
200 char *servers
, *t
, *p
;
213 enum { USER
, INIT
, CRON
} mode
;
215 nu
= nvram_get_int("ntp_updates");
219 if (strcmp(argv
[1], "--cron") == 0) { // try for a few minutes
221 system("cru d ntpsync");
226 else if (strcmp(argv
[1], "--init") == 0) { // try forever, schedule cron job
227 if (fork() != 0) return 0;
234 else if (argc
!= 1) {
238 _dprintf("[ntpsync %ld] start\n", get_uptime());
240 if ((get_wan_proto() != WP_DISABLED
) && (mode
!= INIT
) &&
241 (!check_wanup()) && (nvram_match("ntp_tdod", "0"))) {
242 _dprintf("WAN is down, not updating.");
250 _dprintf("[ntpsync %ld] while\n", get_uptime());
253 servers
= p
= strdup(nvram_safe_get("ntp_server"));
255 printf("Not enough memory\n");
258 while ((count
< 10) && ((t
= strsep(&p
, " ")) != NULL
)) {
259 if (*t
!= 0) addr
[count
++] = t
;
261 if (count
== 0) addr
[count
++] = "pool.ntp.org";
264 i
= (rand() % count
);
265 _dprintf("[ntpsync] i=%d addr=%s\n", i
, addr
[i
]);
267 if ((he
= gethostbyname(addr
[i
])) != NULL
) {
268 memcpy(&ia
, he
->h_addr_list
[0], sizeof(ia
));
270 _dprintf("ip = %s\n", ips
);
272 nvkiss
= nvram_safe_get("ntp_kiss");
273 if (find_word(nvkiss
, ips
)) {
274 _dprintf("kiss: %s\n", ips
);
279 _dprintf("[ntpsync] %ld OK\n", get_uptime());
282 if ((nu
> 0) && ((tms
= localtime(&tt
)) != NULL
)) {
284 // add some randomness to make the servers happier / avoid the xx:00 rush
285 sprintf(s
, "cru a ntpsync \"%d ", (tms
->tm_min
+ 20 + (rand() % 20)) % 60);
287 // schedule every nu hours
288 for (i
= 0; i
< 24; ++i
) {
289 if ((i
% nu
) == 0) sprintf(s
+ strlen(s
), "%s%d", i
? "," : "", (i
+ tms
->tm_hour
+ 1) % 24);
291 strcat(s
, " * * * ntpsync --cron\"");
296 // make sure access restriction is ok
298 _dprintf("[ntpsync] %ld exit\n", get_uptime());
301 while ((nvkiss
) && (strlen(nvkiss
) > 128)) nvkiss
= strchr(nvkiss
+ 1, ' ');
302 if (nvkiss
) strlcpy(s
, nvkiss
, sizeof(s
));
304 add_word(s
, ips
, sizeof(s
));
305 nvram_set("ntp_kiss", s
);
306 syslog(LOG_WARNING
, "Received a kiss of death packet from %s (%s).", addr
[i
], ips
);
312 addr
[i
] = addr
[--count
];
316 if (mode
== USER
) break;
317 if ((mode
== CRON
) && (retries
== 5)) break;
319 if (++retries
> 300) retries
= 300; // 5m
320 _dprintf("[ntpsync %ld] sleep=%d\n", get_uptime(), retries
);
324 _dprintf("[ntpsync] %ld exit\n", get_uptime());
328 // -----------------------------------------------------------------------------
331 static int ntpstep_main(int argc
, char **argv
)
337 printf("Usage: ntpstep <seconds>\n");
341 gettimeofday(&tv
, NULL
);
342 tv
.tv_sec
+= atol(argv
[1]);
343 settimeofday(&tv
, NULL
);
345 strftime(s
, sizeof(s
), "%a, %d %b %Y %H:%M:%S %z", localtime(&tv
.tv_sec
));
351 // -----------------------------------------------------------------------------
353 int main(int argc
, char **argv
)
355 openlog("ntpc", LOG_PID
, LOG_USER
);
356 if (!nvram_contains_word("log_events", "ntp")) {
357 setlogmask(LOG_MASK(LOG_EMERG
)); // can't set to 0
360 if (strstr(argv
[0], "ntpsync") != NULL
) return ntpsync_main(argc
, argv
);
361 if (strstr(argv
[0], "ntpstep") != NULL
) return ntpstep_main(argc
, argv
);
363 return ntpc_main(argc
, argv
);
370 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
371 +---+-----+-----+---------------+---------------+----------------+
372 |LI | VN |Mode | Stratum | Poll | Precision | 0
373 +---+-----+-----+---------------+---------------+----------------+
375 +----------------------------------------------------------------+
376 | Root Dispersion | 2
377 +----------------------------------------------------------------+
378 | Reference Identifier | 3
379 +----------------------------------------------------------------+
380 | Reference Timestamp (64) | 4
381 +----------------------------------------------------------------+
382 | Originate Timestamp (64) | 6
383 +----------------------------------------------------------------+
384 | Receive Timestamp (64) | 8
385 +----------------------------------------------------------------+
386 | Transmit Timestamp (64) | 10
387 +----------------------------------------------------------------+
388 | Key Identifier (optional) (32) | 12
389 +----------------------------------------------------------------+
390 | Message Digest (optional) (128) | 13+
391 +----------------------------------------------------------------+
397 25,567 days can be converted to one of these units:
398 * 2,208,988,800 seconds
401 * 3652 weeks (rounded down)
404 http://www.faqs.org/rfcs/rfc2030.html
405 http://www.ntp.org/ntpfaq/NTP-s-algo.htm