Updated 2015-03-23 15:11:42 by EF

This is the second version of this script, it provides for more information and is more generic than what was posted on this page earlier. At the bottom is the only "interface" that you should know of, a procedure called mac.

  • Call it without argument (or with the argument bound) and you will get the original behaviour, i.e. you will received a list of the MAC addresses of the "real" interfaces that are currently bound and active on your computer.
  • Call it with the argument ethernet and you will get the list of Ethernet MAC addresses, even if they are not bound. These can be used to uniquely identify your computer (at least to some extent, since a MAC address can be spoofed and changed).
  • Call it with the argument wifi (or wireless, they can be used interchangeably) and you will get a list of the wireless interfaces.

This version does its best to perform output from the commands that are called and would not be in English. It also segragates interfaces that are no "real" interfaces (virtual network cards, bluetooth, etc.).

Caveats:

  • Sadly, I only have occasional access to a Mac and the current code will not properly work for ethernet or wireless on that platform. Mac OSX seems to be calling both interfaces en0 and en1 and I couldn't find information that would tell me which one is which.
  • I have only tested this on Ubuntu, ifconfig might behave differently on other distributions (CoreOS, Arch, etc.). Please correct and amend as needed. NetBSD and its friends might also use different naming conventions for the interfaces, somebody?
  • Windows translates the output of ipconfig, so please, please correct and amend all you non-english techies!

A properly packaged version of this code can be found as part of another project on bitbucket
proc mac.section { iface_ptn ipv4_ptn allow deny section } {
    if { [llength $section] > 0 } {
        set mac_ptn {([0-9a-fA-F][0-9a-fA-F][\-:]){5}[0-9a-fA-F][0-9a-fA-F]}
        set mac ""
        set ip4 ""
        set iface ""
        set lno 0
        foreach s $section {
            if { $lno == 0 } {
                if { [regexp $iface_ptn $s - i] } {
                    set iface $i
                }
            }
            if { [regexp $mac_ptn $s m] } {
                set mac $m
            }
            if { $ipv4_ptn ne "" && [regexp -nocase -- $ipv4_ptn $s - - i] } {
                set ip4 $i
            }
            if { ($ip4 ne "" || $ipv4_ptn eq "" ) \
                     && $mac ne "" && $iface ne "" } {
                foreach ptn $allow {
                    if { [regexp $ptn $iface] } {
                        set denied 0
                        foreach ptn $deny {
                            if { [regexp $ptn $iface] } {
                                set denied 1
                                break
                            }
                        }
                        if { ! $denied } {
                            return $mac
                        }
                    }
                }
            }
            incr lno
        }
    }
    return ""
}


proc mac.gather { cmd iface_ptn ipv4_ptn allow deny } {
    set macs {}

    set section {}
    if { [catch {eval [linsert $cmd 0 exec]} res] == 0 } {
        foreach l [split $res "\n\r"] {
            if { [string trim $l] ne "" } {
                if { ![string is space [string index $l 0]] } {
                    set mac [mac.section $iface_ptn $ipv4_ptn $allow $deny $section]
                    if { $mac ne "" } {
                        lappend macs $mac
                    }
                    set section {}
                    lappend section $l
                } else {
                    lappend section [string trim $l]
                }
            }
        }
        set mac [mac.section $iface_ptn $ipv4_ptn $allow $deny $section]
        if { $mac ne "" } {
            lappend macs $mac
        }
    }
    return $macs
}


proc mac { { type "bound" } } {
    global tcl_platform

    switch -nocase -glob -- $type {
        "bound" {
            if { $tcl_platform(platform) eq "windows" } {
                return [mac.gather \
                            [concat [auto_execok ipconfig] /all] \
                            {(.*?):$} \
                            {.*ip.*?:\s*((\d{1,3}.){3}\d{1,3})} \
                            {{[Ee]thernet.*} {[Ww]ireless.*}} \
                            {}]
            } else {
                return [mac.gather \
                            [concat [auto_execok ifconfig] -a] \
                            {^(\w+\d+)} \
                            {^(inet\s+addr:|inet\s+)((\d{1,3}.){3}\d{1,3})} \
                            {{eth\d+} {wlan\d+} {en\d+}} \
                            {}]
            }
        }
        "eth*" {
            if { $tcl_platform(platform) eq "windows" } {
                return [mac.gather \
                            [concat [auto_execok ipconfig] /all] \
                            {(.*?):$} \
                            "" \
                            {{[Ee]thernet.*}} \
                            {{[Bb]luetooth}}]
            } else {
                return [mac.gather \
                            [concat [auto_execok ifconfig] -a] \
                            {^(\w+\d+)} \
                            "" \
                            {{eth\d+} {en\d+}} \
                            {}]
            }
        }
        "wire*" -
        "wifi" {
            if { $tcl_platform(platform) eq "windows" } {
                return [mac.gather \
                            [concat [auto_execok ipconfig] /all] \
                            {(.*?):$} \
                            "" \
                            {{[Ww]ireless.*}} \
                            {}]
            } else {
                return [mac.gather \
                            [concat [auto_execok ifconfig] -a] \
                            {^(\w+\d+)} \
                            "" \
                            {{wlan\d+} {en\d+}} \
                            {}]
            }
        }
    }
}

puts "[mac]"
puts "[mac ethernet]"