/// <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); }
/// <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); }