Skip to content

Instantly share code, notes, and snippets.

@Ultraporing
Last active April 26, 2024 01:41
Show Gist options
  • Save Ultraporing/fe52981f678be6831f747c206a4861cb to your computer and use it in GitHub Desktop.
Save Ultraporing/fe52981f678be6831f747c206a4861cb to your computer and use it in GitHub Desktop.
Golang implementation of an physical network interface filter usefull for packetsniffing and pcap. It provides you with the Adapter Name (in windows Friendly Name in addition) and MAC Address. Tunnels (VMs and such), loopback adapters get ignored. I updated my code from the https://github.com/regner/albiondata-client project and added an example.
package main
import (
"fmt"
ifil "./ifilter"
)
func main() {
physicalInterfaceList := ifil.GetAllPhysicalInterfaces()
fmt.Println("All Physical Network Interfaces:", physicalInterfaceList)
}
// Displays on my Windows PC:
// All Physical Network Interfaces: [{70:85:c2:81:12:b2:00:00 \Device\NPF_{78C88161-D74A-42E5-A0B8-EE6F815905C0} Ethernet 2}]
// On Linux and Mac there are no friendly names, so i replaced it with the name
package ifilter
import (
"strings"
)
type PhysicalInterface struct {
MACAddress string
Name string
FriendlyName string
}
// Mac Address parts to look for, and identify non physical devices. There may be more, update me!
var macAddrPartsToFilter []string = []string{
"00:03:FF", // Microsoft Hyper-V, Virtual Server, Virtual PC
"0A:00:27", // VirtualBox
"00:00:00:00:00", // Teredo Tunneling Pseudo-Interface
"00:50:56", // VMware ESX 3, Server, Workstation, Player
"00:1C:14", // VMware ESX 3, Server, Workstation, Player
"00:0C:29", // VMware ESX 3, Server, Workstation, Player
"00:05:69", // VMware ESX 3, Server, Workstation, Player
"00:1C:42", // Microsoft Hyper-V, Virtual Server, Virtual PC
"00:0F:4B", // Virtual Iron 4
"00:16:3E", // Red Hat Xen, Oracle VM, XenSource, Novell Xen
"08:00:27", // Sun xVM VirtualBox
"7A:79", // Hamachi
}
// Filters the possible physical interface address by comparing it to known popular VM Software adresses
// and Teredo Tunneling Pseudo-Interface.
func isPhysicalInterface(addr string) bool {
for _, macPart := range macAddrPartsToFilter {
if strings.HasPrefix(strings.ToLower(addr), strings.ToLower(macPart)) {
return false
}
}
return true
}
// +build linux darwin
package ifilter
import (
"net"
"fmt"
)
// Gets all physical interfaces based on filter results, ignoring all VM, Loopback and Tunnel interfaces.
func GetAllPhysicalInterfaces() []PhysicalInterface {
ifaces, err := net.Interfaces()
if err != nil {
fmt.Println(err)
return nil
}
var outInterfaces []PhysicalInterface
for _, element := range ifaces {
if element.Flags&net.FlagLoopback == 0 && element.Flags&net.FlagUp == 1 && isPhysicalInterface(element.HardwareAddr.String()) {
outInterfaces = append(outInterfaces, PhysicalInterface{MACAddress:element.HardwareAddr.String(), Name:element.Name, FriendlyName:element.Name})
}
}
return outInterfaces
}
// +build windows
package ifilter
import (
"os"
"syscall"
"unicode/utf16"
"unsafe"
"golang.org/x/sys/windows"
)
const (
IfOperStatusUp = 1
IF_TYPE_SOFTWARE_LOOPBACK = 24
IF_TYPE_TUNNEL = 131
)
const hexDigit = "0123456789abcdef"
func adapterAddresses() ([]*windows.IpAdapterAddresses, error) {
var b []byte
l := uint32(15000) // recommended initial size
for {
b = make([]byte, l)
err := windows.GetAdaptersAddresses(syscall.AF_UNSPEC, windows.GAA_FLAG_INCLUDE_PREFIX, 0, (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])), &l)
if err == nil {
if l == 0 {
return nil, nil
}
break
}
if err.(syscall.Errno) != syscall.ERROR_BUFFER_OVERFLOW {
return nil, os.NewSyscallError("getadaptersaddresses", err)
}
if l <= uint32(len(b)) {
return nil, os.NewSyscallError("getadaptersaddresses", err)
}
}
var aas []*windows.IpAdapterAddresses
for aa := (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])); aa != nil; aa = aa.Next {
aas = append(aas, aa)
}
return aas, nil
}
func bytePtrToString(p *uint8) string {
a := (*[10000]uint8)(unsafe.Pointer(p))
i := 0
for a[i] != 0 {
i++
}
return string(a[:i])
}
func physicalAddrToString(physAddr [8]byte) string {
if len(physAddr) == 0 {
return ""
}
buf := make([]byte, 0, len(physAddr)*3-1)
for i, b := range physAddr {
if i > 0 {
buf = append(buf, ':')
}
buf = append(buf, hexDigit[b>>4])
buf = append(buf, hexDigit[b&0xF])
}
return string(buf)
}
func cStringToString(cs *uint16) (s string) {
if cs != nil {
us := make([]uint16, 0, 256)
for p := uintptr(unsafe.Pointer(cs)); ; p += 2 {
u := *(*uint16)(unsafe.Pointer(p))
if u == 0 {
return string(utf16.Decode(us))
}
us = append(us, u)
}
}
return ""
}
// Gets all physical interfaces based on filter results, ignoring all VM, Loopback and Tunnel interfaces.
func GetAllPhysicalInterfaces() []PhysicalInterface {
aa, _ := adapterAddresses()
var outInterfaces []PhysicalInterface
for _, pa := range aa {
mac := physicalAddrToString(pa.PhysicalAddress)
name := "\\Device\\NPF_" + bytePtrToString(pa.AdapterName)
if pa.IfType != uint32(IF_TYPE_SOFTWARE_LOOPBACK) && pa.IfType != uint32(IF_TYPE_TUNNEL) &&
pa.OperStatus == uint32(IfOperStatusUp) && isPhysicalInterface(mac) {
outInterfaces = append(outInterfaces, PhysicalInterface{MACAddress:mac, Name:name, FriendlyName:cStringToString(pa.FriendlyName)})
}
}
return outInterfaces
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment