Intercepting http traffic
Please tell me how to intercept http requests in c#? I just need to know which sites were clicked on and that's it.
I tried using SharpPcap to intercept packets, but I do not know what to do with them next. Here is the code:
// Когда приходит пакет, вызывается это событие
private static void Program_OnPacketArrival(object sender, CaptureEventArgs e)
{
Packet packet = Packet.ParsePacket(e.Packet.LinkLayerType, e.Packet.Data);
TcpPacket tcp = (TcpPacket)packet.Extract(typeof(TcpPacket));
if (tcp != null)
{
byte[] data = tcp.PayloadData;
string res = Encoding.UTF8.GetString(data);
Console.WriteLine(res);
}
}
But this code prints GET headers, and then only when the site is not https. I hope I asked everything clearly. Thanks.
1 answers
For HTTP packets, parse the GET request and search for the Host parameter. But it may not be, then the site can be obtained by a request to the reverse DNS (if it is there). For HTTPS, you can't get requests without decrypting the traffic, of course, but you can try to find the SSL Handshake and see which domain the request goes to.
Example of capturing HTTP and SSL/TLS traffic on the first IPv4 interface found, using a Raw Socket (rights are required to run the administrator):
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());
}
}
}
}
}
Sources:
CodeProject - A Network Sniffer in C#
Cisco - SSL Introduction with Sample Transaction and Packet Exchange