private ZoneCollection SignWithNSec3(DateTime inception, DateTime expiration, List <DnsKeyRecord> zoneSigningKeys, List <DnsKeyRecord> keySigningKeys, NSec3HashAlgorithm nsec3Algorithm, int nsec3Iterations, byte[] nsec3Salt, bool nsec3OptOut) { var soaRecord = _records.OfType <SoaRecord>().First(); var subZoneNameserver = _records.Where(x => (x.RecordType == RecordType.Ns) && (x.Name != Name)).ToList(); var subZones = subZoneNameserver.Select(x => x.Name).Distinct().ToList(); var unsignedRecords = _records.Where(x => subZones.Any(y => x.Name.IsSubDomainOf(y))).ToList(); // glue records if (nsec3OptOut) { unsignedRecords = unsignedRecords.Union(subZoneNameserver.Where(x => !_records.Any(y => (y.RecordType == RecordType.Ds) && (y.Name == x.Name)))).ToList(); // delegations without DS record } var recordsByName = _records.Except(unsignedRecords).Union(zoneSigningKeys).Union(keySigningKeys).GroupBy(x => x.Name).Select(x => new Tuple <DomainName, List <DnsRecordBase> >(x.Key, x.OrderBy(y => y.RecordType == RecordType.Soa ? -1 : (int)y.RecordType).ToList())).OrderBy(x => x.Item1).ToList(); byte nsec3RecordFlags = (byte)(nsec3OptOut ? 1 : 0); ZoneCollection res = new ZoneCollection(Name, Count * 3); List <NSec3Record> nSec3Records = new List <NSec3Record>(Count); if (nsec3Salt == null) { nsec3Salt = _secureRandom.GenerateSeed(8); } recordsByName[0].Item2.Add(new NSec3ParamRecord(soaRecord.Name, soaRecord.RecordClass, 0, nsec3Algorithm, 0, (ushort)nsec3Iterations, nsec3Salt)); HashSet <DomainName> allNames = new HashSet <DomainName>(); for (int i = 0; i < recordsByName.Count; i++) { List <RecordType> recordTypes = new List <RecordType>(); DomainName currentName = recordsByName[i].Item1; foreach (var recordsByType in recordsByName[i].Item2.GroupBy(x => x.RecordType)) { List <DnsRecordBase> records = recordsByType.ToList(); recordTypes.Add(recordsByType.Key); res.AddRange(records); // do not sign nameserver delegations for sub zones if ((records[0].RecordType == RecordType.Ns) && (currentName != Name)) { continue; } recordTypes.Add(RecordType.RrSig); foreach (var key in zoneSigningKeys) { res.Add(new RrSigRecord(records, key, inception, expiration)); } if (records[0].RecordType == RecordType.DnsKey) { foreach (var key in keySigningKeys) { res.Add(new RrSigRecord(records, key, inception, expiration)); } } } byte[] hash = recordsByName[i].Item1.GetNSec3Hash(nsec3Algorithm, nsec3Iterations, nsec3Salt); nSec3Records.Add(new NSec3Record(DomainName.ParseFromMasterfile(hash.ToBase32HexString()) + Name, soaRecord.RecordClass, soaRecord.NegativeCachingTTL, nsec3Algorithm, nsec3RecordFlags, (ushort)nsec3Iterations, nsec3Salt, hash, recordTypes)); allNames.Add(currentName); for (int j = currentName.LabelCount - Name.LabelCount; j > 0; j--) { DomainName possibleNonTerminal = currentName.GetParentName(j); if (!allNames.Contains(possibleNonTerminal)) { hash = possibleNonTerminal.GetNSec3Hash(nsec3Algorithm, nsec3Iterations, nsec3Salt); nSec3Records.Add(new NSec3Record(DomainName.ParseFromMasterfile(hash.ToBase32HexString()) + Name, soaRecord.RecordClass, soaRecord.NegativeCachingTTL, nsec3Algorithm, nsec3RecordFlags, (ushort)nsec3Iterations, nsec3Salt, hash, new List <RecordType>())); allNames.Add(possibleNonTerminal); } } } nSec3Records = nSec3Records.OrderBy(x => x.Name).ToList(); byte[] firstNextHashedOwnerName = nSec3Records[0].NextHashedOwnerName; for (int i = 1; i < nSec3Records.Count; i++) { nSec3Records[i - 1].NextHashedOwnerName = nSec3Records[i].NextHashedOwnerName; } nSec3Records[nSec3Records.Count - 1].NextHashedOwnerName = firstNextHashedOwnerName; foreach (var nSec3Record in nSec3Records) { res.Add(nSec3Record); foreach (var key in zoneSigningKeys) { res.Add(new RrSigRecord(new List <DnsRecordBase>() { nSec3Record }, key, inception, expiration)); } } res.AddRange(unsignedRecords); return(res); }
private ZoneCollection SignWithNSec(DateTime inception, DateTime expiration, List <DnsKeyRecord> zoneSigningKeys, List <DnsKeyRecord> keySigningKeys) { var soaRecord = _records.OfType <SoaRecord>().First(); var subZones = _records.Where(x => (x.RecordType == RecordType.Ns) && (x.Name != Name)).Select(x => x.Name).Distinct().ToList(); var glueRecords = _records.Where(x => subZones.Any(y => x.Name.IsSubDomainOf(y))).ToList(); var recordsByName = _records.Except(glueRecords).Union(zoneSigningKeys).Union(keySigningKeys).GroupBy(x => x.Name).Select(x => new Tuple <DomainName, List <DnsRecordBase> >(x.Key, x.OrderBy(y => y.RecordType == RecordType.Soa ? -1 : (int)y.RecordType).ToList())).OrderBy(x => x.Item1).ToList(); ZoneCollection res = new ZoneCollection(Name, Count * 3); for (int i = 0; i < recordsByName.Count; i++) { List <RecordType> recordTypes = new List <RecordType>(); DomainName currentName = recordsByName[i].Item1; foreach (var recordsByType in recordsByName[i].Item2.GroupBy(x => x.RecordType)) { List <DnsRecordBase> records = recordsByType.ToList(); recordTypes.Add(recordsByType.Key); res.AddRange(records); // do not sign nameserver delegations for sub zones if ((records[0].RecordType == RecordType.Ns) && (currentName != Name)) { continue; } recordTypes.Add(RecordType.RrSig); foreach (var key in zoneSigningKeys) { res.Add(new RrSigRecord(records, key, inception, expiration)); } if (records[0].RecordType == RecordType.DnsKey) { foreach (var key in keySigningKeys) { res.Add(new RrSigRecord(records, key, inception, expiration)); } } } recordTypes.Add(RecordType.NSec); NSecRecord nsecRecord = new NSecRecord(recordsByName[i].Item1, soaRecord.RecordClass, soaRecord.NegativeCachingTTL, recordsByName[(i + 1) % recordsByName.Count].Item1, recordTypes); res.Add(nsecRecord); foreach (var key in zoneSigningKeys) { res.Add(new RrSigRecord(new List <DnsRecordBase>() { nsecRecord }, key, inception, expiration)); } } res.AddRange(glueRecords); return(res); }