/********************************************************************* ** setclock.c, reads time from RFC868 time ** ** server and sets time on an NT machine. ** ** RFC868 is only to within 1 second, therefore ** ** subsecond sync requirements should _not_ use ** ** this program ** ** -jeffab@jeffab.com ** *********************************************************************/ /* version 0.9 Initial proof of concept version 1.0 New maxdiff prevents reset if difference is greater than max More extensive use of IPOCTETS Included the reverse of the dotted-decimal Added a (nearly) synchronous call to time with the query and generate a delta for the maxdiff. Added hostname lookup. */ #include #include //atoi() #include //localtime() #include //_strrev() #include #define MAXDIFF 1800 //30 mins #define RETRIES 5 //number of times that recv is called #define IPOCTETS 4 //number of octets (IP4 for now) #define IPMAXDIG 3 //Max digits per octet (IP4 for now) #define TIMEDPORT 37 //RFC868 port #define NINTEENSEVENTY 2208988800 //UNIX uses 1900, NT uses 1970 as a base year //remeber 1900 is NOT a leapyear. unsigned __int64 getremoteunixtime( char *, time_t * ); char *rev_byte_order( char *inchar ); int main( int argc, char *argv[] ) { int offset = 0; unsigned __int64 tmset; long maxdiff = MAXDIFF; long tmsetl; long localt; long delta; struct _SYSTEMTIME ltime; struct tm *tmptr; if (argc < 2) { fprintf( stderr, "\nUsage:\n%s {Host | IP} [seconds to offset] [maximum net delta]",argv[0] ); fprintf( stderr, "\n" ); exit( 1 ); } if( argc > 2 ) offset = atoi( argv[2] ); if( argc > 3 ) maxdiff = atoi( argv[3] ); maxdiff = abs( maxdiff ); fprintf( stderr, "\nChecking against server: %s \noffset: %d \nmaximum net delta: %u", argv[1], offset, maxdiff ); fflush( stderr ); tmset = getremoteunixtime( argv[1], &localt ); tmset = tmset + offset - NINTEENSEVENTY; //change to NT time if( abs( tmset - localt ) > maxdiff ) {//test for maxdiff fprintf( stderr, "\nDelta of %d seconds exceeded maximum.\nTime not set", int( tmset - localt )); fprintf( stderr, "\n" ); exit( 1 ); } tmsetl = tmset; delta = tmset - localt; time( &localt ); localt += delta; tmptr = localtime( &localt ); ltime.wYear = tmptr->tm_year + 1900; ltime.wMonth = tmptr->tm_mon + 1; ltime.wDay = tmptr->tm_mday; ltime.wHour = tmptr->tm_hour; ltime.wMinute = tmptr->tm_min; ltime.wSecond = tmptr->tm_sec; ltime.wMilliseconds = 0; if( SetLocalTime( <ime )) fprintf( stderr, "\nTime Set, net delta of %d seconds", delta ); else fprintf( stderr, "\nTime NOT Set, check your user rights?. There was net delta of %d seconds", delta ); fprintf( stderr, "\n" ); exit( 0 ); return( 0 ); } char *rev_byte_order( char *inchar ) {//reverses byte order of dotted decimal char. char *step = inchar; char buffer[IPMAXDIG]; int octets = IPOCTETS; if( isalpha( inchar[0] )) return( inchar ); while( octets-- > 0) { char *step2 = step; int i = 0; while( *step && *step != '.' ) { buffer[i] = *step; i++; step++; } while( --i + 1 > 0) *step2++ = buffer[i]; step++; //step over '.' } _strrev( inchar ); return( inchar ); } unsigned __int64 getremoteunixtime( char *hostdd, time_t *timeval ) { //hostdd = host in dotted decimal //timeval is a ptr to time_t to store the localtime synced with the get of unix time //returns the unix time char *lpbuf="QURY"; unsigned __int64 retval; int port = TIMEDPORT; int looper = 0; unsigned long servbyte; struct sockaddr_in servaddr; WSAData wsaData; WORD wVersionRequested; SOCKET skt; retval = 0; //init Winsock 2.1 wVersionRequested = MAKEWORD( 2, 1 ); looper = WSAStartup( wVersionRequested, &wsaData ); if( looper < 0 ) { fprintf( stderr, "\nCan't Start Winsock 2.1" ); fprintf( stderr, "\n" ); WSACleanup(); exit( 1 ); } memset(( char * ) &servaddr, 0, sizeof( servaddr )); if( isalpha( hostdd[0] ) ) { int x = 0; HOSTENT *hp; hp = gethostbyname( hostdd ); fprintf( stderr, "\nResolving Hostname..." ); if ( hp != 0 ) { int counter = IPOCTETS; // Found an address for that host, so save it while( counter-- ) memcpy((void *)(IPOCTETS - counter - 1 + (int) &servaddr.sin_addr.S_un), &hp->h_addr_list[0][IPOCTETS - counter - 1] , 1); fprintf( stderr, "Resolved" ); } else { // Not a recognized hostname fprintf( stderr, "\nFailed to resolve %s, Error %d", hostdd, WSAGetLastError() ); fprintf( stderr, "\n" ); WSACleanup(); exit( 1 ); } } else { servbyte = inet_addr( rev_byte_order( hostdd )); servaddr.sin_addr.s_addr = htonl( servbyte ); //htonl( servbyte ); } servaddr.sin_family = AF_INET; //AF_INET servaddr.sin_port = htons( port ); //htons( port ); //create the socket ( create the memory structure ) skt = socket( servaddr.sin_family, SOCK_STREAM, 0 ); if( skt == INVALID_SOCKET ) { fprintf( stderr, "\nFailed to create raw socket: %d", WSAGetLastError()); fprintf( stderr, "\n" ); WSACleanup(); exit( 1 ); } //connect the socket ( create connection to remote machine ) looper = 0; looper = connect( skt, ( SOCKADDR * ) &servaddr, sizeof( servaddr )); if( looper < 0 ) { fprintf( stderr, "\nFailed to connect" ); fprintf( stderr, "\n" ); WSACleanup(); exit( 1 ); } looper = 0 - RETRIES; while( looper++ < 0 ) { //the following 2 lines must be left in order and next to each other. looper = recv( skt, lpbuf, 4, 0 ); time( timeval ); } retval = 0; if( looper > 0 ) looper = IPOCTETS; while( looper-- > 0 ) { retval <<= 8; retval += ( int ) LOBYTE( lpbuf[IPOCTETS - 1 - looper] ); } shutdown( skt, SD_BOTH ); WSACleanup(); return( retval ); }