// Spludlow Software // Copyright © Samuel P. Ludlow 2020 All Rights Reserved // Distributed under the terms of the GNU General Public License version 3 // Distributed WITHOUT ANY WARRANTY; without implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE // https://www.spludlow.co.uk/LICENCE.TXT // The Spludlow logo is a registered trademark of Samuel P. Ludlow and may not be used without permission // v1.14 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Data; using System.Net.Sockets; namespace Spludlow.Net { public class PortScanner { public static void Scan(string[] addresses, int threads, int timeoutSeconds) { int[] portNumbers = new int[] { 21, 22, 23, 25, 53, 80, 110, 139, 443, 445, 465, 587, 993, 995, 1433, 5060, 9100 }; Scan(addresses, threads, timeoutSeconds, portNumbers); } public static void Scan(string[] addresses, int threads, int timeoutSeconds, int[] portNumbers) { DataTable table = Spludlow.Data.TextTable.ReadText(new string[] { "Address PortNumber ThreadId ConnectStart ConnectFinish Connectable", "String Int32 Int32 DateTime DateTime Boolean", }); foreach (string address in addresses) { foreach (int portNumber in portNumbers) table.Rows.Add(address, portNumber, -1); } Task[] tasks = new Task[threads]; for (int index = 0; index < threads; ++index) { int threadId = index; tasks[threadId] = new Task(() => ScanWorker(table, threadId, timeoutSeconds)); } foreach (Task task in tasks) task.Start(); Task.WaitAll(tasks); DataView view = new DataView(table); view.RowFilter = "Connectable = true"; Spludlow.Log.Report("PortScanner Scan", view, table); } private static void ScanWorker(DataTable table, int threadId, int timeoutSeconds) { DataRow row; string address; int portNumber; while (true) { lock (table) { DataRow[] rows = table.Select("ThreadId = -1"); if (rows.Length == 0) return; row = rows[0]; row["ThreadId"] = threadId; address = (string)row["Address"]; portNumber = (int)row["PortNumber"]; } DateTime start = DateTime.Now; bool connectable = CanTcpConnect(address, portNumber, timeoutSeconds); DateTime end = DateTime.Now; lock (table) { row["ConnectStart"] = start; row["Connectable"] = connectable; row["ConnectFinish"] = end; } } } public static bool CanTcpConnect(string address, int portNumber, int waitSeconds) { using (TcpClient client = new TcpClient()) { IAsyncResult asyncResult = client.BeginConnect(address, portNumber, null, null); if (asyncResult.AsyncWaitHandle.WaitOne(waitSeconds * 1000) == true) client.EndConnect(asyncResult); return client.Connected; } } } }