1
0
مراية لـ https://github.com/postalserver/postal.git تم المزامنة 2025-11-30 21:32:30 +00:00
الملفات
postal/app/models/concerns/has_dns_checks.rb
Adam Cooke 1a4158699c refactor: refactor DNS resolution
This commit also adds some of tests for the Domain model. It was during the writing of these tests that the DNS resolution refactoring requirement became apparent.
2024-02-23 22:51:34 +00:00

156 أسطر
4.2 KiB
Ruby

# frozen_string_literal: true
require "resolv"
module HasDNSChecks
def dns_ok?
spf_status == "OK" && dkim_status == "OK" && %w[OK Missing].include?(mx_status) && %w[OK Missing].include?(return_path_status)
end
def dns_checked?
spf_status.present?
end
def check_dns(source = :manual)
check_spf_record
check_dkim_record
check_mx_records
check_return_path_record
self.dns_checked_at = Time.now
save!
if source == :auto && !dns_ok? && owner.is_a?(Server)
WebhookRequest.trigger(owner, "DomainDNSError", {
server: owner.webhook_hash,
domain: name,
uuid: uuid,
dns_checked_at: dns_checked_at.to_f,
spf_status: spf_status,
spf_error: spf_error,
dkim_status: dkim_status,
dkim_error: dkim_error,
mx_status: mx_status,
mx_error: mx_error,
return_path_status: return_path_status,
return_path_error: return_path_error
})
end
dns_ok?
end
#
# SPF
#
def check_spf_record
result = resolver.txt(name)
spf_records = result.grep(/\Av=spf1/)
if spf_records.empty?
self.spf_status = "Missing"
self.spf_error = "No SPF record exists for this domain"
else
suitable_spf_records = spf_records.grep(/include:\s*#{Regexp.escape(Postal.config.dns.spf_include)}/)
if suitable_spf_records.empty?
self.spf_status = "Invalid"
self.spf_error = "An SPF record exists but it doesn't include #{Postal.config.dns.spf_include}"
false
else
self.spf_status = "OK"
self.spf_error = nil
true
end
end
end
def check_spf_record!
check_spf_record
save!
end
#
# DKIM
#
def check_dkim_record
domain = "#{dkim_record_name}.#{name}"
records = resolver.txt(domain)
if records.empty?
self.dkim_status = "Missing"
self.dkim_error = "No TXT records were returned for #{domain}"
else
sanitised_dkim_record = records.first.strip.ends_with?(";") ? records.first.strip : "#{records.first.strip};"
if records.size > 1
self.dkim_status = "Invalid"
self.dkim_error = "There are #{records.size} records for at #{domain}. There should only be one."
elsif sanitised_dkim_record != dkim_record
self.dkim_status = "Invalid"
self.dkim_error = "The DKIM record at #{domain} does not match the record we have provided. Please check it has been copied correctly."
else
self.dkim_status = "OK"
self.dkim_error = nil
true
end
end
end
def check_dkim_record!
check_dkim_record
save!
end
#
# MX
#
def check_mx_records
records = resolver.mx(name).map(&:last)
if records.empty?
self.mx_status = "Missing"
self.mx_error = "There are no MX records for #{name}"
else
missing_records = Postal.config.dns.mx_records.dup - records.map { |r| r.to_s.downcase }
if missing_records.empty?
self.mx_status = "OK"
self.mx_error = nil
elsif missing_records.size == Postal.config.dns.mx_records.size
self.mx_status = "Missing"
self.mx_error = "You have MX records but none of them point to us."
else
self.mx_status = "Invalid"
self.mx_error = "MX #{missing_records.size == 1 ? 'record' : 'records'} for #{missing_records.to_sentence} are missing and are required."
end
end
end
def check_mx_records!
check_mx_records
save!
end
#
# Return Path
#
def check_return_path_record
records = resolver.cname(return_path_domain)
if records.empty?
self.return_path_status = "Missing"
self.return_path_error = "There is no return path record at #{return_path_domain}"
elsif records.size == 1 && records.first == Postal.config.dns.return_path
self.return_path_status = "OK"
self.return_path_error = nil
else
self.return_path_status = "Invalid"
self.return_path_error = "There is a CNAME record at #{return_path_domain} but it points to #{records.first} which is incorrect. It should point to #{Postal.config.dns.return_path}."
end
end
def check_return_path_record!
check_return_path_record
save!
end
end
# -*- SkipSchemaAnnotations