I'm trying to create a valid TCP connection to my test server in order to simulate a GET request. Hopefully I'm pretty close to a solution.
Using Wireshark data from a real request, I've managed to get the SYN
& SYN-ACK
when sending one package using PacketCommunicator.SendPacket()
:
However, I can't seem to make the ACK
appear.
The first packets is constructed using EthernetLayer
, IpV4Layer
and a TcpLayer
, while the latter (currently non-working) uses the ones just mentioned + a HttpRequestLayer
.
The last packets TcpLayer
's ControlBits
is set to TcpControlBits.Acknowledgment
. Despite this, it's not showing up in WireShark like on my "real" GET requests.
Hopefully I've posted the relevant part of the code. If not - please let me know.
Here is a draft that works (I've checked).
Please change the values used when constructing HttpGetSender instance to whatever you need.
The tricky part is to get the sequence and acknowledgement numbers right.
using System;
using System.Collections.Generic;
using PcapDotNet.Core;
using PcapDotNet.Packets;
using PcapDotNet.Packets.Ethernet;
using PcapDotNet.Packets.Http;
using PcapDotNet.Packets.IpV4;
using PcapDotNet.Packets.Transport;
namespace SendingHttpGet
{
internal class HttpGetSender
{
public HttpGetSender()
{
}
public MacAddress SourceMac { get; set; }
public MacAddress DestinationMac { get; set; }
public IpV4Address SourceIpV4 { get; set; }
public IpV4Address DestinationIpV4 { get; set; }
public string Host { get; set; }
public void Run(PacketDevice device)
{
using (PacketCommunicator communicator = device.Open(100, // name of the device
PacketDeviceOpenAttributes.Promiscuous,
// promiscuous mode
100)) // read timeout
{
SendSyn(communicator);
WaitForAck(communicator);
}
}
private void WaitForAck(PacketCommunicator communicator)
{
communicator.SetFilter("tcp and src " + DestinationIpV4 + " and dst " + SourceIpV4 + " and src port " + _destinationPort + " and dst port " + _sourcePort);
Packet packet;
while (true)
{
if (communicator.ReceivePacket(out packet) == PacketCommunicatorReceiveResult.Ok)
{
if (packet.Ethernet.IpV4.Tcp.AcknowledgmentNumber == _expectedAckNumber)
{
_seqNumber = _expectedAckNumber;
_ackNumber = packet.Ethernet.IpV4.Tcp.SequenceNumber + 1;
SendGet(communicator);
break;
}
}
SendSyn(communicator);
}
WaitForResponse(communicator);
}
private void WaitForResponse(PacketCommunicator communicator)
{
communicator.SetFilter("tcp and src " + DestinationIpV4 + " and dst " + SourceIpV4 + " and src port " + _destinationPort + " and dst port " + _sourcePort);
Packet packet;
while (true)
{
if (communicator.ReceivePacket(out packet) == PacketCommunicatorReceiveResult.Ok)
{
Console.WriteLine("Expected ack number: " + _expectedAckNumber);
Console.WriteLine("Received ack number: " + packet.Ethernet.IpV4.Tcp.AcknowledgmentNumber);
if (packet.Ethernet.IpV4.Tcp.AcknowledgmentNumber == _expectedAckNumber)
{
break;
}
}
SendGet(communicator);
}
}
private void SendSyn(PacketCommunicator communicator)
{
// Ethernet Layer
EthernetLayer ethernetLayer = new EthernetLayer
{
Source = SourceMac,
Destination = DestinationMac,
};
// IPv4 Layer
IpV4Layer ipV4Layer = new IpV4Layer
{
Source = SourceIpV4,
CurrentDestination = DestinationIpV4,
Ttl = 128,
Fragmentation =
new IpV4Fragmentation(IpV4FragmentationOptions.DoNotFragment, 0),
Identification = 1234,
};
// TCP Layer
TcpLayer tcpLayer = new TcpLayer
{
SourcePort = _sourcePort,
DestinationPort = _destinationPort,
SequenceNumber = _seqNumber,
ControlBits = TcpControlBits.Synchronize,
Window = _windowSize,
};
communicator.SendPacket(PacketBuilder.Build(DateTime.Now, ethernetLayer, ipV4Layer, tcpLayer));
_expectedAckNumber = _seqNumber + 1;
}
private void SendGet(PacketCommunicator communicator)
{
// Ethernet Layer
EthernetLayer ethernetLayer = new EthernetLayer
{
Source = SourceMac,
Destination = DestinationMac,
};
// IPv4 Layer
IpV4Layer ipV4Layer = new IpV4Layer
{
Source = SourceIpV4,
CurrentDestination = DestinationIpV4,
Ttl = 128,
Fragmentation =
new IpV4Fragmentation(IpV4FragmentationOptions.DoNotFragment, 0),
Identification = 1235,
};
// TCP Layer
TcpLayer tcpLayer = new TcpLayer
{
SourcePort = _sourcePort,
DestinationPort = _destinationPort,
SequenceNumber = _seqNumber,
AcknowledgmentNumber = _ackNumber,
ControlBits = TcpControlBits.Acknowledgment,
Window = _windowSize,
};
// HTTP Layer
HttpLayer httpLayer = new HttpRequestLayer
{
Uri = "/",
Header = new HttpHeader(HttpField.CreateField("Host", Host)),
Method = new HttpRequestMethod(HttpRequestKnownMethod.Get),
Version = HttpVersion.Version11,
};
Packet packet = PacketBuilder.Build(DateTime.Now, ethernetLayer, ipV4Layer, tcpLayer, httpLayer);
communicator.SendPacket(packet);
_expectedAckNumber = (uint) (_seqNumber + packet.Ethernet.IpV4.Tcp.PayloadLength);
}
private ushort _sourcePort = (ushort) (4123 + new Random().Next() % 1000);
private ushort _destinationPort = 80;
private uint _seqNumber = (uint) new Random().Next();
private uint _expectedAckNumber;
private ushort _windowSize = 8192;
private uint _ackNumber;
}
internal class Program
{
private static void Main(string[] args)
{
// Retrieve the device list from the local machine
IList<LivePacketDevice> allDevices = LivePacketDevice.AllLocalMachine;
if (allDevices.Count == 0)
{
Console.WriteLine("No interfaces found! Make sure WinPcap is installed.");
return;
}
// Print the list
for (int i = 0; i != allDevices.Count; ++i)
{
LivePacketDevice device = allDevices[i];
Console.Write((i + 1) + ". " + device.Name);
if (device.Description != null)
Console.WriteLine(" (" + device.Description + ")");
else
Console.WriteLine(" (No description available)");
}
int deviceIndex = 0;
do
{
Console.WriteLine("Enter the interface number (1-" + allDevices.Count + "):");
string deviceIndexString = Console.ReadLine();
if (!int.TryParse(deviceIndexString, out deviceIndex) ||
deviceIndex < 1 || deviceIndex > allDevices.Count)
{
deviceIndex = 0;
}
} while (deviceIndex == 0);
// Take the selected adapter
PacketDevice selectedDevice = allDevices[deviceIndex - 1];
HttpGetSender sender = new HttpGetSender
{
SourceMac = new MacAddress("your:host:mac:address:1:2"),
DestinationMac = new MacAddress("gateway:mac:address:1:2:3"),
SourceIpV4 = new IpV4Address("your.host.ip.address"),
DestinationIpV4 = new IpV4Address("target.host.ip.address"),
Host = "targethost.com",
};
sender.Run(selectedDevice);
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With