I'm trying to implement IP fragmentation using Pcap.Net. It is simple for packets that are already built as the L3 payload is just split into parts. I have a code that does it. It returns the list of packet fragments for sending it into the wire.
private static List<Packet> FragmentPacket(Packet packet)
{
EthernetLayer ethernetLayer = (EthernetLayer)packet.Ethernet.ExtractLayer();
IpV4Layer ipV4Layer = (IpV4Layer)packet.Ethernet.IpV4.ExtractLayer();
PayloadLayer payload = (PayloadLayer)packet.Ethernet.IpV4.Payload.ExtractLayer();
// implement IP fragmentation
int totalLength = payload.Length;
int fragmentLength = 1480;
int fragmentOffset = 0;
IpV4FragmentationOptions FragOptions;
List<Packet> fragmentsList = new List<Packet>();
while (fragmentOffset < totalLength)
{
if (fragmentOffset + fragmentLength >= totalLength)
{
//last fragment
FragOptions = IpV4FragmentationOptions.None;
fragmentLength = totalLength - fragmentOffset;
}
else
{
//more fragments to go
FragOptions = IpV4FragmentationOptions.MoreFragments;
}
IpV4Layer newipV4Layer =
new IpV4Layer
{
Source = ipV4Layer.Source,
CurrentDestination = ipV4Layer.CurrentDestination,
Fragmentation = new IpV4Fragmentation(FragOptions, (ushort)fragmentOffset),
HeaderChecksum = null, // Will be filled automatically.
Identification = 123,
Options = IpV4Options.None,
Protocol = ipV4Layer.Protocol,
Ttl = ipV4Layer.Ttl, // 128,
TypeOfService = ipV4Layer.TypeOfService,
};
byte[] newBuffer = payload.Data.ToArray();
PayloadLayer fragmentedPayload = new PayloadLayer { Data = new Datagram(newBuffer, fragmentOffset, fragmentLength) };
PacketBuilder builder = new PacketBuilder(ethernetLayer, ipV4Layer, fragmentedPayload);
fragmentsList.Add(builder.Build(DateTime.Now));
fragmentOffset = fragmentOffset + fragmentedPayload.Length;
}
return fragmentsList;
}
But what I'm actually doing is:
1) receiving large packet via Loopback interface (it is usually bigger than physical interface's MTU)
2) disassembling it, modifying IP addresses
3) building a new packet and sending it via Ethernet interface
Unfortunately, if the IP payload is bigger than MTU, exception happens as the packet needs to be fragmented before sending.
Because I'm changing IP address, then for TCP/UDP packets, the L4 checksum must be recalculated and this recalculation must take into account L3 header. Therefore it is needed to build L3+L4+payload part (to have L4 checksum properly calculated) and then split L4+payload into parts to fit L3 MTU.
I came into a solution in which I'm building a new packet (which is bigger than MTU) and then push it via above function to tear it into parts, and then I'm sending it using:
foreach (Packet newpacket in packetList) communicator.SendPacket(newpacket);
This, however, requires to build the same packet twice and I'm trying to find a way in Pcap.Net to partially build a packet (including recalculation of L4 checksum) and at the same time divide it into fragments to fit MTU.
I don't know how to (and if this is possible in Pcap.Net) prepare L3 payload that would consist of tcpLayer/udpLayer + L4 payload since TCP checksum is calculated during building and then finally build the rest of packet. If that was possible, I would just need to build the packet once splitting it into parts at the same time.