Windows 11でipsendwinを動かす

Network

以前の記事では,Wiresharkを入れた後にipsendwinが起動しなくなり,Win10Pcapを追加して直した話を書きました.Windows 11ではどうなるか,Npcapで試し直しました.

DLL不足はNpcapのWinPcap API互換モードで解消しましたが,今度は「送信可能なインタフェースがありません。」で止まります.調べると,ipsendwinが先頭のNICだけを見て起動の可否を決めていました.列挙結果の並び順を変える互換DLLを挟むと起動し,同じPCの仮想Ethernetで送信フレームをキャプチャできました.

試した環境と,止まったところ

検証日は2026年11月4日です.

OS Windows 11 x64,ビルド26300.9711(DisplayVersion 26H2)
ipsendwin Vector配布版2.4,32ビット
Npcap 1.90,WinPcapCompatible=1,AdminOnly=0
送信に使ったNIC Hyper-V Virtual Ethernet Adapter

ipsendwinは配布MSIのProductVersionが2.4ですが,EXEのバージョン情報にはProductVersion 2.2/FileVersion 1.0.0.1が残っていました.今回使ったEXEのSHA-256は以下です.

7F5C507510CE5C44AB4497F6033D7E826C4282649ABCD3729A38AC5C7D34108D

最初はNpcapが入っておらず,起動時に「wpcap.dllが見つからない」と表示されました.公式サイトからNpcap 1.90を入れ,インストーラーの「Install Npcap in WinPcap API-compatible Mode」にチェックを入れています.このオプションでWinPcap互換アプリが読むDLLもシステム側に配置されます(Npcapのインストールオプション).

DLL不足のエラーは消えました.ただし,操作画面が出る前に次のメッセージで終了します.

送信可能なインタフェースがありません。

ここまでの変化を並べるとこうです.

状態 起動結果
Npcapなし wpcap.dllが見つからない
NpcapをWinPcap API互換モードで導入 送信可能なインタフェースがありません。
後述の互換DLLをEXEの隣に追加 操作画面が開き,NICを選択できる

先頭がWAN Miniportだった

まず,ipsendwinとは別の32ビットプログラムからNpcapのpcap_findalldevs()を呼びました.NICは6つ列挙でき,Hyper-Vの仮想EthernetとRealtekの有線LANをpcap_open_live()で開くこともできました.Npcap側でNICが見えていないわけではありません.

返ってきた順番とアドレスファミリーは以下でした.デバイス固有のGUIDは省いています.

順番  Description                              Address families
1     WAN Miniport (Network Monitor)           なし
2     WAN Miniport (IPv6)                      なし
3     WAN Miniport (IP)                        なし
4     Hyper-V Virtual Ethernet Adapter         2, 23
5     Realtek Gaming 2.5GbE Family Controller   2, 23
6     Adapter for loopback traffic capture     23, 2

2 = AF_INET(IPv4),23 = AF_INET6(IPv6)

pcap_findalldevs()はpcap_if_tの連結リストを返します.NIC間のnextとは別に,各NICのaddressesもpcap_addr_tの連結リストです.アドレスを持たないNICではaddressesがNULLになることがあり,アドレスがあってもIPv4とは限りません(APIの仕様).

ipsendwinの起動処理を逆アセンブルで追うと,先頭NICのaddressesをたどってsa_family == AF_INETを探していました.アドレスのリストは最後まで見ますが,見つからなかった場合に次のNICへ進む処理がありません.確認した分岐を擬似コードにするとこうなります.元のソースコードではありません.

// 列挙成功後の判定部分(エラー処理などは省略)
pcap_findalldevs(&devices, errbuf);
found_ipv4 = false;
for (address = devices->addresses; address; address = address->next) {
    if (address->addr->sa_family == AF_INET) {
        found_ipv4 = true;
        break;
    }
}
if (!found_ipv4) {
    // 「送信可能なインタフェースがありません。」で終了
}
// devices->next に進む処理がない

今回の先頭は,アドレスを持たないWAN Miniportでした.後ろにIPv4を持つNICがあっても,そこまで調べずに終了していたわけです.

この結果からは,Windows 11そのものがipsendwinの送信を禁止したとは言えません.Windows 10との比較試験はしていませんが,今回の起動失敗はアプリ側の判定とNICの列挙順で説明できました.

ipsendwinの横に互換DLLを置く

IPv4を持つNICが先頭に来れば起動できそうなので,wpcap.dllという名前の32ビット互換DLLを作りました.ipsendwinからの呼び出しを受けて,実際の処理はインストール済みNpcapへ渡します.

  1. Vectorからipsendwin 2.4を入手します.
  2. NpcapをWinPcap API互換モードで導入します.今回試したのは1.90です.再起動を求められた場合は,再起動してから続けます.
  3. ipsendwinを閉じ,v0.1.1の配布ページからipsendwin-npcap-compat-win32-v0.1.1.zipをダウンロードして展開します.
  4. ZIPのwpcap.dllを,ipsendwin.exeと同じフォルダーに置きます.同名のDLLがすでにある場合は,元のファイルを別に保管してから置き換えます.
  5. ipsendwinを起動し,使用するインタフェースを選びます.
ipsendwinを置いたフォルダー/
├─ ipsendwin.exe
└─ wpcap.dll       ← 今回の互換DLL

これで操作画面が開きました.このDLLは自作の未署名DLLで,Npcap公式のDLLではありません.System32やSysWOW64,Npcapのインストール先には上書きしません.ZIPにipsendwin本体とNpcap本体は含めていません.

