#!/usr/bin/ruby # a script to try and parse /var/lib/arpwatch/arp.dat # into DHCP/DNS configuration snippets # Copyleft 2006 by Michael Shigorin DEBUG = false # -v DEBUG2 = true # -vv ARPDAT = "arp.dat" #ARPDAT = "arp.test" IGNORE = "arp.ignore" # one MAC per line to ignore PREFIX = "192.168" OLDNET = "#{PREFIX}.0" NEWNET = "#{PREFIX}.10" OLDPAT = Regexp.new(OLDNET) ZONE = NEWNET.split(".").reverse.join(".") + ".in-addr.arpa_ADD" DHCP = "dhcpd.conf_ADD" data = Hash.new result = Hash.new ignored = Array.new begin File.open(IGNORE) do |f| f.each do |mac| ignored << mac.chomp end end rescue puts "** unable to open #{IGNORE}, accepting all MACs" if DEBUG end p ignored if DEBUG File.open(ARPDAT) do |f| f.each do |line| mac,ip,tstamp,host = line.split next if mac.nil? or ip.nil? or tstamp.nil? # broken line next if ignored.include?(mac) # host might be empty... begin data[mac][tstamp] = { ip => host } rescue # new MAC data[mac] = Hash.new retry end end end # let's look closer into different "alias" ip/hosts for the same mac # # note that due to DDNS enabled, "last" IP has a better chance # to have a proper _hostname_ in the corresponding data[] record; # still we prefer "first" _IP_ since these were given out by hand # which seems slightly more honorable than dhcp pool data.each do |mac,tstamps| first_ip = nil last_ip = nil lastname = nil puts "* #{mac}" if DEBUG2 tstamps.sort.each do |tstamp,host| host.each do |ip,hostname| puts " + #{tstamp}\t#{ip}\t#{hostname}" if DEBUG2 first_ip = ip if ip =~ OLDPAT and first_ip.nil? last_ip = ip lastname = hostname end end begin new_ip = first_ip.sub(OLDNET, NEWNET) rescue # mac never seen on oldnet, probably fresh/only one new_ip = last_ip end if lastname.nil? lastname = new_ip.sub(/^#{PREFIX}.(\d+).(\d+)/,'ws\1-\2') end puts "#{mac}\t#{new_ip}\t#{lastname}" if DEBUG result[new_ip] = { 'mac' => mac, 'host' => lastname } end # need something like: result.sort! # # NEED to check hostnames for uniq! (dhcpd chokes otherwise) # finally, construct conf file snippets in question File.open(ZONE, "w") do |f| result.each do |ip,res| f << "#{res['host']} IN A #{ip}\n" end end # output file should be sorted by hostname... File.open(DHCP, "w") do |f| result.each do |ip,res| f << " host #{res['host']} {\n" f << " hardware ethernet #{res['mac']};\n" f << " fixed-address #{res['host']};\n" f << " }\n\n" end end # output file should be sorted somehow