Skip to content

Instantly share code, notes, and snippets.

@erikh
Created April 20, 2010 21:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save erikh/373081 to your computer and use it in GitHub Desktop.
Save erikh/373081 to your computer and use it in GitHub Desktop.
require 'facter'
require 'stringio'
Interface = Struct.new(
:af_type, :address, :broadcast, :netmask, :mtu,
:status, :mac
)
module IFConfig
def ifconfig
interfaces = { }
output = ""
case Facter["Kernel"].value
when "Solaris", "Linux", "Darwin", /BSD/
output = %x(/sbin/ifconfig -a)
else
fail "Couldn't figure out your system ifconfig"
end
unless $?.exitstatus == 0
fail "Error getting data from ifconfig"
end
sio = StringIO.new(output)
case Facter["Kernel"].value
when "Linux"
interfaces = linux(sio)
when "Darwin", /BSD/
interfaces = bsd(sio, Facter["Kernel"].value)
when "Solaris"
interfaces = solaris(sio)
end
return interfaces
end
module_function :ifconfig
def convert_hex_to_octet(hexmask)
hexmask.scan(/.{2}/).collect { |x| x.hex }.join(".")
end
def parse_af_lines(sio)
loop do
ch = sio.getc
if ch and (ch.chr == " " or ch == ?\t)
words = sio.readline.sub(/^\s+/, "").split(/\s+/)
yield words
else
sio.ungetc(ch) if ch
break
end
end
end
def linux(sio)
interfaces = { }
while(!sio.eof?) do
header = sio.readline
m = header.match(/^([^ ]+).*?HWaddr ([^ ]+)/)
# downed and special interfaces have a different syntax
m = header.match(/^([^ ]+)/) unless m
interface,
mac = m[1,2]
mtu = ""
status = ""
interfaces[interface] = []
parse_af_lines(sio) do |words|
if words[0] =~ /^inet/
my_int = Interface.new
interfaces[interface].push(my_int)
case words[0]
when "inet"
my_int.af_type = :inet
# linux chooses to insert bcast in the middle instead of append it like
# freebsd/solaris.
my_int.address = words[1].sub(/^addr:/, "")
my_int.broadcast = words[2] =~ /^Bcast:/ ? words[2].sub(/^Bcast:/, "") : nil
my_int.netmask = words[2] =~ /^Bcast:/ ? words[3].sub(/^Mask:/, "") : words[2].sub(/^Mask:/, "")
when "inet6"
my_int.af_type = :inet6
my_int.address,
my_int.netmask = words[2].split(/\//)
my_int.broadcast = nil
end
elsif words[0] =~ /^UP/
status = :active
mtu = words.find { |x| x =~ /^MTU/ }
mtu.sub!(/^MTU:/, "")
end
end
interfaces[interface].each do |x|
x.status = status.to_s.length ? :active : :down
x.mac = mac
x.mtu = mtu
if interface == "lo"
x.status = :active
x.mac = nil
end
end
sio.readline
end
return interfaces
end
module_function :linux
def bsd(sio, kernel)
interfaces = { }
while(!sio.eof?) do
header = sio.readline
m = header.match(/^([^:]+): .*?mtu (\d+)/)
status = ""
mac = ""
interface,
mtu = m[1,2]
interfaces[interface] = []
parse_af_lines(sio) do |words|
if words[0] =~ /^inet/
my_int = Interface.new
interfaces[interface].push(my_int)
my_int.af_type = case words[0]
when "inet"
:inet
when "inet6"
:inet6
end
# ipv6 addresses in bsd have the interface
# appended after a % sign
my_int.address = words[1].sub(/%.*$/, "")
if words[0] == "inet"
my_int.netmask = convert_hex_to_octet(words[3].sub(/^0x/, ""))
my_int.broadcast = words[5]
elsif words[0] == "inet6"
my_int.netmask = words[3]
end
elsif words[0] =~ /^address/
# openbsd puts the mac on it's own line
mac = words[1]
elsif words[0] =~ /^media/
# darwin does not have "ethernet" in the media: line
status = words[5]
elsif words[0] =~ /^ether/
mac = words[1]
elsif words[0] =~ /^status/
# freebsd puts the status on it's own line.
# this only works because the status line is the last one.
status = words[1]
end # if words
end # parse_af_lines
# update the mac, media, and duplex in the interfaces structures.
interfaces[interface].each do |x|
x.mac = mac
x.status = case status
when "active"
:active
when "inactive"
:down
end
x.mtu = mtu
# force the loopback to have certain states
if interface == "lo0"
x.status = :active
x.mac = nil
x.mtu = nil
end
end # interfaces each
end # while
return interfaces
end
module_function :bsd
def solaris(sio)
interfaces = { }
while (!sio.eof?)
header = sio.readline
m = header.match(/([^ ]+) (.*?)mtu (\d+)/)
interface = m[1].sub(/:$/, "")
mtu = m[3]
status = m[2] =~ /RUNNING/ ? :active : :down
mac = ""
interfaces[interface] ||= []
parse_af_lines(sio) do |words|
if words[0] =~ /^inet/
my_int = Interface.new
interfaces[interface].push(my_int)
case words[0]
when "inet"
my_int.af_type = :inet
my_int.address = words[1]
my_int.netmask = words[3]
my_int.broadcast = words[5]
when "inet6"
my_int.af_type = :inet6
my_int.address = words[1].sub(/\/.*$/, "")
my_int.netmask = words[1].sub(/^[^\/]+\//, "")
end
elsif words[0] =~ /^ether/
mac = words[1]
end
end
interfaces[interface].each do |x|
x.status = status
x.mac = mac
x.mtu = mtu
if interface == "lo0"
x.status = :active
end
end
end
return interfaces
end
module_function :solaris
end
require 'pp'
include IFConfig
pp ifconfig
if File.exists? "openbsd_ifconfig.txt"
$stdout.puts
$stdout.puts "Running openbsd_ifconfig.txt"
$stdout.puts
pp bsd(File.open("openbsd_ifconfig.txt"), Facter["Kernel"].value)
end
if File.exists? "solaris_ifconfig.txt"
$stdout.puts
$stdout.puts "Running solaris_ifconfig.txt"
$stdout.puts
pp solaris(File.open("solaris_ifconfig.txt"))
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment