製品コラム

セイテクエンジニアのブログ  製品コラム  ネットワークポートの枯渇を監視したい-BOM for Windows活用例

 

 

ネットワークポートの枯渇を監視したい-BOM for Windows活用例

2025年12月24日配信
執筆者:セイ・テクノロジーズ エバンジェリスト

 「BOM for Windows Ver.8.0」(以下、BOM)の「カスタム監視」を使用すると、BOM標準の監視設定にはない、独自の監視を行えます。サーバーのポート(エフェメラルポート)の使用状況を監視し、ネットワークやアプリケーションの問題、ポートの枯渇の前兆をいち早く検知する方法を紹介します。ポートの不足/枯渇は、接続失敗を増加させ、さまざまなネットワークトラブルとして顕在化します。しかし、ポートの不足/枯渇状況は、Windows標準のパフォーマンスモニターでは監視できません。

 

エフェメラルポートの枯渇問題とは

 

 TCPやUDPは0~65536(0は予約されており通常使用されません)のポートでアプリケーション(プロセス)を識別します。TCP/IPで通信を行う場合、「発信元ポート-発信元IPアドレス-宛先IPアドレス-宛先ポート」の組み合わせて送信元のプロセスと宛先のプロセス間の通信が可能になります。

 コネクション型のTCPの場合、サーバー(TCPのサーバー)側のサービス(Webサーバーなど)は固定のウェルノウン(Well Known)ポート(例、443)を使用し、クライアントは固定の宛先ポートに対して、動的な発信元ポートを使用して接続を確立します。この動的なポートは、エフェメラル(Ephemeral、一時的な、短命な、儚い)ポートと呼ばれ、通常、49152~65536*1の範囲(RFC6335のDynamic and/or Private
Ports)から未使用のポートがランダムに選択されます。同じWebブラウザーから同時に同じWebサイトにアクセスすることを考えてください。発信元ポートが動的に決まることで、Webブラウザーのプロセス(またはタブのプロセス)が識別されるため、各ブラウザー(またはタブ)で別のページを参照することができるのです。
*1 Windows XPおよびWindows Server 2003までは1025~5000が使用されていました。

 コネクションレス型のUDPの場合、発信元ポートは、エフェメラルポート(49152~65536)、0、サーバーと同じポート(例、53)など、アプリケーションの実装によって異なります。

 サーバーサービスのポートは固定のウェルノウンポートであるため、同じポートをバインドする別のアプリのインストールなどでポートが競合するということはあっても、ポートが不足するということはありません。不足や枯渇する可能性があるのは、常にクライアント(クライアントPCではなく、TCPのクライアント)からの送信接続です。何らかの理由で大量の短い送信接続が発生すると、TIME_WAIT状態の接続が増大し、利用可能なエフェメラルポートの数が大きく減ることになります(画面1)。TIME_WAIT状態とは、接続終了を相手が受け取るのを一定期間待つ待機状態のことです。Windowsの既定で4分間待機します。TIME_WAIT状態の後、CLOSED状態に遷移し、そのポートは再利用可能になります。

 

画面1 TIME_WAIT状態の接続が大量にあると、その分だけエフェメラルポートの利用可能なポート数は減る
画面1 TIME_WAIT状態の接続が大量にあると、その分だけエフェメラルポートの利用可能なポート数は減る

 利用可能なエフェメラルポートが枯渇してしまうと、新たな送信接続ができなくなります。例えば企業ネットワークでは、Active Directoryのドメイン認証が失敗する、リモートデスクトップ接続が失敗する、ファイルサーバーに接続できない、アプリケーションからデータベースへの接続に失敗するなどの影響が出ます。

 ポート不足/枯渇の原因はさまざまです。例えば、マルウェア感染による大量の外部送信、大量のWebアクセスを処理するプロキシサーバー、アプリケーションのバグ(REST APIの非効率な呼び出し、例外時のクリーンアップ処理の欠落、接続プール不使用)、監視エージェントからの大量発信、タイムアウト値の過大設定、狭すぎるカスタム定義のエフェメラルポート範囲などです。アプリケーションが原因の場合、アプリケーションの修正が必要です。

 クラウド上のVMの場合、クラウド特有の影響を受ける場合があります。NATゲートウェイを介して1つのパブリックIPアドレスを複数のVMやコンテナーのポッドが使用するような状況では、NATゲートウェイにトラフィックが集中し、NATゲートウェイ側のポートが不足/枯渇する可能性があります。その場合、間接的にVMではTIME_WAITの増加という形で影響が現れます。KubernetesのボッドやDockerのコンテナーホストでは、インスタンスはコンテナーネットワークに接続され、外部からインスタンスへの接続はコンテナーホストがNATクライアントとして動作します。そのため、大量の接続要求はホストのポートを不足/枯渇させる可能性があります。なお、クラウド特有の問題でポートの不足/枯渇問題が生じた場合は、リソースを増やす(パブリックIPアドレスを追加する、VMやコンテナーをスケールアウトするなど)ことで改善できる場合があります。これはクラウドの利点でもあります。

 

