概要
- 指定した IPv4 ゾーンに対して MAC アドレスを収集するコマンドラインツール。
- IP アドレスを指定しなかった場合は、自身のホストアドレスを元に収集する。
- ファイアウォール等で ping 応答を返さない端末についても収集する。
- 電源が落ちている端末については収集出来ない。
- 要 .NET Framework 4.0
実行ファイルのみ
ソース
-
scanNetArp.zip
/** @file Program.cs @mainpage scan Net Arp - 指定した IPv4 ゾーンに対して MAC アドレスを収集するコマンドラインツール。 - IP アドレスを指定しなかった場合は、自身のホストアドレスを元に収集する。 - ファイアウォール等で ping 応答を返さない端末についても収集する。 - 電源が落ちている端末については収集出来ない。 - 要 .NET Framework 4.0 - ARPによるMACアドレスの取得 @ SIN\@SAPPOROWORKSの覚書<br/> http://d.hatena.ne.jp/spw0022/20111024/1319575443 - マルチスレッド @ ++C++;// 未確認飛行 C<br/> http://ufcpp.net/study/csharp/sp_thread.html */ using System; using System.Collections.Generic; using System.Net; using System.Runtime.InteropServices; using System.Text.RegularExpressions; using System.Threading.Tasks; namespace TakeAsh.scanNetArp { class Program { /// <summary> /// SendARP function<br/> /// http://msdn.microsoft.com/en-us/library/windows/desktop/aa366358.aspx /// </summary> /// <param name="dstIp">The destination IPv4 address</param> /// <param name="srcIp">he source IPv4 address of the sender</param> /// <param name="mac">A pointer to an array of ULONG variables</param> /// <param name="macLen">a pointer to a ULONG value /// that specifies the maximum buffer size, in bytes</param> /// <returns> /// - If the function succeeds, the return value is NO_ERROR. /// - If the function fails, the return value is one of the following error codes. /// </returns> [DllImport("IPHlpApi.dll", ExactSpelling = true)] private static extern uint SendARP(uint dstIp, uint srcIp, Byte[] mac, ref uint macLen); /// <summary> /// ステータスコードとシンボルの対応 (WinError.h) /// </summary> static Dictionary<uint, string> StatusCode = new Dictionary<uint, string>(){ { 0, "NO_ERROR" }, { 67, "ERROR_BAD_NET_NAME" }, { 111, "ERROR_BUFFER_OVERFLOW" }, { 31, "ERROR_GEN_FAILURE" }, { 87, "ERROR_INVALID_PARAMETER" }, { 1784, "ERROR_INVALID_USER_BUFFER" }, { 1168, "ERROR_NOT_FOUND" }, { 50, "ERROR_NOT_SUPPORTED" }, }; /// <summary> /// IP アドレス最大値 /// </summary> const int ipMax = 254; /// <summary> /// ARP問い合わせ結果を格納するためのクラス /// </summary> class ARPresult { /// <summary> /// IPアドレス /// </summary> public string ip; /// <summary> /// MACアドレス /// </summary> public Byte[] mac; /// <summary> /// MACアドレスのバイト数 /// </summary> public uint macLen; /// <summary> /// ARP問い合わせ結果 /// </summary> public uint status; } /// <summary> /// ヘルプメッセージの表示および終了 /// </summary> static void showHelpMessage() { Console.WriteLine( "usage: scanNetArp [aa.bb.cc.dd]\n" + "listup MAC addresses in zone aa.bb.cc.xx or localnet." ); Environment.Exit(-1); } /// <summary> /// ARP 情報の収集を行う /// </summary> /// <param name="zone">対象ゾーン</param> /// <returns>収集結果の配列</returns> static ARPresult[] getArpTable(IPAddress zone) { ARPresult[] results = new ARPresult[ipMax]; Byte[] zoneByte = zone.GetAddressBytes(); Parallel.For(0, ipMax, ip => { ARPresult result = new ARPresult(); result.ip = string.Format("{0}.{1}.{2}.{3}", zoneByte[0], zoneByte[1], zoneByte[2], ip + 1); result.mac = new Byte[sizeof(uint) * 2]; result.macLen = (uint)result.mac.Length; IPAddress dst = IPAddress.Parse(result.ip); Console.Error.WriteLine(string.Format("Request:{0}", dst.ToString())); Byte[] addrByte = dst.GetAddressBytes(); uint addr = 0; for(int i = addrByte.Length - 1; i >= 0; --i) { addr <<= 8; addr |= addrByte[i]; } result.status = SendARP(addr, 0, result.mac, ref result.macLen); results[ip] = result; }); Console.Error.WriteLine(); return results; } /// <summary> /// ARP 情報の表示<br/> /// 収集ステータスが NO_ERROR だったもののみを表示する。 /// </summary> /// <param name="results">ARP 情報テーブル</param> static void printArpTable(ARPresult[] results) { Console.WriteLine("IPAddr\tMACAddr"); for(int ip = 0; ip < ipMax; ++ip) { if(results[ip].status != 0) { // NO_ERROR でなければスキップする continue; } string macStr = ""; for(uint i = 0; i < results[ip].macLen; ++i) { macStr += string.Format("{0:x2}:", results[ip].mac[i]); } /* uint statusCode = results[ip].status; var status = StatusCode.ContainsKey( statusCode ) ? StatusCode[statusCode] : statusCode.ToString(); */ Console.WriteLine(string.Format("{0}\t{1}", results[ip].ip, macStr.TrimEnd(':'))); } Console.WriteLine(); } static void Main(string[] args) { IPAddress[] addrList = new IPAddress[] { new IPAddress(0) }; if(args.Length > 0) { if(!IPAddress.TryParse(args[0], out addrList[0])) { showHelpMessage(); } else { Console.WriteLine("IPAddr:\t" + addrList[0].ToString()); } } else { string hostName = Dns.GetHostName(); Console.WriteLine("Host:\t" + hostName); IPAddress[] addrV4V6List = Dns.GetHostAddresses(hostName); List<IPAddress> addrV4List = new List<IPAddress>(); Regex regIPv4 = new Regex(@"^\d+\.\d+\.\d+\.\d+$"); for(int i = 0; i < addrV4V6List.Length; ++i) { string addrStr = addrV4V6List[i].ToString(); if(regIPv4.IsMatch(addrStr)) { addrV4List.Add(addrV4V6List[i]); Console.WriteLine("IPAddr:\t" + addrStr); } } addrList = addrV4List.ToArray(); } Console.WriteLine("Date:\t" + DateTime.Now.ToString("G") + "\r\n"); foreach(IPAddress address in addrList) { ARPresult[] results = getArpTable(address); printArpTable(results); } } } }