|
| 1 | +using System; |
| 2 | +using System.Collections.Generic; |
| 3 | +using System.Linq; |
| 4 | +using System.Text; |
| 5 | + |
| 6 | +using System.Net; |
| 7 | +using System.Net.Sockets; |
| 8 | +using System.Threading; |
| 9 | + |
| 10 | +namespace ST.Library.Network |
| 11 | +{ |
| 12 | + public class SYNScanner : PortScanner |
| 13 | + { |
| 14 | + private Random m_rnd; |
| 15 | + private Semaphore m_se; |
| 16 | + private ProbeConfiger m_probes; |
| 17 | + private Queue<SYNScanTaskInfo> m_que_task; |
| 18 | + private Queue<SocketAsyncEventArgs> m_que_sae; |
| 19 | + private TCPScanner m_tcp_scanner; |
| 20 | + private Dictionary<uint, SYNScanTaskInfo> m_dic_task_running; |
| 21 | + //private Dictionary<uint, uint> m_dic_uid; |
| 22 | + private Dictionary<uint, SYNScanTaskInfo> m_dic_uid; |
| 23 | + private Thread m_thread_timeout; |
| 24 | + private Socket m_sock_raw; |
| 25 | + private Socket m_sock_bind; |
| 26 | + private uint m_uLocalIP; |
| 27 | + private string m_strLocalIP; |
| 28 | + private ushort m_nLocalPort; |
| 29 | + |
| 30 | + public SYNScanner(int nMaxTask, ProbeConfiger probes) : this(nMaxTask, probes, null) { } |
| 31 | + |
| 32 | + public SYNScanner(int nMaxTask, ProbeConfiger probes, EndPoint bindEndPoint) { |
| 33 | + if (nMaxTask > 60000 || nMaxTask < 1) throw new ArgumentOutOfRangeException("the MaxTask must be between 1 and 30000"); |
| 34 | + m_probes = probes; |
| 35 | + if (bindEndPoint == null) { |
| 36 | + foreach (var v in Dns.GetHostAddresses(Dns.GetHostName())) { |
| 37 | + if (v.IsIPv6LinkLocal || v.IsIPv6Multicast || v.IsIPv6SiteLocal) continue; |
| 38 | + bindEndPoint = new IPEndPoint(v, 0); |
| 39 | + } |
| 40 | + } |
| 41 | + m_rnd = new Random(); |
| 42 | + m_dic_uid = new Dictionary<uint, SYNScanTaskInfo>();// new Dictionary<uint, uint>(); |
| 43 | + m_dic_task_running = new Dictionary<uint, SYNScanTaskInfo>(); |
| 44 | + m_tcp_scanner = new TCPScanner(nMaxTask, probes); |
| 45 | + m_tcp_scanner.Completed += new ScanEventHandler(m_tcp_Completed); |
| 46 | + m_sock_bind = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); |
| 47 | + m_sock_bind.Bind(bindEndPoint); |
| 48 | + bindEndPoint = m_sock_bind.LocalEndPoint; |
| 49 | + m_strLocalIP = bindEndPoint.ToString().Split(':')[0]; |
| 50 | + m_uLocalIP = RAWDefine.IPToINT(m_strLocalIP); |
| 51 | + m_nLocalPort = ushort.Parse(bindEndPoint.ToString().Split(':')[1]); |
| 52 | + m_se = new Semaphore(nMaxTask, nMaxTask); |
| 53 | + |
| 54 | + m_sock_raw = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.IP); |
| 55 | + m_sock_raw.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.HeaderIncluded, true); |
| 56 | + m_sock_raw.Bind(bindEndPoint); |
| 57 | + m_sock_raw.IOControl(IOControlCode.ReceiveAll, new byte[] { 1, 0, 0, 0 }, null); |
| 58 | + |
| 59 | + m_que_task = new Queue<SYNScanTaskInfo>(); |
| 60 | + m_que_sae = new Queue<SocketAsyncEventArgs>(); |
| 61 | + for (int i = 0; i < nMaxTask; i++) { |
| 62 | + SYNScanTaskInfo ti = new SYNScanTaskInfo(); |
| 63 | + ti.TaskID = (uint)((i + 1) << 8); |
| 64 | + ti.SYNPacket = new byte[40]; |
| 65 | + m_que_task.Enqueue(ti); |
| 66 | + } |
| 67 | + |
| 68 | + SocketAsyncEventArgs sae = new SocketAsyncEventArgs(); |
| 69 | + sae.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed); |
| 70 | + sae.SetBuffer(new byte[65535], 0, 65535); |
| 71 | + sae.UserToken = m_sock_raw; |
| 72 | + if (!m_sock_raw.ReceiveAsync(sae)) IOProcessPool.QueueWork(this.ProcessRecv, sae); |
| 73 | + m_thread_timeout = new Thread(this.CheckTimeout); |
| 74 | + m_thread_timeout.IsBackground = true; |
| 75 | + m_thread_timeout.Start(); |
| 76 | + } |
| 77 | + |
| 78 | + void m_tcp_Completed(object sender, ScanEventArgs e) { |
| 79 | + uint uid = e.TaskID; |
| 80 | + SYNScanTaskInfo ti = null; |
| 81 | + lock (m_dic_uid) { |
| 82 | + if (!m_dic_uid.ContainsKey(e.TaskID)) return; |
| 83 | + //e.TaskID = m_dic_uid[e.TaskID]; |
| 84 | + ti = m_dic_uid[e.TaskID]; |
| 85 | + e.TaskID = ti.TaskID; |
| 86 | + m_dic_uid.Remove(uid); |
| 87 | + if (base._IsDisposed) return; |
| 88 | + m_que_task.Enqueue(ti); |
| 89 | + } |
| 90 | + //lock (m_obj_sync) { |
| 91 | + //} |
| 92 | + base.OnCompleted(e); |
| 93 | + m_se.Release(); |
| 94 | + } |
| 95 | + |
| 96 | + private SocketAsyncEventArgs PopSAE() { |
| 97 | + lock (m_obj_sync) { |
| 98 | + if (m_que_sae.Count != 0) return m_que_sae.Dequeue(); |
| 99 | + } |
| 100 | + SocketAsyncEventArgs sae = new SocketAsyncEventArgs(); |
| 101 | + sae.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed); |
| 102 | + sae.SetBuffer(new byte[40], 0, 40); |
| 103 | + return sae; |
| 104 | + } |
| 105 | + |
| 106 | + private void PushSAE(SocketAsyncEventArgs sae) { |
| 107 | + lock (m_obj_sync) { |
| 108 | + if (base._IsDisposed) return; |
| 109 | + m_que_sae.Enqueue(sae); |
| 110 | + } |
| 111 | + } |
| 112 | + |
| 113 | + protected override uint OnScan(int nPort, EndPoint endPoint, int nProbes, int nTimeout, int nRetry, int nTotalTimeout, bool bUseNullProbes) { |
| 114 | + lock (m_obj_sync) { |
| 115 | + if (base._IsDisposed) throw new ObjectDisposedException("SYNScanner", "The scanner was disposed"); |
| 116 | + } |
| 117 | + m_se.WaitOne(); |
| 118 | + SYNScanTaskInfo ti = this.CreateTaskInfo(nPort, endPoint, nProbes, nTimeout, nRetry, nTotalTimeout, bUseNullProbes); |
| 119 | + lock (m_dic_task_running) { |
| 120 | + m_dic_task_running.Add(ti.TaskID, ti); |
| 121 | + } |
| 122 | + this.SendData(ti); |
| 123 | + ti.IsStarted = true; |
| 124 | + return ti.TaskID; |
| 125 | + } |
| 126 | + |
| 127 | + private void SendData(SYNScanTaskInfo ti) { |
| 128 | + SocketAsyncEventArgs sae = this.PopSAE(); |
| 129 | + Array.Copy(ti.SYNPacket, sae.Buffer, ti.SYNPacket.Length); |
| 130 | + ti.LastTime = DateTime.Now; |
| 131 | + sae.RemoteEndPoint = ti.EndPoint; |
| 132 | + if (!m_sock_raw.SendToAsync(sae)) IOProcessPool.QueueWork(this.ProcessSend, sae); |
| 133 | + } |
| 134 | + |
| 135 | + private SYNScanTaskInfo CreateTaskInfo(int nPort, EndPoint endPoint, int nProbes, int nTimeout, int nRetry, int nTotalTimeout, bool bUseNullProbes) { |
| 136 | + SYNScanTaskInfo ti = null; |
| 137 | + lock (m_obj_sync) { |
| 138 | + ti = m_que_task.Dequeue(); |
| 139 | + } |
| 140 | + ti.Retry = nRetry; |
| 141 | + ti.RunedRetry = 0; |
| 142 | + ti.Port = nPort; |
| 143 | + ti.EndPoint = endPoint; |
| 144 | + ti.IsStarted = false; |
| 145 | + ti.Probes = nProbes; |
| 146 | + ti.IsUseNullProbe = bUseNullProbes; |
| 147 | + ti.Timeout = nTimeout; |
| 148 | + ti.TotalTimeout = nTotalTimeout; |
| 149 | + ti.UIP = BitConverter.ToUInt32(((IPEndPoint)endPoint).Address.GetAddressBytes(), 0); |
| 150 | + uint uTemp = 0; |
| 151 | + lock (m_rnd) uTemp = (uint)m_rnd.Next(); |
| 152 | + uTemp &= 0xFF0000FF; |
| 153 | + ti.TaskID = ti.TaskID & 0x00FFFF00 | uTemp; |
| 154 | + ti.SEQ = RAWDefine.GetSynPacket(ti.SYNPacket, m_uLocalIP, ti.UIP, m_nLocalPort, (ushort)ti.Port, ti.TaskID); |
| 155 | + return ti; |
| 156 | + } |
| 157 | + |
| 158 | + void IO_Completed(object sender, SocketAsyncEventArgs e) { |
| 159 | + switch (e.LastOperation) { |
| 160 | + case SocketAsyncOperation.SendTo: |
| 161 | + this.ProcessSend(e); |
| 162 | + break; |
| 163 | + case SocketAsyncOperation.Receive: |
| 164 | + this.ProcessRecv(e); |
| 165 | + break; |
| 166 | + } |
| 167 | + } |
| 168 | + |
| 169 | + private void ProcessSend(SocketAsyncEventArgs e) { |
| 170 | + this.PushSAE(e); |
| 171 | + } |
| 172 | + |
| 173 | + private void ProcessRecv(SocketAsyncEventArgs e) { |
| 174 | + lock (m_obj_sync) { |
| 175 | + if (base._IsDisposed) return; |
| 176 | + } |
| 177 | + Socket sock = e.UserToken as Socket; |
| 178 | + if (e.SocketError == SocketError.Success && e.BytesTransferred > 0) { |
| 179 | + bool b = true; |
| 180 | + uint uSIP = BitConverter.ToUInt32(e.Buffer, 16); |
| 181 | + int nOffset = (e.Buffer[0] & 0x0F) * 4; |
| 182 | + uint uSEQ = RAWDefine.GetACKNumber(e.Buffer, nOffset) - 1; |
| 183 | + if (e.BytesTransferred < 40) b = false; |
| 184 | + else if (nOffset < 20 || e.BytesTransferred - 20 < nOffset) b = false; |
| 185 | + else if (e.Buffer[9] != RAWDefine.PROTO_TCP) b = false; |
| 186 | + else if ((ushort)((e.Buffer[nOffset + 2] << 8) | e.Buffer[nOffset + 3]) != m_nLocalPort) b = false; |
| 187 | + else if (e.Buffer[nOffset + 13] != 0x12) b = false;//syn + ack |
| 188 | + else if (uSIP != m_uLocalIP) b = false; |
| 189 | + SYNScanTaskInfo ti = null; |
| 190 | + if (b) { |
| 191 | + lock (m_dic_task_running) { |
| 192 | + if (m_dic_task_running.ContainsKey(uSEQ)) { |
| 193 | + ti = m_dic_task_running[uSEQ]; |
| 194 | + m_dic_task_running.Remove(uSEQ); |
| 195 | + } |
| 196 | + } |
| 197 | + } |
| 198 | + if (ti != null) { |
| 199 | + uint id = m_tcp_scanner.Scan(ti.UIP, ti.Port, ti.Probes, ti.Timeout, ti.Retry, ti.TotalTimeout, ti.IsUseNullProbe); |
| 200 | + lock (m_dic_uid) m_dic_uid.Add(id, ti); |
| 201 | + } |
| 202 | + } |
| 203 | + if (!sock.ReceiveAsync(e)) IOProcessPool.QueueWork(this.ProcessRecv, e); |
| 204 | + } |
| 205 | + |
| 206 | + private void EndTask(SYNScanTaskInfo ti) { |
| 207 | + ti.IsStarted = false; |
| 208 | + lock (m_dic_task_running) { |
| 209 | + if (!m_dic_task_running.ContainsKey(ti.TaskID)) return; |
| 210 | + m_dic_task_running.Remove(ti.TaskID); |
| 211 | + } |
| 212 | + lock (m_obj_sync) { |
| 213 | + if (base._IsDisposed) return; |
| 214 | + m_que_task.Enqueue(ti); |
| 215 | + } |
| 216 | + base.OnCompleted(new ScanEventArgs(ti.TaskID, ti.EndPoint, "ACK timeout")); |
| 217 | + m_se.Release(); |
| 218 | + } |
| 219 | + |
| 220 | + private void CheckTimeout() { |
| 221 | + DateTime dt = DateTime.Now; |
| 222 | + List<SYNScanTaskInfo> lst_remove = new List<SYNScanTaskInfo>(); |
| 223 | + while (true) { |
| 224 | + Thread.Sleep(1000); |
| 225 | + lst_remove.Clear(); |
| 226 | + dt = DateTime.Now; |
| 227 | + bool bDisposed = base._IsDisposed; |
| 228 | + lock (m_dic_task_running) { |
| 229 | + foreach (var v in m_dic_task_running) { |
| 230 | + if (!v.Value.IsStarted) continue; |
| 231 | + if (dt.Subtract(v.Value.StartTime).TotalMilliseconds > v.Value.TotalTimeout || bDisposed) { |
| 232 | + lst_remove.Add(v.Value); |
| 233 | + continue; |
| 234 | + } |
| 235 | + if (dt.Subtract(v.Value.LastTime).TotalMilliseconds > v.Value.Timeout) { |
| 236 | + if (v.Value.Retry-- == 0) this.SendData(v.Value); |
| 237 | + else lst_remove.Add(v.Value); |
| 238 | + } |
| 239 | + } |
| 240 | + foreach (var v in lst_remove) { |
| 241 | + this.EndTask(v); |
| 242 | + } |
| 243 | + } |
| 244 | + if (bDisposed) break; |
| 245 | + } |
| 246 | + } |
| 247 | + |
| 248 | + public override void Dispose() { |
| 249 | + lock (m_obj_sync) { |
| 250 | + if (base.IsDisposed) return; |
| 251 | + base._IsDisposed = true; |
| 252 | + } |
| 253 | + m_tcp_scanner.Dispose(); |
| 254 | + base.CloseSocket(m_sock_bind); |
| 255 | + } |
| 256 | + } |
| 257 | +} |
0 commit comments