エフェメラルポートの使用状況を監視するPowerShellスクリプト

 

 エフェメラルポートのポート範囲は、次のコマンドラインで確認することができます。


netsh int ipv4 show dynamicport tcp

 ポートの使用状況の監視に、パフォーマンスモニターは利用できません。TCP関連のパフォーマンスカウンター(TCPv4¥Connections Established、Connection Failures、Segments/sec)などパフォーマンス統計(現在値または累積値)が中心であり、ポート番号、ましてやエフェメラルポートや接続の状態を細かく区別するようなカウンターは存在しません。

 エフェメラルポートの使用状況や接続の状態はnetstat -aコマンド(前出の画面1)で確認することができますが、ネットワーク接続数が多いと、名前解決やIPv6の逆引き、ポート番号の変換(443→https)、出力テキストの整形などに時間がかかり、すべての情報が返ってくるまで長い時間待たされることがあります。代わりに、ネットワーク負荷の高い状況でも比較的高速なPowerShellのGet-NetTCPConnectionコマンドレットを使用できます。

 

Get-NetTCPConnection|PowerShell > NetTCPIP Module(Microsoft Learn)

 次のPowerShellスクリプト「ephemeralportstat.ps1」は、エフェメラルポートの範囲で接続に使用中のポート数を取得し、IPv4およびIPv6の現在のTCP接続を対象に、利用可能な空きポートと、接続別の状態(ESTABLISHEDやTIME_WAIT)ごとのポート数を返します(画面2)。

 

[ephemeralportstat.ps1]プレーンテキストで表示)

$ret = cmd /c "chcp 437 > nul && netsh int ipv4 show dynamicport tcp"
$startport = [int](($ret | Select-String 'Start Port').Line -replace '\D','')
$numofports = [int](($ret | Select-String 'Number of Ports').Line -replace '\D','')
$endport = $startport + $numofports - 1
$usedports = Get-NetTCPConnection | Where-Object { $_.LocalPort -ge $startport -and $_.LocalPort -le $endport }
Write-Host "Port Range :" $numofports
Write-Host "Used total :" $usedports.Count
Write-Host "Free ports :" ($numofports - $usedports.Count)
Write-Host "Count by coinnection status :"
$states = $usedports | Group-Object -Property State |Select Name,Count
foreach ($state in $states) {
Write-Host "`t"$state.Name ":" $state.Count
}

 

画面2 netshコマンドによるエフェメラルポートの範囲の取得と、Get-NetTCPConnectionコマンドレットによるポートの使用状況の取得をスクリプト化した「ephemeralportstat.ps1」

画面2 netshコマンドによるエフェメラルポートの範囲の取得と、Get-NetTCPConnectionコマンドレットによるポートの使用状況の取得をスクリプト化した「ephemeralportstat.ps1」

 

スクリプトをBOMのカスタム監視に実装する

 

 BOMを使用すれば、空きポート数やTIME_WAIT状態のポート数を継続的に監視できます。急激に増大し、それに応じて空きポート数が急激に現象する、ポート枯渇につながる異常な状態を早期に検知することができます。

 次のPowerShellスクリプト「bom_ephemeralportstat.ps1」は、「ephemeralportstat.ps1」をBOMのカスタム監視用に変更したものです。「bom_ephemeralportstat.ps1」は返り値として空きポート数だけを返し、同時に「ephemeralportstat.ps1」と同じ出力をログファイルに書き込みます(作成または上書き)。ログファイルの既定は一時フォルダー(TEMP環境変数のパス、BOM実行ユーザーであるシステムアカウントの場合はC:¥Windows¥Temp)内の「bom_ephemeralportstat.log」です。ログファイルの出力先は、スクリプトに-LogFileパラメーターで指定することもできます(例: .\bom_ephemeralportstat.ps1 -LogFile C:¥Logs¥ephemeralportstat.log)。注意や警告時にアクション項目としてログファイルをメールに添付して送信する場合などに利用してください。

 

[bom_ephemeralportstat.ps1](プレーンテキストで表示)

param(
[string]$logfile = "$env:temp\bom_ephemeralportstat.log"
)
$timeout = 60
$ret = cmd /c "chcp 437 > nul && netsh int ipv4 show dynamicport tcp"
$startport = [int](($ret | Select-String 'Start Port').Line -replace '\D','')
$numofports = [int](($ret | Select-String 'Number of Ports').Line -replace '\D','')
$endport = $startport + $numofports - 1
#$usedports = Get-NetTCPConnection | Where-Object { $_.LocalPort -ge $startport -and $_.LocalPort -le $endport }
$job = Start-Job { Get-NetTCPConnection | Select LocalPort,State }
Wait-Job $job -TimeOut $timeout | Out-Null
if ($job.State -eq "Completed") {
$usedports = Receive-Job $job
$usedports = $usedports| Where-Object { $_.LocalPort -ge $startport -and $_.LocalPort -le $endport }
} else {
return "Error: Command Timedout in $($timeout) sec."
}

