通过调用 Go 中的 Windows DLL 发送 ARP 请求不起作用

sending ARP request by calling Windows DLLs inside Go doesn't work

我正在尝试从 Go 调用 Windows API SendARP 以在 Windows 上发送 arp 请求,但它总是 returns 1168,又名 ERROR_NOT_FOUND,MSDN 对此错误代码的描述:

Element not found. This error is returned on Windows Vista if the the SrcIp parameter does not specify a source IPv4 address on an interface on the local computer or the INADDR_ANY IP address (an IPv4 address of 0.0.0.0).

但我在 Windows 7,而且我确实指定了正确的源 IPv4 地址。而且我在 Wireshark 中没有看到发送的 ARP 数据包。那么问题出在哪里呢?

package main

import (
    "fmt"
    "syscall"
    "net"
    "unsafe"
)

var (
    iphlp, _   = syscall.LoadLibrary("iphlpapi.dll")
    SendARP, _ = syscall.GetProcAddress(iphlp, "SendARP")
)

func sendARP(src, dst net.IP) {
    //var nargs uintptr = 4
    var len uint = 6
    mac := []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
    ret, _, callErr := syscall.Syscall6(
    uintptr(SendARP), 4,
    uintptr(unsafe.Pointer(&dst[0])),
    uintptr(unsafe.Pointer(&src[0])),
    uintptr(unsafe.Pointer(&mac[0])),
    uintptr(unsafe.Pointer(&len)),
    0,
    0)

    if callErr == 0 {
        fmt.Printf("result %v\n", int(ret))
    }
}

func main() {
    defer syscall.FreeLibrary(iphlp)

    fmt.Printf("addr: %v\n", sendARP)

    dst := net.IPv4(192,168,1,1)
    src := net.IPv4(192,168,1,103)
    sendARP(src, dst)   
}

请试试这个

package main

import (
    "fmt"
    "log"
    "net"
    "syscall"
    "unsafe"
)

var SendARP = syscall.MustLoadDLL("iphlpapi.dll").MustFindProc("SendARP")

func ip4ToUint32(ip net.IP) (uint32, error) {
    ip = ip.To4()
    if ip == nil {
        return 0, fmt.Errorf("ip address %v is not ip4", ip)
    }
    var ret uint32
    for i := 4; i > 0; i-- {
        ret <<= 8
        ret += uint32(ip[i-1])
    }
    return ret, nil
}

func sendARP(ip net.IP) (net.HardwareAddr, error) {
    dst, err := ip4ToUint32(ip)
    if err != nil {
        return nil, err
    }
    mac := []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
    n := uint32(len(mac))
    ret, _, _ := SendARP.Call(
        uintptr(dst),
        0,
        uintptr(unsafe.Pointer(&mac[0])),
        uintptr(unsafe.Pointer(&n)))
    if ret != 0 {
        return nil, syscall.Errno(ret)
    }
    return mac, nil
}
func main() {
    ip := net.IPv4(192, 168, 1, 1)
    mac, err := sendARP(ip)
    if err != nil {
        log.Fatalf("could not find MAC for %q: %v", ip, err)
    }
    fmt.Printf("MAC address for %v is %v\n", ip, mac)
}

对我有用。

亚历克斯