Unreliable http request extraction from pcap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void Main() | |
{ | |
var readerFactory = new PacketReaderFactory(); | |
var packetReader = readerFactory.Create(@"<>.pcap"); | |
IDisplayer displayer = DisplayerFactory.Text(System.Console.Out); | |
Dictionary<(int, int), HttpRequestCutter> comms = new Dictionary<(int, int), UserQuery.HttpRequestCutter>(); | |
foreach (var packet in packetReader.ReadPackets()) | |
{ | |
Octets octets = packet.ToPDU(); | |
if (octets is EthernetFrame ethFrame) | |
{ | |
if (ethFrame.Payload is IPv4Packet ipPacket) | |
{ | |
if (ipPacket.Payload is TCPSegment tcpSegment) | |
{ | |
//Console.WriteLine(tcpSegment.SourcePort + "->" + tcpSegment.DestinationPort + ":"); | |
//Console.WriteLine(Encoding.UTF8.GetString(tcpSegment.Payload.Bytes.Span)); | |
int tcpDataLength = (ipPacket.TotalLength - (tcpSegment.HeaderLength + ipPacket.HeaderLength) * 4); | |
if (tcpSegment.DestinationPort == 80 && tcpDataLength > 0) | |
{ | |
var key = (tcpSegment.SourcePort, tcpSegment.DestinationPort); | |
if (!comms.ContainsKey(key)) | |
{ | |
comms[key] = new HttpRequestCutter(); | |
} | |
comms[key].Append(tcpSegment.Payload.Bytes.Span); | |
} | |
} | |
} | |
} | |
} | |
foreach (var kv in comms) | |
{ | |
kv.Value.Process(); | |
} | |
} | |
public class HttpRequestSimple | |
{ | |
public string HttpHeaderLine; | |
public List<string> Headers = new List<string>(); | |
public byte[] Body = new byte[0]; | |
} | |
public class HttpRequestCutter | |
{ | |
long startPosition = -1; | |
MemoryStream stream = new MemoryStream(); | |
List<HttpRequestSimple> requests = new List<HttpRequestSimple>(); | |
public void Append(Span<byte> data) | |
{ | |
if (startPosition == -1 && IsHttpHeader(data)) | |
{ | |
startPosition = stream.Position; | |
} | |
stream.Write(data); | |
} | |
public void Process() | |
{ | |
// no HTTP data | |
if (startPosition < 0) return; | |
stream.Position = startPosition; | |
int contentLength; | |
while ((contentLength = ParseHeaders(stream, out var request)) != 0) | |
{ | |
ParseBody(stream, contentLength, request); | |
if (IsHttpHeader(request.HttpHeaderLine)) | |
{ | |
requests.Add(request); | |
request.Dump(); | |
Encoding.ASCII.GetString(request.Body.Take(20).ToArray()).Dump(); | |
} | |
} | |
} | |
private int ParseHeaders(Stream stream, out HttpRequestSimple request) | |
{ | |
try | |
{ | |
var reader = new StreamReader(stream); | |
long position = stream.Position; | |
int contentLength = 0; | |
var line = reader.ReadLine(); position += line.Length + 2; | |
request = new HttpRequestSimple(); | |
request.HttpHeaderLine = line; | |
while (line != "") | |
{ | |
line = reader.ReadLine(); | |
position += line.Length + 2; | |
if (line != "") | |
{ | |
request.Headers.Add(line.Trim()); | |
if (line.StartsWith("content-length:", StringComparison.InvariantCultureIgnoreCase)) | |
{ | |
contentLength = int.Parse(line.Split(':')[1].Trim()); | |
} | |
} | |
} | |
stream.Position = position; | |
return contentLength; | |
} | |
catch | |
{ | |
request = null; | |
return 0; | |
} | |
} | |
private void ParseBody(Stream stream, int contentLength, HttpRequestSimple request) | |
{ | |
var reader = new BinaryReader(stream); | |
request.Body = reader.ReadBytes(contentLength); | |
} | |
private byte[] buf = new byte[1024]; | |
private bool IsHttpHeader(string line) | |
{ | |
try | |
{ | |
var parts = line.Split(' '); | |
if (parts.Length == 3 && parts[2].StartsWith("HTTP")) | |
{ | |
return true; | |
} | |
} | |
catch { } | |
return false; | |
} | |
private bool IsHttpHeader(Span<byte> data) | |
{ | |
int len = 0; | |
int m = 1024 < data.Length ? 1024 : data.Length; | |
for (int i = 0; i < m; i++) | |
{ | |
buf[i] = data[i]; | |
if (data[i] == (byte)'\n') | |
{ | |
len = i; | |
break; | |
} | |
} | |
return len == 0 ? false : IsHttpHeader(Encoding.ASCII.GetString(buf)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment