├── README ├── ntp.c └── rfc.txt /README: -------------------------------------------------------------------------------- 1 | ntp - Network Time Protocol client 2 | author: Eugene Ma (edma2) 3 | -------------------------------------------------------------------------------- /ntp.c: -------------------------------------------------------------------------------- 1 | /* ntp.c - Network Time Protocol client 2 | * author: Eugene Ma (edma) 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define NTP_VERSION 0xe3 16 | #define NTP_DEFAULT_PORT "123" 17 | #define SEC_IN_YEAR 31556926 18 | #define UNIX_OFFSET 2208988800L 19 | #define VN_BITMASK(byte) ((byte & 0x3f) >> 3) 20 | #define LI_BITMASK(byte) (byte >> 6) 21 | #define MODE_BITMASK(byte) (byte & 0x7) 22 | #define ENDIAN_SWAP32(data) ((data >> 24) | /* right shift 3 bytes */ \ 23 | ((data & 0x00ff0000) >> 8) | /* right shift 1 byte */ \ 24 | ((data & 0x0000ff00) << 8) | /* left shift 1 byte */ \ 25 | ((data & 0x000000ff) << 24)) /* left shift 3 bytes */ 26 | 27 | struct ntpPacket { 28 | uint8_t flags; 29 | uint8_t stratum; 30 | uint8_t poll; 31 | uint8_t precision; 32 | uint32_t root_delay; 33 | uint32_t root_dispersion; 34 | uint8_t referenceID[4]; 35 | uint32_t ref_ts_sec; 36 | uint32_t ref_ts_frac; 37 | uint32_t origin_ts_sec; 38 | uint32_t origin_ts_frac; 39 | uint32_t recv_ts_sec; 40 | uint32_t recv_ts_frac; 41 | uint32_t trans_ts_sec; 42 | uint32_t trans_ts_frac; 43 | } __attribute__((__packed__)); /* this is not strictly necessary, 44 | * structure follows alignment rules */ 45 | 46 | int main(int argc, char *argv[]) { 47 | char *server; /* no default server */ 48 | char *port = NTP_DEFAULT_PORT; 49 | struct addrinfo hints, *res, *ap; /* address info structs */ 50 | socklen_t addrlen = sizeof(struct sockaddr_storage); 51 | 52 | struct ntpPacket packet; 53 | uint8_t *ptr = (uint8_t *)(&packet); /* to read raw bytes */ 54 | 55 | int server_sock; /* send through this socket */ 56 | int error; /* error checking */ 57 | int i; 58 | unsigned int recv_secs; 59 | 60 | time_t total_secs; 61 | struct tm *now; 62 | 63 | /* server is required, port is optional */ 64 | if (argc < 2) { 65 | fprintf(stderr, "Usage: %s [port]\n", argv[0]); 66 | exit(1); 67 | } 68 | server = argv[1]; 69 | if (argc > 2) 70 | port = argv[2]; 71 | 72 | memset(&packet, 0, sizeof(struct ntpPacket)); 73 | packet.flags = NTP_VERSION; 74 | 75 | memset(&hints, 0, sizeof(hints)); 76 | hints.ai_socktype = SOCK_DGRAM; 77 | 78 | /* fill our address structs for ntp server */ 79 | error = getaddrinfo(server, port, &hints, &res); 80 | /* error checking */ 81 | if (error != 0) { 82 | fprintf(stderr, "getaddrinfo() error: %s", gai_strerror(error)); 83 | exit(1); 84 | } 85 | /* loop through results */ 86 | for (ap = res; ap != NULL; ap = ap->ai_next) { 87 | server_sock = socket(ap->ai_family, ap->ai_socktype, ap->ai_protocol); 88 | if (server_sock == -1) 89 | continue; 90 | break; 91 | } 92 | if (ap == NULL) { 93 | fprintf(stderr, "socket() error\n"); 94 | exit(2); 95 | } 96 | 97 | error = sendto(server_sock, &packet, sizeof(struct ntpPacket), 0, ap->ai_addr, addrlen); 98 | if (error == -1) { 99 | fprintf(stderr, "sendto() error\n"); 100 | exit(2); 101 | } 102 | error = recvfrom(server_sock, &packet, sizeof(struct ntpPacket), 0, ap->ai_addr, &addrlen); 103 | if (error == -1) { 104 | fprintf(stderr, "recvfrom() error\n"); 105 | exit(2); 106 | } 107 | 108 | freeaddrinfo(res); /* all done */ 109 | 110 | /* print raw bytes */ 111 | for (i = 0; i < sizeof(struct ntpPacket); i++) { 112 | if (i != 0 && i % 8 == 0) 113 | printf("\n"); 114 | printf("0x%2x ", ptr[i]); 115 | } 116 | printf("\n"); 117 | 118 | /* correct for right endianess */ 119 | packet.root_delay = ENDIAN_SWAP32(packet.root_delay); 120 | packet.root_dispersion = ENDIAN_SWAP32(packet.root_dispersion); 121 | packet.ref_ts_sec = ENDIAN_SWAP32(packet.ref_ts_sec); 122 | packet.ref_ts_frac = ENDIAN_SWAP32(packet.ref_ts_frac); 123 | packet.origin_ts_sec = ENDIAN_SWAP32(packet.origin_ts_sec); 124 | packet.origin_ts_frac = ENDIAN_SWAP32(packet.origin_ts_frac); 125 | packet.recv_ts_sec = ENDIAN_SWAP32(packet.recv_ts_sec); 126 | packet.recv_ts_frac = ENDIAN_SWAP32(packet.recv_ts_frac); 127 | packet.trans_ts_sec = ENDIAN_SWAP32(packet.trans_ts_sec); 128 | packet.trans_ts_frac = ENDIAN_SWAP32(packet.trans_ts_frac); 129 | 130 | /* print raw data */ 131 | printf("LI: %u\n", LI_BITMASK(packet.flags)); 132 | printf("VN: %u\n", VN_BITMASK(packet.flags)); 133 | printf("Mode: %u\n", MODE_BITMASK(packet.flags)); 134 | printf("stratum: %u\n", packet.stratum); 135 | printf("poll: %u\n", packet.poll); 136 | printf("precision: %u\n", packet.precision); 137 | printf("root delay: %u\n", packet.root_delay); 138 | printf("root dispersion: %u\n", packet.root_dispersion); 139 | printf("reference ID: %u.", packet.referenceID[0]); 140 | printf("%u.", packet.referenceID[1]); 141 | printf("%u.", packet.referenceID[2]); 142 | printf("%u\n", packet.referenceID[3]); 143 | printf("reference timestamp: %u.", packet.ref_ts_sec); 144 | printf("%u\n", packet.ref_ts_frac); 145 | printf("origin timestamp: %u.", packet.origin_ts_sec); 146 | printf("%u\n", packet.origin_ts_frac); 147 | printf("receive timestamp: %u.", packet.recv_ts_sec); 148 | printf("%u\n", packet.recv_ts_frac); 149 | printf("transmit timestamp: %u.", packet.trans_ts_sec); 150 | printf("%u\n", packet.trans_ts_frac); 151 | 152 | /* print date with receive timestamp */ 153 | recv_secs = packet.recv_ts_sec - UNIX_OFFSET; /* convert to unix time */ 154 | total_secs = recv_secs; 155 | printf("Unix time: %u\n", (unsigned int)total_secs); 156 | now = localtime(&total_secs); 157 | printf("%02d/%02d/%d %02d:%02d:%02d\n", now->tm_mday, now->tm_mon+1, \ 158 | now->tm_year+1900, now->tm_hour, now->tm_min, now->tm_sec); 159 | 160 | return 0; 161 | } 162 | --------------------------------------------------------------------------------