commit 7754309aba744c2b7f32b32af522029087122e6d Author: hellerve Date: Wed Dec 19 18:18:13 2018 +0100 30m version diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e660fd9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +bin/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9e6e1f1 --- /dev/null +++ b/Makefile @@ -0,0 +1,18 @@ +SRC=main.c +TARGET=n +BUILDDIR=bin/ +PREFIX=/usr/local/bin/ +override CFLAGS+=-O3 + +all: + mkdir -p $(BUILDDIR) + $(CC) $(CFLAGS) $(SRC) -o $(BUILDDIR)$(TARGET) + +clean: + rm -r $(BUILDDIR) + +install: all + install $(BUILDDIR)$(TARGET) $(PREFIX)$(TARGET) + +uninstall: + rm -rf $(PREFIX)$(TARGET) diff --git a/README.md b/README.md new file mode 100644 index 0000000..eb86e58 --- /dev/null +++ b/README.md @@ -0,0 +1,28 @@ +# n + +A simple NTP client. + +## Installation + +Don’t use mine, because it will explode, launch missiles, and rain on your +porch. + +If you still want to, `make install` will install this utility to +`/usr/local/bin`. You can change the installation directory by providing the +`PREFIX` option to `make install`. + +## Usage + +``` +Usage: bin/n [options] +Options: + -h HOST, --host=HOST NTP server to use + defaults to 'europe.pool.ntp.org' + -p PORT, --port=PORT NTP server port to use (must be numerical) + defaults to '123' + --help Display this message and exit +``` + +
+ +Have fun! diff --git a/main.c b/main.c new file mode 100644 index 0000000..e3dcada --- /dev/null +++ b/main.c @@ -0,0 +1,129 @@ +#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; +}