/// <summary> /// Serlialize this routing option into something which /// can be passed to an IpV4Packet class. /// </summary> /// <returns> /// An IpV4Option class which can be passed to an IpV4Packet. /// </returns> public IpV4Option Serialize () { IpV4Option newOption = new IpV4Option (); // fill in basic fields newOption.Class = IpV4OptionClass.DebuggingAndMeasurement; newOption.OptionType = IpV4OptionNumber.InternetTimestamp; newOption.IsCopied = false; newOption.Length = (m_timestamps.Length * (m_type == IpV4TimestampType.TimestampAndAddress ? 8 : 4)) + 4; newOption.Data = new byte[newOption.Length - 2]; // first copy in the pointer newOption.Data[0] = (byte)m_pointer; // then the overflow and type newOption.Data[1] = (byte)(m_overflow << 4); newOption.Data[1] |= (byte)m_type; // loop through each field and add that for (int i = 0; i < m_timestamps.Length; i++) { if (m_type == IpV4TimestampType.TimestampAndAddress) { Array.Copy (m_addressstamps[i].GetAddressBytes (), 0, newOption.Data, (i * 8) + 2, 4); Array.Copy (BitConverter.GetBytes (m_timestamps[i]), 0, newOption.Data, (i * 8) + 6, 4); } else { Array.Copy (BitConverter.GetBytes (m_timestamps[i]), 0, newOption.Data, (i * 4) + 2, 4); } } return newOption; }
/// <summary> /// Serlialize this routing option into something which /// can be passed to an IpV4Packet class. /// </summary> /// <returns> /// An IpV4Option class which can be passed to an IpV4Packet. /// </returns> public IpV4Option Serialize () { IpV4Option newOption = new IpV4Option (); // fill in basic fields newOption.Class = IpV4OptionClass.Control; newOption.OptionType = IpV4OptionNumber.StreamId; newOption.IsCopied = true; newOption.Length = 4; newOption.Data = new byte[2]; // copy in the stream id newOption.Data = BitConverter.GetBytes (m_id); return newOption; }
/// <summary> /// Create a new time stamp option. /// </summary> /// <param name="option"> /// The option to parse. /// </param> /// <exception cref="ArgumentNullException"> /// The option argument is null. /// </exception> /// <exception cref="ArgumentException"> /// The option argument is not a timestamp option. /// </exception> public IpV4TimeStampOption (IpV4Option option) { if (option == null) { throw new ArgumentNullException ("option"); } if (option.OptionType != IpV4OptionNumber.InternetTimestamp) { throw new ArgumentException ("The option passed was not compatible with this class. This class accepts timestamp options only", "option"); } // extract the pointer m_pointer = (byte)option.Data[0]; // extract the overflow field m_overflow = (byte)((option.Data[1] & 0xf0) >> 4); // extract the type m_type = (IpV4TimestampType)(option.Data[1] & 0xf); // calculate how many fields there are and allocate space int numberStamps = (option.Data.Length - 2) / 4; if (m_type == IpV4TimestampType.TimestampAndAddress) { numberStamps /= 2; m_addressstamps = new IPAddress[numberStamps]; } m_timestamps = new uint[numberStamps]; // extract the time stamps and addresses for (int i = 0; i < numberStamps; i++) { if (m_type == IpV4TimestampType.TimestampAndAddress) { uint address = BitConverter.ToUInt32 (option.Data, (i * 8) + 2); m_addressstamps[i] = new IPAddress ((long)address); m_timestamps[i] = BitConverter.ToUInt32 (option.Data, (i * 8) + 6); } else { m_timestamps[i] = BitConverter.ToUInt32 (option.Data, (i * 4) + 2); } } }
/// <summary> /// Serlialize this routing option into something which /// can be passed to an IpV4Packet class. /// </summary> /// <param name="optionType"> /// There are 3 types of routing option: loose source, strict source and record. /// </param> /// <returns> /// An IpV4Option class which can be passed to an IpV4Packet. /// </returns> /// <exception cref="ArgumentException"> /// The option type is not a routing option. /// </exception> public IpV4Option Serialize (IpV4OptionNumber optionType) { IpV4Option newOption = new IpV4Option (); if (optionType != IpV4OptionNumber.LooseSourceRouting && optionType != IpV4OptionNumber.StrictSourceRouting && optionType != IpV4OptionNumber.RecordRoute) { throw new ArgumentException ("The option type must be a routing option (strict source routing, loose source routing or record route", "option"); } // fill in basic fields newOption.Class = IpV4OptionClass.Control; newOption.OptionType = optionType; newOption.IsCopied = true; newOption.Length = (m_routeData.Length * 4) + 3; newOption.Data = new byte[(m_routeData.Length * 4) + 1]; // fill in the pointer newOption.Data [0] = (byte)m_pointer; // fill in the route data for (int i = 0; i < m_routeData.Length; i++) { Array.Copy (m_routeData[i].GetAddressBytes (), 0, newOption.Data, (i * 4) + 1, 4); } return newOption; }
/// <summary> /// Create a new stream identifier option. /// </summary> /// <param name="option"> /// The option to parse. /// </param> public IpV4StreamIdentifierOption (IpV4Option option) { if (option == null) { throw new ArgumentNullException ("option"); } if (option.OptionType != IpV4OptionNumber.StreamId) { throw new ArgumentException ("The option passed was not compatible with this class. This class accepts stream id options only", "option"); } // extract the stream id m_id = BitConverter.ToUInt16 (option.Data, 0); }
/// <summary> /// Create a new routing option. /// </summary> /// <param name="option"> /// The option to parse. /// </param> /// <exception cref="ArgumentNullException"> /// The option argument is null. /// </exception> /// <exception cref="ArgumentException"> /// The option argument is not a routing option. /// </exception> public IpV4RoutingOption (IpV4Option option) { if (option == null) { throw new ArgumentNullException ("option"); } if (option.OptionType != IpV4OptionNumber.LooseSourceRouting && option.OptionType != IpV4OptionNumber.StrictSourceRouting && option.OptionType != IpV4OptionNumber.RecordRoute) { throw new ArgumentException ("The option passed was not compatible with this class. This class accepts routing options only", "option"); } // read the pointer m_pointer = (byte)option.Data[0]; // get the number of addresses in the route // and allocate enough space int routeSize = (option.Length - 3) / 4; m_routeData = new IPAddress[routeSize]; // extract each address from the data for (int i = 0; i < m_routeData.Length; i++) { uint address = BitConverter.ToUInt32 (option.Data, i * 4 + 1); m_routeData[i] = new IPAddress ((long)address); } }
/// <summary> /// Serlialize this routing option into something which /// can be passed to an IpV4Packet class. /// </summary> /// <returns> /// An IpV4Option class which can be passed to an IpV4Packet. /// </returns> public IpV4Option Serialize () { IpV4Option newOption = new IpV4Option (); // fill in basic fields newOption.Class = IpV4OptionClass.Control; newOption.OptionType = IpV4OptionNumber.Security; newOption.IsCopied = true; newOption.Length = 11; newOption.Data = new byte[9]; // fill in the security bytes newOption.Data[0] = (byte)((int)m_level & 0x00ff); newOption.Data[1] = (byte)(((int)m_level & 0xff00) >> 8); // fill in the compartment bytes newOption.Data[2] = (byte)(m_compartment & 0x00ff); newOption.Data[3] = (byte)((m_compartment & 0xff00) >> 8); // fill in the handling bytes newOption.Data[4] = (byte)(m_handling & 0x00ff); newOption.Data[5] = (byte)((m_handling & 0xff00) >> 8); // fill in the transmission control code bytes newOption.Data[6] = (byte)((m_tcc & 0xff0000) >> 16); newOption.Data[7] = (byte)((m_tcc & 0x00ff00) >> 8); newOption.Data[8] = (byte)(m_tcc & 0x0000ff); return newOption; }
/// <summary> /// Create a new security option. /// </summary> /// <param name="option"> /// The option to parse. /// </param> /// <exception cref="ArgumentNullException"> /// The option argument is null. /// </exception> /// <exception cref="ArgumentException"> /// The option argument is not a security option. /// </exception> public IpV4SecurityOption (IpV4Option option) { if (option == null) { throw new ArgumentNullException ("option"); } if (option.OptionType != IpV4OptionNumber.Security) { throw new ArgumentException ("The option passed was not compatible with this class. This class accepts security options only", "option"); } // extract the security level field m_level = (IpV4SecurityLevelType) BitConverter.ToUInt16 (option.Data, 0); // extract the compartment field m_compartment = BitConverter.ToUInt16 (option.Data, 2); // extract the handling restrictions field m_handling = BitConverter.ToUInt16 (option.Data, 4); // extract the 24 bits of the transmission control code m_tcc = (uint)(option.Data[6] << 0x10); m_tcc |= (uint)(option.Data[7] << 0x08); m_tcc |= option.Data[8]; }
/// <summary> /// The fragment method will turn this IP packet into several using fragmentation. /// </summary> /// <param name="maximumTransmissionUnit"> /// The maximum size of the data in each fragment. The maximum transmission unit must /// be a multiple of 8. For example 8, 16, 24, 32 etc. /// </param> /// <returns> /// This method returns an array of fragmented IP packets which can be sent over the /// network. /// </returns> /// <exception cref="ArgumentException"> /// The MTU (maximum Transmission Unit) must be a multiple of 8 bytes /// </exception> public IpV4Packet[] Fragment (int maximumTransmissionUnit) { if (maximumTransmissionUnit % 8 != 0 && maximumTransmissionUnit > 0) { throw new ArgumentException ("The MTU (maximum Transmission Unit) must be a multiple of 8 bytes", "maximumTransmissionUnit"); } // calculate how many fragments of the maximum transmission unit size we need int fragmentCount = m_data.Length / maximumTransmissionUnit; // and if the data doesn't exactly divide up into the maximum transmission unit // size then add a new fragment for the bit on the end if (m_data.Length % maximumTransmissionUnit != 0) { fragmentCount++; } // allocate space for the fragments IpV4Packet[] fragments = new IpV4Packet[fragmentCount]; // build each fragment for (int i = 0; i < fragments.Length; i++) { fragments[i] = new IpV4Packet (); fragments[i].SourceAddress = m_sourceAddress; fragments[i].DestinationAddress = m_destAddress; fragments[i].Identification = m_id; fragments[i].HeaderLength = 0x14; fragments[i].TimeToLive = m_ttl; fragments[i].TransportProtocol = m_protocol; fragments[i].TypeOfService = m_tos; fragments[i].Version = 0x04; #region Add Options // if there are options... if (m_options != null) { int optionsLength = 0; // if this is the first fragment, simply copy in all the options. if (i == 0) { fragments[i].Options = new IpV4Option[m_options.Length]; m_options.CopyTo (fragments[i].Options, 0); // calculate the size in bytes of the options field for (int j = 0; j < m_options.Length; j++) { optionsLength += m_options[j].Length; } } // if not, copy in the ones which have the copy flag set else { for (int j = 0; j < m_options.Length; j++) { if (m_options[j].IsCopied) { if (fragments[i].Options == null) { fragments[i].Options = new IpV4Option[1]; } else { // add this new option to the array IpV4Option[] tempOptions = new IpV4Option[fragments[i].Options.Length]; Array.Copy (fragments[i].Options, 0, tempOptions, 0, fragments[i].Options.Length); fragments[i].Options = new IpV4Option[fragments[i].Options.Length + 1]; Array.Copy (tempOptions, 0, fragments[i].Options, 0, tempOptions.Length); } fragments[i].Options[fragments[i].Options.Length - 1] = m_options[j]; // calculate the new size of the options optionsLength += m_options[j].Length; } } } fragments[i].HeaderLength += (ushort)optionsLength; // if we need padding to end the header on a 32 bit boundary if (optionsLength % 4 != 0) { // then add padding! fragments[i].Padding = new byte[4 - (optionsLength % 4)]; fragments[i].HeaderLength += (ushort)(4 - (optionsLength % 4)); } } #endregion // calculate the offset fragments[i].ControlFlags.Offset = (ushort)(i * maximumTransmissionUnit); // set up the control flags fragments[i].ControlFlags.MoreFragments = (i < fragments.Length - 1); fragments[i].ControlFlags.DontFragment = false; // copy the data into the buffer at the correct offset if ((i < fragments.Length - 1) || m_data.Length % maximumTransmissionUnit == 0) { fragments[i].Data = new byte[maximumTransmissionUnit]; Array.Copy (m_data, fragments[i].ControlFlags.Offset, fragments[i].Data, 0, maximumTransmissionUnit); } else { fragments[i].Data = new byte[m_data.Length % maximumTransmissionUnit]; Array.Copy (m_data, fragments[i].ControlFlags.Offset, fragments[i].Data, 0, m_data.Length % maximumTransmissionUnit); } // and finally the total size fragments[i].TotalLength = (ushort)(fragments[i].HeaderLength + fragments[i].Data.Length); } return fragments; }
/// <summary> /// Create a new IPv4 packet. /// </summary> /// <param name="data"> /// The byte array representing the IP packet. /// </param> public IpV4Packet (byte[] data) { int position = 0; #region Basic Fields // extract the version field from the first 4 bits of the packet m_version = Convert.ToByte ((data[position] >> 4)); // extract the header length field from the next 4 bits. This is the number // of 32 bit words so multiply by 4 to get the number of 8 bit words..i.e..bytes m_headerLength = Convert.ToByte ((data[position] & 0x0f) * 4); position++; // extract the precedence from the next 3 bits m_tos.Precedence = (IpV4PrecedenceType) (data[position] >> 5); // then extract the delay, throughput and reliability bits m_tos.Delay = (IpV4DelayType) ((data[position] & 0x10) >> 4); m_tos.Throughput = (IpV4ThroughputType) ((data[position] & 0x8) >> 3); m_tos.Reliability = (IpV4ReliabilityType) ((data[position] & 0x4) >> 2); position++; // get the total length (remembering to convert it to host order) m_totalLength = (ushort)(IPAddress.NetworkToHostOrder (BitConverter.ToInt16 (data, position))); position += 2; // same with the identification field m_id = (ushort)(IPAddress.NetworkToHostOrder (BitConverter.ToInt16 (data, position))); position += 2; // extract the internet control flags m_icf.DontFragment = ((data[position] & 0x40) >> 6) == 1; m_icf.MoreFragments = ((data[position] & 0x20) >> 5) == 1; // and the fragmentation offsent (remember to convert to host order) m_icf.Offset = (ushort)(IPAddress.NetworkToHostOrder ((Convert.ToInt16 (BitConverter.ToInt16 (data, position) & 0x1fff))) * 8); position += 2; // the time to live is just in a single byte m_ttl = data[position]; position++; // as is the protocol m_protocol = (ProtocolType)(data[position]); position++; // the checksum m_checksum = (ushort)(IPAddress.NetworkToHostOrder (BitConverter.ToInt16 (data, position))); position += 2; // now copy in the source address m_sourceAddress = new IPAddress (BitConverter.ToUInt32 (data, position)); position += 4; // and the destination address m_destAddress = new IPAddress (BitConverter.ToUInt32 (data, position)); position += 4; #endregion #region Options and Padding // check if there are any options (if the header length is greater than the // smallest, 0x14 bytes) if (m_headerLength > 0x14) { // create a new buffer of the correct size and copy the options into it byte[] optionsAndPadding = new byte[m_headerLength - 0x14]; Array.Copy (data, position, optionsAndPadding, 0, optionsAndPadding.Length); // go through each byte of the options for (int i = 0; i < optionsAndPadding.Length;) { IpV4Option option = new IpV4Option (); // fill in basic fields option.OptionType = (IpV4OptionNumber)optionsAndPadding[i]; i++; #region Fill in Basic Option Fields if (option.OptionType == IpV4OptionNumber.EndOfOptions) { // copy the padding field out of the header if (optionsAndPadding.Length - i > 0) { m_padding = new byte[optionsAndPadding.Length - i]; Array.Copy (optionsAndPadding, i, m_padding, 0, m_padding.Length); } // add this option to the array option.Length = 1; } else if (option.OptionType != IpV4OptionNumber.NoOperation) { // copy out the length field option.Length = (int)(optionsAndPadding[i]); option.Data = new byte[option.Length - 2]; // copy the actual data out of the packet i++; Array.Copy (optionsAndPadding, i, option.Data, 0, option.Data.Length); // add this new option to the array i += option.Data.Length; } else { option.Length = 1; } #endregion #region Add Option if (m_options == null) { m_options = new IpV4Option[1]; } else { IpV4Option[] tempOptions = new IpV4Option[m_options.Length]; Array.Copy (m_options, 0, tempOptions, 0, m_options.Length); m_options = new IpV4Option[m_options.Length + 1]; Array.Copy (tempOptions, 0, m_options, 0, tempOptions.Length); m_options[m_options.Length - 1] = option; } m_options[m_options.Length - 1] = option; #endregion if (option.OptionType == IpV4OptionNumber.EndOfOptions) { break; } } position += optionsAndPadding.Length; } #endregion // now check if there is any data (which there should be) if (data.Length > m_headerLength) { // allocate a new buffer for it and copy the data in to the buffer m_data = new byte[data.Length - m_headerLength]; Array.Copy (data, position, m_data, 0, m_data.Length); } }