/* This file is part of PacketDotNet PacketDotNet is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. PacketDotNet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PacketDotNet. If not, see . */ /* * Copyright 2009 Chris Morgan */ using System; using System.Collections.Generic; using System.Text; using PacketDotNet.Utils; using MiscUtil.Conversion; namespace PacketDotNet { /// /// User datagram protocol /// See http://en.wikipedia.org/wiki/Udp /// public class UdpPacket : TransportPacket { // NOTE: No need to warn about lack of use, the compiler won't // put any calls to 'log' here but we need 'log' to exist to compile #pragma warning disable 0169, 0649 private static readonly ILogInactive log; #pragma warning restore 0169, 0649 /// Fetch the port number on the source host. virtual public ushort SourcePort { get { return EndianBitConverter.Big.ToUInt16(header.Bytes, header.Offset + UdpFields.SourcePortPosition); } set { var val = value; EndianBitConverter.Big.CopyBytes(val, header.Bytes, header.Offset + UdpFields.SourcePortPosition); } } /// Fetch the port number on the target host. virtual public ushort DestinationPort { get { return EndianBitConverter.Big.ToUInt16(header.Bytes, header.Offset + UdpFields.DestinationPortPosition); } set { var val = value; EndianBitConverter.Big.CopyBytes(val, header.Bytes, header.Offset + UdpFields.DestinationPortPosition); } } /// /// Length in bytes of the header and payload, minimum size of 8, /// the size of the Udp header /// virtual public int Length { get { return EndianBitConverter.Big.ToInt16(header.Bytes, header.Offset + UdpFields.HeaderLengthPosition); } // Internal because it is updated based on the payload when // its bytes are retrieved internal set { var val = (Int16)value; EndianBitConverter.Big.CopyBytes(val, header.Bytes, header.Offset + UdpFields.HeaderLengthPosition); } } /// Fetch the header checksum. override public ushort Checksum { get { return EndianBitConverter.Big.ToUInt16(header.Bytes, header.Offset + UdpFields.ChecksumPosition); } set { var val = value; EndianBitConverter.Big.CopyBytes(val, header.Bytes, header.Offset + UdpFields.ChecksumPosition); } } /// Check if the UDP packet is valid, checksum-wise. public bool ValidChecksum { get { // IPv6 has no checksum so only the TCP checksum needs evaluation if (ParentPacket.GetType() == typeof(IPv6Packet)) return ValidUDPChecksum; // For IPv4 both the IP layer and the TCP layer contain checksums else return ((IPv4Packet)ParentPacket).ValidIPChecksum && ValidUDPChecksum; } } /// /// True if the udp checksum is valid /// virtual public bool ValidUDPChecksum { get { log.Debug("ValidUDPChecksum"); var retval = IsValidChecksum(TransportPacket.TransportChecksumOption.AttachPseudoIPHeader); log.DebugFormat("ValidUDPChecksum {0}", retval); return retval; } } /// Fetch ascii escape sequence of the color associated with this packet type. override public System.String Color { get { return AnsiEscapeSequences.LightGreen; } } /// /// Update the Udp length /// public override void UpdateCalculatedValues () { // update the length field based on the length of this packet header // plus the length of all of the packets it contains Length = TotalPacketLength; UpdateUDPChecksum(); } /// /// Create from values /// /// /// A /// /// /// A /// public UdpPacket(ushort SourcePort, ushort DestinationPort) { log.Debug(""); // allocate memory for this packet int offset = 0; int length = UdpFields.HeaderLength; var headerBytes = new byte[length]; header = new ByteArraySegment(headerBytes, offset, length); // set instance values this.SourcePort = SourcePort; this.DestinationPort = DestinationPort; } /// /// Constructor /// /// /// A /// public UdpPacket(ByteArraySegment bas) { log.DebugFormat("bas {0}", bas.ToString()); // set the header field, header field values are retrieved from this byte array header = new ByteArraySegment(bas); RandomUtils.EnsurePacketLength(this, UdpFields.HeaderLength, header.Length); header.Length = UdpFields.HeaderLength; payloadPacketOrData = new PacketOrByteArraySegment(); // is this packet going to port 7 or 9? if so it might be a WakeOnLan packet const int wakeOnLanPort0 = 7; const int wakeOnLanPort1 = 9; if(DestinationPort.Equals(wakeOnLanPort0) || DestinationPort.Equals (wakeOnLanPort1)) { payloadPacketOrData.ThePacket = new WakeOnLanPacket(header.EncapsulatedBytes()); } else { // store the payload bytes payloadPacketOrData.TheByteArraySegment = header.EncapsulatedBytes(); } } /// /// Constructor /// /// /// A /// /// /// A /// public UdpPacket(ByteArraySegment bas, Packet ParentPacket) : this(bas) { this.ParentPacket = ParentPacket; } /// /// Calculates the UDP checksum, optionally updating the UDP checksum header. /// /// The calculated UDP checksum. public int CalculateUDPChecksum() { var newChecksum = CalculateChecksum(TransportChecksumOption.AttachPseudoIPHeader); return newChecksum; } /// /// Update the checksum value. /// public void UpdateUDPChecksum() { this.Checksum = (ushort)CalculateUDPChecksum(); } /// public override string ToString(StringOutputType outputFormat) { var buffer = new StringBuilder(); string color = ""; string colorEscape = ""; if(outputFormat == StringOutputType.Colored || outputFormat == StringOutputType.VerboseColored) { color = Color; colorEscape = AnsiEscapeSequences.Reset; } if(outputFormat == StringOutputType.Normal || outputFormat == StringOutputType.Colored) { buffer.AppendFormat("{0}[UDPPacket: SourcePort={2}, DestinationPort={3}]{1}", color, colorEscape, SourcePort, DestinationPort); } if(outputFormat == StringOutputType.Verbose || outputFormat == StringOutputType.VerboseColored) { // collect the properties and their value Dictionary properties = new Dictionary(); properties.Add("source", SourcePort.ToString()); properties.Add("destination", DestinationPort.ToString()); properties.Add("length", Length.ToString()); properties.Add("checksum", "0x" + Checksum.ToString("x") + " [" + (ValidUDPChecksum ? "valid" : "invalid") + "]"); // calculate the padding needed to right-justify the property names int padLength = Utils.RandomUtils.LongestStringLength(new List(properties.Keys)); // build the output string buffer.AppendLine("UDP: ******* UDP - \"User Datagram Protocol\" - offset=? length=" + TotalPacketLength); buffer.AppendLine("UDP:"); foreach(var property in properties) { buffer.AppendLine("UDP: " + property.Key.PadLeft(padLength) + " = " + property.Value); } buffer.AppendLine("UDP:"); } // append the base string output buffer.Append(base.ToString(outputFormat)); return buffer.ToString(); } /// /// Returns the UdpPacket inside of the Packet p or null if /// there is no encapsulated packet /// /// /// A /// /// /// A /// [Obsolete("Use Packet.Extract() instead")] public static UdpPacket GetEncapsulated(Packet p) { if(p is InternetLinkLayerPacket) { var payload = InternetLinkLayerPacket.GetInnerPayload((InternetLinkLayerPacket)p); if(payload is IpPacket) { var innerPayload = payload.PayloadPacket; if(innerPayload is UdpPacket) { return (UdpPacket)innerPayload; } } } return null; } /// /// Generate a random packet /// /// /// A /// public static UdpPacket RandomPacket() { var rnd = new Random(); var SourcePort = (ushort)rnd.Next(ushort.MinValue, ushort.MaxValue); var DestinationPort = (ushort)rnd.Next(ushort.MinValue, ushort.MaxValue); return new UdpPacket(SourcePort, DestinationPort); } } }