Skip to content

net: real MAC address cannot be obtained after a NIC is bound on linux #47828

@mzky

Description

@mzky

What version of Go are you using (go version)?

$ go version
go version go1.16.2 linux/amd64

Does this issue reproduce with the latest release?

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
amd64 and arm64

What did you expect to see?

net.Interfaceaddrs () gets the real MAC address

What did you see instead?

net.Interfaceaddrs () gets the fake MAC address after the network adapter is bound

What did you do?

image

Code sample:

package main

import (
	"encoding/hex"
	"fmt"
	"net"
	"strings"
	"syscall"
	"unsafe"
)

func main() {
	getPermanentMacAddr()
}

// If we use bond or team technology
// to use two or more adapters as a virtual one
// use net.Interface.HardwareAddr will get the same mac address
// The following code thinking was borrowed from ethtool's source code ethtool.c
// this code will get the permanent mac address
func getPermanentMacAddr() error {
	var err error
	fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, 0)
	if err != nil {
		fd, err = syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, syscall.NETLINK_GENERIC)
		if err != nil {
			return err
		}
	}

	defer func() {
		_ = syscall.Close(fd)
	}()
	var adapters []net.Interface
	adapters, _ = net.Interfaces()

	for _, adapter := range adapters {
		var data struct {
			cmd  uint32
			size uint32
			data [128]byte
		}

		data.cmd = 0x20
		data.size = 128
		// data.data = make([]byte, 128)

		var ifr struct {
			IfrName [16]byte
			IfrData unsafe.Pointer
		}
		copy(ifr.IfrName[:], adapter.Name)
		ifr.IfrData = unsafe.Pointer(&data)

		_, _, sysErr := syscall.RawSyscall(syscall.SYS_IOCTL,
			uintptr(fd), uintptr(0x8946), uintptr(unsafe.Pointer(&ifr)))

		if sysErr != 0 {
			fmt.Println("调用ioctl获取网口", adapter.Name, "物理MAC地址错误")
			// return errors.New("call ioctl get permanent mac address error")
			continue
		}
		// If mac address is all zero, this is a virtual adapter
		// we ignore it
		bAllZERO := true
		var i uint32 = 0
		for i = 0; i < data.size; i++ {
			if data.data[i] != 0x00 {
				bAllZERO = false
				break
			}
		}

		if bAllZERO {
			continue
		}

		if len(hex.EncodeToString(data.data[0:data.size])) > 12 {
			continue
		}

		mac := strings.ToUpper(hex.EncodeToString(data.data[0:data.size]))
		for i := 10; i > 0; i = i - 2 {
			mac = fmt.Sprintf("%s:%s", mac[:i], mac[i:])
		}

		fmt.Println(mac)
	}

	return nil
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    NeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions