Page MenuHomeGRNET

No OneTemporary

File Metadata

Created
Sun, May 18, 3:15 AM
diff --git a/app/models/domain.rb b/app/models/domain.rb
index deafa86..0fd518f 100644
--- a/app/models/domain.rb
+++ b/app/models/domain.rb
@@ -1,110 +1,124 @@
class Domain < ActiveRecord::Base
+ class NotAChild < StandardError; end
self.inheritance_column = :nx
# List all supported domain types.
def self.domain_types
[
'NATIVE',
'MASTER',
'SLAVE',
]
end
# List domain types that can be created.
def self.allowed_domain_types
domain_types - WebDNS.settings[:prohibit_domain_types]
end
belongs_to :group
has_many :records
# BUG in bump_serial_trigger
has_one :soa, -> { unscope(where: :type) }, class_name: SOA
validates :group_id, presence: true
validates :name, uniqueness: true, presence: true
validates :type, presence: true, inclusion: { in: domain_types }
validates :master, presence: true, ipv4: true, if: :slave?
after_create :generate_soa
after_create :generate_ns
attr_writer :serial_strategy
# Get the zone's serial strategy.
#
# Returns one of the supported serial strategies.
def serial_strategy
@serial_strategy ||= WebDNS.settings[:serial_strategy]
end
# Returns true if this a reverse zone.
def reverse?
name.end_with?('.in-addr.arpa') || name.end_with?('.ip6.arpa')
end
# Returns true if this a ENUM zone.
def enum?
name.end_with?('.e164.arpa')
end
# Returns true if this is a slave zone.
def slave?
type == 'SLAVE'
end
# Compute subnet for reverse records
def subnet
return if not reverse?
if name.end_with?('.in-addr.arpa')
subnet_v4
elsif name.end_with?('.ip6.arpa')
subnet_v6
end
end
+ def self.replace_ds(parent, child, records)
+ parent = find_by_name!(parent)
+ fail NotAChild if not child.end_with?(parent.name)
+
+ existing = parent.records.where(name: child, type: 'DS')
+ recs = records.map { |rec| DS.new(domain: parent, name: child, content: rec) }
+
+ ActiveRecord::Base.transaction do
+ existing.destroy_all
+ recs.map(&:save!)
+ end
+ end
+
private
def subnet_v4
# get ip octets (remove .in-addr.arpa)
octets = name.split('.')[0...-2].reverse
return if octets.any? { |_| false }
mask = 8 * octets.size
octets += [0, 0, 0, 0]
ip = IPAddr.new octets[0, 4].join('.')
[ip, mask].join('/')
end
def subnet_v6
nibbles = name.split('.')[0...-2].reverse
return if nibbles.any? { |_| false }
mask = 4 * nibbles.size
nibbles += [0] * 32
ip = IPAddr.new nibbles[0, 32].in_groups_of(4).map(&:join).join(':')
[ip, mask].join('/')
end
# Hooks
def generate_soa
soa_record = SOA.new(domain: self)
soa_record.save!
end
def generate_ns
return if slave?
return if WebDNS.settings[:default_ns].empty?
WebDNS.settings[:default_ns].each { |ns|
Record.find_or_create_by!(domain: self, type: 'NS', name: '', content: ns)
}
end
end
diff --git a/test/models/domain_test.rb b/test/models/domain_test.rb
index 44852e2..6479a74 100644
--- a/test/models/domain_test.rb
+++ b/test/models/domain_test.rb
@@ -1,87 +1,116 @@
require 'test_helper'
class DomainTest < ActiveSupport::TestCase
def setup
@domain = build(:domain)
end
test 'automatic SOA creation' do
@domain.save!
@domain.reload
assert_not_nil @domain.soa
end
test 'increment serial on new record' do
@domain.save!
soa = @domain.soa
assert_serial_update soa do
www = A.new(name: 'www', domain: @domain, content: '1.2.3.4')
www.save!
end
end
test 'increment serial on record update' do
@domain.save!
www = A.new(name: 'www', domain: @domain, content: '1.2.3.4')
www.save!
soa = @domain.soa.reload
assert_serial_update soa do
www.content = '1.2.3.5'
www.save!
end
end
test 'automatic NS creation' do
@domain.save!
@domain.reload
assert_equal WebDNS.settings[:default_ns].sort,
@domain.records.where(type: 'NS').pluck(:content).sort
end
test 'increment serial on record destroy' do
@domain.save!
www = A.new(name: 'www', domain: @domain, content: '1.2.3.4')
www.save!
soa = @domain.soa.reload
assert_serial_update soa do
www.destroy!
end
end
class SlaveDomainTest < ActiveSupport::TestCase
def setup
@domain = build(:slave)
end
test 'saves' do
@domain.save
assert_empty @domain.errors
end
test 'automatic SOA creation' do
@domain.save!
@domain.reload
assert_not_nil @domain.soa
assert_equal 1, @domain.soa.serial
end
test 'validates master' do
@domain.master = 'not-an-ip'
@domain.save
assert_not_empty @domain.errors['master']
end
test 'no records are allowed for users' do
@domain.save!
rec = build(:a, domain_id: @domain.id)
assert_not rec.valid?
assert_not_empty rec.errors[:type]
end
end
+
+ class DsDomainTest < ActiveSupport::TestCase
+ def setup
+ @domain = create(:domain)
+ @ds = [
+ '31406 8 1 189968811e6eba862dd6c209f75623d8d9ed9142',
+ '31406 8 2 f78cf3344f72137235098ecbbd08947c2c9001c7f6a085a17f518b5d8f6b916d',
+ ]
+ @child = "dnssec.#{@domain.name}"
+ @extra = DS.create(domain: @domain, name: @child, content: 'other')
+ end
+
+ test 'add ds records' do
+ Domain.replace_ds(@domain.name, @child, @ds)
+ @extra.save! # Should be deleted
+
+ assert_equal @ds.size, DS.where(name: "dnssec.#{@domain.name}").count
+ @ds.each { |ds|
+ assert_equal 1, DS.where(name: "dnssec.#{@domain.name}", content: ds).count
+ }
+ end
+
+ test 'check if child is a valid subdomain' do
+ assert_raise Domain::NotAChild do
+ Domain.replace_ds(@domain.name, 'dnssec.example.net', @ds)
+ end
+ end
+
+ end
end

Event Timeline