#!/usr/bin/perl use strict; use warnings; #use diagnostics; use Data::Dumper; use IO::Socket::INET; use POSIX qw( CLOCKS_PER_SEC ); use Time::HiRes qw( gettimeofday CLOCK_REALTIME clock_getres ); use constant TRUE => scalar 1; use constant ARGUMENTS => scalar 1; use constant MAXBYTES => scalar 512; use constant MAX_PORT => scalar 65536; use constant MIN_PORT => scalar 1; my $dot = "."; my $rcvSntpPacket; if ( @ARGV > ARGUMENTS ) { print "\nPlease no more than ".ARGUMENTS." argument input!\n"; print "\nCorrect Syntax: perl $0 IP:PORT (e.g. 127.0.0.1:12345)\n"; exit(0); } elsif ( @ARGV < ARGUMENTS ) { print "\nPlease no less than ".ARGUMENTS." argument input!\n"; print "\nCorrect Syntax: perl $0 IP:PORT (e.g. 127.0.0.1:12345)\n"; exit(0); } else { my $info = $ARGV[0]; # User input IP:PORT; my $string = index($info, ':'); if ($string == '-1') { die "Please include ':' in between the IP and Port - ".$info."\n"; } my @input = split( ':' , $info ); die "\nPlease use PORT number between ".MIN_PORT." - ".MAX_PORT."\n\n" if ( ( $input[1] > MAX_PORT ) || ( $input[1] < MIN_PORT ) ); my $client_socket = new IO::Socket::INET ( PeerHost => $input[0], Type => SOCK_DGRAM, PeerPort => $input[1], # Default NTP port 123, due to permission denied switch to client set Proto => 'udp' ) or die "ERROR in Socket Creation: $@\n"; my $Peer_Port = $client_socket->peerport(); my $client_li_vm_mode = '00100011'; # 8 bit my $client_stratum = '0'; # 8 bit my $client_poll = '0'; # 8 bit my $client_precision = '0'; # 8 bit my $client_root_delay = '0'; # 32 bit my $client_dispersion = '0'; # 32 bit my $client_reference_identifier = '0'; # 32 bit my $client_reference_timestamp_sec = '0'; # 32 bit my $client_reference_timestamp_microsec = '0'; # 32 bit my $client_receive_timestamp_sec = '0'; # 32 bit my $client_receive_timestamp_microsec = '0'; # 32 bit my ( $client_transmit_sec , $client_transmit_microsec ) = gettimeofday(); # 64 bit my $client_originate_timestamp_sec = $client_transmit_sec; my $client_originate_timestamp_microsec = $client_transmit_microsec; my @arraySendSntpPacket = ($client_li_vm_mode , $client_stratum , $client_poll , $client_precision , $client_root_delay , $client_dispersion , $client_reference_identifier , $client_reference_timestamp_sec , $client_reference_timestamp_microsec , $client_originate_timestamp_sec , $client_originate_timestamp_microsec , $client_receive_timestamp_sec , $client_receive_timestamp_microsec , $client_transmit_sec , $client_transmit_microsec ); warn Dumper \@arraySendSntpPacket; my $sendSntpPacket = pack "B8 C3 N11", @arraySendSntpPacket; $client_socket->send( $sendSntpPacket ) or die "Client error while send: $!\n"; $client_socket->recv( $rcvSntpPacket , MAXBYTES ) or die "Client error while received: $!\n"; my ( $client_rcv_sec , $client_rcv_microsec ) = gettimeofday(); $client_socket->close(); # Close socket() my @arrayRcvSntpPacket = unpack("B8 C3 N11" , $rcvSntpPacket); my ( $server_li_vm_mode , $server_stratum , $server_poll_interval , $server_precision , $server_root_delay , $server_dispersion , $server_reference_identifier , $server_reference_timestamp_sec , $server_reference_timestamp_microsec , $server_originate_timestamp_sec , $server_originate_timestamp_microsec , $server_rcv_timestamp_sec , $server_rcv_timestamp_microsec , $server_transmit_timestamp_sec , $server_transmit_timestamp_microsec ) = @arrayRcvSntpPacket; warn Dumper \@arrayRcvSntpPacket; } # End of else ARGV provided #### $VAR1 = [ '00100011', '0', '0', '0', '0', '0', '0', '0', '0', 1425730335, 839953, '0', '0', 1425730335, 839953 ]; $VAR1 = [ '00100100', 1, 110, 0, 0, 4294942144, 2214694912, 1425730335, 2080374784, 1425730335, 268435456, 1425730335, 0, 0, 0 ]; #### $VAR1 = [ '00100011', '0', '0', '0', '0', '0', '0', '0', '0', 1425730335, 839953, '0', '0', 1425730335, 839953 ]; $VAR1 = [ '00100100', 1, 110, 0, 0, 4294942144, 2214694912, 1425730335, 2080374784, # instead 839953, 1425730335, 268435456, # instead 839953, 1425730335, 0, 0, 0 ]; #### #!/usr/bin/perl use strict; use warnings; use IO::Socket::INET; use Time::HiRes qw( gettimeofday ); use constant TRUE => scalar 1; use constant ARGUMENTS => scalar 1; use constant MAXBYTES => scalar 512; use constant MAX_PORT => scalar 65536; use constant MIN_PORT => scalar 1; use constant UNIX_EPOCH => 2208988800; my $unpack_ip = sub { my $ip; my $stratum = shift; my $tmp_ip = shift; if($stratum < 2){ $ip = unpack("A4", pack("H8", $tmp_ip) ); }else{ $ip = sprintf("%d.%d.%d.%d", unpack("C4", pack("H8", $tmp_ip) ) ); } return $ip; }; my $frac2bin = sub { my $bin = ''; my $frac = shift; while ( length($bin) < 32 ) { $bin = $bin . int( $frac * 2 ); $frac = ( $frac * 2 ) - ( int( $frac * 2 ) ); } return $bin; }; my $bin2frac = sub { my @bin = split '', shift; my $frac = 0; while (@bin) { $frac = ( $frac + pop @bin ) / 2; } return $frac; }; my $dot = "."; my $rcvSntpPacket; my $serverPrecision; my $info = $ARGV[0]; # User input IP:PORT; my $string = index($info, ':'); if ($string == '-1') { die "Please include ':' in between the IP and Port - ".$info."\n"; } my @input = split( ':' , $info ); my $client_socket = new IO::Socket::INET ( PeerHost => $input[0], Type => SOCK_DGRAM, PeerPort => $input[1], Proto => 'udp' ) or die "ERROR in Socket Creation: $@\n"; my $Peer_Port = $client_socket->peerport(); my $client_li_vn_mode = '00100011'; # 8 bit my $client_stratum = '0'; # 8 bit my $client_poll = '0'; # 8 bit my $client_precision = '0'; # 8 bit my $client_root_delay = '0'; # 32 bit my $client_dispersion = '0'; # 32 bit my $client_reference_identifier = '0'; # 32 bit my $client_reference_timestamp_sec = '0'; # 32 bit my $client_reference_timestamp_microsec = '0'; # 32 bit my $client_originate_timestamp_sec = 0; # 32 bit my $client_originate_timestamp_microsec = 0; # 32 bit my $client_receive_timestamp_sec = '0'; # 32 bit my $client_receive_timestamp_microsec = '0'; # 32 bit my ($client_transmit_sec , $client_transmit_microsec) = gettimeofday(); my $client_transmit_timestamp = $client_transmit_sec . $dot . $client_transmit_microsec; my @arraySendSntpPacket = ($client_li_vn_mode , $client_stratum , $client_poll , $client_precision , $client_root_delay , $client_dispersion , $client_reference_identifier , $client_reference_timestamp_sec , $client_reference_timestamp_microsec , $client_originate_timestamp_sec , $client_originate_timestamp_microsec , $client_receive_timestamp_sec , $client_receive_timestamp_microsec , $client_transmit_sec , $client_transmit_microsec ); my $sendSntpPacket = pack "B8 C3 N10 B32", @arraySendSntpPacket; $client_socket->send( $sendSntpPacket ) or die "Client error while send: $!\n"; $client_socket->recv( $rcvSntpPacket , MAXBYTES ) or die "Client error while received: $!\n"; my ($client_rcv_sec , $client_rcv_microsec) = gettimeofday(); my $client_rcv_timestamp = $client_rcv_sec . $dot . $client_rcv_microsec; $client_socket->close(); # Close socket() my @arrayRcvSntpPacket = unpack("a C3 n B16 n B16 H8 N B32 N B32 N B32 N B32" , $rcvSntpPacket); my ( $server_li_vm_mode , $server_stratum , $server_poll_interval , $server_precision , $server_root_delay_sec , $server_root_delay_microsec , $server_dispersion_sec , $server_dispersion_microsec , $server_reference_identifier , $server_reference_timestamp_sec , $server_reference_timestamp_microsec , $server_originate_timestamp_sec , $server_originate_timestamp_microsec , $server_rcv_timestamp_sec , $server_rcv_timestamp_microsec , $server_transmit_timestamp_sec , $server_transmit_timestamp_microsec ) = @arrayRcvSntpPacket; my @serverLiVnMode = ((unpack( "C", $server_li_vm_mode & "\xC0" ) >> 6), (unpack( "C", $server_li_vm_mode & "\x38" ) >> 3), (unpack( "C", $server_li_vm_mode & "\x07" ))); my $serverPoll = (sprintf("%0.1d", $server_poll_interval)); if ($server_precision < 127) { $server_precision = 0; } else { $server_precision = $server_precision - 255; } my $serverRootDelay = ($bin2frac -> ($server_root_delay_microsec)); my $serverDispersionSeconds = sprintf("%0.10f", $server_dispersion_sec); $serverDispersionSeconds =~ s/\..*$//; my $serverDispersionFinalSeconds = $bin2frac->($serverDispersionSeconds); my $serverDispersionMicroSeconds = sprintf("%0.10f", $server_dispersion_microsec); $serverDispersionMicroSeconds =~ s/\..*$//; my $serverDispersionFinalMicroSeconds = $bin2frac->($serverDispersionMicroSeconds); my $serverReferenceIdentifier = $unpack_ip->($server_stratum,$server_reference_identifier); (($server_reference_timestamp_sec += $bin2frac->($server_reference_timestamp_microsec)) -= UNIX_EPOCH); ($server_originate_timestamp_sec += $bin2frac->($server_originate_timestamp_microsec)); (($server_rcv_timestamp_sec += $bin2frac->($server_rcv_timestamp_microsec)) -= UNIX_EPOCH); (($server_transmit_timestamp_sec += $bin2frac->($server_transmit_timestamp_microsec)) -= UNIX_EPOCH); # RFC2030 reference https://tools.ietf.org/html/rfc4330 my $d = ( ( $client_rcv_timestamp - $client_transmit_timestamp ) - ( $server_rcv_timestamp_sec - $server_transmit_timestamp_sec ) ); my $t = ( ( ( $server_rcv_timestamp_sec - $client_transmit_timestamp ) + ( $server_transmit_timestamp_sec - $client_rcv_timestamp ) ) / 2 ); # Clear screen for viewing the output system $^O eq 'MSWin32' ? 'cls' : 'clear'; print "Round Trip delay: ".$d."\n"; print "Clock offset: ".$t."\n"; #### Round Trip delay: 0.0255537033081055 Clock offset: 0.000513792037963867