x/platform mac address retrieval?

ddick on 2007-07-26T06:28:02

How to get a mac address from linux/solaris/aix/hpux/MSWin32?

don't think this would be useful enough to send to cpan.org... but for future reference...

#! /usr/bin/perl -w

use strict; use FileHandle();

MAIN: { my ($macAddress); if (($^O eq 'linux') || ($^O eq 'solaris') || ($^O eq 'hpux') || ($^O eq 'aix')) {

$ENV{PATH} = '/sbin:/usr/sbin:/bin:/usr/bin'; delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};

my ($ifconfig) = new FileHandle(); if (my $pid = $ifconfig->open('-|')) { my ($buffer); unless (defined $ifconfig->read($buffer, 8192)) { die("Failed to read from ifconfig:$!"); } if (($^O eq 'linux') || ($^O eq 'solaris')) { # linux preceeded by HWaddr, solaris by ether if ($buffer =~ /(?:HWaddr +|ether +)([0-9A-Fa-f]{1,2}):([0-9A-Fa-f]{1,2}):([0-9A-Fa-f]{1,2}):([0-9A-Fa-f]{1,2}):([0-9A-Fa-f]{1,2}):([0-9A-Fa-f]{1,2})/) { $macAddress = formatMac($1, $2, $3, $4, $5, $6); } } elsif ($^O eq 'hpux') { if ($buffer =~ /^0x([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2}) +$/) { $macAddress = formatMac($1, $2, $3, $4, $5, $6); } } elsif ($^O eq 'aix') { if ($buffer =~ / +([0-9A-Fa-f]{1,2})\.([0-9A-Fa-f]{1,2})\.([0-9A-Fa-f]{1,2})\.([0-9A-Fa-f]{1,2})\.([0-9A-Fa-f]{1,2})\.([0-9A-Fa-f]{1,2}) +/) { $macAddress = formatMac($1, $2, $3, $4, $5, $6); } } unless ($ifconfig->close()) { if (($^O eq 'linux') || ($^O eq 'solaris')) { die("Failed to successfully execute 'ifconfig -a':$!"); } elsif ($^O eq 'hpux') { die("Failed to successfully execute 'lanscan -a':$!"); } elsif ($^O eq 'aix') { die("Failed to successfully execute 'netstat -ia':$!"); } else { die("Unknown failure when determining mac address for '$^O'"); } } } elsif (defined $pid) { eval { if (($^O eq 'linux') || ($^O eq 'solaris')) { unless (exec({ 'ifconfig' } 'ifconfig', '-a')) { die("Failed to execute 'ifconfig -a':$!"); } } elsif ($^O eq 'hpux') { unless (exec({ 'lanscan' } 'lanscan', '-a')) { die("Failed to execute 'lanscan -a':$!"); } } elsif ($^O eq 'aix') { unless (exec({ 'netstat' } 'netstat', '-ia')) { die("Failed to execute 'netstat -ia':$!"); } } else { die("Failed to find a command to produce the mac address for '$^O'"); } }; print STDERR $@; exit(1); } else { die("Failed to fork:$!"); } } elsif ($^O eq 'MSWin32') { my ($ipconfig) = new FileHandle("ipconfig /all |"); unless ($ipconfig) { die("Failed to 'ipconfig /all':$!"); } my ($buffer); unless (defined $ipconfig->read($buffer, 8192)) { die("Failed to read from ipconfig:$!"); } if ($buffer =~ /^ +Physical Address(?:\. )+: ([0-9A-Fa-f]{1,2})\-([0-9A-Fa-f]{1,2})\-([0-9A-Fa-f]{1,2})\-([0-9A-Fa-f]{1,2})\-([0-9A-Fa-f]{1,2})\-([0-9A-Fa-f]{1,2})/m) { $macAddress = formatMac($1, $2, $3, $4, $5, $6); } unless ($ipconfig->close()) { die("Failed to close 'ipconfig /all':$!"); } } else { die("'$^O' cannot be recognised"); } print "mac address is $macAddress\n"; }

sub formatMac { my (@octets) = @_; return join(':', map { sprintf('%.2X', hex($_)) } @_); }


Multiple MACs

brian_d_foy on 2007-07-26T18:15:35

This is a really good start, but what I'd really like to have is a hash of interfaces and their MACs. Right now I have at least two MACs on my laptop: wireless card and cabled-ethernet.

Re:Multiple MACs

ddick on 2007-07-26T20:51:02

Yeah, this started as a way to uniquely identify a computer... GUID/MessageID sort of thingy

Does this do the job?

ddick on 2007-07-27T06:40:29

#! /usr/bin/perl -w

use strict;
use FileHandle();

MAIN: {
  my ($mac_address) = {};
  if (($^O eq 'linux') || ($^O eq 'solaris') || ($^O eq 'hpux') || ($^O eq 'aix')) {

    $ENV{PATH} = '/sbin:/usr/sbin:/bin:/usr/bin';
    delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};

    my ($ifconfig) = new FileHandle();
    if (my $pid = $ifconfig->open('-|')) {
      my ($buffer);
      unless (defined $ifconfig->read($buffer, 8192)) {
        die("Failed to read from ifconfig:$!");
      }
      if ($^O eq 'linux') {
        if ($buffer =~ /(\w+) +Link encap:Ethernet +HWaddr +([0-9A-Fa-f]{2}):([0-9A-Fa-f]{2}):([0-9A-Fa-f]{2}):([0-9A-Fa-f]{2}):([0-9A-Fa-f ]{2}):([0-9A-Fa-f]{2})/m)
        {
          $mac_address->{$1} = _format_mac($2, $3, $4, $5, $6, $7);
        }
      } elsif ($^O eq 'solaris') {
        my ($interface_name);
        foreach my $line (split(/\n/, $buffer)) {
          if ($line =~ /^(\w+): +/) {
            ($interface_name) = ($1);
          } elsif ($line =~ /^\tether +([0-9A-Fa-f]{1,2}):([0-9A-Fa-f]{1,2}):([0-9A-Fa-f]{1,2}):([0-9A-Fa-f]{1,2}):([0 -9A-Fa-f]{1,2}):([0-9A-Fa-f]{1,2}) +$/)
          {
            $mac_address->{$interface_name} = _format_mac($1, $2, $3, $4, $5, $6);
          }
        }
      } elsif ($^O eq 'hpux') {
        # hardware_path station_address crd_in# hdw_state net_name
        if ($buffer =~ /^\S+ +0x([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{ 2})([0-9A-Fa-f]{2}) +\d+ +\w+ +(\w+) +/m)
        {
          $mac_address->{$7} = _format_mac($1, $2, $3, $4, $5, $6);
        }
      } elsif ($^O eq 'aix') {
        # interface_name mtu network address
        if ($buffer =~ /^(\w+) +\d+ +\S+ +([0-9A-Fa-f]{1,2})\.([0-9A-Fa-f]{1,2})\.([0-9A-Fa-f]{1,2})\.([0-9A-Fa-f]{1,2})\ .([0-9A-Fa-f]{1,2})\.([0-9A-Fa-f]{1,2}) +/m)
        {
          $mac_address->{$1} = _format_mac($2, $3, $4, $5, $6, $7);
        }
      }
      unless ($ifconfig->close()) {
        if (($^O eq 'linux') || ($^O eq 'solaris')) {
          die("Failed to successfully execute 'ifconfig -a':$!");
        } elsif ($^O eq 'hpux') {
          die("Failed to successfully execute 'lanscan -a':$!");
        } elsif ($^O eq 'aix') {
          die("Failed to successfully execute 'netstat -ia':$!");
        } else {
          die("Unknown failure when determining mac address for '$^O'");
        }
      }
    } elsif (defined $pid) {
      eval {
        if (($^O eq 'linux') || ($^O eq 'solaris')) {
          unless (exec({ 'ifconfig' } 'ifconfig', '-a')) {
            die("Failed to execute 'ifconfig -a':$!");
          }
        } elsif ($^O eq 'hpux') {
          unless (exec({ 'lanscan' } 'lanscan', '-v')) {
            die("Failed to execute 'lanscan -v':$!");
          }
        } elsif ($^O eq 'aix') {
          unless (exec({ 'netstat' } 'netstat', '-ia')) {
            die("Failed to execute 'netstat -ia':$!");
          }
        } else {
          die("Failed to find a command to produce the mac address for '$^O'");
        }
      };
      print STDERR $@;
      exit(1);
    } else {
      die("Failed to fork:$!");
    }
  } elsif ($^O eq 'MSWin32') {
    my ($ipconfig) = new FileHandle("ipconfig /all |");
    unless ($ipconfig) {
      die("Failed to 'ipconfig /all':$!");
    }
    my ($buffer);
    unless (defined $ipconfig->read($buffer, 8192)) {
      die("Failed to read from ipconfig:$!");
    }
    my ($interface_name);
    foreach my $line (split(/\n/, $buffer)) {
      if ($line =~ /^(\w.*):\r$/) {
        ($interface_name) = ($1);
      } elsif ($line =~ /^ +Physical Address(?:\. )+: ([0-9A-Fa-f]{1,2})\-([0-9A-Fa-f]{1,2})\-([0-9A-Fa-f]{1,2})\-([0-9A-Fa-f]{1,2})\- ([0-9A-Fa-f]{1,2})\-([0-9A-Fa-f]{1,2})\r$/) {
        $mac_address->{$interface_name} = _format_mac($1, $2, $3, $4, $5, $6);
      }
    }
    unless ($ipconfig->close()) {
      die("Failed to close 'ipconfig /all':$!");
    }
  } else {
    die("'$^O' cannot be recognised");
  }
  use Data::Dumper;
  print Dumper($mac_address);
}

sub _format_mac {
  my (@octets) = @_;
  return join(':', map { sprintf('%.2X', hex($_)) } @_);
}