# frozen_string_literal: true
#
# ronin-dns-proxy - A DNS server and proxy library.
#
# Copyright (c) 2023-2024 Hal Brodigan (postmodern.mod3@gmail.com)
#
# ronin-dns-proxy is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# ronin-dns-proxy is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with ronin-dns-proxy. If not, see .
#
module Ronin
module DNS
module Proxy
#
# Represents a DNS rule for the DNS {Server}.
#
# @api private
#
class Rule
# The record type to match.
#
# @return [:A, :AAAA, :ANY, :CNAME, :HINFO, :LOC, :MINFO, :MX, :NS, :PTR, :SOA, :SRV, :TXT, :WKS]
attr_reader :type
# The record name or regex to match.
#
# @return [String, Regexp]
attr_reader :name
# The result to return.
#
# @return [String, Array, Symbol, #call]
attr_reader :result
#
# Initializes the DNS rule.
#
# @param [:A, :AAAA, :ANY, :CNAME, :HINFO, :LOC, :MINFO, :MX, :NS, :PTR, :SOA, :SRV, :TXT, :WKS] type
# The rule's record type.
#
# @param [String, Regexp] name
# The rule's name to match.
#
# @param [String, Array, Symbol, #call] result
# The result to return.
#
# @yield [type, name, transaction]
# If no result argument is given, the given block will be passed the
# DNS query's type, name, and transaction object.
#
# @yieldparam [Symbol] type
# The query type.
#
# @yieldparam [String] name
# The queried host name.
#
# @yieldparam [Async::DNS::Transaction] transaction
# The DNS query transaction object.
#
# @raise [ArgumentError]
# Must specify a `result` argument or a block.
#
def initialize(type,name,result=nil,&block)
unless (result || block)
raise(ArgumentError,"must specify a result value or a block")
end
@type = type
@name = name
@result = result || block
end
#
# Determines if the rule matches the query type and query name.
#
# @param [:A, :AAAA, :ANY, :CNAME, :HINFO, :LOC, :MINFO, :MX, :NS, :PTR, :SOA, :SRV, :TXT, :WKS] query_type
# The query's type (ex: `:A`).
#
# @param [String] query_name
# The query's name (ex: 'www.example.com').
#
# @return [Boolean]
# Indicates whether the rule matches the query.
#
def matches?(query_type,query_name)
(@type == query_type) && (@name === query_name)
end
#
# Invokes the rule with the given query type, query name, and DNS
# transaction object.
#
# @param [:A, :AAAA, :ANY, :CNAME, :HINFO, :LOC, :MINFO, :MX, :NS, :PTR, :SOA, :SRV, :TXT, :WKS] query_type
# The query's type (ex: `:A`).
#
# @param [String] query_name
# The query's name (ex: 'www.example.com').
#
# @return [Async::DNS::Transaction] transaction
# The DNS query transaction.
#
def call(query_type,query_name,transaction)
if @result.respond_to?(:call)
@result.call(query_type,query_name,transaction)
elsif @result.kind_of?(Symbol)
transaction.fail!(@result)
elsif @result
transaction.respond!(@result)
end
end
end
end
end
end