Go: 原始的winsock

huangapple go评论76阅读模式
英文:

Go : Raw winsock

问题

我正在尝试创建一个简单的TCP原始Winsock,但是我的socket.Recvfrom抛出一个错误"不支持的套接字",我做错了什么?

package main

import (
	"golang.org/x/sys/windows"
	"github.com/google/gopacket"
	"github.com/google/gopacket/layers"
	"log"
	"net"
	"sync"
	"os"
	"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
}

这段代码中的问题是socket.Recvfrom抛出了一个"不支持的套接字"错误。

英文:

Am trying to create a simple tcp raw winsock but my socket.Recvfrom trows an error "Not supported socket", what am i doing wrong ?

package main
import (
&quot;golang.org/x/sys/windows&quot;
&quot;github.com/google/gopacket&quot;
&quot;github.com/google/gopacket/layers&quot;
&quot;log&quot;
&quot;net&quot;
&quot;sync&quot;
&quot;os&quot;
//~ &quot;syscall&quot;
&quot;time&quot;
&quot;fmt&quot;
&quot;errors&quot;
&quot;unsafe&quot;
)
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        = &quot;eth0&quot;
Snaplen int32         = 65536
Timeout     time.Duration = 30 * time.Second
)
var (
ip4 layers.IPv4
tcp layers.TCP
)
parser := gopacket.NewDecodingLayerParser(layers.LayerTypeIPv4, &amp;ip4, &amp;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(), &amp;decoded)
if packetData == nil || err != nil {
continue
}
for _, layerType := range decoded {
switch layerType {
case layers.LayerTypeIPv4:
log.Println(&quot;    IP4 &quot;, 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 := &amp;Handle{}
p.blockForever = timeout &lt; 0
p.timeout = timeout
p.snaplen = snaplen
var d windows.WSAData
log.Println(&quot;Initialising Winsock...&quot;)
err = windows.WSAStartup(uint32(0x202), &amp;d)
if err != nil {
return nil, fmt.Errorf(&quot;Error: WSAStartup - %v&quot;, err)
}
log.Println(&quot;Initialised&quot;)
//Create a RAW Socket
log.Println(&quot;Creating RAW Socket...&quot;);
fd, err := windows.Socket(windows.AF_INET, windows.SOCK_RAW, windows.IPPROTO_IP)
if err != nil {
return nil, fmt.Errorf(&quot;Error: socket - %v&quot;, err)
}
p.socket = fd
log.Println(&quot;Created.&quot;)
// Retrieve the local hostname
hostname, err := os.Hostname()
if err != nil {
return nil, fmt.Errorf(&quot;Error: Hostname() - %v&quot;, err)
}
log.Printf(&quot;\nHost name : %s \n&quot;,hostname)
//Retrieve the available IPs of the local host
log.Println(&quot;Available Network Interfaces : \n&quot;)
_ , err = windows.GetHostByName(hostname)
if err != nil {
return nil, fmt.Errorf(&quot;Error: GetHostByName() - %v&quot;, err)
}
ip4 , iFcindex, err := externalIP()
if err != nil {
return nil, fmt.Errorf(&quot;Error: getIpv4() - %v&quot;, err)
} 
p.deviceIndex = iFcindex
la := new(windows.SockaddrInet4)
la.Port = int(0)
for i := 0; i &lt; net.IPv4len; i++ {
la.Addr[i] = ip4[i]
}
if err := windows.Bind(fd, la); err != nil {
return nil, fmt.Errorf (&quot;Error:Bind - %v&quot;, err)
}
inbuf := uint32(1)
sizebuf := uint32(unsafe.Sizeof(inbuf))
ret := uint32(0)
err = windows.WSAIoctl(fd, SIO_RCVALL , (*byte)(unsafe.Pointer(&amp;inbuf)) ,sizebuf, nil ,0 ,&amp;ret , nil, 0); 
if err != nil {
return nil, fmt.Errorf (&quot;Error:WSAIoctl() failed - %v&quot;, 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(&quot;Error:Recvfrom() - %v&quot;, 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))&lt;&lt;8 | int16(byte(n&gt;&gt;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&amp;net.FlagUp == 0 {
continue // interface down
}
if iface.Flags&amp;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(&quot;Active Network Interfaces %v : %v &quot; ,iface.Index , ip.String())
return IPBYTE ,ifaceIndex ,  nil 
}
}
err = errors.New(&quot;are you connected to the network?&quot;)
return 
}
// LinkType returns pcap_datalink, as a layers.LinkType.
func (p *Handle) LinkType() layers.LinkType {
return layers.LinkTypeIPv4
}

答案1

得分: 2

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

> not supported by windows

这是不言自明的。

如果你跟踪调用Recvfrom(),你会发现

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

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

英文:

In the current version of Go, the error message is

> not supported by windows

which is self-explanatory.

If you follow your call to Recvfrom(), you will find

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

which is the return of a static error message above.

huangapple
  • 本文由 发表于 2017年2月27日 06:37:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/42475093.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定