Socketを利用したパケットモニタ (C#)(F#)
IP層で動作するパケットモニタです。
SocketType.Raw, ProtocolType.IPでSocketを作成し、IOControlでIOControlCode.ReceiveAllをセットします。
IOControlCode.ReceiveAllは、SIO_RCVALLと同じです。
取得したデータは、IP層のデータですので、8バイト目がTTL、9バイト目がプロトコル番号、12バイト目から4バイトが送信IPアドレス、16バイト目から4バイトが受信IPアドレスとして解釈して表示しています。
IP層で動作していますので、当然ですがMACアドレスやIP以外のパケット(ARPなど)を表示する事はできません。
C#サンプル
using System; using System.Net; using System.Net.Sockets; using System.Linq; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { //インターフェースのアドレス取得 var he = Dns.GetHostEntry(Dns.GetHostName()); var addr = he.AddressList.Where((h) => h.AddressFamily == AddressFamily.InterNetwork).ToList(); var socket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.IP); socket.Bind(new IPEndPoint(addr[0], 0)); socket.SetSocketOption(SocketOptionLevel.IP,SocketOptionName.AcceptConnection,1); byte [] ib = new byte[]{1,0,0,0}; byte [] ob = new byte[]{0,0,0,0}; socket.IOControl(IOControlCode.ReceiveAll, ib, ob);//SIO_RCVALL byte[] buf = new byte[4096]; int i = 0; while (true) { IAsyncResult iares = socket.BeginReceive(buf, 0, buf.Length, SocketFlags.None, null, null); var len = socket.EndReceive(iares); Console.WriteLine("[{0}] Protocol={1} src={2} dst={3} TTL={4} Len={5}" ,i++,Proto(buf[9]),Ip(buf,12),Ip(buf,16),buf[8],len); } } static string Ip(byte [] buf,int i){ return string.Format("{0}.{1}.{2}.{3}", buf[i], buf[i+1], buf[i+2], buf[i+3]); } static string Proto(byte b) { if(b==6) return "TCP"; else if(b==17) return "UDP"; return "Other"; } } }
F#サンプル
open System
open System.Net
open System.Net.Sockets
open System.Linq
let Ip(buf:byte[],i)=
sprintf "%d.%d.%d.%d" (buf.[i]) (buf.[i+1]) (buf.[i+2]) (buf.[i+3])
let Proto(b)=
match b with
|6uy -> "TCP"
|17uy -> "UDP"
|_ -> "other"
//インターフェースのアドレス取得
let addr:IPAddress =
Dns.GetHostEntry(Dns.GetHostName())
|>fun n -> n.AddressList
|>Seq.filter(fun h -> h.AddressFamily = AddressFamily.InterNetwork)
|>fun n -> n.First()
let socket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.IP)
socket.Bind(new IPEndPoint(addr, 0))
socket.SetSocketOption(SocketOptionLevel.IP,SocketOptionName.AcceptConnection,1)
let ib = [|1uy;0uy;0uy;0uy|]
let ob = [|0uy;0uy;0uy;0uy|]
socket.IOControl(IOControlCode.ReceiveAll,ib, ob)|>ignore//SIO_RCVALL
let buf : byte array = Array.create 4096 0uy
let mutable i=0
while true do
let iares = socket.BeginReceive(buf, 0, buf.Length, SocketFlags.None, null, null)
let len = socket.EndReceive(iares)
printfn "[%d] Protocol=%s src=%s dst=%s TTL=%d Len=%d"
i (Proto(buf.[9])) (Ip(buf,12)) (Ip(buf,16)) (buf.[8]) len
i <- i+1