/// <inheritdoc />
        public override IWireSerialiser Read(WireReader reader)
        {
            // Read standard properties of a resource record.
            Name  = reader.ReadDomainName();
            Type  = (DnsType)reader.ReadUInt16();
            Class = (DnsClass)reader.ReadUInt16();
            TTL   = reader.ReadTimeSpan32();
            int length = reader.ReadUInt16();

            // Find a specific class for the TYPE or default
            // to UnknownRecord.
            var specific = ResourceRegistry.Create(Type);

            specific.Name  = Name;
            specific.Type  = Type;
            specific.Class = Class;
            specific.TTL   = TTL;

            // Read the specific properties of the resource record.
            var end = reader.Position + length;

            specific.ReadData(reader, length);
            if (reader.Position != end)
            {
                throw new InvalidDataException("Found extra data while decoding RDATA.");
            }

            return(specific);
        }
Exemple #2
0
        /// <summary>
        ///   Read a resource record.
        /// </summary>
        /// <returns>
        ///   A <see cref="ResourceRecord"/> or <b>null</b> if no more
        ///   resource records are available.
        /// </returns>
        /// <remarks>
        ///   Processes the "$ORIGIN" and "$TTL" specials that define the
        ///   <see cref="Origin"/> and a default time-to-live respectively.
        ///   <para>
        ///   A domain name can be "@" to refer to the <see cref="Origin"/>.
        ///   A missing domain name will use the previous record's domain name.
        ///   </para>
        ///   <para>
        ///   Defaults the <see cref="ResourceRecord.Class"/> to <see cref="DnsClass.IN"/>.
        ///   Defaults the <see cref="ResourceRecord.TTL"/>  to either the "$TTL" or
        ///   the <see cref="ResourceRecord.DefaultTTL"/>.
        ///   </para>
        /// </remarks>
        public ResourceRecord ReadResourceRecord()
        {
            DomainName domainName = defaultDomainName;
            DnsClass   klass      = DnsClass.IN;
            TimeSpan?  ttl        = defaultTTL;
            DnsType?   type       = null;

            while (!type.HasValue)
            {
                var token = ReadToken(ignoreEscape: true);
                if (token == "")
                {
                    return(null);
                }

                // Domain names and directives must be at the start of a line.
                if (tokenStartsNewLine)
                {
                    switch (token)
                    {
                    case "$ORIGIN":
                        Origin = ReadDomainName();
                        break;

                    case "$TTL":
                        defaultTTL = ttl = ReadTimeSpan32();
                        break;

                    case "@":
                        domainName        = Origin;
                        defaultDomainName = domainName;
                        break;

                    default:
                        domainName        = MakeAbsoluteDomainName(token);
                        defaultDomainName = domainName;
                        break;
                    }
                    continue;
                }

                // Is TTL?
                if (token.All(c => Char.IsDigit(c)))
                {
                    ttl = TimeSpan.FromSeconds(uint.Parse(token));
                    continue;
                }

                // Is TYPE?
                if (token.StartsWith("TYPE"))
                {
                    type = (DnsType)ushort.Parse(token.Substring(4), CultureInfo.InvariantCulture);
                    continue;
                }
                if (token.ToLowerInvariant() != "any" && Enum.TryParse <DnsType>(token, out DnsType t))
                {
                    type = t;
                    continue;
                }

                // Is CLASS?
                if (token.StartsWith("CLASS"))
                {
                    klass = (DnsClass)ushort.Parse(token.Substring(5), CultureInfo.InvariantCulture);
                    continue;
                }
                if (Enum.TryParse <DnsClass>(token, out DnsClass k))
                {
                    klass = k;
                    continue;
                }

                throw new InvalidDataException($"Unknown token '{token}', expected a Class, Type or TTL.");
            }

            if (domainName == null)
            {
                throw new InvalidDataException("Missing resource record name.");
            }

            // Create the specific resource record based on the type.
            var resource = ResourceRegistry.Create(type.Value);

            resource.Name  = domainName;
            resource.Type  = type.Value;
            resource.Class = klass;
            if (ttl.HasValue)
            {
                resource.TTL = ttl.Value;
            }

            // Read the specific properties of the resource record.
            resource.ReadData(this);

            return(resource);
        }