Go:Raw winsock

时间:2017-02-26 22:37:59

标签: windows go winsock

我试图创建一个简单的tcp raw winsock,但我的socket.Recvfrom收到错误"不支持套接字",我做错了什么?

package main

import (
    "golang.org/x/sys/windows"
    "github.com/google/gopacket"
    "github.com/google/gopacket/layers"
    "log"
    "net"
    "sync"
    "os"
    //~ "syscall"
    "time"
    "fmt"
    "errors"
    "unsafe"
)

const SIO_RCVALL = windows.IOC_IN | windows.IOC_VENDOR | 1

type Handle struct {
    blockForever bool
    device       string
    deviceIndex  int
    mu           sync.Mutex
    socket       windows.Handle
    timeout      time.Duration
    snaplen      int32
}

const BlockForever = -time.Millisecond * 10

func main() {
    var (
        device    string        = "eth0"
        Snaplen int32         = 65536
        Timeout     time.Duration = 30 * time.Second
    )

    var (
       ip4 layers.IPv4
       tcp layers.TCP
    )

    parser := gopacket.NewDecodingLayerParser(layers.LayerTypeIPv4, &ip4, &tcp)
    decoded := []gopacket.LayerType{}

    hnd, err := OpenLive(device, Snaplen, Timeout)
    if err != nil {
        log.Fatal(err)
    }
    defer hnd.Close()

    packetSource := gopacket.NewPacketSource(hnd, hnd.LinkType())

    for packetData := range packetSource.Packets() {
        err := parser.DecodeLayers(packetData.Data(), &decoded)

        if packetData == nil || err != nil {
            continue
        }

        for _, layerType := range decoded {
          switch layerType {
            case layers.LayerTypeIPv4:
                log.Println("    IP4 ", ip4.SrcIP, ip4.DstIP)
            case layers.LayerTypeTCP:
                log.Println(tcp.TransportFlow().Src().String())
          }
        }
  }

}

func OpenLive(device string, snaplen int32, timeout time.Duration) (handle *Handle, err error) {
    p := &Handle{}
    p.blockForever = timeout < 0
    p.timeout = timeout
    p.snaplen = snaplen

    var d windows.WSAData

    log.Println("Initialising Winsock...")
    err = windows.WSAStartup(uint32(0x202), &d)
    if err != nil {
        return nil, fmt.Errorf("Error: WSAStartup - %v", err)
    }
    log.Println("Initialised")

    //Create a RAW Socket
    log.Println("Creating RAW Socket...");
    fd, err := windows.Socket(windows.AF_INET, windows.SOCK_RAW, windows.IPPROTO_IP)
    if err != nil {
        return nil, fmt.Errorf("Error: socket - %v", err)
    }
    p.socket = fd
    log.Println("Created.")

    // Retrieve the local hostname
    hostname, err := os.Hostname()

    if err != nil {
        return nil, fmt.Errorf("Error: Hostname() - %v", err)
    }
    log.Printf("\nHost name : %s \n",hostname)

    //Retrieve the available IPs of the local host
    log.Println("Available Network Interfaces : \n")
    _ , err = windows.GetHostByName(hostname)

    if err != nil {
        return nil, fmt.Errorf("Error: GetHostByName() - %v", err)
    }

    ip4 , iFcindex, err := externalIP()
    if err != nil {
        return nil, fmt.Errorf("Error: getIpv4() - %v", err)
    } 
    p.deviceIndex = iFcindex

    la := new(windows.SockaddrInet4)
    la.Port = int(0)

    for i := 0; i < net.IPv4len; i++ {
        la.Addr[i] = ip4[i]
    }

    if err := windows.Bind(fd, la); err != nil {
        return nil, fmt.Errorf ("Error:Bind - %v", err)
    }

    inbuf := uint32(1)
    sizebuf := uint32(unsafe.Sizeof(inbuf))
    ret := uint32(0)

    err = windows.WSAIoctl(fd, SIO_RCVALL , (*byte)(unsafe.Pointer(&inbuf)) ,sizebuf, nil ,0 ,&ret , nil, 0); 

    if err != nil {
        return nil, fmt.Errorf ("Error:WSAIoctl() failed - %v", err)
    }

    return p, nil

}

// Close closes the underlying socket handle.
func (p *Handle) Close() {
    p.mu.Lock()
    defer p.mu.Unlock()

    windows.Close(p.socket)
}

func (p *Handle) ReadPacketData() (data []byte, ci gopacket.CaptureInfo, err error) {
    p.mu.Lock()
    data = make([]byte, 65536)
    n, _, err := windows.Recvfrom(p.socket, data, 0)
    log.Println(n)
    if err != nil {
        log.Printf("Error:Recvfrom() - %v", err)
    }
    ci = gopacket.CaptureInfo{Timestamp: time.Now(), CaptureLength: len(data), Length: n, InterfaceIndex: p.deviceIndex}

    p.mu.Unlock()

    return
}

func htons(n int) int {
    return int(int16(byte(n))<<8 | int16(byte(n>>8)))
}

func externalIP() (IPBYTE []byte, ifaceIndex int ,err error) {

    ifaces, err := net.Interfaces()
    if err != nil {
        return 
    }

    IPBYTE = make([]byte, 4)
    ifaceIndex =  0

    for _, iface := range ifaces {
        if iface.Flags&net.FlagUp == 0 {
            continue // interface down
        }
        if iface.Flags&net.FlagLoopback != 0 {
            continue // loopback interface
        }
        addrs, err := iface.Addrs()
        if err != nil {
            continue 
        }

        for _, addr := range addrs {
            var ip net.IP
            switch v := addr.(type) {
            case *net.IPNet:
                ip = v.IP
            case *net.IPAddr:
                ip = v.IP
            }
            if ip == nil || ip.IsLoopback() {
                continue
            }
            IPBYTE = ip.To4()
            ifaceIndex = iface.Index
            if IPBYTE == nil {
                continue // not an ipv4 address
            }
            //~ err = nil

            log.Printf("Active Network Interfaces %v : %v " ,iface.Index , ip.String())
            return IPBYTE ,ifaceIndex ,  nil 
        }
    }

    err = errors.New("are you connected to the network?")
    return 
}

// LinkType returns pcap_datalink, as a layers.LinkType.
func (p *Handle) LinkType() layers.LinkType {
    return layers.LinkTypeIPv4
}

1 个答案:

答案 0 :(得分:2)

在当前版本的Go中,错误消息为

  

不支持Windows

这是不言自明的。

如果你跟随Recvfrom()的电话,你会发现

func Recvfrom(fd Handle, p []byte, flags int) (n int, from Sockaddr, err error) {
    return 0, nil, syscall.EWINDOWS
}

这是上面的静态错误消息的返回。