Last active
December 6, 2021 14:43
-
-
Save ooltcloud/1ed59c8ff72a24b273269aa403f6b01f to your computer and use it in GitHub Desktop.
NTP の応答を表示する
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#-------------- | |
# NTP の応答を表示する | |
#-------------- | |
# NTP 積算秒数の起点時刻 (JST) | |
$ntpEpoch = New-Object System.Datetime @(1900, 1, 1, 9, 0, 0) | |
# 符号付き Int8 を取得 | |
Function getInt8($byte) { | |
$a = [int32]$byte | |
if ($a -ge 128) { | |
$a -= 256 | |
} | |
return $a | |
} | |
# Big Endian の符号なし Int16 を取得 | |
Function getUInt16BE($bytes, $startIndex) { | |
# BE→LE 変換 | |
$a = $bytes[($startIndex + 1) .. $startIndex] | |
# UInt16 取得 | |
$b = [System.BitConverter]::ToUInt16($a, 0) | |
return $b | |
} | |
# Big Endian の符号なし Int32 を取得 | |
Function getUInt32BE($bytes, $startIndex) { | |
# BE→LE 変換 | |
$a = $bytes[($startIndex + 3) .. $startIndex] | |
# UInt32 取得 | |
$b = [System.BitConverter]::ToUInt32($a, 0) | |
return $b | |
} | |
# 固定小数点(整数部 16bit / 小数部 16bit) を取得 | |
Function getFixedPointDecimal1616($bytes, $startIndex) { | |
# 整数部取得 | |
$int = getUInt16BE $bytes $startIndex | |
# 小数部取得 | |
$dec = getUInt16BE $bytes ($startIndex + 2) | |
# 合成 | |
$value = $int + $dec * [Math]::Pow(2,-16) | |
return $value | |
} | |
# 固定小数点(整数部 32bit / 小数部 32bit) を取得 | |
Function getFixedPointDecimal3232($bytes, $startIndex) { | |
# 整数部取得 | |
$int = getUInt32BE $bytes $startIndex | |
# 小数部取得 | |
$dec = getUInt32BE $bytes ($startIndex + 4) | |
# 合成 | |
$value = $int + $dec * [Math]::Pow(2,-32) | |
return $value | |
} | |
# タイムスタンプ値から JST を求める | |
Function getJST($timeSerial) { | |
$date = $ntpEpoch.AddSeconds($timeSerial) | |
return $date | |
} | |
# 現在時刻(UTC)からタイムスタンプ値を求める | |
Function getNTPSerial($date) { | |
$buf = @() | |
# 積算秒数を求める | |
$timeSerial = ($date - $ntpEpoch).TotalSeconds | |
# 整数部 | |
$int = [Math]::Floor($timeSerial) | |
$intBytes = [System.BitConverter]::GetBytes([UInt32]$int) | |
$buf += $intBytes[3..0] # LE→BE変換 | |
# 小数部 | |
$dec = ($timeSerial % 1) * [Math]::Pow(2,32) | |
$decBytes = [System.BitConverter]::GetBytes([UInt32]$dec) | |
$buf += $decBytes[3..0] # LE→BE変換 | |
return $buf | |
} | |
# 送信電文作成 | |
Function getSendBytes() { | |
$buf = @() | |
# header | |
$li = 0 # 空設定 | |
$vn = 3 # Version 3 | |
$mode = 3 # Client Mode | |
$buf += [byte](($li * 64) + ($vn * 8) + $mode) | |
# stratum | |
$buf += [byte]2 # 空設定 | |
# poll | |
$buf += [byte]10 # 空設定 | |
# precision | |
$buf += [byte]0 # 空設定 | |
# RootDelay | |
$buf += @([Byte]0) * 4 # 空設定 | |
# RootDispersion | |
$buf += @([Byte]0) * 4 # 空設定 | |
# ReferenceID | |
$buf += @([Byte]0) * 4 # 空設定 | |
# Reference Timestamp | |
$buf += @([Byte]0) * 8 # 空設定 | |
# Origin Timestamp | |
$buf += @([Byte]0) * 8 # 空設定 | |
# Receive Timestamp | |
$buf += @([Byte]0) * 8 # 空設定 | |
# Transmit Timestamp | |
$buf += getNTPSerial ([Datetime]::Now) | |
return $buf | |
} | |
# NTP サーバーと通信 | |
Function inquiryNTP($ntpServerAddress, $sendBytes) | |
{ | |
$udp = New-Object Net.Sockets.UdpClient | |
$udp.Client.ReceiveTimeout = 2000 | |
try | |
{ | |
# UDP Port 123 に送信 | |
$a = $udp.Send($sendBytes, $sendBytes.Length, $ntpServerAddress, 123) | |
# 応答を受信 | |
$ret = $udp.Receive([ref]$null) | |
# 終了 | |
$udp.Close() | |
return $ret | |
} catch { | |
Throw | |
} finally { | |
$udp.Dispose() | |
} | |
} | |
# 受信電文解析 | |
Function getResult($recvBytes) { | |
$result = @{} | |
# header | |
$result["LI"] = ($recvBytes[0] -band 0xC0) / 64 | |
$result["VN"] = ($recvBytes[0] -band 0x38) / 8 | |
$result["Mode"] = $recvBytes[0] -band 0x7 | |
# stratum | |
$result["Stratum"] = [int]$recvBytes[1] | |
# poll | |
$result["Poll"] = [int]$recvBytes[2] | |
# precision | |
$result["Precision"] = getInt8 $recvBytes[3] | |
# RootDelay | |
$result["RootDelay"] = getFixedPointDecimal1616 $recvBytes 4 | |
# RootDispersion | |
$result["RootDispersion"] = getFixedPointDecimal1616 $recvBytes 8 | |
# ReferenceID | |
$refID = $recvBytes[12..15] | |
$result["RefID"] = [System.BitConverter]::ToUInt32($refID, 0) | |
$IsIP = ($refID | ? {(0x20 -le $_) -and ($_ -le 0x7e)}).Length -eq 4 | |
if ($IsIP) { | |
$result["RefIP"] = [System.Text.Encoding]::ASCII.GetString($refID) | |
} else { | |
$result["RefIP"] = "{0}.{1}.{2}.{3}" -f $refID | |
} | |
# Reference Timestamp | |
$result["ReferenceTS"] = getFixedPointDecimal3232 $recvBytes 16 | |
$result["ReferenceJST"] = getJST $result["ReferenceTS"] | |
# Origin Timestamp | |
$result["OriginTS"] = getFixedPointDecimal3232 $recvBytes 24 | |
$result["OriginJST"] = getJST $result["OriginTS"] | |
# Receive Timestamp | |
$result["ReceiveTS"] = getFixedPointDecimal3232 $recvBytes 32 | |
$result["ReceiveJST"] = getJST $result["ReceiveTS"] | |
# Transmit Timestamp | |
$result["TransmitTS"] = getFixedPointDecimal3232 $recvBytes 40 | |
$result["TransmitJST"] = getJST $result["TransmitTS"] | |
return $result | |
} | |
# 結果表示 | |
Function display($result) { | |
$li = @("警告なし", "最後の1分が61秒", "最後の1分が59秒", "警告。時刻が同期していない") | |
$mode = @("予約", "Symmetric Active", "Symmetric Passive", "Client", "Server", "Broadcast", "予約", "予約") | |
$stratum = @(0..255) | |
$stratum[0] = "0 (原子時計等。または時刻同期していない)" | |
$stratum[1] = "1 (1次参照。原子時計等を参照)" | |
$stratum[16] = "16 (最下層。同期できない)" | |
Write-Output (" 閏インジケーター : {0} ({1})" -f $result["LI"], $li[$result["LI"]]) | |
Write-Output (" 階層 : {0}" -f $stratum[$result["Stratum"]]) | |
Write-Output (" モード : {0} ({1})" -f $result["Mode"], $mode[$result["Mode"]]) | |
Write-Output (" 精度 : {0}" -f $result["Precision"]) | |
Write-Output (" ルート遅延 : {0}" -f $result["RootDelay"]) | |
Write-Output (" ルート分散(拡散) : {0}" -f $result["RootDispersion"]) | |
Write-Output (" 参照 ID : 0x{0:X} ({1})" -f $result["RefID"] , $result["RefIP"]) | |
Write-Output (" 時刻源参照時刻 (JST) : {0:yyyy/MM/dd HH:mm:ss.fff} ({1})" -f $result["ReferenceJST"], $result["ReferenceTS"] ) | |
Write-Output (" 要求送信時刻 (JST) : {0:yyyy/MM/dd HH:mm:ss.fff} ({1})" -f $result["OriginJST"], $result["OriginTS"] ) | |
Write-Output (" 要求受信時刻 (JST) : {0:yyyy/MM/dd HH:mm:ss.fff} ({1})" -f $result["ReceiveJST"], $result["ReceiveTS"] ) | |
Write-Output (" 応答送信時刻 (JST) : {0:yyyy/MM/dd HH:mm:ss.fff} ({1})" -f $result["TransmitJST"], $result["TransmitTS"] ) | |
} | |
# 時刻サーバー問い合わせ | |
Function QueryNTPStatus($ntpServerAddress) { | |
Write-Output ("{0}" -f $ntpServerAddress) | |
try { | |
$send = getSendBytes | |
$recv = inquiryNTP $ntpServerAddress $send | |
$result = getResult $recv | |
display $result | |
} catch { | |
Throw | |
} | |
Write-Output ("") | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
QueryNTPStatus "ntp.nict.jp" |
表示例
ntp.nict.jp
閏インジケーター : 0 (警告なし)
階層 : 1 (1次参照。原子時計等を参照)
モード : 2 (Symmetric Passive)
精度 : -20
ルート遅延 : 0
ルート分散(拡散) : 0
参照 ID : 0x5443494E (NICT)
時刻源参照時刻 (JST) : 2018/12/05 20:08:48.000 (3752996928)
要求送信時刻 (JST) : 2018/12/05 20:08:48.634 (3752996928.63423)
要求受信時刻 (JST) : 2018/12/05 20:08:48.861 (3752996928.86148)
応答送信時刻 (JST) : 2018/12/05 20:08:48.861 (3752996928.86148)
同期先 NTP サーバーの stratum や ルート分散 (Dispersion) を確認する用途で使用。
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
powershell 5.1 & Win10 (ver1803) で確認。