From 69ce69b7716fd78226437323dae965d48675cd1e Mon Sep 17 00:00:00 2001 From: DevRas Date: Sun, 4 Sep 2022 08:35:19 +0900 Subject: [PATCH] first commit --- .gitignore | 2 + DeviceInfo.cs | 36 +++++++++++ DicSerialize.cs | 104 ++++++++++++++++++++++++++++++++ LanguageXml.cs | 25 ++++++++ LanguageXmlLoader.cs | 47 +++++++++++++++ NetworkService.cs | 131 ++++++++++++++++++++++++++++++++++++++++ NetworkService.csproj | 10 ++++ OptionConsole.cs | 74 +++++++++++++++++++++++ Program.cs | 135 ++++++++++++++++++++++++++++++++++++++++++ ServiceMode.cs | 8 +++ language.xml | 47 +++++++++++++++ 11 files changed, 619 insertions(+) create mode 100644 .gitignore create mode 100644 DeviceInfo.cs create mode 100644 DicSerialize.cs create mode 100644 LanguageXml.cs create mode 100644 LanguageXmlLoader.cs create mode 100644 NetworkService.cs create mode 100644 NetworkService.csproj create mode 100644 OptionConsole.cs create mode 100644 Program.cs create mode 100644 ServiceMode.cs create mode 100644 language.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8d4a6c0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +bin +obj \ No newline at end of file diff --git a/DeviceInfo.cs b/DeviceInfo.cs new file mode 100644 index 0000000..c463839 --- /dev/null +++ b/DeviceInfo.cs @@ -0,0 +1,36 @@ +using System.Net; +using System.Text; + +namespace NWService +{ + public class DeviceInfo + { + private IPAddress ipAddr; + private byte[] macAddr; + + public DeviceInfo(IPAddress iPAddress, byte[] macAddressBytes) + { + this.ipAddr = iPAddress; + this.macAddr = macAddressBytes; + } + + public IPAddress GetIPAddress() + { + return ipAddr; + } + + public string GetMacAddress(char separate = ':') + { + StringBuilder sb = new StringBuilder(18); + foreach (byte b in this.macAddr) { + if (sb.Length > 0) + { + sb.Append(separate); + } + sb.Append(string.Format("{0:X2}", b)); + } + + return sb.ToString(); + } + } +} \ No newline at end of file diff --git a/DicSerialize.cs b/DicSerialize.cs new file mode 100644 index 0000000..d0d365f --- /dev/null +++ b/DicSerialize.cs @@ -0,0 +1,104 @@ +using System.Xml.Serialization; +using System.Text; +using System.Text.Encodings; + +namespace NWService +{ + public class DicSerialize + { + /// + /// シリアル化できる、KeyValuePairに代わる構造体 + /// + /// Keyの型 + /// Valueの型 + [Serializable] + public struct KeyAndValue + { + public TKey Key; + public TValue Value; + + public KeyAndValue(KeyValuePair pair) + { + Key = pair.Key; + Value = pair.Value; + } + } + + /// + /// DictionaryをKeyAndValueのListに変換する + /// + /// Dictionaryのキーの型 + /// Dictionaryの値の型 + /// 変換するDictionary + /// 変換されたKeyAndValueのList + public static List> ConvertDictionaryToList(Dictionary dic) + { + List> lst = new List>(); + foreach (KeyValuePair pair in dic) + { + lst.Add(new KeyAndValue(pair)); + } + + return lst; + } + + /// + /// KeyAndValueのListをDictionaryに変換する + /// + /// KeyAndValueのKeyの型 + /// KeyAndValueのValueの型 + /// 変換するKeyAndValueのList + /// 変換されたDictionary + public static Dictionary ConvertListToDictionary(List> lst) + { + Dictionary dic = new Dictionary(); + foreach (KeyAndValue pair in lst) + { + dic.Add(pair.Key, pair.Value); + } + return dic; + } + + /// + /// DictionaryをXMLファイルに保存する + /// + /// Dictionaryのキーの型 + /// Dictionaryの値の型 + /// 保存先のXMLファイル名 + /// 保存するDictionary + public static void XmlSerialize(string fileName, Dictionary dic) + { + //シリアル化できる型に変換 + List> obj = ConvertDictionaryToList(dic); + + //XMLファイルに保存 + XmlSerializer serializer = new XmlSerializer(typeof(List>)); + StreamWriter sw = + new StreamWriter(fileName, false, new UTF8Encoding(false)); + serializer.Serialize(sw, obj); + sw.Close(); + } + + /// + /// シリアル化されたXMLファイルをDictionaryに復元する + /// + /// Dictionaryのキーの型 + /// Dictionaryの値の型 + /// 復元するXMLファイル名 + /// 復元されたDictionary + public static Dictionary XmlDeserialize( + string fileName) + { + //XMLファイルから復元 + XmlSerializer serializer = new XmlSerializer(typeof(List>)); + StreamReader sr = new StreamReader(fileName, new UTF8Encoding(false)); + List> obj = + (List>)serializer.Deserialize(sr); + sr.Close(); + + //Dictionaryに戻す + Dictionary dic = ConvertListToDictionary(obj); + return dic; + } + } +} \ No newline at end of file diff --git a/LanguageXml.cs b/LanguageXml.cs new file mode 100644 index 0000000..0e831a3 --- /dev/null +++ b/LanguageXml.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; + +namespace NWService +{ + public class LanguageXml + { + public LanguageXml() + { + this.messageMaps = new Dictionary(); + } + + public Dictionary messageMaps = new Dictionary(); + public string GetMessage(string key, string defaultMessage) + { + if (messageMaps.ContainsKey(key)) + { + return messageMaps[key]; + } + else + { + return defaultMessage; + } + } + } +} \ No newline at end of file diff --git a/LanguageXmlLoader.cs b/LanguageXmlLoader.cs new file mode 100644 index 0000000..77a2187 --- /dev/null +++ b/LanguageXmlLoader.cs @@ -0,0 +1,47 @@ +using System.Xml; +using System.Xml.Serialization; +using System.IO; + +namespace NWService +{ + public class LanguageXmlLoader + { + public static string GetPath() + { + return Path.Combine(Directory.GetCurrentDirectory(), "language.xml"); + } + + public static LanguageXml Load() + { + if (!File.Exists(GetPath())) + { + return default; + } + + try + { + Dictionary dic = DicSerialize.XmlDeserialize(GetPath()); + return new LanguageXml() + { + messageMaps = dic + }; + } + catch(Exception e) + { + Console.WriteLine(e); + return default; + } + } + public static void Save(LanguageXml xml) + { + try + { + DicSerialize.XmlSerialize(GetPath(), xml.messageMaps); + } + catch(Exception e) + { + Console.WriteLine(e); + } + } + } +} diff --git a/NetworkService.cs b/NetworkService.cs new file mode 100644 index 0000000..a62431d --- /dev/null +++ b/NetworkService.cs @@ -0,0 +1,131 @@ +using System.Net; +using System.Net.NetworkInformation; +using System.Runtime.InteropServices; + +namespace NWService +{ + public class NetworkService + { + [DllImport("iphlpapi.dll", ExactSpelling = true)] + private static extern int SendARP(int dstIp, int srcIp, byte[] mac, ref int macLen); + + public static PingReply Ping(IPAddress iPAddress) + { + using (Ping ping = new Ping()) + { + PingReply reply = ping.Send(iPAddress); + return reply; + } + } + + public static List SearchByPing(IPAddress targetIPv4) + { + int workThreadsMin; + int ioThreadsMin; + + ThreadPool.GetMinThreads(out workThreadsMin, out ioThreadsMin); + ThreadPool.SetMinThreads(260, ioThreadsMin); + + List avaIPs = new List(); + List allTasks = new List(); + + for (int i = 1 ; i <= 254 ; i++) + { + int hostPart = i; + allTasks.Add(Task.Run(() => { + List separateIP = targetIPv4.ToString().Split('.').ToList(); + separateIP.RemoveAt(3); + separateIP.Add(hostPart.ToString()); + string networkPart = string.Join(".", separateIP); + PingReply reply = Ping(IPAddress.Parse(networkPart)); + if (reply != null && reply.Status == IPStatus.Success) + { + avaIPs.Add(reply); + } + })); + } + + Task t = Task.WhenAll(allTasks); + try + { + t.Wait(); + } + catch(Exception error) + { + Console.WriteLine(error); + } + + return avaIPs; + } + + public static List SearchARP(IPAddress targetIPv4) + { + int workThreadsMin; + int ioThreadsMin; + + ThreadPool.GetMinThreads(out workThreadsMin, out ioThreadsMin); + ThreadPool.SetMinThreads(260, ioThreadsMin); + + List avaIPs = new List(); + + List allTasks = new List(); + for (int i = 1 ; i <= 254; i++) + { + int hostPart = i; + allTasks.Add(Task.Run(() => { + List separateIP = targetIPv4.ToString().Split('.').ToList(); + separateIP.RemoveAt(3); + separateIP.Add(hostPart.ToString()); + string networkPart = string.Join(".", separateIP); + + int IPBytes = BitConverter.ToInt32(IPAddress.Parse(networkPart).GetAddressBytes(), 0); + byte[] macAddressPointer = new byte[6]; + int physicalAddressLength = macAddressPointer.Length; + + // ARP + int ret = SendARP(IPBytes, 0, macAddressPointer, ref physicalAddressLength); + if (ret == 0) + { + DeviceInfo info = new DeviceInfo(IPAddress.Parse(networkPart), macAddressPointer); + avaIPs.Add(info); + } + })); + } + + Task t = Task.WhenAll(allTasks); + try + { + t.Wait(); + } + catch(Exception error) + { + Console.WriteLine(error); + } + + return avaIPs; + } + + public static IEnumerable GetLocalIPv4() + { + List list = new List(); + NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces(); + foreach (NetworkInterface nic in nics) + { + if (nic.OperationalStatus == OperationalStatus.Up + && nic.NetworkInterfaceType != NetworkInterfaceType.Loopback + && nic.NetworkInterfaceType != NetworkInterfaceType.Tunnel) + { + UnicastIPAddressInformationCollection unicast = nic.GetIPProperties().UnicastAddresses; + foreach (UnicastIPAddressInformation ip in unicast) + { + if (ip.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) + { + list.Add(ip.Address); + } + } + } + } + return list; + } + } +} \ No newline at end of file diff --git a/NetworkService.csproj b/NetworkService.csproj new file mode 100644 index 0000000..5eb1e84 --- /dev/null +++ b/NetworkService.csproj @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + enable + disable + + + diff --git a/OptionConsole.cs b/OptionConsole.cs new file mode 100644 index 0000000..39a57af --- /dev/null +++ b/OptionConsole.cs @@ -0,0 +1,74 @@ +using System.Net; + +namespace NWService +{ + public class OptionConsole + { + public static ServiceMode GetServiceMode(LanguageXml language) + { + var arry = Enum.GetValues(typeof(ServiceMode)); + for (int i = 0 ; i < arry.Length ; i++) + { + Console.WriteLine("[{0}]: {1}", i, language.GetMessage(arry.GetValue(i).ToString(), arry.GetValue(i).ToString())); + } + + Console.Write("{0} ", language.GetMessage("select_service_mode", "Please type service mode:")); + string tInput = Console.ReadLine(); + if (string.IsNullOrWhiteSpace(tInput) || !int.TryParse(tInput, out int mode)) + { + throw new ArgumentException(string.Format("{0}", language.GetMessage("exception_invalid_input_mode", "invalid input mode."))); + } + + if (mode < 0 || mode > arry.Length) + { + throw new ArgumentException(string.Format("{0}", language.GetMessage("exception_invalid_input_mode", "invalid input mode."))); + } + + return (ServiceMode) mode; + } + + public static IPAddress GetIPAddress(List localIPv4, LanguageXml language) + { + for (int i = 0 ; i < localIPv4.Count(); i++) + { + Console.WriteLine("#{0}: {1}", i + 1, localIPv4[i]); + } + + Console.WriteLine("[0]: {0}", language.GetMessage("select_target_ipaddr", "Type target IPAddress.")); + Console.WriteLine("[1-]: {0}", language.GetMessage("select_local_ipaddr", "Select local IPAddress.")); + Console.Write("{0} ", language.GetMessage("type_mode", "Please type select mode:")); + + string tMode = Console.ReadLine(); + if (string.IsNullOrWhiteSpace(tMode)) + { + throw new ArgumentException(string.Format("{0}", language.GetMessage("exception_invalid_input_mode", "invalid input mode."))); + } + + if (!int.TryParse(tMode, out int mode)) + { + throw new ArgumentException(string.Format("{0}", language.GetMessage("exception_invalid_input_mode", "invalid input mode."))); + } + + if (mode == 0) + { + Console.Write("{0} ", language.GetMessage("type_target_ipaddr", "Please type target IPAddress:")); + string tmpAddr = Console.ReadLine(); + if (!IPAddress.TryParse(tmpAddr, out IPAddress addr)) + { + throw new ArgumentException(string.Format("{0}", language.GetMessage("exception_invalid_input_ipaddr", "invalid input IPAddress."))); + } + + return addr; + } + + mode = mode - 1; + + if (mode < 0 || mode > localIPv4.Count()) + { + throw new ArgumentException(string.Format("{0}", language.GetMessage("exception_invalid_input_mode", "invalid input mode."))); + } + + return localIPv4[mode]; + } + } +} \ No newline at end of file diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..2cfad68 --- /dev/null +++ b/Program.cs @@ -0,0 +1,135 @@ +using System.Net; +using System.Net.NetworkInformation; + +namespace NWService +{ + public class Program + { + public static void Main() + { + try + { + LanguageXml language = LanguageXmlLoader.Load(); + + ServiceMode mode = OptionConsole.GetServiceMode(language); + + List localIPv4 = NetworkService.GetLocalIPv4().ToList(); + IPAddress targetIPv4 = OptionConsole.GetIPAddress(localIPv4, language); + + switch(mode) + { + case ServiceMode.SEARCH_ARP: + Search_ARP(targetIPv4, language); + break; + case ServiceMode.SEARCH_PING: + Search_Ping(targetIPv4, language); + break; + default: + Console.WriteLine("unknown mode..."); + break; + } + } + catch(Exception error) + { + Console.WriteLine(error.Message); + } + } + + public static void Search_ARP(IPAddress targetIPv4, LanguageXml language) + { + try + { + List findList = new List(); + Task task = Task.Run(() => { + findList.AddRange(NetworkService.SearchARP(targetIPv4)); + + Thread.Sleep(10); + }); + + string[] frames = {"\","|","/"}; + int frameCount = 0; + (int cpL, int cpT) = Console.GetCursorPosition(); + while (!task.IsCompleted) + { + Console.SetCursorPosition(cpL, cpT); + frameCount++; + int targetFrameNumber = frameCount%frames.Length; + Console.WriteLine("{0} {1}", frames[targetFrameNumber], language.GetMessage("searching", "searching...")); + Thread.Sleep(100); + } + + Console.SetCursorPosition(cpL, cpT); + Console.WriteLine(" "); + + if (findList.Count() == 0) + { + Console.WriteLine("{0}", language.GetMessage("empty_find_list", "Not found...")); + } + else + { + Console.WriteLine(string.Format(language.GetMessage("found_devices","Found {0} Devices."), findList.Count())); + + foreach (DeviceInfo deviceInfo in findList) + { + Console.WriteLine("――――――――――――――――――――――――――――"); + Console.WriteLine("IP: {0}", deviceInfo.GetIPAddress().ToString()); + Console.WriteLine("Mac: {0}", deviceInfo.GetMacAddress()); + } + } + } + catch(Exception e) + { + Console.WriteLine(e); + } + } + + public static void Search_Ping(IPAddress targetIPv4, LanguageXml language) + { + try + { + List findList = new List(); + Task task = Task.Run(() => { + findList.AddRange(NetworkService.SearchByPing(targetIPv4)); + Thread.Sleep(10); + }); + + string[] frames = {"\","|","/"}; + int frameCount = 0; + (int cpL, int cpT) = Console.GetCursorPosition(); + while (!task.IsCompleted) + { + Console.SetCursorPosition(cpL, cpT); + frameCount++; + int targetFrameNumber = frameCount%frames.Length; + Console.WriteLine("{0} {1}", frames[targetFrameNumber], language.GetMessage("searching", "searching...")); + Thread.Sleep(100); + } + + Console.SetCursorPosition(cpL, cpT); + Console.WriteLine(" "); + + if (findList.Count() == 0) + { + Console.WriteLine("{0}", language.GetMessage("empty_find_list", "Not found...")); + } + else + { + Console.WriteLine(string.Format(language.GetMessage("found_devices","Found {0} Devices."), findList.Count())); + + foreach (var reply in findList) + { + Console.WriteLine("――――――――――――――――――――――――――――"); + Console.WriteLine("IP: {0}", reply.Address.ToString()); + Console.WriteLine("Time: {0}ms", reply.RoundtripTime); + Console.WriteLine("Status: {0}", reply.Status); + Console.WriteLine("Ttl: {0}", reply.Options.Ttl); + } + } + } + catch(Exception e) + { + Console.WriteLine(e); + } + } + } +} \ No newline at end of file diff --git a/ServiceMode.cs b/ServiceMode.cs new file mode 100644 index 0000000..ad1769c --- /dev/null +++ b/ServiceMode.cs @@ -0,0 +1,8 @@ +namespace NWService +{ + public enum ServiceMode + { + SEARCH_ARP, + SEARCH_PING, + } +} \ No newline at end of file diff --git a/language.xml b/language.xml new file mode 100644 index 0000000..68b175a --- /dev/null +++ b/language.xml @@ -0,0 +1,47 @@ + + + + SEARCH_ARP + 検索 [ARP] + + + SEARCH_PING + 検索 [PING] + + + searching + 検索中 + + + empty_find_list + IPアドレスが見つかりませんでした。 + + + select_target_ipaddr + 対象のIPアドレスを入力する + + + select_local_ipaddr + ローカルIPアドレスから選択する + + + type_target_ipaddr + 対象のIPアドレスを入力してください: + + + type_mode + モードを入力してください: + + + exception_invalid_input_mode + 入力されたモードが正しくありません。 + + + exception_invalid_input_ipaddr + 入力されたIPアドレスが正しくありません。 + + + version + 1.0.0 + + \ No newline at end of file