dimanche 29 mars 2015

decoding sntp client fields from a 48 byte char buffer



I am trying to create a simple network time protocol (sntp) client in c on linux. I am trying to decode the 32 and 64bit ntp fields recieved from the server. I am using a char buffer[48] to store the sntp header. So buffer[4] to 8 is root delay, buffer[8] to 12 is root dispersion etc. The fields i have mentioned have to be changed from big to little endian, and converted from ntp to unix time. I then write the final values to a sntp header struct for printing.


I have an sntp client which i have attempted, but I currently do not have a linux compiler to test the client, so would appreciate if anyone could run it and make any corrections and suggestions. I am happy to elaborate further if needed.


Thanks in advance.


sntp client:



/* talker.c - a datagram 'client'
* need to supply host name/IP and one word message,
* e.g. talker localhost hello
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h> //network byte order
#include <arpa/inet.h>
#include <netdb.h>
#include <math.h>
#include <stdint.h>
#include <inttypes.h>
#include <endian.h>
//#include <byteswap.h>
/* for gethostbyname() */
//164.11.80.76
#define PORT 123
struct s_ntp {
unsigned char VN;
unsigned char LI;
unsigned char Mode;
unsigned char Stratum;
unsigned char Poll;
unsigned char Precision;
signed long root_delay;
unsigned long root_dispersion;
unsigned long reference_identifier;
int64_t reference_timestamp;
int64_t originate_timestamp;
int64_t recieve_timestamp;
int64_t transmit_timestamp;
};

//ntp structs
struct ntp_time_t {
uint32_t second;
uint32_t fraction;
};

//struct timeval {
// uint32_t sec;
// uint32_t usec;
//}

