#include #include #include #include #include #include #include #include #include #include #include #define EPOCH 2208988800ull // assumes either little or big endian. pdp-endian, youre out of luck #define NLITTLE 0x41424344UL #define NENDIAN ('ABCD') typedef struct { #if NENDIAN == NLITTLE unsigned int mode: 3; unsigned int vn: 3; unsigned int li: 2; #else unsigned int li: 2; unsigned int vn: 3; unsigned int mode: 3; #endif uint8_t stratum; uint8_t poll; uint8_t prec; uint32_t delay; uint32_t dispersion; uint32_t refid; uint32_t rtms; uint32_t rtmf; uint32_t otms; uint32_t otmf; uint32_t rctms; uint32_t rctmf; uint32_t ttms; uint32_t ttmf; } __attribute__((packed, aligned(1))) ntp; typedef struct { const char* host; int port; } ntp_info; ntp_info NDEFAULT = {.host="europe.pool.ntp.org", .port = 123}; void err(char* msg) { fprintf(stderr, "Error %s.\n", msg); exit(1); } void usage(char* program, int code) { fprintf(stderr, "Usage: %s [options]\n", program); fputs("Options:\n", stderr); fputs(" -h HOST, --host=HOST NTP server to use\n", stderr); fputs(" defaults to 'europe.pool.ntp.org'\n", stderr); fputs(" -p PORT, --port=PORT NTP server port to use (must be numerical)\n", stderr); fputs(" defaults to '123'\n", stderr); fputs(" --help Display this message and exit\n", stderr); exit(code); } ntp_info args(int argc, char** argv) { char c; ntp_info res = NDEFAULT; static struct option long_options[] = { {"host", required_argument, 0, 'h'}, {"port", required_argument, 0, 'p'}, {"help", no_argument, 0, 'u'}, {NULL, 0, NULL, 0} }; while ((c = getopt_long(argc, argv, "t:a:", long_options, 0)) != -1) { switch (c) { case 'h': res.host = optarg; break; case 'p': { char* end; res.port = strtol(optarg, &end, 10); if (end[0] != 0) { fputs("Port is not numerical.\n", stderr); usage(argv[0], 1); } break; } case 'u': usage(argv[0], 0); default: usage(argv[0], 1); } } return res; } int main(int argc, char** argv) { int sock; ntp n; struct sockaddr_in a; struct hostent* s; ntp_info i = args(argc, argv); memset(&n, 0, sizeof(ntp)); n.vn = 3; n.mode = 3; sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (sock < 0) err("opening socket"); s = gethostbyname(i.host); if (!s) err("resolving host"); bzero(&a, sizeof(a)); a.sin_family = AF_INET; a.sin_port = htons(i.port); bcopy(s->h_addr, &a.sin_addr.s_addr, s->h_length); if (connect(sock, (struct sockaddr *) &a, sizeof(a)) < 0) err("connecting"); if (write(sock, &n, sizeof(ntp)) < 0) err("writing to network"); if (read(sock, &n, sizeof(ntp)) < 0) err("reading from network"); n.ttms = ntohl(n.ttms); time_t tm = n.ttms - EPOCH; fputs(ctime(&tm), stdout); return 0; }