Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 56 additions & 71 deletions lib/macaddr.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# * /bin/ifconfig
# * ifconfig
# * ipconfig /all
# * cat /sys/class/net/*/address
#
# To return the first MAC address on the system:
#
Expand All @@ -24,30 +25,27 @@
require 'socket'

module Mac
VERSION = '1.7.2'

def Mac.version
::Mac::VERSION
end

def Mac.dependencies
{
'systemu' => [ 'systemu' , '~> 2.6.5' ]
}
end

def Mac.description
'cross platform mac address determination for ruby'
end

RE = %r/(?:[^:\-]|\A)(?:[0-9A-F][0-9A-F][:\-]){5}[0-9A-F][0-9A-F](?:[^:\-]|\Z)/io.freeze
CMDS = ['/sbin/ifconfig', '/bin/ifconfig', 'ifconfig', 'ipconfig /all', 'cat /sys/class/net/*/address'].freeze
PF_LINK = Socket.const_defined?(:PF_LINK) ? Socket::PF_LINK : nil
PF_PACKET = Socket.const_defined?(:PF_PACKET) ? Socket::PF_PACKET : nil
INTERFACE_PACKET_FAMILY = PF_LINK || PF_PACKET # :nodoc:
VERSION = '1.8.0'

class << self
def version
VERSION
end

##
# Accessor for the system's first MAC address, requires a call to #address
# first
def dependencies
{
'systemu' => [ 'systemu' , '~> 2.6.5' ]
}
end

attr_accessor "mac_address"
def description
'cross platform mac address determination for ruby'
end

##
# Discovers and returns the system's MAC addresses. Returns the first
Expand All @@ -57,77 +55,64 @@ class << self
# Mac.addr.list # => all addresses

def address
return @mac_address if defined? @mac_address and @mac_address
@mac_address ||= from_getifaddrs || from_cmds
end

@mac_address = from_getifaddrs
return @mac_address if @mac_address
##
# Shorter alias for #address

cmds = '/sbin/ifconfig', '/bin/ifconfig', 'ifconfig', 'ipconfig /all', 'cat /sys/class/net/*/address'
alias_method :addr, :address

output = nil
cmds.each do |cmd|
_, stdout, _ = systemu(cmd) rescue next
next unless stdout and stdout.size > 0
output = stdout and break
end
raise "all of #{ cmds.join ' ' } failed" unless output
def from_getifaddrs
return unless Socket.respond_to?(:getifaddrs)

interfaces = Socket.getifaddrs.map do |addr|
# Some VPN ifcs don't have an addr - ignore them
addr.addr if addr.addr.pfamily == INTERFACE_PACKET_FAMILY
end.compact

maddrs =
if PF_LINK
interfaces.map { |addr| addr.getnameinfo.first }.reject(&:empty?)
elsif PF_PACKET
interfaces.
map { |addr| addr.inspect_sockaddr[/hwaddr=([\h:]+)/, 1] }.
select { |mac_addr| mac_addr != '00:00:00:00:00:00' }
end

@mac_address = parse(output)
end
maddr = maddrs.first.dup

link = Socket::PF_LINK if Socket.const_defined? :PF_LINK
packet = Socket::PF_PACKET if Socket.const_defined? :PF_PACKET
INTERFACE_PACKET_FAMILY = link || packet # :nodoc:
maddr.instance_eval { @list = maddrs; def list() @list end }
maddr
end

def from_getifaddrs
return unless Socket.respond_to? :getifaddrs
def from_cmds
output = CMDS.detect do |cmd|
_, stdout, _ = systemu(cmd) rescue next

interfaces = Socket.getifaddrs.select do |addr|
if addr.addr # Some VPN ifcs don't have an addr - ignore them
addr.addr.pfamily == INTERFACE_PACKET_FAMILY
end
break parse(stdout)
end

mac, =
if Socket.const_defined? :PF_LINK then
interfaces.map do |addr|
addr.addr.getnameinfo
end.find do |m,|
!m.empty?
end
elsif Socket.const_defined? :PF_PACKET then
interfaces.map do |addr|
addr.addr.inspect_sockaddr[/hwaddr=([\h:]+)/, 1]
end.find do |mac_addr|
mac_addr != '00:00:00:00:00:00'
end
end

@mac_address = mac if mac
output.nil? ? (raise "all of #{ CMDS.join ' ' } failed") : output
end

def parse(output)
lines = output.split(/\n/)

candidates = lines.select{|line| line =~ RE}
raise 'no mac address candidates' unless candidates.first
candidates.map!{|c| c[RE].strip}
candidates = lines.map do |line|
candidate = line[RE].to_s.strip

candidate unless candidate.empty?
end.compact

maddr = candidates.first.dup

maddr = candidates.first
raise 'no mac address found' unless maddr

maddr.strip!
maddr.instance_eval{ @list = candidates; def list() @list end }
maddr.instance_eval { @list = candidates; def list() @list end }
maddr
end

##
# Shorter alias for #address

alias_method "addr", "address"
end

RE = %r/(?:[^:\-]|\A)(?:[0-9A-F][0-9A-F][:\-]){5}[0-9A-F][0-9A-F](?:[^:\-]|\Z)/io
end

MacAddr = Macaddr = Mac
8 changes: 3 additions & 5 deletions macaddr.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

Gem::Specification::new do |spec|
spec.name = "macaddr"
spec.version = "1.7.2"
spec.version = "1.8.0"
spec.platform = Gem::Platform::RUBY
spec.summary = "macaddr"
spec.description = "cross platform mac address determination for ruby"
Expand All @@ -27,14 +27,12 @@ Gem::Specification::new do |spec|
"test/testing.rb"]

spec.executables = []

spec.require_path = "lib"

spec.test_files = nil


spec.add_dependency(*["systemu", "~> 2.6.5"])

spec.add_dependency(*["systemu", "~> 2.6.5"])

spec.extensions.push(*[])

Expand Down