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