#!/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