使用RawSocket进行网络抓包
目錄
簡介編輯
1.socket(AF_INET,?SOCK_RAW,?IPPROTO_TCP|IPPROTO_UDP|IPPROTO_ICMP)發送接收ip數據包 2.socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL))發送接收以太網數據幀 3.socket(AF_INET, SOCK_PACKET, htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL))過時了,不要用啊 理解一下SOCK_RAW的原理, 比如網卡收到了一個 14+20+8+100+4 的udp的以太網數據幀. 首先,網卡對該數據幀進行硬過濾(根據網卡的模式不同會有不同的動作,如果設置了promisc混雜模式的話,則不做任何過濾直接交給下一層輸入例程,否則非本機mac或者廣播mac會被直接丟棄).按照上面的例子,如果成功的話,會進入ip輸入例程.但是在進入ip輸入例程之前,系統會檢查系統中是否有通過socket(AF_PACKET, SOCK_RAW, ..)創建的套接字.如果有的話并且協議相符,在這個例子中就是需要ETH_P_IP或者ETH_P_ALL類型.系統就給每個這樣的socket接收緩沖區發送一個數據幀拷貝.然后進入下一步. 其次,進入了ip輸入例程(ip層會對該數據包進行軟過濾,就是檢查校驗或者丟棄非本機ip或者廣播ip的數據包等,具體要參考源代碼),例子中就是如果成功的話會進入udp輸入例程.但是在交給udp輸入例程之前,系統會檢查系統中是否有通過socket(AF_INET,SOCK_RAW, ..)創建的套接字.如果有的話并且協議相符,在這個例子中就是需要IPPROTO_UDP類型.系統就給每個這樣的socket接收緩沖區發送一個數據幀拷貝.然后進入下一步. 最后,進入udp輸入例程 ... ps:如果校驗和出錯的話,內核會直接丟棄該數據包的.而不會拷貝給sock_raw的套接字,因為校驗和都出錯了,數據肯定有問題的包括所有信息都沒有意義了. 進一步分析他們的能力. 1. socket(AF_INET,?SOCK_RAW, IPPROTO_UDP); 能:該套接字可以接收協議類型為(tcp udp icmp等)發往本機的ip數據包,從上面看的就是20+8+100. 不能:不能收到非發往本地ip的數據包(ip軟過濾會丟棄這些不是發往本機ip的數據包). 不能:不能收到從本機發送出去的數據包. 發送的話需要自己組織tcp udp icmp等頭部.可以setsockopt來自己包裝ip頭部 這種套接字用來寫個ping程序比較適合 2. socket(PF_PACKET, SOCK_RAW, htons(x)); 這個套接字比較強大,創建這種套接字可以監聽網卡上的所有數據幀.從上面看就是20+20+8+100.最后一個以太網crc從來都不算進來的,因為內核已經判斷過了,對程序來說沒有任何意義了. 能: 接收發往本地mac的數據幀 能: 接收從本機發送出去的數據幀(第3個參數需要設置為ETH_P_ALL) 能: 接收非發往本地mac的數據幀(網卡需要設置為promisc混雜模式) 協議類型一共有四個 ETH_P_IP 0x800 只接收發往本機mac的ip類型的數據幀 ETH_P_ARP 0x806 只接受發往本機mac的arp類型的數據幀 ETH_P_RARP 0x8035 只接受發往本機mac的rarp類型的數據幀 ETH_P_ALL 0x3 接收發往本機mac的所有類型ip arp rarp的數據幀, 接收從本機發出的所有類型的數據幀.(混雜模式打開的情況下,會接收到非發往本地mac的數據幀) 3. socket(AF_INET, SOCK_PACKET, htons(ETH_P_ALL)),這個一般用于抓包程序。總結編輯
1.只想收到發往本機某種協議的ip數據包的話用第一種就足夠了 2. 更多的詳細的內容請使用第二種.包括ETH_P_ALL參數和混雜模式都可以使它的能力不斷的加強.1.1 原始套接字工作原理與規則
? ?? ?? ?原始套接字是一個特殊的套接字類型,它的創建方式跟TCP/UDP創建方法幾乎是
一摸一樣,例如,通過
? ?? ? sockfd = socktet(AF_INET, SOCK_RAW, IPPROTO_ICMP);
這兩句程序你就可以創建一個原始套接字.然而這種類型套接字的功能卻與TCP或者UDP類型套接字的功能有很大的不同:TCP/UDP類型的套接字只能夠訪問傳輸層以及傳輸層以上的數據,因為當IP層把數據傳遞給傳輸層時,下層的數據包頭已經被丟掉了.而原始套接字卻可以訪問傳輸層以下的數據,,所以使用 raw套接字你可以實現上至應用層的數據操作,也可以實現下至鏈路層的數據操作.
? ?? ?? ?比如:通過
方式創建的raw socket就能直接讀取鏈路層的數據.
1)使用原始套接字時應該注意的問題(參考<<unix網絡編程>>以及網上的優秀文檔)
(1):對于UDP/TCP產生的IP數據包,內核不將它傳遞給任何原始套接字,而只是將這些數據交給對應的UDP/TCP數據處理句柄(所以,如果你想要通過原始套接字來訪問TCP/UDP或者其它類型的數據,調用socket函數創建原始套接字第三個參數應該指定為htons(ETH_P_IP),也就是通過直接訪問數據鏈路層來實現.(我們后面的密碼竊取器就是基于這種類型的).
(2):對于ICMP和EGP等使用IP數據包承載數據但又在傳輸層之下的協議類型的IP數據包,內核不管是否已經有注冊了的句柄來處理這些數據,都會將這些IP數據包復制一份傳遞給協議類型匹配的原始套接字.
(3):對于不能識別協議類型的數據包,內核進行必要的校驗,然后會查看是否有類型匹配的原始套接字負責處理這些數據,如果有的話,就會將這些IP數據包復制一份傳遞給匹配的原始套接字,否則,內核將會丟棄這個IP數據包,并返回一個ICMP主機不可達的消息給源主機.
(4): 如果原始套接字bind綁定了一個地址,核心只將目的地址為本機IP地址的數包傳遞給原始套接字,如果某個原始套接字沒有bind地址,核心就會把收到的所有IP數據包發給這個原始套接字.
(5): 如果原始套接字調用了connect函數,則核心只將源地址為connect連接的IP地址的IP數據包傳遞給這個原始套接字.
(6):如果原始套接字沒有調用bind和connect函數,則核心會將所有協議匹配的IP數據包傳遞給這個原始套接字.
2).編程選項
? ???原始套接字是直接使用IP協議的非面向連接的套接字,在這個套接字上可以調用bind和connect函數進行地址綁定.說明如下:
(1)bind函數:調用bind函數后,發送數據包的源IP地址將是bind函數指定的地址。如是不調用bind,則內核將以發送接口的主IP地址填充 IP頭. 如果使用setsockopt設置了IP_HDRINCL(header including)選項,就必須手工填充每個要發送的數據包的源IP地址,否則,內核將自動創建IP首部.
(2)connetc函數:調用connect函數后,就可以使用write和send函數來發送數據包,而且內核將會用這個綁定的地址填充IP數據包的目的IP地址,否則的話,則應使用sendto或sendmsg函數來發送數據包,并且要在函數參數中指定對方的IP地址。
? ? 綜合以上種種功能和特點,我們可以使用原始套接字來實現很多功能,比如最基本的數據包分析,主機嗅探等.其實也可以使用原始套接字作一個自定義的傳輸層協議.
namespace test.test {public class RawSocket{private Socket _socket;private IPAddress _address;public Action<TcpPacket> OnTcpPacketCapture;public Action<byte[], int> OnRawDataCapure;ILog log = LogManager.GetLogger("ErrorLog");public RawSocket(IPAddress address){_address = address;_socket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.IP);_socket.Bind(new IPEndPoint(address, 0));}public bool Capture(){bool isOk = true;try{_socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.HeaderIncluded, 1);byte[] inBytes = new byte[] { 1, 0, 0, 0 };byte[] outBytes = new byte[] { 0, 0, 0, 0 };_socket.IOControl(IOControlCode.ReceiveAll, inBytes, outBytes);if (0 != outBytes[0] + outBytes[1] + outBytes[2] + outBytes[3]) { isOk = false; }}catch (SocketException){isOk = false;}if (isOk){while (true){//以太網MTU 最大為1500 似乎1500會有錯誤byte[] buffer = new byte[15000];int count = _socket.Receive(buffer, SocketFlags.None);//if (OnRawDataCapure != null)// OnRawDataCapure(buffer, count);//if (OnTcpPacketCapture != null) {IPPacket ip = new IPPacket(buffer, 0, count);if (ip.Protocol == IPProtocolType.UDP){log.ErrorFormat(ip.ToString());log.ErrorFormat(System.Text.Encoding.ASCII.GetString(ip.Data.Data));//TcpPacket tcp = new TcpPacket(ip);// OnTcpPacketCapture(tcp); }}}}return isOk;}public void Stop(){if (_socket != null){_socket.Shutdown(SocketShutdown.Both);_socket.Close();}}}class SocketData{public Socket Socket { get; set; }public Byte[] Data { get; set; }}public class DataBuffer{public byte[] RawBuffer;public int RawStart;public int RawCount;private byte[] buffer;private int start;private int end;public int Length { get { return end - start; } }public byte this[int index] { get { return buffer[start + index]; } }public DataBuffer(byte[] data): this(data, 0, data.Length) { }public DataBuffer(byte[] data, int start, int count){this.RawBuffer = this.buffer = data;this.RawStart = this.start = start;this.RawCount = count;this.end = start + count;}public void SetPosition(int position){this.start += position;}public byte[] Data{get{byte[] data = new byte[this.Length];Array.Copy(this.buffer, this.start, data, 0, data.Length);return data;}}}public class IPPacket{public int Version; //版本號public int HeadLen; //頭長度public int DiffServices; //區分服務public int DataLen;//數據長度public int Identification; //標志public int Flag; //標識 3bitpublic int Excursion;//片偏移 13bitpublic byte TTL;//生存周期public IPProtocolType Protocol; //協議public int CheckSum; //校驗和public IPAddress SrcAddr; //源地址public IPAddress DestAddr; //目標地址public byte[] option; //選項public DataBuffer Data; //IP Payloadpublic IPPacket(byte[] data) : this(new DataBuffer(data)) { }public IPPacket(byte[] data, int start, int count) : this(new DataBuffer(data, start, count)) { }public IPPacket(DataBuffer data){Version = (data[0] & 0xF0) >> 4;HeadLen = (int)(data[0] & 0x0F) * 4;DiffServices = (int)data[1];DataLen = ((int)data[2] << 8) + (int)data[3];Identification = ((int)data[5] << 8) + (int)data[5];Flag = data[6] >> 5;Excursion = (((int)data[6] & 0x1F) << 8) + (int)data[7];TTL = data[8];Protocol = (IPProtocolType)data[9];CheckSum = ((int)data[10] << 8) + (int)data[11];byte[] addr = new byte[4];for (int i = 0; i < 4; i++)addr[i] = data[12 + i];SrcAddr = new IPAddress(addr);addr = new byte[4];for (int i = 0; i < 4; i++)addr[i] = data[16 + i];DestAddr = new IPAddress(addr);//optionif (HeadLen > 20){option = new byte[HeadLen - 20];for (int i = 0; i < option.Length; i++)option[i] = data[20 + i]; //會包括填充部分 }data.SetPosition(HeadLen);Data = data;}public override string ToString(){StringBuilder sb = new StringBuilder();sb.AppendFormat("SrcAddr:{0} DestAddr={1}\r\n", SrcAddr.ToString(), DestAddr.ToString());sb.AppendFormat("CheckSum: {0} Protocol:{1}\r\n", CheckSum, Protocol.ToString());sb.AppendFormat("Version: {0} HeadLen:{1}\r\n", Version, HeadLen);sb.AppendFormat("DataLen: {0} DiffServices:{1}\r\n", DataLen, DiffServices);return sb.ToString();}}public class TcpPacket{public int SrcPort = 0;//源端口public int DestPort = 0;//目標端口public uint SequenceNo = 0;//序號public uint NextSeqNo = 0;//確認號public int HeadLen = 0;//頭長度public int Flag = 0;//控制位public int WindowSize = 0;//窗口public int CheckSum = 0;//校驗和public int UrgPtr = 0;//緊急指針public byte[] option;//選項public IPPacket IPPacket;public DataBuffer Data;public byte[] Body { get { return Data.Data; } }public TcpPacket(byte[] data) : this(new IPPacket(new DataBuffer(data))) { }public TcpPacket(byte[] data, int start, int count) : this(new IPPacket(new DataBuffer(data, start, count))) { }public TcpPacket(IPPacket packet){if (packet.Protocol != IPProtocolType.TCP)throw new NotSupportedException(string.Format("TcpPacket not support {0}", packet.Protocol));this.IPPacket = packet;DataBuffer data = packet.Data;SrcPort = ((int)data[0] << 8) + (int)data[1];DestPort = ((int)data[2] << 8) + (int)data[3];SequenceNo = ((uint)data[7] << 24) + ((uint)data[6] << 16) + ((uint)data[5] << 8) + ((uint)data[4]);NextSeqNo = ((uint)data[11] << 24) + ((uint)data[10] << 16) + ((uint)data[9] << 8) + ((uint)data[8]);HeadLen = ((data[12] & 0xF0) >> 4) * 4;//6bit保留位Flag = (data[13] & 0x3F);WindowSize = ((int)data[14] << 8) + (int)data[15];CheckSum = ((int)data[16] << 8) + (int)data[17];UrgPtr = ((int)data[18] << 8) + (int)data[19];//optionif (HeadLen > 20){option = new byte[HeadLen - 20];for (int i = 0; i < option.Length; i++)option[i] = data[20 + i]; //會包括填充部分 }data.SetPosition(this.HeadLen);Data = data;}public override string ToString(){StringBuilder sb = new StringBuilder();sb.AppendFormat("SrcPort:{0} DestPort={1}\r\n", SrcPort, DestPort);sb.AppendFormat("SequenceNo:{0} NextSeqNo={1}\r\n", SequenceNo, NextSeqNo);sb.AppendFormat("HeadLen:{0} Flag={1}\r\n", HeadLen, Flag);sb.AppendFormat("WindowSize:{0} CheckSum={1}\r\n", WindowSize, CheckSum);return sb.ToString();}}public enum IPProtocolType : byte{/// <summary> Dummy protocol for TCP. </summary>IP = 0,/// <summary> IPv6 Hop-by-Hop options. </summary>HOPOPTS = 0,/// <summary> Internet Control Message Protocol. </summary>ICMP = 1,/// <summary> Internet Group Management Protocol.</summary>IGMP = 2,/// <summary> IPIP tunnels (older KA9Q tunnels use 94). </summary>IPIP = 4,/// <summary> Transmission Control Protocol. </summary>TCP = 6,/// <summary> Exterior Gateway Protocol. </summary>EGP = 8,/// <summary> PUP protocol. </summary>PUP = 12,/// <summary> User Datagram Protocol. </summary>UDP = 17,/// <summary> XNS IDP protocol. </summary>IDP = 22,/// <summary> SO Transport Protocol Class 4. </summary>TP = 29,/// <summary> IPv6 header. </summary>IPV6 = 41,/// <summary> IPv6 routing header. </summary>ROUTING = 43,/// <summary> IPv6 fragmentation header. </summary>FRAGMENT = 44,/// <summary> Reservation Protocol. </summary>RSVP = 46,/// <summary> General Routing Encapsulation. </summary>GRE = 47,/// <summary> encapsulating security payload. </summary>ESP = 50,/// <summary> authentication header. </summary>AH = 51,/// <summary> ICMPv6. </summary>ICMPV6 = 58,/// <summary> IPv6 no next header. </summary>NONE = 59,/// <summary> IPv6 destination options. </summary>DSTOPTS = 60,/// <summary> Multicast Transport Protocol. </summary>MTP = 92,/// <summary> Encapsulation Header. </summary>ENCAP = 98,/// <summary> Protocol Independent Multicast. </summary>PIM = 103,/// <summary> Compression Header Protocol. </summary>COMP = 108,/// <summary> Raw IP packets. </summary>RAW = 255,/// <summary> IP protocol mask.</summary>MASK = 0xff} }
?
?
總結
以上是生活随笔為你收集整理的使用RawSocket进行网络抓包的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CSS实现垂直居中的5种思路
- 下一篇: iOS-设计模式-观察者模式-KVO