$output = "Port Range : $($numofports)`n"
$output += "Used total : $($usedports.Count)`n"
$freeports = $numofports - $usedports.Count
$output += "Free ports : $($freeports)`n"
$output += "Count by coinnection status :`n"
$states = $usedports | Group-Object -Property State |Select Name,Count
foreach ($state in $states) {
$output += "`t$($state.Name) : $($state.Count)`n"
}
$output | Out-File $logfile
return ($numofports - $usedports.Count)

 

 他の情報もBOMで監視したいところですが、同じようなPowerShellスクリプトを別のカスタム監視で並列に実行するのは効率的ではありません。「bom_ephemeralportstat.ps1」でログファイルに出力した理由は、そのためです。ログファイルから行を読み取って特定の数字を取り出せば、効率的に監視できます(画面3)。次の「bom_porttimewait.ps1」と「bom_portestablished.ps1」は、ログファイルから1行読み取ってTIME_WAITのポート数とESTABLISHED(接続確立済み)のポート数を返します。「bom_ephemeralportstat.ps1」に-LogFileパラメーターを指定した場合は、同じようにログファイルを指定してください。なお、「bom_portestablished.ps1」は、パフォーマンスカウンター「TCPv4およびTCPv6¥Connections Established」にならってESTABLISHEDとCLOSE_WAIT(CloseWait)の合計を返します。

 

画面3 「ephemeralportstat.ps1」をBOMのカスタム監視用に変更した「bom_ephemeralportstat.ps1」。「bom_ephemeralportstat.ps1」は空きポート数のみを返し、その他のポート数はログファイルに出力
画面3 「ephemeralportstat.ps1」をBOMのカスタム監視用に変更した「bom_ephemeralportstat.ps1」。このスクリプトは空きポート数のみを返し、その他のポート数はログファイルに出力する

 

[bom_porttimewait.ps1](プレーンテキストで表示)

param(
[string]$logfile = "$env:temp\bom_ephemeralportstat.log"
)
if (Test-Path($logfile)) {
$ret= [int]((Select-String "TimeWait" $logfile).Line -Replace "\D","")
return $ret
} else {
return "Error: no monitoring data."
}

[bom_portestablished.ps1](プレーンテキストで表示)
param(
[string]$logfile = "$env:temp\bom_ephemeralportstat.log"
)
if (Test-Path($logfile)) {
$ret = [int]((Select-String "Established" $logfile).Line -Replace "\D","")
$ret += [int]((Select-String "CloseWait" $logfile).Line -Replace "\D","")
return $ret
} else {
return "Error: no monitoring data."
}
# Or Perfmon Counter TCPv4/TCPv6\Connections Established

 

 これらのスクリプトを使用してBOMで監視を行うには、エフェメラルポートの空きポート監視用のカスタム監視項目を作成し、「bom_ephemeralportstat.ps1」を実行するように、スクリプトをpowershell.exeの引数として(powershell.exe -ExecutionPolicy Bypass -File <スクリプトのパス>)設定します。また、しきい値を例えば「8192」(既定のエフェメラルポートの範囲16384の半分)を下回れば注意、「1000」を下回れば警告のように設定します(画面4)。

 TIME_WAITとESTABLISHEDのポート数は、それぞれに監視用のカスタム監視項目を作成し、「bom_porttimewait.ps1」と「bom_portestablished.ps1」を実行するように設定します。しきい値は一例ですが、「1000」以上を注意、「5000」以上を警告としました。

 

画面4 BOMで監視用PowerShellスクリプトを5分ごとに実行するように設定し、しきい値を調整する
画面4 BOMで監視用PowerShellスクリプトを5分ごとに実行するように設定し、しきい値を調整する

 必要に応じて各カスタム監視にアクション項目を設定し、状態が変化した際にメール通知を行うなど設定します。TIME_WAIT状態の接続が急増した場合は、メールなどによるアラート通知の他、BOMマネージャーのログ(グラフ表示)で視覚的に確認することができます(画面5)。

 

画面5 TIME_WAIT状態の接続が急増した時のBOMマネージャーの表示(この例と画面1は大量で短時間のTCP接続を意図的に発生させたもの)
画面5 TIME_WAIT状態の接続が急増した時のBOMマネージャーの表示(この例と画面1は大量で短時間のTCP接続を意図的に発生させたもの)

blog_column_subscribe

blog_column_comment

最新記事