Skip to content

Instantly share code, notes, and snippets.

@ooltcloud
Last active December 6, 2021 14:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ooltcloud/1ed59c8ff72a24b273269aa403f6b01f to your computer and use it in GitHub Desktop.
Save ooltcloud/1ed59c8ff72a24b273269aa403f6b01f to your computer and use it in GitHub Desktop.
NTP の応答を表示する
#--------------
# 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 ("")
}
QueryNTPStatus "ntp.nict.jp"
@ooltcloud
Copy link
Author

powershell 5.1 & Win10 (ver1803) で確認。

@ooltcloud
Copy link
Author

表示例

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)

@ooltcloud
Copy link
Author

同期先 NTP サーバーの stratum や ルート分散 (Dispersion) を確認する用途で使用。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment