Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
mzky opened this issue Aug 20, 2021 · 1 comment
Open

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

mzky opened this issue Aug 20, 2021 · 1 comment

Comments

@mzky
Copy link

@mzky mzky commented Aug 20, 2021

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
}
@mknyszek mknyszek changed the title In Linux, the real MAC address cannot be obtained after a NIC is bound net: real MAC address cannot be obtained after a NIC is bound on linux Aug 20, 2021
@mknyszek mknyszek added this to the Backlog milestone Aug 20, 2021
@mknyszek
Copy link
Contributor

@mknyszek mknyszek commented Aug 20, 2021

CC @neild

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants