Class: BetterCap::Network::Servers::DNSD

Inherits:
Object
  • Object
show all
Defined in:
lib/bettercap/network/servers/dnsd.rb

Overview

Simple DNS server class used for DNS spoofing.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(hosts_filename = nil, address = '0.0.0.0', port = 5300) ⇒ DNSD

Initialize the DNS server with the specified address and tcp/udp port. The server will load hosts_filename composed by 'regexp -> ip' entries to do custom DNS spoofing/resolution.


48
49
50
51
52
53
54
55
56
57
# File 'lib/bettercap/network/servers/dnsd.rb', line 48

def initialize( hosts_filename = nil, address = '0.0.0.0', port = 5300 )
  @port    = port
  @address = address
  @hosts   = hosts_filename
  @server  = nil
  @ifaces  = [
    [:udp, address, port],
    [:tcp, address, port]
  ]
end

Class Method Details

.parse_hosts(filename) ⇒ Object

Parse hosts from filename, example host file:

# *.google.com will point to the attacker's computer. local .*google.com

# a custom redirection 12.12.12.12 wtf.idontexist.com

Raises:


110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/bettercap/network/servers/dnsd.rb', line 110

def self.parse_hosts( filename )
  raise BetterCap::Error, "File '#{filename}' does not exist." unless File.exist?(filename)

  hosts = {}
  File.open(filename).each_with_index do |line,lineno|
    line = line.strip
    # skip empty lines and comments
    next if line.empty? or line[0] == '#'
    if line =~ /^([^\s]+)\s+(.+)$/
      address    = $1
      expression = $2

      if address == 'local'
        address = Context.get.ifconfig[:ip_saddr].to_s
      end

      raise BetterCap::Error, "Invalid IPv4 address '#{address}' on line #{lineno + 1} of '#{filename}'." \
        unless Network::Validator.is_ip?(address)

      begin
        hosts[ expression ] = address
      rescue RegexpError
        raise BetterCap::Error, "Invalid expression '#{expression}' on line #{lineno + 1} of '#{filename}'."
      end
    end
  end

  hosts
end

Instance Method Details

#add_rule!(exp, addr) ⇒ Object

Add a rule to the DNS resolver at runtime.


60
61
62
63
64
65
66
67
68
69
# File 'lib/bettercap/network/servers/dnsd.rb', line 60

def add_rule!( exp, addr )
  Logger.debug "[#{'DNS'.green}] Adding rule: '#{exp}' -> '#{addr}' ..."

  block = Proc.new do |transaction|
    Logger.info "[#{transaction.options[:peer]} > #{'DNS'.green}] Received request for '#{transaction.question.to_s.yellow}', sending spoofed reply #{addr.yellow} ..."
    transaction.respond!(addr)
  end

  DnsWrapper.get.rules << RubyDNS::RuleBasedServer::Rule.new( [ Regexp.new(exp), Resolv::DNS::Resource::IN::A ], block )
end

#startObject

Start the server.


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
# File 'lib/bettercap/network/servers/dnsd.rb', line 72

def start
  Logger.info "[#{'DNS'.green}] Starting on #{@address}:#{@port} ..."

  options = {
    :listen => @ifaces,
    :asynchronous => true,
    :server_class => DnsWrapper
  }

  RubyDNS::run_server( options ) do
    # Suppress RubyDNS logging.
    @logger.level = ::Logger::ERROR
    @upstream ||= RubyDNS::Resolver.new([[:udp, "8.8.8.8", 53], [:tcp, "8.8.8.8", 53]])

    # Default DNS handler
    otherwise do |transaction|
      Logger.debug "[#{transaction.options[:peer]} > #{'DNS'.green}] Received request for '#{transaction.question.to_s.yellow}' -> upstream DNS"
      transaction.passthrough!(@upstream)
    end
  end

  unless @hosts.nil?
    DNSD.parse_hosts( @hosts ).each do |exp,addr|
      add_rule!( exp, addr )
    end
  end
end

#stopObject

Stop the server.


101
# File 'lib/bettercap/network/servers/dnsd.rb', line 101

def stop; end