/// <summary> /// Resolves the specified IPv4 destination address to a physical /// address and hands the specified IPv4 packet down to the link /// layer. /// </summary> /// <param name="ifc">The interface through which to output the /// data.</param> /// <param name="destination">The logical address of the destination /// host, which can different from the final destination address /// contained in the IP packet.</param> /// <param name="packet">The IPv4 packet to transmit.</param> /// <exception cref="ArgumentNullException">Thrown if any of the arguments /// is null.</exception> void Output(Interface ifc, IpAddress destination, IpPacket packet) { ifc.ThrowIfNull("ifc"); destination.ThrowIfNull("destination"); packet.ThrowIfNull("packet"); // Translate IP address into MAC-Address. var macDestination = arp.Lookup(ifc, destination); // IP address is not in our ARP table. if (macDestination == null) { // Put packet on hold until the MAC-48 destination address has // been figured out. WaitingPacketsOf(ifc).Add( new Tuple <IpAddress, IpPacket>(destination, packet)); WriteLine(ifc.FullName + " is putting IP packet on-hold due to pending ARP request."); // Schedule a new ARP request. arp.Resolve(ifc, destination); } else { WriteLine(ifc.FullName + " is queueing IP packet for " + destination); Output(ifc, macDestination, packet); } }
/// <summary> /// Private constructor used for deserialization. /// </summary> private IpPacket(IpVersion version, byte ihl, byte dscp, ushort totalLength, ushort identification, IpFlag flags, ushort fragmentOffset, byte ttl, IpProtocol protocol, ushort checksum, IpAddress source, IpAddress destination) { destination.ThrowIfNull("destination"); source.ThrowIfNull("source"); if (ihl > 0x0F) { throw new ArgumentException("The Internet Header Length field must " + "be in the range from 0 to 15.", nameof(ihl)); } if (fragmentOffset > 0x1FFF) { throw new ArgumentException("The Fragment Offset field must be in " + "the range from 0 to 8191.", nameof(fragmentOffset)); } Version = version; Ihl = ihl; Dscp = dscp; TotalLength = totalLength; Identification = identification; Flags = flags; FragmentOffset = fragmentOffset; TimeToLive = ttl; Protocol = protocol; Checksum = checksum; Source = source; Destination = destination; Data = new byte[0]; }
/// <summary> /// Initializes a new instance of the IpPacket class using the specified /// values. /// </summary> /// <param name="destination">The IPv4 address of the destination /// host.</param> /// <param name="source">The IPv4 address of the sending host.</param> /// <param name="type">The type of the transport protocol encapsulated in /// the IP packet's data section.</param> /// <param name="fragmentOffset">The fragment offset of the packet.</param> /// <param name="data">The transport data to transfer as part of the IP /// packet.</param> /// <param name="ihl">The Internet Header Length.</param> /// <param name="dscp">The Differentiated Services Code Point.</param> /// <param name="ttl">The time-to-live of the IP packet.</param> /// <param name="identification">The idenfication used for uniquely identifying /// fragments of a fragmented IP packet.</param> /// <param name="flags">The flags set on the IP packet.</param> /// <exception cref="ArgumentNullException">Thrown if any of the arguments /// is null.</exception> public IpPacket(IpAddress destination, IpAddress source, IpProtocol type, byte ihl, byte dscp, byte ttl, ushort identification, IpFlag flags, ushort fragmentOffset, byte[] data) { destination.ThrowIfNull("destination"); source.ThrowIfNull("source"); data.ThrowIfNull("data"); if (ihl > 0x0F) { throw new ArgumentException("The Internet Header Length field must " + "be in the range from 0 to 15.", nameof(ihl)); } if (fragmentOffset > 0x1FFF) { throw new ArgumentException("The Fragment Offset field must be in " + "the range from 0 to 8191.", nameof(fragmentOffset)); } Version = IpVersion.Ipv4; Ihl = ihl; Dscp = dscp; Identification = identification; Flags = flags; FragmentOffset = fragmentOffset; TimeToLive = ttl; Protocol = type; Source = source; Destination = destination; Data = data; TotalLength = (ushort)(20 + Data.Length); Checksum = ComputeChecksum(this); }
/// <summary> /// Sends the specified ICMP packet to the specified destination host. /// </summary> /// <param name="ifc">The interface through which the ICMP packet /// should be sent.</param> /// <param name="destination">The IP address of the destination host /// of the ICMP packet.</param> /// <param name="packet">The ICMP packet to send.</param> /// <exception cref="ArgumentNullException">Thrown if any of the arguments /// is null.</exception> void SendIcmp(Interface ifc, IpAddress destination, IcmpPacket packet) { ifc.ThrowIfNull("ifc"); destination.ThrowIfNull("destination"); packet.ThrowIfNull("packet"); Simulation.WriteLine(OutputLevel.Icmp, ifc.FullName + " is queueing a " + packet.Type + " ICMP packet to " + destination, ConsoleColor.Magenta); Output(ifc, destination, packet.Serialize(), IpProtocol.Icmp); }
/// <summary> /// Initializes a new instance of the IpPacket class using the specified /// values. /// </summary> /// <param name="destination">The IPv4 address of the destination /// host.</param> /// <param name="source">The IPv4 address of the sending host.</param> /// <param name="type">The type of the transport protocol encapsulated in /// the IP packet's data section.</param> /// <param name="data">The transport data to transfer as part of the IP /// packet.</param> /// <exception cref="ArgumentNullException">Thrown if any of the arguments /// is null.</exception> public IpPacket(IpAddress destination, IpAddress source, IpProtocol type, byte[] data) { destination.ThrowIfNull("destination"); source.ThrowIfNull("source"); data.ThrowIfNull("data"); Destination = destination; Source = source; Protocol = type; Data = data; TimeToLive = 64; Ihl = 5; TotalLength = (ushort)(20 + Data.Length); Version = IpVersion.Ipv4; Checksum = ComputeChecksum(this); }
/// <summary> /// Wraps the specified higher-level data into IP packets and /// transmits them to the specified destination. /// </summary> /// <param name="ifc">The interface through which to output the data.</param> /// <param name="destination">The logical address of the destination /// host.</param> /// <param name="data">The higher-level data to transmit.</param> /// <param name="type">The type of the higher-level data.</param> /// <exception cref="ArgumentNullException">Thrown if any of the arguments /// is null.</exception> /// <remarks>This API is exposed to the next higher-up layer.</remarks> public void Output(Interface ifc, IpAddress destination, byte[] data, IpProtocol type) { ifc.ThrowIfNull("ifc"); destination.ThrowIfNull("destination"); data.ThrowIfNull("data"); // Construct IP packets of the size of the MTU of the data-link. var maxDataSize = ifc.MaximumTransmissionUnit - 20; var numPackets = (int)Math.Ceiling(data.Length / (double)maxDataSize); var sameSubnet = (destination & ifc.Netmask) == (ifc.IpAddress & ifc.Netmask); for (int i = 0, index = 0; i < numPackets; i++) { var numBytes = Math.Min(maxDataSize, data.Length - index); var packetData = new byte[numBytes]; Array.Copy(data, index, packetData, 0, numBytes); index = index + numBytes; // Construct the packet. var packet = new IpPacket(destination, ifc.IpAddress, type, packetData); // If source and destination are in the same subnet, we can deliver the // packet directly. Otherwise send it to the configured default gateway. Output(ifc, sameSubnet ? destination : ifc.Gateway, packet); } }
/// <summary> /// Initializes the interface. /// </summary> /// <param name="nic">The network interface card (NIC) this interface /// represents.</param> /// <param name="name">A unique name (such as eth0) for identifing the /// interface.</param> /// <param name="ipAddress">The IPv4 address to associate with this /// interface.</param> /// <param name="netmask">The subnetmask to assign to this interface.</param> /// <param name="gateway">The IPv4 address of the default gateway to /// configure this interface with.</param> void Init(Nic nic, string name, IpAddress ipAddress, IpAddress netmask, IpAddress gateway) { nic.ThrowIfNull("nic"); name.ThrowIfNull("name"); ipAddress.ThrowIfNull("ipAddress"); netmask.ThrowIfNull("netmask"); Nic = nic; Name = name; IpAddress = ipAddress; Netmask = netmask; Gateway = gateway; Nic.Interrupt += OnInterrupt; }
/// <summary> /// Private constructor used for deserialization. /// </summary> private IpPacket(IpVersion version, byte ihl, byte dscp, ushort totalLength, ushort identification, IpFlag flags, ushort fragmentOffset, byte ttl, IpProtocol protocol, ushort checksum, IpAddress source, IpAddress destination) { destination.ThrowIfNull("destination"); source.ThrowIfNull("source"); if (ihl > 0x0F) throw new ArgumentException("The Internet Header Length field must " + "be in the range from 0 to 15.", nameof(ihl)); if (fragmentOffset > 0x1FFF) throw new ArgumentException("The Fragment Offset field must be in " + "the range from 0 to 8191.", nameof(fragmentOffset)); Version = version; Ihl = ihl; Dscp = dscp; TotalLength = totalLength; Identification = identification; Flags = flags; FragmentOffset = fragmentOffset; TimeToLive = ttl; Protocol = protocol; Checksum = checksum; Source = source; Destination = destination; Data = new byte[0]; }
/// <summary> /// Initializes a new instance of the IpPacket class using the specified /// values. /// </summary> /// <param name="destination">The IPv4 address of the destination /// host.</param> /// <param name="source">The IPv4 address of the sending host.</param> /// <param name="type">The type of the transport protocol encapsulated in /// the IP packet's data section.</param> /// <param name="fragmentOffset">The fragment offset of the packet.</param> /// <param name="data">The transport data to transfer as part of the IP /// packet.</param> /// <param name="ihl">The Internet Header Length.</param> /// <param name="dscp">The Differentiated Services Code Point.</param> /// <param name="ttl">The time-to-live of the IP packet.</param> /// <param name="identification">The idenfication used for uniquely identifying /// fragments of a fragmented IP packet.</param> /// <param name="flags">The flags set on the IP packet.</param> /// <exception cref="ArgumentNullException">Thrown if any of the arguments /// is null.</exception> public IpPacket(IpAddress destination, IpAddress source, IpProtocol type, byte ihl, byte dscp, byte ttl, ushort identification, IpFlag flags, ushort fragmentOffset, byte[] data) { destination.ThrowIfNull("destination"); source.ThrowIfNull("source"); data.ThrowIfNull("data"); if (ihl > 0x0F) throw new ArgumentException("The Internet Header Length field must " + "be in the range from 0 to 15.", nameof(ihl)); if (fragmentOffset > 0x1FFF) throw new ArgumentException("The Fragment Offset field must be in " + "the range from 0 to 8191.", nameof(fragmentOffset)); Version = IpVersion.Ipv4; Ihl = ihl; Dscp = dscp; Identification = identification; Flags = flags; FragmentOffset = fragmentOffset; TimeToLive = ttl; Protocol = type; Source = source; Destination = destination; Data = data; TotalLength = (ushort) (20 + Data.Length); Checksum = ComputeChecksum(this); }
/// <summary> /// Initializes a new instance of the IpPacket class using the specified /// values. /// </summary> /// <param name="destination">The IPv4 address of the destination /// host.</param> /// <param name="source">The IPv4 address of the sending host.</param> /// <param name="type">The type of the transport protocol encapsulated in /// the IP packet's data section.</param> /// <param name="data">The transport data to transfer as part of the IP /// packet.</param> /// <exception cref="ArgumentNullException">Thrown if any of the arguments /// is null.</exception> public IpPacket(IpAddress destination, IpAddress source, IpProtocol type, byte[] data) { destination.ThrowIfNull("destination"); source.ThrowIfNull("source"); data.ThrowIfNull("data"); Destination = destination; Source = source; Protocol = type; Data = data; TimeToLive = 64; Ihl = 5; TotalLength = (ushort) (20 + Data.Length); Version = IpVersion.Ipv4; Checksum = ComputeChecksum(this); }