NetPacketTool.cs 20 KB

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