Example #1
0
        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();
                    }
                }
            }
        }
Example #2
0
        public void AddRecord(DnsResourceRecord record)
        {
            AuthZone zone = GetOrAddSubDomainZone(record.Name);

            zone.AddRecord(record);

            if (zone is SubDomainZone)
            {
                (zone as SubDomainZone).AutoUpdateState();
            }
        }
Example #3
0
        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();
            }
        }
Example #4
0
        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();
            }
        }
Example #5
0
        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);
        }
Example #6
0
        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));
        }
Example #7
0
        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));
        }
Example #8
0
        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();
            }
        }
Example #9
0
        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);
        }
Example #10
0
        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();
                }
            }
        }
Example #11
0
        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);
        }
Example #12
0
        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);
                    }
                }
            }
        }
Example #13
0
        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;
            }
        }
Example #14
0
        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);
                }
            }
        }
Example #15
0
        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.");
            }
        }
Example #16
0
        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));
            }
        }