元に戻すときはipsendwinを閉じ,追加したwpcap.dllをフォルダーの外へ移します.元の同名ファイルを保管していた場合は,それを戻します.

互換DLLで変えているところ

実装はwpcap-compat.cにあります.今回の変更はpcap_findalldevs()が返したリストの先頭を入れ替えるところです.

  1. インストール済みNpcapのpcap_findalldevs()を呼ぶ.
  2. 先頭が「IPv4を持つ非ループバックNIC」なら,そのまま返す.
  3. そうでなければ後続を探し,最初に見つかった該当NICを元の位置から外して先頭につなぐ.

この環境では,先頭3つのWAN Miniportの後ろにあったHyper-V仮想Ethernetが先頭になります.残りのNICを削除したり,構造体を複製したりはしていません.リスト全体をNpcapのpcap_freealldevs()へ返して解放します.

中継する関数はpcap_findalldevs,pcap_freealldevs,pcap_open_live,pcap_sendpacket,pcap_close,pcap_lib_versionです.ipsendwinが序数で参照するエクスポートは,.defファイルで元の序数に合わせています.WinPcap API全体を実装した汎用の代替DLLではありません.

Npcap本体はGetSystemDirectoryW()で求めたシステムディレクトリのNpcapサブディレクトリから読み込みます.32ビットプロセスなので,使うのは32ビットのNpcapです.同名の自作DLLを再度読み込まないよう,本体には絶対パスを指定しています.パスをソースに固定する必要はありません.送信時のハンドルやフレームはNpcapへそのまま渡します.

この判定で見るのはIPv4アドレスの有無とループバックフラグです.リンク状態や送信先への疎通までは判定しないので,起動後に目的のNICを自分で選びます.IPv4を持つ非ループバックNICが1つもない環境や,Npcap自体を読み込めない状態は,並べ替えでは直りません.

1フレーム送って,別のプロセスで捕まえる

起動だけで終わらせず,Hyper-Vの仮想Ethernetへ1フレーム送ってみました.設定は以下です.送信元MACは選択した仮想NICに合わせ,送信先には検証用のローカルMACを指定しています.

設定項目 値
フレーム構成 MAC+その他
Ethernetタイプ 自動を外し,0x88B5
ペイロード 64バイト,すべて0x00
送信フレーム数 1
ipsendwinで仮想Ethernetへの1フレーム送信が完了した画面
互換DLLを追加すると起動でき,1/1完了になった.

キャプチャには,切り分けで使った別の32ビットプログラムを使いました.source/pcap-probe.csです.互換DLLとは別のフォルダーで実行し,通常のNpcapを呼び出します.pcap_open_live()で同じ仮想NICを開き,BPFフィルターをether proto 0x88b5にして待ち受けました.

取得できたフレームは78バイトで,Ethernetヘッダー14バイトとペイロード64バイトが設定と一致しました.この78バイトにはFCSを含みません.v0.1.1のDLLでも同じ内容を確認し,アプリの保存先を変えて設定ファイルを読み直した後も,再度送信・キャプチャできました.

同じ確認をする場合は,リポジトリのルートから次のようにプローブをビルドできます..NET FrameworkのC#コンパイラーを使い,/platform:x86を指定します.

New-Item -ItemType Directory -Path .\probe -Force | Out-Null
& "$env:WINDIR\Microsoft.NET\Framework\v4.0.30319\csc.exe" /nologo /platform:x86 /out:probe\pcap-probe.exe source\pcap-probe.cs
.\probe\pcap-probe.exe

引数なしではNIC一覧を表示します.出力されたデバイス名を指定すると,そのNICを開いてデータリンク種別を表示します.さらに未作成の出力ファイル名を渡すと,EtherType 0x88B5の最初の1フレームを最大30秒待ち,生のフレームバイト列を保存します.PCAP形式ではありません.

# 一覧に表示されたデバイス名をコピーして入力する
$deviceName = Read-Host 'キャプチャするデバイス名'
.\probe\pcap-probe.exe $deviceName
.\probe\pcap-probe.exe $deviceName .\probe\test-frame.bin

キャプチャを開始してから,ipsendwinで1フレーム送ります.正常に取れればData link type: 1とCaptured test frame: 78 bytesが表示されます.このプローブはEthernet用で,既存の出力ファイルは上書きしません.NIC名を渡す段階で開けない場合は,並び順とは別にNpcapの導入状態やアクセス権を確認する必要があります.

今回確認したのは,同じPC上の仮想Ethernetで送信したフレームを別プロセスで取得できるところまでです.Wiresharkはこの検証環境に入れていないので,Wiresharkとの同時動作と,物理LAN上の別端末への到達は未検証です.

ソースと配布ファイル

GitHubのリポジトリにソースとビルドスクリプトを置いています.配布DLLはGitHub Releasesのv0.1.1です.

互換DLLを自分でビルドする場合は,32ビットPEを生成できるMinGWのGCCとbinutilsを用意し,リポジトリのルートで実行します.

$toolchainBin = Read-Host 'GCCとdlltoolがあるbinフォルダー'
.\source\build.ps1 -ToolchainBin $toolchainBin

出力はリポジトリ直下のwpcap.dllです.Windowsが64ビットでも,ipsendwinに合わせて-m32で生成します.ビルドスクリプトが外部ファイルをダウンロードする処理はありません.

配布DLLのSHA-256:

968E261DCF4D627F3402AD98E89C3B39CC155257C64D10FE51892C2DA1B1F8FC

v0.1.1 ZIPのSHA-256:

8DD2B7B93E7C28C70354C8CDABC438CD7050EF3F9F78C1A907A7DA9EB81D7D83