private void LoadRecords(AuthZone authZone, IReadOnlyList <DnsResourceRecord> records) { Dictionary <string, Dictionary <DnsResourceRecordType, List <DnsResourceRecord> > > groupedByDomainRecords = DnsResourceRecord.GroupRecords(records); foreach (KeyValuePair <string, Dictionary <DnsResourceRecordType, List <DnsResourceRecord> > > groupedByTypeRecords in groupedByDomainRecords) { if (authZone.Name.Equals(groupedByTypeRecords.Key, StringComparison.OrdinalIgnoreCase)) { foreach (KeyValuePair <DnsResourceRecordType, List <DnsResourceRecord> > groupedRecords in groupedByTypeRecords.Value) { authZone.LoadRecords(groupedRecords.Key, groupedRecords.Value); } } else { AuthZone zone = GetOrAddSubDomainZone(groupedByTypeRecords.Key); if (zone is SubDomainZone) { foreach (KeyValuePair <DnsResourceRecordType, List <DnsResourceRecord> > groupedRecords in groupedByTypeRecords.Value) { zone.LoadRecords(groupedRecords.Key, groupedRecords.Value); } (zone as SubDomainZone).AutoUpdateState(); } } } }
public void AddRecord(DnsResourceRecord record) { AuthZone zone = GetOrAddSubDomainZone(record.Name); zone.AddRecord(record); if (zone is SubDomainZone) { (zone as SubDomainZone).AutoUpdateState(); } }
public void AddRecord(string domain, DnsResourceRecordType type, uint ttl, DnsResourceRecordData record) { AuthZone zone = GetOrAddSubDomainZone(domain); zone.AddRecord(new DnsResourceRecord(zone.Name, type, DnsClass.IN, ttl, record)); if (zone is SubDomainZone) { (zone as SubDomainZone).AutoUpdateState(); } }
public void SetRecord(DnsResourceRecord record) { AuthZone zone = GetOrAddSubDomainZone(record.Name); zone.SetRecords(record.Type, new DnsResourceRecord[] { record }); if (zone is SubDomainZone) { (zone as SubDomainZone).AutoUpdateState(); } }
public bool TryGet(string zoneName, string domain, out AuthZone authZone) { if (TryGet(domain, out AuthZoneNode authZoneNode)) { authZone = authZoneNode.GetAuthZone(zoneName); return(authZone is not null); } authZone = null; return(false); }
private static DnsDatagram GetForwarderResponse(DnsDatagram request, AuthZone zone, AuthZone forwarderZone, bool isRecursionAllowed) { IReadOnlyList <DnsResourceRecord> authority = null; if (zone != null) { authority = zone.QueryRecords(DnsResourceRecordType.FWD); } if ((authority == null) || (authority.Count == 0)) { authority = forwarderZone.QueryRecords(DnsResourceRecordType.FWD); } return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, null, authority)); }
private DnsDatagram GetReferralResponse(DnsDatagram request, AuthZone delegationZone, bool isRecursionAllowed) { IReadOnlyList <DnsResourceRecord> authority; if (delegationZone is StubZone) { authority = delegationZone.GetRecords(DnsResourceRecordType.NS); //stub zone has no authority so cant query } else { authority = delegationZone.QueryRecords(DnsResourceRecordType.NS); } IReadOnlyList <DnsResourceRecord> additional = GetAdditionalRecords(authority); return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, null, authority, additional)); }
public void SetRecords(string domain, DnsResourceRecordType type, uint ttl, DnsResourceRecordData[] records) { DnsResourceRecord[] resourceRecords = new DnsResourceRecord[records.Length]; for (int i = 0; i < records.Length; i++) { resourceRecords[i] = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, records[i]); } AuthZone zone = GetOrAddSubDomainZone(domain); zone.SetRecords(type, resourceRecords); if (zone is SubDomainZone) { (zone as SubDomainZone).AutoUpdateState(); } }
public async Task <AuthZoneInfo> CreateStubZoneAsync(string domain, string primaryNameServerAddresses = null) { AuthZone authZone = await StubZone.CreateAsync(_dnsServer, domain, primaryNameServerAddresses); if (_root.TryAdd(authZone)) { (authZone as StubZone).RefreshZone(); return(new AuthZoneInfo(authZone)); } if (_root.TryGet(domain, out AuthZone existingZone) && (existingZone is SubDomainZone)) { _root[domain] = authZone; (authZone as StubZone).RefreshZone(); return(new AuthZoneInfo(authZone)); } return(null); }
private void LoadRecords(IReadOnlyList <DnsResourceRecord> records) { Dictionary <string, Dictionary <DnsResourceRecordType, List <DnsResourceRecord> > > groupedByDomainRecords = DnsResourceRecord.GroupRecords(records); foreach (KeyValuePair <string, Dictionary <DnsResourceRecordType, List <DnsResourceRecord> > > groupedByTypeRecords in groupedByDomainRecords) { AuthZone zone = GetOrAddZone(groupedByTypeRecords.Key); foreach (KeyValuePair <DnsResourceRecordType, List <DnsResourceRecord> > groupedRecords in groupedByTypeRecords.Value) { zone.LoadRecords(groupedRecords.Key, groupedRecords.Value); } if (zone is SubDomainZone) { (zone as SubDomainZone).AutoUpdateState(); } } }
private IReadOnlyList <DnsResourceRecord> GetAdditionalRecords(IReadOnlyList <DnsResourceRecord> nsRecords) { IReadOnlyList <DnsResourceRecord> glueRecords = nsRecords.GetGlueRecords(); if (glueRecords.Count > 0) { return(glueRecords); } List <DnsResourceRecord> additionalRecords = new List <DnsResourceRecord>(); foreach (DnsResourceRecord nsRecord in nsRecords) { if (nsRecord.Type != DnsResourceRecordType.NS) { continue; } AuthZone authZone = _root.FindZone((nsRecord.RDATA as DnsNSRecord).NameServer, out _, out _, out _); if ((authZone != null) && authZone.IsActive) { { IReadOnlyList <DnsResourceRecord> records = authZone.QueryRecords(DnsResourceRecordType.A); if ((records.Count > 0) && (records[0].RDATA is DnsARecord)) { additionalRecords.AddRange(records); } } { IReadOnlyList <DnsResourceRecord> records = authZone.QueryRecords(DnsResourceRecordType.AAAA); if ((records.Count > 0) && (records[0].RDATA is DnsAAAARecord)) { additionalRecords.AddRange(records); } } } } return(additionalRecords); }
private void ResolveAdditionalRecords(string domain, List <DnsResourceRecord> additionalRecords) { AuthZone authZone = _root.FindZone(domain, out _, out _, out _); if ((authZone != null) && authZone.IsActive) { { IReadOnlyList <DnsResourceRecord> records = authZone.QueryRecords(DnsResourceRecordType.A); if ((records.Count > 0) && (records[0].RDATA is DnsARecord)) { additionalRecords.AddRange(records); } } { IReadOnlyList <DnsResourceRecord> records = authZone.QueryRecords(DnsResourceRecordType.AAAA); if ((records.Count > 0) && (records[0].RDATA is DnsAAAARecord)) { additionalRecords.AddRange(records); } } } }
public void UpdateRecord(DnsResourceRecord oldRecord, DnsResourceRecord newRecord) { if (oldRecord.Type != newRecord.Type) { throw new DnsServerException("Cannot update record: new record must be of same type."); } if (oldRecord.Type == DnsResourceRecordType.SOA) { throw new DnsServerException("Cannot update record: use SetRecords() for updating SOA record."); } if (!_root.TryGet(oldRecord.Name, out AuthZone zone)) { throw new DnsServerException("Cannot update record: zone does not exists."); } switch (oldRecord.Type) { case DnsResourceRecordType.CNAME: case DnsResourceRecordType.PTR: case DnsResourceRecordType.APP: if (oldRecord.Name.Equals(newRecord.Name, StringComparison.OrdinalIgnoreCase)) { zone.SetRecords(newRecord.Type, new DnsResourceRecord[] { newRecord }); if (zone is SubDomainZone) { (zone as SubDomainZone).AutoUpdateState(); } } else { zone.DeleteRecords(oldRecord.Type); if (zone is SubDomainZone) { if (zone.IsEmpty) { _root.TryRemove(oldRecord.Name, out _); //remove empty sub zone } else { (zone as SubDomainZone).AutoUpdateState(); } } AuthZone newZone = GetOrAddSubDomainZone(newRecord.Name); newZone.SetRecords(newRecord.Type, new DnsResourceRecord[] { newRecord }); if (newZone is SubDomainZone) { (newZone as SubDomainZone).AutoUpdateState(); } } break; default: if (oldRecord.Name.Equals(newRecord.Name, StringComparison.OrdinalIgnoreCase)) { zone.DeleteRecord(oldRecord.Type, oldRecord.RDATA); zone.AddRecord(newRecord); if (zone is SubDomainZone) { (zone as SubDomainZone).AutoUpdateState(); } } else { zone.DeleteRecord(oldRecord.Type, oldRecord.RDATA); if (zone is SubDomainZone) { if (zone.IsEmpty) { _root.TryRemove(oldRecord.Name, out _); //remove empty sub zone } else { (zone as SubDomainZone).AutoUpdateState(); } } AuthZone newZone = GetOrAddSubDomainZone(newRecord.Name); newZone.AddRecord(newRecord); if (newZone is SubDomainZone) { (newZone as SubDomainZone).AutoUpdateState(); } } break; } }
public void SyncRecords(string domain, IReadOnlyList <DnsResourceRecord> syncRecords, IReadOnlyList <DnsResourceRecord> additionalRecords = null, bool dontRemoveRecords = false) { List <DnsResourceRecord> newRecords = new List <DnsResourceRecord>(syncRecords.Count); List <DnsResourceRecord> allGlueRecords = new List <DnsResourceRecord>(); if (additionalRecords != null) { foreach (DnsResourceRecord additionalRecord in additionalRecords) { if (!allGlueRecords.Contains(additionalRecord)) { allGlueRecords.Add(additionalRecord); } } } int i = 0; if ((syncRecords.Count > 1) && (syncRecords[0].Type == DnsResourceRecordType.SOA) && (syncRecords[syncRecords.Count - 1].Type == DnsResourceRecordType.SOA)) { i = 1; //skip first SOA in AXFR } if (domain.Length == 0) { //root zone case for (; i < syncRecords.Count; i++) { DnsResourceRecord record = syncRecords[i]; switch (record.Type) { case DnsResourceRecordType.A: case DnsResourceRecordType.AAAA: if (!allGlueRecords.Contains(record)) { allGlueRecords.Add(record); } break; default: newRecords.Add(record); break; } } } else { for (; i < syncRecords.Count; i++) { DnsResourceRecord record = syncRecords[i]; if (record.Name.Equals(domain, StringComparison.OrdinalIgnoreCase) || record.Name.EndsWith("." + domain, StringComparison.OrdinalIgnoreCase)) { newRecords.Add(record); } else if (!allGlueRecords.Contains(record)) { allGlueRecords.Add(record); } } } if (allGlueRecords.Count > 0) { foreach (DnsResourceRecord record in newRecords) { switch (record.Type) { case DnsResourceRecordType.NS: record.SyncGlueRecords(allGlueRecords); break; } } } List <DnsResourceRecord> oldRecords = ListAllRecords(domain); Dictionary <string, Dictionary <DnsResourceRecordType, List <DnsResourceRecord> > > newRecordsGroupedByDomain = DnsResourceRecord.GroupRecords(newRecords); Dictionary <string, Dictionary <DnsResourceRecordType, List <DnsResourceRecord> > > oldRecordsGroupedByDomain = DnsResourceRecord.GroupRecords(oldRecords); if (!dontRemoveRecords) { //remove domains that do not exists in new records foreach (KeyValuePair <string, Dictionary <DnsResourceRecordType, List <DnsResourceRecord> > > oldDomain in oldRecordsGroupedByDomain) { if (!newRecordsGroupedByDomain.ContainsKey(oldDomain.Key)) { _root.TryRemove(oldDomain.Key, out _); } } } //sync new records foreach (KeyValuePair <string, Dictionary <DnsResourceRecordType, List <DnsResourceRecord> > > newEntries in newRecordsGroupedByDomain) { AuthZone zone = GetOrAddSubDomainZone(newEntries.Key); if (zone.Name.Equals(domain, StringComparison.OrdinalIgnoreCase)) { zone.SyncRecords(newEntries.Value, dontRemoveRecords); } else if (zone is SubDomainZone) { zone.SyncRecords(newEntries.Value, dontRemoveRecords); } } }
public void LoadZoneFrom(Stream s) { BinaryReader bR = new BinaryReader(s); if (Encoding.ASCII.GetString(bR.ReadBytes(2)) != "DZ") { throw new InvalidDataException("DnsServer zone file format is invalid."); } switch (bR.ReadByte()) { case 2: { DnsResourceRecord[] records = new DnsResourceRecord[bR.ReadInt32()]; if (records.Length > 0) { DnsResourceRecord soaRecord = null; for (int i = 0; i < records.Length; i++) { records[i] = new DnsResourceRecord(s); if (records[i].Type == DnsResourceRecordType.SOA) { soaRecord = records[i]; } } if (soaRecord == null) { throw new InvalidDataException("Zone does not contain SOA record."); } //make zone info AuthZoneType zoneType; if (_dnsServer.ServerDomain.Equals((soaRecord.RDATA as DnsSOARecord).PrimaryNameServer, StringComparison.OrdinalIgnoreCase)) { zoneType = AuthZoneType.Primary; } else { zoneType = AuthZoneType.Stub; } AuthZoneInfo zoneInfo = new AuthZoneInfo(records[0].Name, zoneType, false); //create zone AuthZone authZone = CreateEmptyZone(zoneInfo); try { //load records LoadRecords(authZone, records); } catch { DeleteZone(zoneInfo.Name); throw; } //init zone switch (zoneInfo.Type) { case AuthZoneType.Primary: (authZone as PrimaryZone).NotifyNameServers(); break; } } } break; case 3: { bool zoneDisabled = bR.ReadBoolean(); DnsResourceRecord[] records = new DnsResourceRecord[bR.ReadInt32()]; if (records.Length > 0) { DnsResourceRecord soaRecord = null; for (int i = 0; i < records.Length; i++) { records[i] = new DnsResourceRecord(s); records[i].Tag = new DnsResourceRecordInfo(bR); if (records[i].Type == DnsResourceRecordType.SOA) { soaRecord = records[i]; } } if (soaRecord == null) { throw new InvalidDataException("Zone does not contain SOA record."); } //make zone info AuthZoneType zoneType; if (_dnsServer.ServerDomain.Equals((soaRecord.RDATA as DnsSOARecord).PrimaryNameServer, StringComparison.OrdinalIgnoreCase)) { zoneType = AuthZoneType.Primary; } else { zoneType = AuthZoneType.Stub; } AuthZoneInfo zoneInfo = new AuthZoneInfo(records[0].Name, zoneType, zoneDisabled); //create zone AuthZone authZone = CreateEmptyZone(zoneInfo); try { //load records LoadRecords(authZone, records); } catch { DeleteZone(zoneInfo.Name); throw; } //init zone switch (zoneInfo.Type) { case AuthZoneType.Primary: (authZone as PrimaryZone).NotifyNameServers(); break; } } } break; case 4: { //read zone info AuthZoneInfo zoneInfo = new AuthZoneInfo(bR); //create zone AuthZone authZone = CreateEmptyZone(zoneInfo); //read all zone records DnsResourceRecord[] records = new DnsResourceRecord[bR.ReadInt32()]; if (records.Length > 0) { for (int i = 0; i < records.Length; i++) { records[i] = new DnsResourceRecord(s); records[i].Tag = new DnsResourceRecordInfo(bR); } try { //load records LoadRecords(authZone, records); } catch { DeleteZone(zoneInfo.Name); throw; } //init zone switch (zoneInfo.Type) { case AuthZoneType.Primary: (authZone as PrimaryZone).NotifyNameServers(); break; case AuthZoneType.Secondary: (authZone as SecondaryZone).RefreshZone(); break; case AuthZoneType.Stub: (authZone as StubZone).RefreshZone(); break; } } } break; default: throw new InvalidDataException("DNS Zone file version not supported."); } }
public DnsDatagram Query(DnsDatagram request, bool isRecursionAllowed) { AuthZone zone = _root.FindZone(request.Question[0].Name, out AuthZone delegation, out AuthZone authZone, out bool hasSubDomains); if ((authZone == null) || !authZone.IsActive) //no authority for requested zone { return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.Refused, request.Question)); } if ((delegation != null) && delegation.IsActive) { return(GetReferralResponse(request, delegation, isRecursionAllowed)); } if ((zone == null) || !zone.IsActive) { //zone not found if (authZone is StubZone) { return(GetReferralResponse(request, authZone, isRecursionAllowed)); } else if (authZone is ForwarderZone) { return(GetForwarderResponse(request, null, authZone, isRecursionAllowed)); } DnsResponseCode rCode = DnsResponseCode.NoError; IReadOnlyList <DnsResourceRecord> authority = authZone.QueryRecords(DnsResourceRecordType.APP); if (authority.Count == 0) { if (!hasSubDomains) { rCode = DnsResponseCode.NxDomain; } authority = authZone.GetRecords(DnsResourceRecordType.SOA); } return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, true, false, request.RecursionDesired, isRecursionAllowed, false, false, rCode, request.Question, null, authority)); } else { //zone found IReadOnlyList <DnsResourceRecord> authority; IReadOnlyList <DnsResourceRecord> additional; IReadOnlyList <DnsResourceRecord> answers = zone.QueryRecords(request.Question[0].Type); if (answers.Count == 0) { //record type not found if (authZone is StubZone) { return(GetReferralResponse(request, authZone, isRecursionAllowed)); } else if (authZone is ForwarderZone) { return(GetForwarderResponse(request, zone, authZone, isRecursionAllowed)); } authority = zone.QueryRecords(DnsResourceRecordType.APP); if (authority.Count == 0) { authority = authZone.QueryRecords(DnsResourceRecordType.APP); if (authority.Count == 0) { authority = authZone.GetRecords(DnsResourceRecordType.SOA); } } additional = null; } else { //record type found if (zone.Name.Contains("*")) { //wildcard zone; generate new answer records DnsResourceRecord[] wildcardAnswers = new DnsResourceRecord[answers.Count]; for (int i = 0; i < answers.Count; i++) { wildcardAnswers[i] = new DnsResourceRecord(request.Question[0].Name, answers[i].Type, answers[i].Class, answers[i].TtlValue, answers[i].RDATA) { Tag = answers[i].Tag } } ; answers = wildcardAnswers; } switch (request.Question[0].Type) { case DnsResourceRecordType.NS: case DnsResourceRecordType.MX: case DnsResourceRecordType.SRV: authority = null; additional = GetAdditionalRecords(answers); break; case DnsResourceRecordType.ANY: authority = null; additional = null; break; default: authority = authZone.QueryRecords(DnsResourceRecordType.NS); additional = GetAdditionalRecords(authority); break; } } return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answers, authority, additional)); } }