aboutsummaryrefslogtreecommitdiff
path: root/lib/mauve/source_list.rb
blob: 23f5ae18ec9b0e16977d818107edfe2e488363af (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# encoding: UTF-8
require 'log4r'
require 'resolv-replace'

module Mauve

  # A simple construct to match sources.
  #
  # This class stores mamed lists of IP addresses.  It stores them in a hash
  # indexed by the name of the list.  One can pass IPv4, IPv6 and hostnames
  # as list elements but they will all be converted into IP addresses at 
  # the time of the list creation.
  #
  # One can ask if an IPv4, IPv6, hostname or url (match on hostname only) is
  # contained within a list.  If the query is not an IP address, it will be
  # converted into one before the checks are made.
  #
  # Note that the matching is greedy.  When a hostname maps to several IP
  # addresses and only one of tbhose is included in the list, a match 
  # will occure.  
  #
  # @author Yann Golanski
  class SourceList

    # Accessor, read only.  Use create_new_list() to create lists.
    attr_reader :hash

    ## Default contructor.
    def initialize ()
      @logger = Log4r::Logger.new "Mauve::SourceList"
      @hash = Hash.new
      @http_head = Regexp.compile(/^http[s]?:\/\//)
      @http_tail = Regexp.compile(/\/.*$/)
    end

    ## Return whether or not a list contains a source.
    #
    # @param [String] lst The list name.
    # @param [String] src The hostname or IP of the source.
    # @return [Boolean] true if there is such a source, false otherwise.
    def does_list_contain_source?(lst, src)
      raise ArgumentError.new("List name must be a String, not a #{lst.class}") if String != lst.class
      raise ArgumentError.new("Source name must be a String, not a #{src.class}") if String != src.class
      raise ArgumentError.new("List #{lst} does not exist.") if false == @hash.has_key?(lst)
      if src.match(@http_head)
        src = src.gsub(@http_head, '').gsub(@http_tail, '')
      end
      begin
        Resolv.getaddresses(src).each do |ip|
          return true if @hash[lst].include?(ip)
        end
      rescue Resolv::ResolvError, Resolv::ResolvMauveTimeout => e
        @logger.warn("#{lst} could not be resolved because #{e.message}.")
        return false
      rescue => e
        @logger.error("Unknown exception raised: #{e.class} #{e.message}")
        return false
      end
      return false
    end

    ## Create a list.
    # 
    # Note that is no elements give IP addresses, we have an empty list. 
    # This gets logged but otherwise does not stop mauve from working.
    #
    # @param [String] name The name of the list.
    # @param [Array] elem A list of source either hostname or IP.
    def create_new_list(name, elem)
      raise ArgumentError.new("Name of list is not a String but a #{name.class}") if String != name.class
      raise ArgumentError.new("Element list is not an Array but a #{elem.class}") if Array != elem.class
      raise ArgumentError.new("A list called #{name} already exists.") if @hash.has_key?(name)
      arr = Array.new
      elem.each do |host| 
        begin
          Resolv.getaddresses(host).each do |ip|
            arr << ip
          end
        rescue Resolv::ResolvError, Resolv::ResolvMauveTimeout => e
          @logger.warn("#{host} could not be resolved because #{e.message}.")
        rescue => e 
          @logger.error("Unknown exception raised: #{e.class} #{e.message}")
        end
      end
      @hash[name] = arr.flatten.uniq.compact
      if true == @hash[name].empty?
        @logger.error("List #{name} is empty! "+
                      "Nothing from element list '#{elem}' "+
                      "has resolved to anything useable.")
      end
    end

  end

  ## temporary object to convert from configuration file to the SourceList class
  class AddSoruceList < Struct.new(:label, :list)

    # Default constructor.
    def initialize (*args)
      super(*args)
    end

  end

end