NetPacketTool.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. using System;
  2. using System.Text;
  3. using System.Net;
  4. using System.Net.Sockets;
  5. using Azylee.Core.AppUtils;
  6. namespace Azylee.Core.NetUtils
  7. {
  8. /// <summary>
  9. /// A class that intercepts IP packets on a specific interface.
  10. /// </summary>
  11. /// <remarks>
  12. /// This class only works on Windows 2000 and higher.
  13. /// </remarks>
  14. public class NetPacketTool
  15. {
  16. /// <summary>
  17. /// Initializes a new instance of the PacketMonitor class.
  18. /// </summary>
  19. /// <param name="ip">The interface on which to listen for IP packets.</param>
  20. /// <exception cref="NotSupportedException">The operating system does not support intercepting packets.</exception>
  21. public NetPacketTool(IPAddress ip)
  22. {
  23. // make sure the user runs this program on Windows NT 5.0 or higher
  24. if (Environment.OSVersion.Platform != PlatformID.Win32NT || Environment.OSVersion.Version.Major < 5)
  25. throw new NotSupportedException("This program requires Windows 2000, Windows XP or Windows .NET Server!");
  26. // make sure the user is an Administrator
  27. if (!PermissionTool.IsAdmin())
  28. throw new NotSupportedException("This program can only be run by administrators!");
  29. m_IP = ip;
  30. m_Buffer = new byte[65535];
  31. }
  32. /// <summary>
  33. /// Cleans up the unmanaged resources.
  34. /// </summary>
  35. ~NetPacketTool()
  36. {
  37. Stop();
  38. }
  39. /// <summary>
  40. /// Starts listening on the specified interface.
  41. /// </summary>
  42. /// <exception cref="SocketException">An error occurs when trying to intercept IP packets.</exception>
  43. public void Start()
  44. {
  45. if (m_Monitor == null)
  46. {
  47. try
  48. {
  49. m_Monitor = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.IP);
  50. m_Monitor.Bind(new IPEndPoint(IP, 0));
  51. byte[] outValue = BitConverter.GetBytes(0);
  52. byte[] inValue = BitConverter.GetBytes(1);
  53. m_Monitor.IOControl(IOControlCode.ReceiveAll, inValue, outValue);
  54. m_Monitor.BeginReceive(m_Buffer, 0, m_Buffer.Length, SocketFlags.None, new AsyncCallback(this.OnReceive), null);
  55. }
  56. catch
  57. {
  58. m_Monitor = null;
  59. throw new SocketException();
  60. }
  61. }
  62. }
  63. /// <summary>
  64. /// Stops listening on the specified interface.
  65. /// </summary>
  66. public void Stop()
  67. {
  68. if (m_Monitor != null)
  69. {
  70. m_Monitor.Close();
  71. m_Monitor = null;
  72. }
  73. }
  74. /// <summary>
  75. /// Called when the socket intercepts an IP packet.
  76. /// </summary>
  77. /// <param name="ar">The asynchronous result.</param>
  78. private void OnReceive(IAsyncResult ar)
  79. {
  80. try
  81. {
  82. int received = m_Monitor.EndReceive(ar);
  83. try
  84. {
  85. if (m_Monitor != null)
  86. {
  87. byte[] packet = new byte[received];
  88. Array.Copy(Buffer, 0, packet, 0, received);
  89. OnNewPacket(new Packet(packet));
  90. }
  91. }
  92. catch (Exception e)
  93. {
  94. // invalid packet; ignore
  95. }
  96. m_Monitor.BeginReceive(Buffer, 0, Buffer.Length, SocketFlags.None, new AsyncCallback(this.OnReceive), null);
  97. }
  98. catch
  99. {
  100. Stop();
  101. }
  102. }
  103. /// <summary>
  104. /// The interface used to intercept IP packets.
  105. /// </summary>
  106. /// <value>An <see cref="IPAddress"/> instance.</value>
  107. public IPAddress IP
  108. {
  109. get
  110. {
  111. return m_IP;
  112. }
  113. }
  114. /// <summary>
  115. /// The buffer used to store incoming IP packets.
  116. /// </summary>
  117. /// <value>An array of bytes.</value>
  118. protected byte[] Buffer
  119. {
  120. get
  121. {
  122. return m_Buffer;
  123. }
  124. }
  125. /// <summary>
  126. /// Raises an event that indicates a new packet has arrived.
  127. /// </summary>
  128. /// <param name="p">The arrived <see cref="Packet"/>.</param>
  129. protected void OnNewPacket(Packet p)
  130. {
  131. NewPacket?.Invoke(this, p);
  132. }
  133. /// <summary>
  134. /// Holds all the listeners for the NewPacket event.
  135. /// </summary>
  136. public event NewPacketEventHandler NewPacket;
  137. // private variables
  138. private Socket m_Monitor;
  139. private IPAddress m_IP;
  140. private byte[] m_Buffer;
  141. private const int IOC_VENDOR = 0x18000000;
  142. private const int IOC_IN = -2147483648; //0x80000000; /* copy in parameters */
  143. private const int SIO_RCVALL = IOC_IN | IOC_VENDOR | 1;
  144. private const int SECURITY_BUILTIN_DOMAIN_RID = 0x20;
  145. private const int DOMAIN_ALIAS_RID_ADMINS = 0x220;
  146. }
  147. /// <summary>
  148. /// Represents the method that will handle the NewPacket event.
  149. /// </summary>
  150. /// <param name="pm">The <see cref="PacketMonitor"/> that intercepted the <see cref="Packet"/>.</param>
  151. /// <param name="p">The newly arrived <see cref="Packet"/>.</param>
  152. public delegate void NewPacketEventHandler(NetPacketTool pm, Packet p);
  153. #region Ïà¹ØÄ£ÐÍ
  154. /// <summary>
  155. /// The Network Control precedence designation is intended to be used within a network only. The actual use and control of that designation is up to each network. The Internetwork Control designation is intended for use by gateway control originators only. If the actual use of these precedence designations is of concern to a particular network, it is the responsibility of that network to control the access to, and use of, those precedence designations.
  156. /// </summary>
  157. public enum Precedence
  158. {
  159. Routine = 0,
  160. Priority = 1,
  161. Immediate = 2,
  162. Flash = 3,
  163. FlashOverride = 4,
  164. CRITICECP = 5,
  165. InternetworkControl = 6,
  166. NetworkControl = 7
  167. }
  168. /// <summary>
  169. /// The use of the Delay, Throughput, and Reliability indications may increase the cost (in some sense) of the service. In many networks better performance for one of these parameters is coupled with worse performance on another.
  170. /// </summary>
  171. public enum Delay
  172. {
  173. NormalDelay = 0,
  174. LowDelay = 1
  175. }
  176. /// <summary>
  177. /// The use of the Delay, Throughput, and Reliability indications may increase the cost (in some sense) of the service. In many networks better performance for one of these parameters is coupled with worse performance on another.
  178. /// </summary>
  179. public enum Throughput
  180. {
  181. NormalThroughput = 0,
  182. HighThroughput = 1
  183. }
  184. /// <summary>
  185. /// The use of the Delay, Throughput, and Reliability indications may increase the cost (in some sense) of the service. In many networks better performance for one of these parameters is coupled with worse performance on another.
  186. /// </summary>
  187. public enum Reliability
  188. {
  189. NormalReliability = 0,
  190. HighReliability = 1
  191. }
  192. /// <summary>
  193. /// This field indicates the next level protocol used in the data portion of the internet datagram.
  194. /// </summary>
  195. public enum Protocol
  196. {
  197. Ggp = 3,
  198. Icmp = 1,
  199. Idp = 22,
  200. Igmp = 2,
  201. IP = 4,
  202. ND = 77,
  203. Pup = 12,
  204. Tcp = 6,
  205. Udp = 17,
  206. Other = -1
  207. }
  208. /// <summary>
  209. /// Represents an IP packet.
  210. /// </summary>
  211. public class Packet
  212. {
  213. /// <summary>
  214. /// Initializes a new version of the Packet class.
  215. /// </summary>
  216. /// <param name="raw">The raw bytes of the IP packet.</param>
  217. /// <exception cref="ArgumentNullException"><paramref name="raw"/> is a null reference (<b>Nothing</b> in Visual Basic).</exception>
  218. /// <exception cref="ArgumentException"><paramref name="raw"/> represents an invalid IP packet.</exception>
  219. /// <remarks>The intercept time will be set to DateTime.Now.</remarks>
  220. public Packet(byte[] raw) : this(raw, DateTime.Now) { }
  221. /// <summary>
  222. /// Initializes a new version of the Packet class.
  223. /// </summary>
  224. /// <param name="raw">The raw bytes of the IP packet.</param>
  225. /// <param name="time">The time when the IP packet was intercepted.</param>
  226. /// <exception cref="ArgumentNullException"><paramref name="raw"/> is a null reference (<b>Nothing</b> in Visual Basic).</exception>
  227. /// <exception cref="ArgumentException"><paramref name="raw"/> represents an invalid IP packet.</exception>
  228. public Packet(byte[] raw, DateTime time)
  229. {
  230. if (raw == null)
  231. throw new ArgumentNullException();
  232. if (raw.Length < 20)
  233. throw new ArgumentException(); // invalid IP packet
  234. m_Raw = raw;
  235. m_Time = time;
  236. m_Version = (raw[0] & 0xF0) >> 4;
  237. m_HeaderLength = (raw[0] & 0x0F) * 4 /* sizeof(int) */;
  238. if ((raw[0] & 0x0F) < 5)
  239. throw new ArgumentException(); // invalid header of packet
  240. m_Precedence = (Precedence)((raw[1] & 0xE0) >> 5);
  241. m_Delay = (Delay)((raw[1] & 0x10) >> 4);
  242. m_Throughput = (Throughput)((raw[1] & 0x8) >> 3);
  243. m_Reliability = (Reliability)((raw[1] & 0x4) >> 2);
  244. m_TotalLength = raw[2] * 256 + raw[3];
  245. if (m_TotalLength != raw.Length)
  246. throw new ArgumentException(); // invalid size of packet
  247. m_Identification = raw[4] * 256 + raw[5];
  248. m_TimeToLive = raw[8];
  249. if (Enum.IsDefined(typeof(Protocol), (int)raw[9]))
  250. m_Protocol = (Protocol)raw[9];
  251. else
  252. m_Protocol = Protocol.Other;
  253. m_Checksum = new byte[2];
  254. m_Checksum[0] = raw[11];
  255. m_Checksum[1] = raw[10];
  256. m_SourceAddress = new IPAddress(BitConverter.ToUInt32(raw, 12));
  257. m_DestinationAddress = new IPAddress(BitConverter.ToUInt32(raw, 16));
  258. if (m_Protocol == Protocol.Tcp || m_Protocol == Protocol.Udp)
  259. {
  260. m_SourcePort = raw[m_HeaderLength] * 256 + raw[m_HeaderLength + 1];
  261. m_DestinationPort = raw[m_HeaderLength + 2] * 256 + raw[m_HeaderLength + 3];
  262. }
  263. else
  264. {
  265. m_SourcePort = -1;
  266. m_DestinationPort = -1;
  267. }
  268. }
  269. /// <summary>
  270. /// Gets the raw bytes of the IP packet.
  271. /// </summary>
  272. /// <value>An array of bytes.</value>
  273. protected byte[] Raw
  274. {
  275. get
  276. {
  277. return m_Raw;
  278. }
  279. }
  280. /// <summary>
  281. /// Gets the time when the IP packet was intercepted.
  282. /// </summary>
  283. /// <value>A <see cref="DateTime"/> value.</value>
  284. public DateTime Time
  285. {
  286. get
  287. {
  288. return m_Time;
  289. }
  290. }
  291. /// <summary>
  292. /// Gets the version of the IP protocol used.
  293. /// </summary>
  294. /// <value>A 32-bits signed integer.</value>
  295. public int Version
  296. {
  297. get
  298. {
  299. return m_Version;
  300. }
  301. }
  302. /// <summary>
  303. /// Gets the length of the IP header [in bytes].
  304. /// </summary>
  305. /// <value>A 32-bits signed integer.</value>
  306. public int HeaderLength
  307. {
  308. get
  309. {
  310. return m_HeaderLength;
  311. }
  312. }
  313. /// <summary>
  314. /// Gets the precedence parameter.
  315. /// </summary>
  316. /// <value>A <see cref="Precedence"/> instance.</value>
  317. public Precedence Precedence
  318. {
  319. get
  320. {
  321. return m_Precedence;
  322. }
  323. }
  324. /// <summary>
  325. /// Gets the delay parameter.
  326. /// </summary>
  327. /// <value>A <see cref="Delay"/> instance.</value>
  328. public Delay Delay
  329. {
  330. get
  331. {
  332. return m_Delay;
  333. }
  334. }
  335. /// <summary>
  336. /// Gets the throughput parameter.
  337. /// </summary>
  338. /// <value>A <see cref="Throughput"/> instance.</value>
  339. public Throughput Throughput
  340. {
  341. get
  342. {
  343. return m_Throughput;
  344. }
  345. }
  346. /// <summary>
  347. /// Gets the reliability parameter.
  348. /// </summary>
  349. /// <value>A <see cref="Reliability"/> instance.</value>
  350. public Reliability Reliability
  351. {
  352. get
  353. {
  354. return m_Reliability;
  355. }
  356. }
  357. /// <summary>
  358. /// Gets the total length of the IP packet.
  359. /// </summary>
  360. /// <value>A 32-bits signed integer.</value>
  361. public int TotalLength
  362. {
  363. get
  364. {
  365. return m_TotalLength;
  366. }
  367. }
  368. /// <summary>
  369. /// Gets the identification number of the IP packet.
  370. /// </summary>
  371. /// <value>A 32-bits signed integer.</value>
  372. public int Identification
  373. {
  374. get
  375. {
  376. return m_Identification;
  377. }
  378. }
  379. /// <summary>
  380. /// Gets the time-to-live [hop count] of the IP packet.
  381. /// </summary>
  382. /// <value>A 32-bits signed integer.</value>
  383. public int TimeToLive
  384. {
  385. get
  386. {
  387. return m_TimeToLive;
  388. }
  389. }
  390. /// <summary>
  391. /// Gets the protocol of the IP packet.
  392. /// </summary>
  393. /// <value>A <see cref="Protocol"/> instance.</value>
  394. public Protocol Protocol
  395. {
  396. get
  397. {
  398. return m_Protocol;
  399. }
  400. }
  401. /// <summary>
  402. /// Gets the checksum of the IP packet.
  403. /// </summary>
  404. /// <value>An array of two bytes.</value>
  405. public byte[] Checksum
  406. {
  407. get
  408. {
  409. return m_Checksum;
  410. }
  411. }
  412. /// <summary>
  413. /// Gets the source address of the IP packet.
  414. /// </summary>
  415. /// <value>An <see cref="IPAddress"/> instance.</value>
  416. public IPAddress SourceAddress
  417. {
  418. get
  419. {
  420. return m_SourceAddress;
  421. }
  422. }
  423. /// <summary>
  424. /// Gets the destination address of the IP packet.
  425. /// </summary>
  426. /// <value>An <see cref="IPAddress"/> instance.</value>
  427. public IPAddress DestinationAddress
  428. {
  429. get
  430. {
  431. return m_DestinationAddress;
  432. }
  433. }
  434. /// <summary>
  435. /// Gets the source port of the packet.
  436. /// </summary>
  437. /// <value>A 32-bits signed integer.</value>
  438. /// <remarks>
  439. /// This property will only return meaningful data if the IP packet encapsulates either a TCP or a UDP packet.
  440. /// If the IP address encapsulates a packet of another protocol, the returned source port will be set to minus one.
  441. /// </remarks>
  442. public int SourcePort
  443. {
  444. get
  445. {
  446. return m_SourcePort;
  447. }
  448. }
  449. /// <summary>
  450. /// Gets the destination port of the packet.
  451. /// </summary>
  452. /// <value>A 32-bits signed integer.</value>
  453. /// <remarks>
  454. /// This property will only return meaningful data if the IP packet encapsulates either a TCP or a UDP packet.
  455. /// If the IP address encapsulates a packet of another protocol, the returned destination port will be set to minus one.
  456. /// </remarks>
  457. public int DestinationPort
  458. {
  459. get
  460. {
  461. return m_DestinationPort;
  462. }
  463. }
  464. /// <summary>
  465. /// Gets a string representation of the source.
  466. /// </summary>
  467. /// <value>An <see cref="String"/> instance.</value>
  468. /// <remarks>
  469. /// If the encapsulated packet is a TCP or UDP packet, the returned string will consist of the IP address and the port number.
  470. /// If the IP packet does not encapsulate a TCP or UDP packet, the returned string will consist of the IP address.
  471. /// </remarks>
  472. public string Source
  473. {
  474. get
  475. {
  476. if (m_SourcePort != -1)
  477. return SourceAddress.ToString() + ":" + m_SourcePort.ToString();
  478. else
  479. return SourceAddress.ToString();
  480. }
  481. }
  482. /// <summary>
  483. /// Gets a string representation of the destination.
  484. /// </summary>
  485. /// <value>An <see cref="String"/> instance.</value>
  486. /// <remarks>
  487. /// If the encapsulated packet is a TCP or UDP packet, the returned string will consist of the IP address and the port number.
  488. /// If the IP packet does not encapsulate a TCP or UDP packet, the returned string will consist of the IP address.
  489. /// </remarks>
  490. public string Destination
  491. {
  492. get
  493. {
  494. if (m_DestinationPort != -1)
  495. return DestinationAddress.ToString() + ":" + m_DestinationPort.ToString();
  496. else
  497. return DestinationAddress.ToString();
  498. }
  499. }
  500. /// <summary>
  501. /// Returns a string representation of the Packet
  502. /// </summary>
  503. /// <returns>An instance of the <see cref="String"/> class.</returns>
  504. public override string ToString()
  505. {
  506. return this.ToString(false);
  507. }
  508. /// <summary>
  509. /// Returns a string representation of the Packet
  510. /// </summary>
  511. /// <param name="raw"><b>true</b> if the returned string should ony contain the raw bytes, <b>false</b> if the returned string should also contain a hexadecimal representation.</param>
  512. /// <returns>An instance of the <see cref="String"/> class.</returns>
  513. public string ToString(bool raw)
  514. {
  515. StringBuilder sb = new StringBuilder(Raw.Length);
  516. if (raw)
  517. {
  518. for (int i = 0; i < Raw.Length; i++)
  519. {
  520. if (Raw[i] > 31)
  521. sb.Append((char)Raw[i]);
  522. else
  523. sb.Append(".");
  524. }
  525. }
  526. else
  527. {
  528. string rawString = this.ToString(true);
  529. for (int i = 0; i < Raw.Length; i += 16)
  530. {
  531. for (int j = i; j < Raw.Length && j < i + 16; j++)
  532. {
  533. sb.Append(Raw[j].ToString("X2") + " ");
  534. }
  535. if (rawString.Length < i + 16)
  536. {
  537. sb.Append(' ', ((16 - (rawString.Length % 16)) % 16) * 3);
  538. sb.Append(" " + rawString.Substring(i) + "\r\n");
  539. }
  540. else
  541. {
  542. sb.Append(" " + rawString.Substring(i, 16) + "\r\n");
  543. }
  544. }
  545. }
  546. return sb.ToString();
  547. }
  548. // private variables
  549. private byte[] m_Raw;
  550. private DateTime m_Time;
  551. private int m_Version;
  552. private int m_HeaderLength;
  553. private Precedence m_Precedence;
  554. private Delay m_Delay;
  555. private Throughput m_Throughput;
  556. private Reliability m_Reliability;
  557. private int m_TotalLength;
  558. private int m_Identification;
  559. private int m_TimeToLive;
  560. private Protocol m_Protocol;
  561. private byte[] m_Checksum;
  562. private IPAddress m_SourceAddress;
  563. private IPAddress m_DestinationAddress;
  564. private int m_SourcePort;
  565. private int m_DestinationPort;
  566. }
  567. #endregion
  568. }