Windows and Linux script to monitor NTP offset value
NTP is a time synchronization protocol, which can be used to synchronize the system time from an external resource.
If you are a network, system or application administrator who managing a large number of servers and application environment, it is important that NTP is configured and running correctly. This is also a security concern that all servers in an application environment are running in same time with same CPU clock.
NTP offset value can be used for monitor the time differences between NTP server and client. I have complied Powershell and KornShell script to monitor NTP offset time and create alert if NTP offset value is larger than “60000”.
Script Details:
- Get System defined NTP Servers.
- Calculate NTP offset Value.
- Check if offset is larger than 60000 miliseconds.
- Send alert to HP Operation Manager.
Windows Servers NTP Offset Monitor
Before Running:
- Check Powershell version on your server with $PSVersionTable . PS version must be minimum 3.
- Change $path_ntp parameter on script that where you located your this script.
- Alert rule created for HP Operation Manager. If you need change it to your as you wish.
Script Added Githup Repository. You can get it from this link.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
#Requires -Version 3 ################################################### # Abdurrahim YILDIRIM # ################################################### #C:\HPOOconfig\SystemControl\Ntp_Offset_Control.ps1 Set-StrictMode -Version 3 Function Get-NtpTime { [CmdletBinding()] [OutputType()] Param ( [String]$Server = 'pool.ntp.org', [Int]$MaxOffset = 1000000, # (Milliseconds) Throw exception if network time offset is larger [Switch]$NoDns = $True # Do not attempt to lookup V3 secondary-server referenceIdentifier ) # NTP Times are all UTC and are relative to midnight on 1/1/1900 $StartOfEpoch=New-Object DateTime(1900,1,1,0,0,0,[DateTimeKind]::Utc) Function OffsetToLocal($Offset) { # Convert milliseconds since midnight on 1/1/1900 to local time $StartOfEpoch.AddMilliseconds($Offset).ToLocalTime() } # Construct a 48-byte client NTP time packet to send to the specified server # (Request Header: [00=No Leap Warning; 011=Version 3; 011=Client Mode]; 00011011 = 0x1B) [Byte[]]$NtpData = ,0 * 48 $NtpData[0] = 0x1B # NTP Request header in first byte $Socket = New-Object Net.Sockets.Socket([Net.Sockets.AddressFamily]::InterNetwork, [Net.Sockets.SocketType]::Dgram, [Net.Sockets.ProtocolType]::Udp) $Socket.SendTimeOut = 2000 # ms $Socket.ReceiveTimeOut = 2000 # ms Try { $Socket.Connect($Server,123) } Catch { Write-Error "Failed to connect to server $Server" Throw } # NTP Transaction ------------------------------------------------------- $t1 = Get-Date # t1, Start time of transaction... Try { [Void]$Socket.Send($NtpData) [Void]$Socket.Receive($NtpData) } Catch { Write-Error "Failed to communicate with server $Server" Throw } $t4 = Get-Date # End of NTP transaction time # End of NTP Transaction ------------------------------------------------ $Socket.Shutdown("Both") $Socket.Close() # We now have an NTP response packet in $NtpData to decode. Start with the LI flag # as this is used to indicate errors as well as leap-second information # Check the Leap Indicator (LI) flag for an alarm condition - extract the flag # from the first byte in the packet by masking and shifting $LI = ($NtpData[0] -band 0xC0) -shr 6 # Leap Second indicator If ($LI -eq 3) { Throw 'Alarm condition from server (clock not synchronized)' } # Decode the 64-bit NTP times # The NTP time is the number of seconds since 1/1/1900 and is split into an # integer part (top 32 bits) and a fractional part, multipled by 2^32, in the # bottom 32 bits. # Convert Integer and Fractional parts of the (64-bit) t3 NTP time from the byte array $IntPart = [BitConverter]::ToUInt32($NtpData[43..40],0) $FracPart = [BitConverter]::ToUInt32($NtpData[47..44],0) # Convert to Millseconds (convert fractional part by dividing value by 2^32) $t3ms = $IntPart * 1000 + ($FracPart * 1000 / 0x100000000) # Perform the same calculations for t2 (in bytes [32..39]) $IntPart = [BitConverter]::ToUInt32($NtpData[35..32],0) $FracPart = [BitConverter]::ToUInt32($NtpData[39..36],0) $t2ms = $IntPart * 1000 + ($FracPart * 1000 / 0x100000000) # Calculate values for t1 and t4 as milliseconds since 1/1/1900 (NTP format) $t1ms = ([TimeZoneInfo]::ConvertTimeToUtc($t1) - $StartOfEpoch).TotalMilliseconds $t4ms = ([TimeZoneInfo]::ConvertTimeToUtc($t4) - $StartOfEpoch).TotalMilliseconds # Calculate the NTP Offset and Delay values $Offset = (($t2ms - $t1ms) + ($t3ms-$t4ms))/2 $Delay = ($t4ms - $t1ms) - ($t3ms - $t2ms) # Make sure the result looks sane... If ([Math]::Abs($Offset) -gt $MaxOffset) { # Network server time is too different from local time Throw "Network time offset exceeds maximum ($($MaxOffset)ms)" } # Decode other useful parts of the received NTP time packet # We already have the Leap Indicator (LI) flag. Now extract the remaining data # flags (NTP Version, Server Mode) from the first byte by masking and shifting (dividing) $LI_text = Switch ($LI) { 0 {'no warning'} 1 {'last minute has 61 seconds'} 2 {'last minute has 59 seconds'} 3 {'alarm condition (clock not synchronized)'} } $VN = ($NtpData[0] -band 0x38) -shr 3 # Server version number $Mode = ($NtpData[0] -band 0x07) # Server mode (probably 'server') $Mode_text = Switch ($Mode) { 0 {'reserved'} 1 {'symmetric active'} 2 {'symmetric passive'} 3 {'client'} 4 {'server'} 5 {'broadcast'} 6 {'reserved for NTP control message'} 7 {'reserved for private use'} } # Other NTP information (Stratum, PollInterval, Precision) $Stratum = [UInt16]$NtpData[1] # Actually [UInt8] but we don't have one of those... $Stratum_text = Switch ($Stratum) { 0 {'unspecified or unavailable'} 1 {'primary reference (e.g., radio clock)'} {$_ -ge 2 -and $_ -le 15} {'secondary reference (via NTP or SNTP)'} {$_ -ge 16} {'reserved'} } $PollInterval = $NtpData[2] # Poll interval - to neareast power of 2 $PollIntervalSeconds = [Math]::Pow(2, $PollInterval) $PrecisionBits = $NtpData[3] # Precision in seconds to nearest power of 2 # ...this is a signed 8-bit int If ($PrecisionBits -band 0x80) { # ? negative (top bit set) [Int]$Precision = $PrecisionBits -bor 0xFFFFFFE0 # Sign extend } else { # ..this is unlikely - indicates a precision of less than 1 second [Int]$Precision = $PrecisionBits # top bit clear - just use positive value } $PrecisionSeconds = [Math]::Pow(2, $Precision) # Determine the format of the ReferenceIdentifier field and decode If ($Stratum -le 1) { # Response from Primary Server. RefId is ASCII string describing source $ReferenceIdentifier = [String]([Char[]]$NtpData[12..15] -join '') } Else { # Response from Secondary Server; determine server version and decode Switch ($VN) { 3 { # Version 3 Secondary Server, RefId = IPv4 address of reference source $ReferenceIdentifier = $NtpData[12..15] -join '.' If (-Not $NoDns) { If ($DnsLookup = Resolve-DnsName $ReferenceIdentifier -QuickTimeout -ErrorAction SilentlyContinue) { $ReferenceIdentifier = "$ReferenceIdentifier <$($DnsLookup.NameHost)>" } } Break } 4 { # Version 4 Secondary Server, RefId = low-order 32-bits of # latest transmit time of reference source $ReferenceIdentifier = [BitConverter]::ToUInt32($NtpData[15..12],0) * 1000 / 0x100000000 Break } Default { # Unhandled NTP version... $ReferenceIdentifier = $Null } } } # Calculate Root Delay and Root Dispersion values $RootDelay = [BitConverter]::ToInt32($NtpData[7..4],0) / 0x10000 $RootDispersion = [BitConverter]::ToUInt32($NtpData[11..8],0) / 0x10000 # Finally, create output object and return $NtpTimeObj = [PSCustomObject]@{ NtpServer = $Server NtpTime = OffsetToLocal($t4ms + $Offset) Offset = $Offset OffsetSeconds = [Math]::Round($Offset/1000, 3) Delay = $Delay t1ms = $t1ms t2ms = $t2ms t3ms = $t3ms t4ms = $t4ms t1 = OffsetToLocal($t1ms) t2 = OffsetToLocal($t2ms) t3 = OffsetToLocal($t3ms) t4 = OffsetToLocal($t4ms) LI = $LI LI_text = $LI_text NtpVersionNumber = $VN Mode = $Mode Mode_text = $Mode_text Stratum = $Stratum Stratum_text = $Stratum_text PollIntervalRaw = $PollInterval PollInterval = New-Object TimeSpan(0,0,$PollIntervalSeconds) Precision = $Precision PrecisionSeconds = $PrecisionSeconds ReferenceIdentifier = $ReferenceIdentifier RootDelay = $RootDelay RootDispersion = $RootDispersion Raw = $NtpData # The undecoded bytes returned from the NTP server } # Set the default display properties for the returned object [String[]]$DefaultProperties = 'NtpServer', 'NtpTime', 'OffsetSeconds', 'NtpVersionNumber', 'Mode_text', 'Stratum', 'ReferenceIdentifier' # Create the PSStandardMembers.DefaultDisplayPropertySet member $ddps = New-Object Management.Automation.PSPropertySet('DefaultDisplayPropertySet', $DefaultProperties) # Attach default display property set and output object $PSStandardMembers = [Management.Automation.PSMemberInfo[]]$ddps $NtpTimeObj | Add-Member -MemberType MemberSet -Name PSStandardMembers -Value $PSStandardMembers -PassThru } $Servername = $env:computername $path_ntp = "C:\HPOOconfig\SystemControl\ntp_offset_control" $NTPserver = w32tm /query /source|%{ $_.Split(',')[0]; } $NTPValue = Get-NtpTime $NTPserver $OffsetValue = $NTPValue.OffsetSeconds if ($OffsetValue -lt '-60000' -or $OffsetValue -gt '60000' -or !$OffsetValue) { Write-Host("NTP offset high: $OffsetValue") if (Test-Path $path_ntp) { Write-Host("Aler Dublicated") } else { opcmsg a=Offset o=Offset severity=Critical msg_text=" $servername NTP Offset Problem " node="$servername" echo $null >> $path_ntp } } else { if (Test-Path $path_ntp) { opcmsg a=Offset o=Offset severity=Normal msg_text=" $servername NTP Offset Fixed" node="$servername" del $path_ntp } } |
Linux NTP Offset Monitor
- Change Script_Path where you located script.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#!/bin/ksh Offset=`ntpq -p |grep -e '*'|awk '{print $9}'` Offset=${Offset%.*} Script_Path=/unixadmin/controlfile if [ "$Offset" -lt "-60000" ] || [ "$Offset" -gt 60000 ] || [ -z "$Offset" ] then if [ ! -f $Script_Path/ntp_offset_critical ] then /opt/OV/bin/opcmsg a=Offset o=Offset severity=Critical msg_text="`hostname` NTP Offset Problem !!! " node=`hostname` touch $Script_Path/ntp_offset_critical fi else if [ -f $Script_Path/ntp_offset_critical ] then /opt/OV/bin/opcmsg a=Offset o=Offset severity=Normal msg_text="`hostname` NTP Offset Fixed. !!! " node=`hostname` rm -rf $Script_Path/ntp_offset_critical fi fi |
Abdurrahim
Latest posts by Abdurrahim (see all)
- Deployment of Ansible AWX on OpenShift Origin - February 12, 2019
- OpenShift LDAP Integration - February 6, 2019
- TCP 3-Way Handshake - January 14, 2019