/* server port the client connects to */
int main( int argc, char * argv[]) {
int sockfd, numbytes;
//sntp struct
struct s_ntp sntpHeader;
struct hostent *he;
struct sockaddr_in their_addr;
//ntp and unix structs
struct ntp_time_t ntp;
struct timeval unix;
int address_length = 0;
//long ntp fields
int offset, delay;
unsigned long root_delay = 0, root_dis = 0, ref_iden = 0;
int64_t ref_time, ori_time, rec_time, trans_time;
//ntp buffer
unsigned char buffer[48] = {0x0};
unsigned char charSeconds[4];
unsigned char charFractions[4];
unsigned char *bytes32;
unsigned char *bytes64;
//seconds and fractions - transmit timestamp
//buffer[40] + buffer[41] + buffer[42] + buffer[43]
buffer[0] = 0x1B;

/* server address info */
if( argc != 2) {
fprintf( stderr, "usage: talker hostname\n");
exit( 1);
}
/* resolve server host name or IP address */
if( (he = gethostbyname( argv[1])) == NULL) {
perror( "Talker gethostbyname");
exit( 1);
}
if( (sockfd = socket( AF_INET, SOCK_DGRAM, 0)) == -1) {
perror( "Talker socket");
exit( 1);
}
memset( &their_addr,0, sizeof(their_addr));
/* zero struct */
their_addr.sin_family = AF_INET;
/* host byte order .. */
their_addr.sin_port = htons( PORT);
/* .. short, netwk byte order */
their_addr.sin_addr = *((struct in_addr *)he -> h_addr);
//set transmit time
gettimeofday(&unixtime, NULL);
// get time unix time via gettimeofday
gettimeofday(&unix, NUL);
unixtontp(&unix, &ntp);
//write times to buffer (transmit timestamp)
charSeconds = (unsigned char *)&ntp.second;
//fractions
charFractions = (unsigned char *)&ntp.fraction;
buffer[40] = charSeconds[1];
buffer[41] = charSeconds[2];
buffer[43] = charSeconds[3];
buffer[44] = charSeconds[4];
//seconds
buffer[45] = charFractions[1];
buffer[46] = charFractions[2];
buffer[47] = charFractions[3];
buffer[48] = charFractions[4];
if( (numbytes = sendto( sockfd, buffer, 48, 0,
(struct sockaddr *)&their_addr, sizeof( struct sockaddr))) == -1) {
perror( "Talker sendto");
exit( 1);
}
printf( "Sent %d bytes to %s\n", numbytes,
inet_ntoa( their_addr.sin_addr));
//wait for a response
address_length = sizeof (struct sockaddr);
numbytes = recvfrom(sockfd, &buffer, sizeof(buffer),
MSG_WAITALL, (struct sockaddr *)
&their_addr, &address_length);
//decode recieved sntp packet
sntpHeader.Mode = (buffer[0] & 0x04);
sntpHeader.VN = ((buffer[0] >> 3));
sntpHeader.Stratum = buffer[1];
sntpHeader.Poll = pow(2, buffer[2]);
sntpHeader.Precision = pow(2, buffer[3]);
//root delay:
//big e to little e
root_delay = ntohl((long *) concat(&buffer[4], &buffer[5], &buffer[6], &buffer[7]));
//charSeconds = ((char *) root_delay);
bytes32 = (unsigned char*)&root_delay;
ntp.second = ((long *) concat(bytes16[0], bytes[1]);
ntp.fraction = ((long *) concat(bytes16[2], bytes[3]);
ntptounix(ntp, unix);
sntpHeader.root_delay = unix.second + unix.fraction;
sntpHeader.root_delay = root_delay;
//sntpHeader.root_delay = secondsFractions32Bit(root_delay));
//root dispersion
root_dis = ntohl((long *) concat(&buffer[8], &buffer[9], &buffer[10], &buffer[11]));
bytes32 = (unsigned char*)&root_dis;
ntp.second = ((long *) concat(bytes32[0], bytes32[1]);
ntp.fraction = ((long *) concat(bytes32[2], bytes32[3]);
ntptounix(ntp, unix);
sntpHeader.root_dispersion = unix.second + unix.fraction;
//sntpHeader.root_dispersion = ntohl(root_dis);
//ref identifier
root_iden = ntohl((long *) concat(&buffer[12], &buffer[13], &buffer[14], &buffer[15]));
bytes32 = (unsigned char*)&root_dis;
ntp.second = ((long *) concat(bytes32[0], bytes32[1]);
ntp.fraction = ((long *) concat(bytes32[2], bytes32[3]);
ntptounix(ntp, unix);
sntpHeader.reference_identifier = unix.second + unix.fraction;
//reference time stamp
ref_time = htole64((uint64_t *) concat(&buffer[16], &buffer[17], &buffer[18], &buffer[19],
&buffer[20], &buffer[21], &buffer[22], &buffer[23]));
bytes64 = (unsigned char*)&ref_time;
ntp.second = ((long *) concat(bytes32[0], bytes32[1], bytes32[2], bytes32[3]);
ntp.fraction = ((long *) concat(bytes32[4], bytes32[5], bytes32[6], bytes32[7]);
ntptounix(ntp, unix);
sntpHeader.reference_timestamp = unix.second + unix.fraction;
//originate time stamp
ori_time = htole64((uint64_t *) concat(&buffer[24], &buffer[25], &buffer[26], &buffer[27],
&buffer[28], &buffer[29], &buffer[30], &buffer[31]));
bytes64 = (unsigned char*)&ori_time;
ntp.second = ((long *) concat(bytes32[0], bytes32[1], bytes32[2], bytes32[3]);
ntp.fraction = ((long *) concat(bytes32[4], bytes32[5], bytes32[6], bytes32[7]);
ntptounix(ntp, unix);
sntpHeader.reference_timestamp = unix.second + unix.fraction;
//recieve timestamp
rec_time = htole64((uint64_t *) concat(&buffer[32], &buffer[33], &buffer[34], &buffer[35],
&buffer[36], &buffer[37], &buffer[38], &buffer[39]));
bytes64 = (unsigned char*)&rec_time;
ntp.second = ((long *) concat(bytes32[0], bytes32[1], bytes32[2], bytes32[3]);
ntp.fraction = ((long *) concat(bytes32[4], bytes32[5], bytes32[6], bytes32[7]);
ntptounix(ntp, unix);
sntpHeader.reference_timestamp = unix.second + unix.fraction;
//transmit timestamp
trans_time = htole64((uint64_t *) concat(&buffer[40], &buffer[41], &buffer[42], &buffer[43],
&buffer[44], &buffer[45], &buffer[46], &buffer[47]));
bytes64 = (unsigned char*)&trans_time;
ntp.second = ((long *) concat(bytes32[0], bytes32[1], bytes32[2], bytes32[3]);
ntp.fraction = ((long *) concat(bytes32[4], bytes32[5], bytes32[6], bytes32[7]);
ntptounix(ntp, unix);
sntpHeader.reference_timestamp = unix.second + unix.fraction;
//offset and delay
offset = ((ori_time - ref_time) + (rec_time - trans_time)) / 2;
delay = (trans_time - ref_time) - (rec_time - trans_time);
//print sntp packet
printf("\nMode: %d" ,sntpHeader.Mode);
printf("\nVN : %d", sntpHeader.VN);
printf("\nStratum: %d\n", sntpHeader.Stratum);
printf("Poll: %d\n", sntpHeader.Poll);
printf("Precision: %d\n", sntpHeader.Precision);
printf("Root delay: %f\n", sntpHeader.root_delay);
printf("Root dispersion: %f\n", sntpHeader.root_dispersion);
printf("Root identifier: %f\n", sntpHeader.reference_identifier);
//timestamps
printf("Reference timestamp: %d\n", sntpHeader.reference_timestamp);
printf("Originate timestamp: %d\n", sntpHeader.originate_timestamp);
printf("Recieve timestamp: %d\n", sntpHeader.recieve_timestamp);
printf("Transmit timestamp: %d\n", sntpHeader.transmit_timestamp);
printf("Offset: %d", offset);
printf("Delay: %d", delay);
//close socket
close( sockfd);
return 0;
}

time_t transmittime() {
time_t sys_time;
sys_time = time(NULL);
//fprintf(stdout, "%u\n", (unsigned)sys_time(NULL));
return sys_time;
}

void ntptounix(struct ntp_time_t *ntptime, struct ntp_time_t *unixtime)
{
unixtime->second = ntptime->second - 0x83AA7E80; // the seconds from Jan 1, 1900 to Jan 1, 1970
unixtime->fraction = (uint32_t)( (double)ntptime->fraction * 1.0e6 / (double)(1LL<<32) );
}

void unixtontp(struct ntp_time_t *unixtime, struct ntp_time_t *ntptime) {
ntptime->second = unixtime->second + 0x83AA7E80;
ntptime->fraction = (uint32_t)( (double)(unixtime->fraction+1) * (double)(1LL<<32) * 1.0e-6 );
}



Aucun commentaire:

Enregistrer un commentaire