diff --git a/app/helpers/records_helper.rb b/app/helpers/records_helper.rb new file mode 100644 index 0000000..98283f0 --- /dev/null +++ b/app/helpers/records_helper.rb @@ -0,0 +1,8 @@ +module RecordsHelper + + def name_field_append(record) + return ".#{record.domain.name}" if not record.domain.reverse? + + ".#{record.domain.name} (#{record.domain.subnet})" + end +end diff --git a/app/models/domain.rb b/app/models/domain.rb index 6829f81..512f582 100644 --- a/app/models/domain.rb +++ b/app/models/domain.rb @@ -1,37 +1,73 @@ class Domain < ActiveRecord::Base self.inheritance_column = :nx def self.domain_types [ 'NATIVE', 'MASTER', 'SLAVE', ] end has_many :records has_one :soa, class_name: SOA validates :name, uniqueness: true, presence: true validates :type, presence: true, inclusion: { in: domain_types } after_create :generate_soa attr_writer :serial_strategy def serial_strategy @serial_strategy ||= WebDNS.settings[:serial_strategy] end def reverse? name.end_with?('.in-addr.arpa') || name.end_with?('.ip6.arpa') 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 + 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 end diff --git a/app/views/records/_form.html.erb b/app/views/records/_form.html.erb index c5ef837..418f2ba 100644 --- a/app/views/records/_form.html.erb +++ b/app/views/records/_form.html.erb @@ -1,14 +1,14 @@ -<%= bootstrap_form_for([@domain, @record], layout: :horizontal, label_col: 'col-sm-2', control_col: 'col-sm-4') do |f| %> +<%= bootstrap_form_for([@domain, @record], layout: :horizontal, label_col: 'col-sm-2', control_col: 'col-sm-8') do |f| %> - <%= f.text_field :name, value: @record.short, label: 'Record', append: ".#{@domain.name}" %> + <%= f.text_field :name, value: @record.short, label: 'Record', append: name_field_append(@record) %> <% if @record.persisted? %> <%= f.static_control :type %> <% else %> <%= f.select :type, Record.record_types %> <% end %> <%= f.text_field :prio, placeholder: 10, wrapper_class: @record.supports_prio? ? '' : 'hidden' %> <%= f.text_field :content %> <%= f.submit 'Save', class: 'btn btn-primary col-sm-offset-2' %> <% end %>