diff --git a/README.md b/README.md index 00969a5..69563e7 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,15 @@ func main() { if err != nil { log.Fatal(err) } + + ifce.SetMAC("d6:db:b0:42:2c:7e") + + mac, err := ifce.GetMAC() + if err != nil { + log.Fatal(err) + } + fmt.Println("MAC address:", mac) + var frame ethernet.Frame for { diff --git a/if.go b/if.go index 4023a1a..d2d87ee 100644 --- a/if.go +++ b/if.go @@ -3,6 +3,10 @@ package water import ( "errors" "io" + "net" + "os" + "syscall" + "unsafe" ) // Interface is a TUN/TAP interface. @@ -78,3 +82,57 @@ func (ifce *Interface) IsTAP() bool { func (ifce *Interface) Name() string { return ifce.name } + +// GetMAC returns the created interface's MAC address +func (ifce *Interface) GetMAC() (string, error) { + var req ifReq + req.Flags = syscall.AF_UNIX + copy(req.Name[:], ifce.name) + + fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, 0) + if err != nil { + return "", os.NewSyscallError("socket", err) + } + defer syscall.Close(fd) + + err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1) + if err != nil { + return "", os.NewSyscallError("setsockopt", err) + } + + err = ioctl(uintptr(fd), syscall.SIOCGIFHWADDR, uintptr(unsafe.Pointer(&req))) + if err != nil { + return "", err + } + return net.HardwareAddr(req.Mac[:]).String(), nil +} + +// SetMAC sets the MAC address for the interface +func (ifce *Interface) SetMAC(mac string) error { + var req ifReq + req.Flags = syscall.AF_UNIX + copy(req.Name[:], ifce.name) + + macBytes, err := net.ParseMAC(mac) + if err != nil { + return err + } + copy(req.Mac[:], macBytes) + + fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, 0) + if err != nil { + return os.NewSyscallError("socket", err) + } + defer syscall.Close(fd) + + err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1) + if err != nil { + return os.NewSyscallError("setsockopt", err) + } + + err = ioctl(uintptr(fd), syscall.SIOCSIFHWADDR, uintptr(unsafe.Pointer(&req))) + if err != nil { + return err + } + return nil +} diff --git a/syscalls_linux.go b/syscalls_linux.go index af382d1..dced6f2 100644 --- a/syscalls_linux.go +++ b/syscalls_linux.go @@ -17,7 +17,8 @@ const ( type ifReq struct { Name [0x10]byte Flags uint16 - pad [0x28 - 0x10 - 2]byte + Mac [6]byte + pad [0x28 - 0x10 - 8]byte } func ioctl(fd uintptr, request uintptr, argp uintptr) error {