/* 
 * ntpprobe.c
 *
 * Shows version and stratum of a NTP server.
 *
 * Usage:
 *   ntpprobe host
 * 
 * by Michal Wojciechowski <odyniec(at)odyniec.net>
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <string.h>
#include <errno.h>
#include <netdb.h>

#define MAXATTEMPTS 3

main(int argc, char *argv[])
{
  int sock;
  struct sockaddr_in sa;
  struct hostent *hptr;
  char sntpmsg[48];
  char response[128];
  struct in_addr *ia;
  struct timeval tv;
  int attempt = 0;
  int r;

  if (argc < 2) {
    fprintf(stderr, "Usage: %s host\n", argv[0]);
    exit(1);
  }

  sock = socket(AF_INET, SOCK_DGRAM, 0);
  if (sock == -1) {
    perror(argv[0]);
    exit(1);
  }

  tv.tv_sec = 5;
  tv.tv_usec = 0;
  if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
    perror(argv[0]);
    exit(1);
  }

  memset(&sa, 0, sizeof(sa));
  sa.sin_family = AF_INET;
  sa.sin_port = htons(123);
  
  if ((hptr = gethostbyname(argv[1])) == NULL) {
    fprintf(stderr, "Host not found.\n");
    exit(1);
  }

  ia = (struct in_addr *)hptr->h_addr_list[0];
  memcpy(&sa.sin_addr, ia, sizeof(*ia));

  memset(sntpmsg, 0, sizeof(sntpmsg));
  /* LI = 0, VN = 3, Mode = client  (see RFC 2030) */
  sntpmsg[0] = 0 << 6 | 3 << 3 | 3;

  while (attempt < MAXATTEMPTS) {
    if (sendto(sock, sntpmsg, sizeof(sntpmsg), 0, 
	       (struct sockaddr *)&sa, sizeof(sa)) == -1) 
    {
      fprintf(stderr, "Can't send\n");
      exit(1);
    }

    if ((r = recvfrom(sock, response, sizeof(response), 0, NULL, NULL)) < 0) {
      if (++attempt > MAXATTEMPTS)
	break;
    }
    else {
      printf("%s: NTP server version %d, stratum %d.\n", argv[1],
	     (unsigned char)((response[0] & 0x38) >> 3),
	     (unsigned char)response[1]);
      exit(0);
    }
  }

  printf("%s: NTP server not available.\n", argv[1]);
  exit(0);
}

