Commit bcd8ec16 authored by Brickner_cp's avatar Brickner_cp

New PacketBuilder design

parent 8122647a
...@@ -66,11 +66,25 @@ namespace PcapDotNet.Packets.Test ...@@ -66,11 +66,25 @@ namespace PcapDotNet.Packets.Test
byte[] arpTargetHardwareAddress = random.NextBytes(hardwareAddressLength); byte[] arpTargetHardwareAddress = random.NextBytes(hardwareAddressLength);
byte[] arpTargetProtocolAddress = random.NextBytes(protocolAddressLength); byte[] arpTargetProtocolAddress = random.NextBytes(protocolAddressLength);
Packet packet = PacketBuilder.EthernetArp(DateTime.Now, Packet packet = new PacketBuilder2(new EthernetLayer
ethernetSource, {
ethernetType, arpOperation, Source = ethernetSource,
arpSenderHardwareAddress, arpSenderProtocolAddress, },
arpTargetHardwareAddress, arpTargetProtocolAddress); new ArpLayer
{
ProtocolType = ethernetType,
Operation=arpOperation,
SenderHardwareAddress = arpSenderHardwareAddress,
SenderProtocolAddress = arpSenderProtocolAddress,
TargetHardwareAddress = arpTargetHardwareAddress,
TargetProtocolAddress = arpTargetProtocolAddress
})
.Build(DateTime.Now);
// Packet packet = PacketBuilder.EthernetArp(DateTime.Now,
// ethernetSource,
// ethernetType, arpOperation,
// arpSenderHardwareAddress, arpSenderProtocolAddress,
// arpTargetHardwareAddress, arpTargetProtocolAddress);
Assert.IsTrue(packet.IsValid, "IsValid"); Assert.IsTrue(packet.IsValid, "IsValid");
......
...@@ -72,10 +72,18 @@ namespace PcapDotNet.Packets.Test ...@@ -72,10 +72,18 @@ namespace PcapDotNet.Packets.Test
int ethernetPayloadLength = random.Next(1500); int ethernetPayloadLength = random.Next(1500);
Datagram ethernetPayload = random.NextDatagram(ethernetPayloadLength); Datagram ethernetPayload = random.NextDatagram(ethernetPayloadLength);
Packet packet = PacketBuilder.Ethernet(DateTime.Now, Packet packet =
ethernetSource, ethernetDestination, ethernetType, new PacketBuilder2(new EthernetLayer
ethernetPayload); {
Source = ethernetSource,
Destination = ethernetDestination,
EtherType = ethernetType
},
new PayloadLayer
{
Data = ethernetPayload
})
.Build(DateTime.Now);
// Ethernet // Ethernet
Assert.AreEqual(packet.Length - EthernetDatagram.HeaderLength, packet.Ethernet.PayloadLength, "PayloadLength"); Assert.AreEqual(packet.Length - EthernetDatagram.HeaderLength, packet.Ethernet.PayloadLength, "PayloadLength");
......
...@@ -123,11 +123,33 @@ namespace PcapDotNet.Packets.Test ...@@ -123,11 +123,33 @@ namespace PcapDotNet.Packets.Test
random.NextBytes(ipV4PayloadBuffer); random.NextBytes(ipV4PayloadBuffer);
Datagram ipV4Payload = new Datagram(ipV4PayloadBuffer); Datagram ipV4Payload = new Datagram(ipV4PayloadBuffer);
Packet packet = PacketBuilder.EthernetIpV4(DateTime.Now, Packet packet =
ethernetSource, ethernetDestination, new PacketBuilder2(new EthernetLayer
ipV4TypeOfService, ipV4Identification, ipV4Fragmentation, ipV4Ttl, ipV4Protocol, {
ipV4Source, ipV4Destination, ipV4Options, Source = ethernetSource,
ipV4Payload); Destination = ethernetDestination,
},
new IpV4Layer
{
TypeOfService = ipV4TypeOfService,
Identification = ipV4Identification,
Fragmentation = ipV4Fragmentation,
Ttl = ipV4Ttl,
Protocol = ipV4Protocol,
Source = ipV4Source,
Destination = ipV4Destination,
Options = ipV4Options,
},
new PayloadLayer
{
Data = ipV4Payload
}
).Build(DateTime.Now);
// Packet packet = PacketBuilder.EthernetIpV4(DateTime.Now,
// ethernetSource, ethernetDestination,
// ipV4TypeOfService, ipV4Identification, ipV4Fragmentation, ipV4Ttl, ipV4Protocol,
// ipV4Source, ipV4Destination, ipV4Options,
// ipV4Payload);
Assert.IsTrue(ipV4Protocol == IpV4Protocol.Udp || Assert.IsTrue(ipV4Protocol == IpV4Protocol.Udp ||
......
...@@ -92,13 +92,44 @@ namespace PcapDotNet.Packets.Test ...@@ -92,13 +92,44 @@ namespace PcapDotNet.Packets.Test
TcpOptions tcpOptions = random.NextTcpOptions(); TcpOptions tcpOptions = random.NextTcpOptions();
Datagram tcpPayload = random.NextDatagram(random.Next(60000)); Datagram tcpPayload = random.NextDatagram(random.Next(60000));
Packet packet = PacketBuilder.EthernetIpV4Tcp(DateTime.Now, Packet packet = new PacketBuilder2(new EthernetLayer
ethernetSource, ethernetDestination, {
ipV4TypeOfService, ipV4Identification, ipV4Fragmentation, ipV4Ttl, Source = ethernetSource,
ipV4Source, ipV4Destination, ipV4Options, Destination = ethernetDestination
tcpSourcePort, tcpDestinationPort, tcpSequenceNumber, tcpAcknowledgmentNumber, tcpControlBits, tcpWindow, tcpUrgentPointer, },
tcpOptions, new IpV4Layer
tcpPayload); {
TypeOfService = ipV4TypeOfService,
Identification = ipV4Identification,
Fragmentation = ipV4Fragmentation,
Ttl = ipV4Ttl,
Source = ipV4Source,
Destination = ipV4Destination,
Options = ipV4Options,
},
new TcpLayer
{
SourcePort = tcpSourcePort,
DestinationPort = tcpDestinationPort,
SequenceNumber = tcpSequenceNumber,
AcknowledgmentNumber = tcpAcknowledgmentNumber,
ControlBits = tcpControlBits,
Window = tcpWindow,
UrgentPointer = tcpUrgentPointer,
Options = tcpOptions,
},
new PayloadLayer
{
Data = tcpPayload
}
).Build(DateTime.Now);
// Packet packet = PacketBuilder.EthernetIpV4Tcp(DateTime.Now,
// ethernetSource, ethernetDestination,
// ipV4TypeOfService, ipV4Identification, ipV4Fragmentation, ipV4Ttl,
// ipV4Source, ipV4Destination, ipV4Options,
// tcpSourcePort, tcpDestinationPort, tcpSequenceNumber, tcpAcknowledgmentNumber, tcpControlBits, tcpWindow, tcpUrgentPointer,
// tcpOptions,
// tcpPayload);
Assert.IsTrue(packet.IsValid); Assert.IsTrue(packet.IsValid);
......
...@@ -86,12 +86,38 @@ namespace PcapDotNet.Packets.Test ...@@ -86,12 +86,38 @@ namespace PcapDotNet.Packets.Test
bool udpCalculateChecksum = random.NextBool(); bool udpCalculateChecksum = random.NextBool();
Datagram udpPayload = random.NextDatagram(random.Next(60000)); Datagram udpPayload = random.NextDatagram(random.Next(60000));
Packet packet = PacketBuilder.EthernetIpV4Udp(DateTime.Now, Packet packet = new PacketBuilder2(new EthernetLayer
ethernetSource, ethernetDestination, {
ipV4TypeOfService, ipV4Identification, ipV4Fragmentation, ipV4Ttl, Source = ethernetSource,
ipV4Source, ipV4Destination, ipV4Options, Destination = ethernetDestination,
udpSourcePort, udpDestinationPort, udpCalculateChecksum, },
udpPayload); new IpV4Layer
{
TypeOfService = ipV4TypeOfService,
Identification = ipV4Identification,
Fragmentation = ipV4Fragmentation,
Ttl = ipV4Ttl,
Source = ipV4Source,
Destination = ipV4Destination,
Options = ipV4Options,
},
new UdpLayer
{
SourcePort = udpSourcePort,
DestinationPort = udpDestinationPort,
CalculateChecksum = udpCalculateChecksum,
},
new PayloadLayer
{
Data = udpPayload
})
.Build(DateTime.Now);
// Packet packet = PacketBuilder.EthernetIpV4Udp(DateTime.Now,
// ethernetSource, ethernetDestination,
// ipV4TypeOfService, ipV4Identification, ipV4Fragmentation, ipV4Ttl,
// ipV4Source, ipV4Destination, ipV4Options,
// udpSourcePort, udpDestinationPort, udpCalculateChecksum,
// udpPayload);
Assert.IsTrue(packet.IsValid); Assert.IsTrue(packet.IsValid);
......
...@@ -14,6 +14,11 @@ namespace PcapDotNet.Packets.Ethernet ...@@ -14,6 +14,11 @@ namespace PcapDotNet.Packets.Ethernet
/// </summary> /// </summary>
public const int SizeOf = UInt48.SizeOf; public const int SizeOf = UInt48.SizeOf;
public static MacAddress Zero
{
get { return _zero; }
}
/// <summary> /// <summary>
/// Constructs the address from a 48 bit integer. /// Constructs the address from a 48 bit integer.
/// </summary> /// </summary>
...@@ -105,6 +110,7 @@ namespace PcapDotNet.Packets.Ethernet ...@@ -105,6 +110,7 @@ namespace PcapDotNet.Packets.Ethernet
(byte)(_value)); (byte)(_value));
} }
private static readonly MacAddress _zero;
private readonly UInt48 _value; private readonly UInt48 _value;
} }
} }
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Linq;
using PcapDotNet.Packets.Arp;
using PcapDotNet.Packets.Ethernet;
using PcapDotNet.Packets.IpV4;
using PcapDotNet.Packets.Transport;
namespace PcapDotNet.Packets
{
public interface ILayer
{
int Length { get; }
void Write(byte[] buffer, int offset, int payloadLength, ILayer previousLayer, ILayer nextLayer);
void Finalize(byte[] buffer, int offset, int payloadLength, ILayer nextLayer);
DataLinkKind? DataLink { get; }
}
public interface IEthernetNextLayer : ILayer
{
EthernetType PreviousLayerEtherType { get; }
MacAddress? PreviousLayerDefaultDestination { get; }
}
public interface IIpV4NextLayer : ILayer
{
IpV4Protocol PreviousLayerProtocol { get; }
}
public interface IIpV4NextTransportLayer : IIpV4NextLayer
{
int NextLayerChecksumOffset { get; }
bool NextLayerIsChecksumOptional { get; }
bool NextLayerCalculateChecksum { get; }
}
public interface IArpPreviousLayer : ILayer
{
ArpHardwareType PreviousLayerHardwareType { get; }
}
public abstract class Layer : ILayer
{
public abstract int Length { get; }
public abstract void Write(byte[] buffer, int offset, int payloadLength, ILayer previousLayer, ILayer nextLayer);
public virtual void Finalize(byte[] buffer, int offset, int payloadLength, ILayer nextLayer)
{
}
public virtual DataLinkKind? DataLink
{
get { return null; }
}
}
public abstract class SimpleLayer : Layer
{
public override sealed void Write(byte[] buffer, int offset, int payloadLength, ILayer nextLayer, ILayer nextLayer1)
{
Write(buffer, offset);
}
protected abstract void Write(byte[] buffer, int offset);
}
public class EthernetLayer : Layer, IArpPreviousLayer
{
public MacAddress Source { get; set; }
public MacAddress Destination { get; set; }
public EthernetType EtherType { get; set; }
public EthernetLayer()
{
Source = MacAddress.Zero;
Destination = MacAddress.Zero;
EtherType = EthernetType.None;
}
public override int Length
{
get { return EthernetDatagram.HeaderLength; }
}
public override void Write(byte[] buffer, int offset, int payloadLength, ILayer previousLayer, ILayer nextLayer)
{
EthernetType etherType = EtherType;
MacAddress destination = Destination;
IEthernetNextLayer ethernetNextLayer = nextLayer as IEthernetNextLayer;
if (etherType == EthernetType.None)
{
if (nextLayer == null)
throw new ArgumentException("Can't determine ether type automatically from next layer because there is not next layer");
if (ethernetNextLayer == null)
throw new ArgumentException("Can't determine ether type automatically from next layer (" + nextLayer.GetType() + ")");
etherType = ethernetNextLayer.PreviousLayerEtherType;
}
if (destination == MacAddress.Zero)
{
if (ethernetNextLayer != null && ethernetNextLayer.PreviousLayerDefaultDestination != null)
destination = ethernetNextLayer.PreviousLayerDefaultDestination.Value;
}
EthernetDatagram.WriteHeader(buffer, 0, Source, destination, etherType);
}
public override DataLinkKind? DataLink
{
get { return DataLinkKind.Ethernet; }
}
public ArpHardwareType PreviousLayerHardwareType
{
get { return ArpHardwareType.Ethernet; }
}
}
public class PayloadLayer : SimpleLayer
{
public Datagram Data { get; set; }
public PayloadLayer()
{
Data = Datagram.Empty;
}
public override int Length
{
get { return Data.Length; }
}
protected override void Write(byte[] buffer, int offset)
{
Data.Write(buffer, offset);
}
}
public class IpV4Layer : Layer, IEthernetNextLayer
{
public IpV4Layer()
{
TypeOfService = 0;
Identification = 0;
Fragmentation = IpV4Fragmentation.None;
Ttl = 0;
Protocol = null;
Source = IpV4Address.Zero;
Destination = IpV4Address.Zero;
Options = IpV4Options.None;
}
public byte TypeOfService { get; set; }
public ushort Identification { get; set; }
public IpV4Fragmentation Fragmentation { get; set; }
public byte Ttl { get; set; }
public IpV4Protocol? Protocol { get; set; }
public IpV4Address Source { get; set; }
public IpV4Address Destination { get; set; }
public IpV4Options Options { get; set; }
public EthernetType PreviousLayerEtherType
{
get { return EthernetType.IpV4; }
}
public MacAddress? PreviousLayerDefaultDestination
{
get { return null; }
}
public override int Length
{
get { return IpV4Datagram.HeaderMinimumLength + Options.BytesLength; }
}
public override void Write(byte[] buffer, int offset, int payloadLength, ILayer previousLayer, ILayer nextLayer)
{
IpV4Protocol protocol;
if (Protocol == null)
{
if (nextLayer == null)
throw new ArgumentException("Can't determine protocol automatically from next layer because there is no next layer");
IIpV4NextLayer ipV4NextLayer = nextLayer as IIpV4NextLayer;
if (ipV4NextLayer == null)
throw new ArgumentException("Can't determine protocol automatically from next layer (" + nextLayer.GetType() + ")");
protocol = ipV4NextLayer.PreviousLayerProtocol;
}
else
protocol = Protocol.Value;
IpV4Datagram.WriteHeader(buffer, offset,
TypeOfService, Identification, Fragmentation,
Ttl, protocol,
Source, Destination,
Options, payloadLength);
}
public override void Finalize(byte[] buffer, int offset, int payloadLength, ILayer nextLayer)
{
IIpV4NextTransportLayer nextTransportLayer = nextLayer as IIpV4NextTransportLayer;
if (nextTransportLayer == null || !nextTransportLayer.NextLayerCalculateChecksum)
return;
IpV4Datagram.WriteTransportChecksum(buffer, offset, Length, (ushort)payloadLength,
nextTransportLayer.NextLayerChecksumOffset, nextTransportLayer.NextLayerIsChecksumOptional);
}
}
public abstract class TransportLayer : Layer, IIpV4NextTransportLayer
{
public ushort SourcePort { get; set; }
public ushort DestinationPort { get; set; }
public abstract IpV4Protocol PreviousLayerProtocol { get; }
public abstract int NextLayerChecksumOffset { get; }
public abstract bool NextLayerIsChecksumOptional { get; }
public abstract bool NextLayerCalculateChecksum { get; }
}
public class TcpLayer : TransportLayer
{
public uint SequenceNumber{get;set;}
public uint AcknowledgmentNumber{get;set;}
public TcpControlBits ControlBits{get;set;}
public ushort Window{get; set;}
public ushort UrgentPointer{get; set;}
public TcpOptions Options{get;set;}
public override IpV4Protocol PreviousLayerProtocol
{
get { return IpV4Protocol.Tcp; }
}
public override int NextLayerChecksumOffset
{
get { return TcpDatagram.Offset.Checksum; }
}
public override bool NextLayerIsChecksumOptional
{
get { return false; }
}
public override bool NextLayerCalculateChecksum
{
get { return true; }
}
public override int Length
{
get { return TcpDatagram.HeaderMinimumLength + Options.BytesLength; }
}
public override void Write(byte[] buffer, int offset, int payloadLength, ILayer previousLayer, ILayer nextLayer)
{
TcpDatagram.WriteHeader(buffer, offset,
SourcePort, DestinationPort,
SequenceNumber, AcknowledgmentNumber,
ControlBits, Window, UrgentPointer,
Options);
}
}
public class UdpLayer : TransportLayer
{
public bool CalculateChecksum { get; set; }
public override IpV4Protocol PreviousLayerProtocol
{
get { return IpV4Protocol.Udp; }
}
public override int NextLayerChecksumOffset
{
get { return UdpDatagram.Offset.Checksum; }
}
public override bool NextLayerIsChecksumOptional
{
get { return true; }
}
public override bool NextLayerCalculateChecksum
{
get { return CalculateChecksum; }
}
public override int Length
{
get { return UdpDatagram.HeaderLength; }
}
public override void Write(byte[] buffer, int offset, int payloadLength, ILayer previousLayer, ILayer nextLayer)
{
UdpDatagram.WriteHeader(buffer, offset, SourcePort, DestinationPort, payloadLength);
}
}
public class ArpLayer : Layer, IEthernetNextLayer
{
public EthernetType ProtocolType { get; set; }
public ArpOperation Operation { get; set; }
public byte[] SenderHardwareAddress { get; set; }
public byte[] SenderProtocolAddress { get; set; }
public byte[] TargetHardwareAddress { get; set; }
public byte[] TargetProtocolAddress { get; set; }
public EthernetType PreviousLayerEtherType
{
get { return EthernetType.Arp; }
}
public MacAddress? PreviousLayerDefaultDestination
{
get { return EthernetDatagram.BroadcastAddress; }
}
public override int Length
{
get { return ArpDatagram.GetHeaderLength(SenderHardwareAddress.Length, SenderProtocolAddress.Length); }
}
public override void Write(byte[] buffer, int offset, int payloadLength, ILayer previousLayer, ILayer nextLayer)
{
if (previousLayer == null)
throw new ArgumentException("Must have a previous layer");
IArpPreviousLayer arpPreviousLayer = previousLayer as IArpPreviousLayer;
if (arpPreviousLayer == null)
throw new ArgumentException("The layer before the ARP layer must be an ARP previous layer and can't be " + previousLayer.GetType());
if (SenderHardwareAddress.Length != TargetHardwareAddress.Length)
{
throw new ArgumentException("Sender hardware address length is " + SenderHardwareAddress.Length + " bytes " +
"while target hardware address length is " + TargetHardwareAddress.Length + " bytes");
}
if (SenderProtocolAddress.Length != TargetProtocolAddress.Length)
{
throw new ArgumentException("Sender protocol address length is " + SenderProtocolAddress.Length + " bytes " +
"while target protocol address length is " + TargetProtocolAddress.Length + " bytes");
}
ArpDatagram.WriteHeader(buffer, offset,
arpPreviousLayer.PreviousLayerHardwareType, ProtocolType, Operation,
SenderHardwareAddress, SenderProtocolAddress, TargetHardwareAddress, TargetProtocolAddress);
}
}
public class PacketBuilder2
{
public PacketBuilder2(params ILayer[] layers)
{
if (layers.Length == 0)
throw new ArgumentException("At least one layer must be given", "layers");
DataLinkKind? dataLinkKind = layers[0].DataLink;
if (dataLinkKind == null)
throw new ArgumentException("First layer (" + layers[0].GetType() + ") must provide a DataLink", "layers");
_layers = layers;
_dataLink = new DataLink(dataLinkKind.Value);
}
public Packet Build(DateTime timestamp)
{
int length = _layers.Select(layer => layer.Length).Sum();
byte[] buffer = new byte[length];
WriteLayers(buffer, length);
FinalizeLayers(buffer, length);
return new Packet(buffer, timestamp, _dataLink);
}
private void WriteLayers(byte[] buffer, int length)
{
int offset = 0;
for (int i = 0; i != _layers.Length; ++i)
{
ILayer layer = _layers[i];
ILayer previousLayer = i == 0 ? null : _layers[i - 1];
ILayer nextLayer = i == _layers.Length - 1 ? null : _layers[i + 1];
layer.Write(buffer, offset, length - offset - layer.Length, previousLayer, nextLayer);
offset += layer.Length;
}
}
private void FinalizeLayers(byte[] buffer, int length)
{
int offset = 0;
for (int i = 0; i != _layers.Length; ++i)
{
ILayer layer = _layers[i];
ILayer nextLayer = i == _layers.Length - 1 ? null : _layers[i + 1];
layer.Finalize(buffer, offset, length - offset - layer.Length, nextLayer);
offset += layer.Length;
}
}
private readonly ILayer[] _layers;
private readonly DataLink _dataLink;
}
}
\ No newline at end of file
...@@ -134,6 +134,7 @@ ...@@ -134,6 +134,7 @@
<Compile Include="OptionTypeRegistrationAttribute.cs" /> <Compile Include="OptionTypeRegistrationAttribute.cs" />
<Compile Include="Packet.cs" /> <Compile Include="Packet.cs" />
<Compile Include="PacketBuilder.cs" /> <Compile Include="PacketBuilder.cs" />
<Compile Include="PacketBuilder2.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Transport\TcpDatagram.cs" /> <Compile Include="Transport\TcpDatagram.cs" />
<Compile Include="Transport\TcpControlBits.cs" /> <Compile Include="Transport\TcpControlBits.cs" />
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment