Class: Matchd::Rule

Inherits:
Object
  • Object
show all
Defined in:
lib/matchd/rule.rb

Direct Known Subclasses

Append, Fail, Invalid, Passthrough, Respond

Defined Under Namespace

Modules: Factory Classes: Append, Fail, Invalid, Passthrough, Respond

Constant Summary collapse

REGEXP_MATCHER =
%r{\A/(.*)/([mix]*)\Z}m
REGEXP_OPTIONS =
{
  "m" => Regexp::MULTILINE,
  "i" => Regexp::IGNORECASE,
  "x" => Regexp::EXTENDED
}.freeze
NotImplementedError =
Class.new(RuntimeError)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ Rule

Returns a new instance of Rule.



42
43
44
45
46
# File 'lib/matchd/rule.rb', line 42

def initialize(options)
  @raw = options
  @name = options.fetch("match")
  @resource_classes = Array(options.fetch("resource_class"))
end

Instance Attribute Details

#rawObject (readonly)

Returns the value of attribute raw.



47
48
49
# File 'lib/matchd/rule.rb', line 47

def raw
  @raw
end

Class Method Details

.parse_match(name) ⇒ Object

parses a Regexp lookalike String into Regexp or returns the String



20
21
22
23
24
25
26
27
28
29
# File 'lib/matchd/rule.rb', line 20

def self.parse_match(name)
  if name.is_a?(Regexp)
    name
  elsif (r = name.match(REGEXP_MATCHER))
    regexp_opts = r[2].each_char.reduce(0) { |o, c| o |= REGEXP_OPTIONS[c] } # rubocop:disable Lint/UselessAssignment # No, it's not!
    Regexp.new(r[1], regexp_opts)
  else
    name
  end
end

.parse_resource_class(resource_class) ⇒ Object



31
32
33
34
35
36
37
38
# File 'lib/matchd/rule.rb', line 31

def self.parse_resource_class(resource_class)
  resource_class.map do |klass|
    case klass
    when ::Resolv::DNS::Resource then klass
    when String, Symbol then ::Resolv::DNS::Resource::IN.const_get(klass.upcase)
    end
  end
end

Instance Method Details

#call(server, name, resource_class, transaction) ⇒ TrueClass|FalseClass

This is the main interface for executing rules. It tests if this rule matches by calling #matches? and runs it by calling #visit!

Parameters:

  • server (Matchd::Server)
  • name (String)

    The query name

  • resource_class (Resolv::DNS::Resource)

    The query IN ressource

  • transaction (Async::DNS::Transaction)

Returns:

  • (TrueClass|FalseClass)

    Whether further processing shall stop



82
83
84
85
86
# File 'lib/matchd/rule.rb', line 82

def call(server, name, resource_class, transaction)
  return false unless matches?(name, resource_class)

  visit!(server, name, resource_class, transaction)
end

#match_nameObject



89
90
91
# File 'lib/matchd/rule.rb', line 89

def match_name
  @match_name ||= self.class.parse_match(@name)
end

#match_resource_classesObject



94
95
96
# File 'lib/matchd/rule.rb', line 94

def match_resource_classes
  @match_resource_classes ||= self.class.parse_resource_class(@resource_classes)
end

#matches?(query_name, query_resource_class) ⇒ TrueClass|FalseClass

Checks if this rule matches a DNS query (name and ressource class).

Returns:

  • (TrueClass|FalseClass)


68
69
70
71
# File 'lib/matchd/rule.rb', line 68

def matches?(query_name, query_resource_class)
  name_for_match === query_name && # rubocop:disable Style/CaseEquality #  This does string equality and Regexp matching at the same time
    resource_classes_for_match.include?(query_resource_class)
end

#visit!(_server, _name, _resource_class, _transaction) ⇒ TrueClass|FalseClass

This method is abstract.

This method needs to be implemented by subclasses.

Note:

You should not need to call this method directly, use #call instead .

Implements the rule logic formulating the DNS response to a query. It’s return value signals whether this rule was a successful match (in the sense of the rule) and evaluating later rules shall be stopped.

Parameters:

  • server (Matchd::Server)
  • name (String)

    The query name

  • resource_class (Resolv::DNS::Resource)

    The query IN ressource

  • transaction (Async::DNS::Transaction)

Returns:

  • (TrueClass|FalseClass)

    Whether further processing shall stop

Raises:



62
63
64
# File 'lib/matchd/rule.rb', line 62

def visit!(_server, _name, _resource_class, _transaction)
  raise NotImplementedError
end