MSDN.WhiteKnight - Stack Overflow answers
Ответ на "Перехват http-трафика"
Answer 846042
Для HTTP-пакетов - парсить GET-запрос и искать параметр Host. Но его может и не быть, тогда сайт можно получить запросом к обратному DNS (если он там есть). Для HTTPS получить запросы без расшифровки трафика, понятное дело, нельзя, но можно попробовать найти SSL Handshake и посмотреть, к какому домену идет запрос.
Пример захвата HTTP и SSL/TLS трафика на первом найденном IPv4-интерфейсе, с использованием Raw Socket (для запуска требуются права администратора):
using System; using System.Collections.Generic; using System.Data; using System.Text; using System.Diagnostics; using System.Threading; using System.IO; using System.Net; using System.Net.Sockets; using System.Net.NetworkInformation; namespace ConsoleTest1 { class Program { //Получает все локальные IP-адреса public static List<IPAddress> GetIpAddresses() { List<IPAddress> res = new List<IPAddress>(10); var ifs = NetworkInterface.GetAllNetworkInterfaces(); foreach (var interf in ifs) { var ipprop = interf.GetIPProperties(); if (ipprop == null) continue; var unicast = ipprop.UnicastAddresses; if (unicast == null) continue; //находим первый Unicast-адрес foreach (var addr in unicast) { if (addr.Address.AddressFamily != AddressFamily.InterNetwork) continue; res.Add(addr.Address); break; } } return res; } const byte PROTO_TCP = 6; const byte SSL_HANDSHAKE = 0x16; public class ParseResult { public string TrafficType {get;set;} public string Host { get; set; } } public static ParseResult ParseIpPacket(byte[] data, IPAddress src_ip) { ushort dummy; byte b; MemoryStream ms = new MemoryStream(data); BinaryReader br = new BinaryReader(ms); uint header_len; uint total_len; IPAddress src,dst; string host=""; ParseResult result; //parse IP packet header using (ms) using (br) { b = br.ReadByte(); byte ver = (byte)((b & (byte)0xF0) >> 4); //IP version if (ver != 4) { Console.WriteLine("Unsupported IP version: {0}", ver); return null; } byte ihl = (byte)(b & (byte)0x0F);//header length header_len = ihl * 4u; b = br.ReadByte(); //packet length byte[] temp = new byte[2]; temp[1] = br.ReadByte(); temp[0] = br.ReadByte(); total_len = BitConverter.ToUInt16(temp, 0); dummy = br.ReadUInt16(); dummy = br.ReadUInt16(); byte ttl = br.ReadByte(); byte proto = br.ReadByte(); dummy = br.ReadUInt16(); //source IP temp = new byte[4]; temp[0] = br.ReadByte(); temp[1] = br.ReadByte(); temp[2] = br.ReadByte(); temp[3] = br.ReadByte(); src = new IPAddress(temp); //destination IP temp[0] = br.ReadByte(); temp[1] = br.ReadByte(); temp[2] = br.ReadByte(); temp[3] = br.ReadByte(); dst = new IPAddress(temp); if (proto != PROTO_TCP) return null; } //Parse TCP packet uint tcp_size = total_len - header_len; byte[] tcp_data = new byte[tcp_size]; Array.Copy(data, header_len, tcp_data, 0, tcp_size); ms = new MemoryStream(tcp_data); br = new BinaryReader(ms); byte tcp_header_size; uint http_size; using (ms) using (br) { var src_port = br.ReadUInt16(); var dst_port = br.ReadUInt16(); br.ReadUInt32(); br.ReadUInt32(); tcp_header_size = (byte)(br.ReadByte() >> 4); tcp_header_size *= 4; http_size = tcp_size - tcp_header_size; } byte[] http_data = new byte[http_size]; Array.Copy(tcp_data, tcp_header_size, http_data, 0, http_size); //parse SSL record if (http_data.Length >= 5 && src.Equals(src_ip)) { ms = new MemoryStream(http_data); br = new BinaryReader(ms); using (ms) using (br) { byte record_type = br.ReadByte(); byte b1 = br.ReadByte(); byte b2 = br.ReadByte(); byte[] bytes = new byte[]{b2,b1}; ushort ssl_ver = BitConverter.ToUInt16(bytes,0); ushort ssl_len = br.ReadUInt16(); if ( ((ssl_ver >= 0x0300 && ssl_ver <= 0x0304) || ssl_ver == 0x0002) && (record_type == SSL_HANDSHAKE)) { //пытаемся получить имя узла из обратного DNS try { host = Dns.GetHostEntry(dst).HostName; } catch (SocketException) { host = ""; } result = new ParseResult(); result.TrafficType = "SSL / TLS"; if (host != "") result.Host = host; else result.Host = dst.ToString(); return result; } } } //Parse HTTP data string res = Encoding.UTF8.GetString(http_data); string[] arr = res.Split("\n\r".ToCharArray(),StringSplitOptions.RemoveEmptyEntries); if (arr.Length > 2 && arr[0].StartsWith("GET") && arr[0].Contains("HTTP/")) { //найдем поле Host for(int i=1;i<arr.Length;i++) { if (arr[i].StartsWith("Host: ")) { host = arr[i].Replace("Host: ", ""); break; } } if (host == "") { //пытаемся получить имя узла из обратного DNS try { host = Dns.GetHostEntry(dst).HostName; } catch (SocketException) { host = ""; } } result = new ParseResult(); result.TrafficType = "HTTP"; result.Host = host; return result; } return null; } static void Main(string[] args) { var mainSocket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.IP); var ips = GetIpAddresses(); IPAddress ipaddr=new IPAddress(0L); foreach (var ip in ips) { if (ip.GetAddressBytes()[0] != 127) { Console.WriteLine("Interface IP: {0}",ip); ipaddr = ip; break; } } mainSocket.Bind(new IPEndPoint(ipaddr, 0)); mainSocket.SetSocketOption(SocketOptionLevel.IP, //Applies only to IP packets SocketOptionName.HeaderIncluded, //Set the include header true); //option to true byte[] byTrue = new byte[4] { 1, 0, 0, 0 }; byte[] byOut = new byte[4]; //Socket.IOControl is analogous to the WSAIoctl method of Winsock 2 mainSocket.IOControl(IOControlCode.ReceiveAll, //SIO_RCVALL of Winsock byTrue, byOut); byte[] buffer = new byte[1024*20]; int res; while (true) { try { res = mainSocket.Receive(buffer); ParseResult result = ParseIpPacket(buffer, ipaddr); if (result != null) { Console.WriteLine("[{0}] {1}",result.TrafficType,result.Host); } } catch (Exception ex) { Console.WriteLine(ex.ToString()); } } } } }
Источники:
CodeProject - A Network Sniffer in C#
Cisco - SSL Introduction with Sample Transaction and Packet Exchange
Content is retrieved from StackExchange API.
Auto-generated by ruso-archive tools.