├── README.md └── ntpc.c /README.md: -------------------------------------------------------------------------------- 1 | # ntpc 2 | A simple NTP client for Linux 3 | 4 | # How to compile ? 5 | gcc ntpc.c -o ntpc 6 | 7 | # How to use ? 8 | ```bash 9 | Usage: ntpc server1 server2 ... 10 | Example: ntpc 0.asia.pool.ntp.org 1.asia.pool.ntp.org 2.asia.pool.ntp.org 11 | 12 | ``` 13 | -------------------------------------------------------------------------------- /ntpc.c: -------------------------------------------------------------------------------- 1 | /* forgotfun.org forgotfun(佐须之男) */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define I_MISC 0 16 | #define I_ORTIME 6 17 | #define I_TXTIME 10 18 | 19 | #define TIMEFIX 2208988800UL 20 | 21 | #ifdef DEBUG_NOISY 22 | #define _dprintf cprintf 23 | #else 24 | #define _dprintf(args...) do { } while(0) 25 | #endif 26 | 27 | 28 | // 0 = ok, 1 = failed, 2 = permanent failure 29 | static int ntpc(struct in_addr addr) 30 | { 31 | uint32_t packet[12]; 32 | struct timeval txtime; 33 | struct timeval rxtime; 34 | struct timeval tv; 35 | uint32_t u; 36 | uint32_t txn; 37 | int fd; 38 | fd_set fds; 39 | int len; 40 | struct sockaddr_in sa; 41 | char s[64], q[128]; 42 | time_t t; 43 | time_t ntpt; 44 | time_t diff; 45 | 46 | memset(&sa, 0, sizeof(sa)); 47 | sa.sin_addr = addr; 48 | sa.sin_port = htons(123); 49 | sa.sin_family = AF_INET; 50 | 51 | if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { 52 | printf("Unable to create a socket\n"); 53 | return 1; 54 | } 55 | 56 | if (connect(fd, (struct sockaddr*)&sa, sizeof(sa)) == -1) { 57 | printf("Unable to connect\n"); 58 | } 59 | else { 60 | memset(&packet, 0, sizeof(packet)); 61 | packet[I_MISC] = htonl((4 << 27) | (3 << 24)); // VN=v4 | mode=3 (client) 62 | // packet[I_MISC] = htonl((3 << 27) | (3 << 24)); // VN=v3 | mode=3 (client) 63 | gettimeofday(&txtime, NULL); 64 | packet[I_TXTIME] = txn = htonl(txtime.tv_sec + TIMEFIX); 65 | send(fd, packet, sizeof(packet), 0); 66 | 67 | FD_ZERO(&fds); 68 | FD_SET(fd, &fds); 69 | tv.tv_sec = 3; // no more than 3 seconds 70 | tv.tv_usec = 0; 71 | if (select(fd + 1, &fds, NULL, NULL, &tv) != 1) { 72 | printf("Timeout\n"); 73 | } 74 | else { 75 | len = recv(fd, packet, sizeof(packet), 0); 76 | if (len != sizeof(packet)) { 77 | printf("Invalid packet size\n"); 78 | } 79 | else { 80 | gettimeofday(&rxtime, NULL); 81 | 82 | u = ntohl(packet[0]); 83 | 84 | _dprintf("u = 0x%08x\n", u); 85 | _dprintf("LI = %u\n", u >> 30); 86 | _dprintf("VN = %u\n", (u >> 27) & 0x07); 87 | _dprintf("mode = %u\n", (u >> 24) & 0x07); 88 | _dprintf("stratum = %u\n", (u >> 16) & 0xFF); 89 | _dprintf("poll interval = %u\n", (u >> 8) & 0xFF); 90 | _dprintf("precision = %u\n", u & 0xFF); 91 | 92 | if ((u & 0x07000000) != 0x04000000) { // mode != 4 (server) 93 | printf("Invalid response\n"); 94 | } 95 | else { 96 | close(fd); 97 | 98 | // notes: 99 | // - Windows' ntpd returns vn=3, stratum=0 100 | 101 | if ((u & 0x00FF0000) == 0) { // stratum == 0 102 | printf("Received stratum=0\n"); 103 | #if 0 104 | if (!nvram_match("ntp_kiss_ignore", "1")) { 105 | return 2; 106 | } 107 | #endif 108 | } 109 | 110 | ntpt = ntohl(packet[I_TXTIME]) - TIMEFIX; 111 | t = (rxtime.tv_sec - txtime.tv_sec) >> 1; 112 | diff = (ntpt - rxtime.tv_sec) + t; 113 | 114 | _dprintf("txtime = %ld\n", txtime.tv_sec); 115 | _dprintf("rxtime = %ld\n", rxtime.tv_sec); 116 | _dprintf("ntpt = %ld\n", ntpt); 117 | _dprintf("rtt/2 = %ld\n", t); 118 | _dprintf("diff = %ld\n", diff); 119 | 120 | if (diff != 0) { 121 | gettimeofday(&tv, NULL); 122 | tv.tv_sec += diff; 123 | // tv.tv_usec = 0;// sorry, I'm not a time geek :P 124 | settimeofday(&tv, NULL); 125 | 126 | _dprintf("new = %lu\n", tv.tv_sec); 127 | 128 | strftime(s, sizeof(s), "%a, %d %b %Y %H:%M:%S %z", localtime(&tv.tv_sec)); 129 | sprintf(q, "Time Updated: %s [%s%lds]", s, diff > 0 ? "+" : "", diff); 130 | } 131 | else { 132 | t = time(0); 133 | strftime(s, sizeof(s), "%a, %d %b %Y %H:%M:%S %z", localtime(&t)); 134 | sprintf(q, "Time: %s, no change was needed.", s); 135 | } 136 | printf("\n\n%s\n", q); 137 | syslog(LOG_INFO, q); 138 | return 0; 139 | } 140 | } 141 | } 142 | } 143 | 144 | close(fd); 145 | return 1; 146 | } 147 | 148 | 149 | // ----------------------------------------------------------------------------- 150 | 151 | 152 | int main(int argc, char **argv) 153 | { 154 | struct hostent *he; 155 | struct in_addr ia; 156 | const char *s; 157 | int i; 158 | 159 | for (i = 1; i < argc; ++i) { 160 | if ((he = gethostbyname(argv[i])) != NULL) { 161 | memcpy(&ia, he->h_addr_list[0], sizeof(ia)); 162 | s = inet_ntoa(ia); 163 | if (strcmp(s, argv[i]) == 0) printf("Trying %s: ", s); 164 | else printf("Trying %s [%s]:", argv[i], s); 165 | if (ntpc(ia) == 0) return 0; 166 | } 167 | else { 168 | printf("Unable to resolve: %s\n", argv[i]); 169 | } 170 | } 171 | 172 | if (argc < 2) { 173 | printf("Usage: ntpc \n"); 174 | printf("Example: ntpc 0.asia.pool.ntp.org 1.asia.pool.ntp.org 2.asia.pool.ntp.org\n"); 175 | } 176 | 177 | return 1; 178 | } 179 | 180 | /* 181 | 182 | 1 2 3 183 | 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 184 | +---+-----+-----+---------------+---------------+----------------+ 185 | |LI | VN |Mode | Stratum | Poll | Precision | 0 186 | +---+-----+-----+---------------+---------------+----------------+ 187 | | Root Delay | 1 188 | +----------------------------------------------------------------+ 189 | | Root Dispersion | 2 190 | +----------------------------------------------------------------+ 191 | | Reference Identifier | 3 192 | +----------------------------------------------------------------+ 193 | | Reference Timestamp (64) | 4 194 | +----------------------------------------------------------------+ 195 | | Originate Timestamp (64) | 6 196 | +----------------------------------------------------------------+ 197 | | Receive Timestamp (64) | 8 198 | +----------------------------------------------------------------+ 199 | | Transmit Timestamp (64) | 10 200 | +----------------------------------------------------------------+ 201 | | Key Identifier (optional) (32) | 12 202 | +----------------------------------------------------------------+ 203 | | Message Digest (optional) (128) | 13+ 204 | +----------------------------------------------------------------+ 205 | 206 | timestamp: 207 | since 1900 208 | 209 | 1970-1900: 210 | 25,567 days can be converted to one of these units: 211 | * 2,208,988,800 seconds 212 | * 36,816,480 minutes 213 | * 613,608 hours 214 | * 3652 weeks (rounded down) 215 | 216 | refs: 217 | http://www.faqs.org/rfcs/rfc2030.html 218 | http://www.ntp.org/ntpfaq/NTP-s-algo.htm 219 | 220 | */ 221 | --------------------------------------------------------------------------------