Module: ArpRevolver

Defined in:
lib/arp_revolver.rb,
lib/arp_revolver/version.rb

Defined Under Namespace

Classes: Error

Constant Summary collapse

VERSION =
"0.1.1"

Class Method Summary collapse

Class Method Details

.current_mac_addr(host) ⇒ Object



78
79
80
81
82
83
84
# File 'lib/arp_revolver.rb', line 78

def current_mac_addr(host)
  IO.popen("arp -e") do |io|
    info = io.read.lines.select { |line| line.match(/#{host}/) }

    info.first&.split(" ")&.[](2)
  end
end

.health_trigger(interface, host) ⇒ Object



70
71
72
73
74
75
76
# File 'lib/arp_revolver.rb', line 70

def health_trigger(interface, host)
  IO.popen("arping -c #{revolver_config["pings"]} -I #{interface} #{host}") do |io|
    result = io.read.lines.last.strip.match(/Received\ (?<num>\d)\ response\(s\)/)

    result[:num].to_i >= revolver_config["online_threshold"]
  end
end

.revolver_configObject

Raises:

  • (StandardError)


22
23
24
25
26
27
28
29
30
31
32
# File 'lib/arp_revolver.rb', line 22

def revolver_config
  file_path = "/etc/arp-revolver.yml"

  raise StandardError, "config file must be 640 mode" unless File.stat(file_path).mode.to_s(8)[3..5] == "640"

  @revolver_config ||= YAML.load_file(file_path)

  raise StandardError, "config file is needed" unless @revolver_config

  @revolver_config
end

.send_sentry(message, level: :error) ⇒ Object



86
87
88
89
90
91
92
93
94
# File 'lib/arp_revolver.rb', line 86

def send_sentry(message, level: :error)
  return puts(message) unless (sentry_dsn = revolver_config["sentry_dsn"])

  Raven.configure do |config|
    config.dsn = revolver_config["sentry_dsn"]
  end

  Raven.capture_message(message, level: level)
end

.triggerObject



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
# File 'lib/arp_revolver.rb', line 34

def trigger
  revolver_config["hosts"]&.each do |host, config|
    return puts "Info: #{host} connection is OK" if health_trigger(config["interface"], host)

    error_msg = "Error: #{host} connection Fail, try to change the MAC address."

    puts error_msg

    send_sentry(error_msg, level: :error)

    old_mac_addr = config["mac_addrs"].delete(current_mac_addr(host))

    config["mac_addrs"].each do |mac_addr|
      IO.popen "echo $(arp -s #{host} #{mac_addr})"

      if health_trigger(config["interface"], host)
        puts "ARP Revolver: switch mac address from <#{old_mac_addr}> to <#{mac_addr}> for HOST (#{host})"

        return
      else
        error_msg = "Error: #{host}[#{current_mac_addr(host)}] connection Fail, try to change the MAC address."

        puts error_msg
      end
    end

    unless health_trigger(config["interface"], host)
      error_msg = "Error: #{host} connection still Fail, after tried all MAC addresses."

      puts error_msg

      send_sentry(error_msg, level: :error)
    end
  end
end