如何使用Golang编写原始TCP数据包(使用gopacket)并通过原始套接字发送 [英] How to use Golang to compose raw TCP packet (using gopacket) and send it via raw socket

查看:4835
本文介绍了如何使用Golang编写原始TCP数据包(使用gopacket)并通过原始套接字发送的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用gopacket制作custome TCP数据包,然后
使用原始套接字发送它们。

这是一个简短易读的示例go程序,
演示了我想要做的事情:

  package main 

import(
code.google.com/p/gopacket
code.google.com/p/gopacket/examples/util
code.google.com/p/gopacket/layers
log
net


func main(){
defer util.Run()()

// XXX创建tcp / ip包
srcIP:= net.ParseIP(127.0.0.1)
dstIP:= net.ParseIP(192.168.0.1)
// srcIPaddr:= net.IPAddr {
// IP:srcIP,
//}
dstIPaddr:= net.IPAddr {
IP:dstIP,
}
ipLayer:= layers.IPv4 {
SrcIP:srcIP,
DstIP:dstIP,
协议:layers.IPProtocolTCP,
}
tcpLayer:= layers.TCP {
SrcPort:layers.TCPPort(666),
DstPort:layers.TCPPort(22),
SYN:true,
}
tcpLayer.SetNetworkLayerForChecksum(& ipLayer)
buf:= gopacket.NewSerializeBuffer()
opts:= gopacket.SerializeOptions {
FixLengths:true,
ComputeChecksums:true,
}
err:= gopacket.SerializeLayers(buf,opts,& ipLayer,& amp ; tcpLayer)
如果err!= nil {
panic(err)
}
// XXX创建数据包结束

// XXX发送数据包
ipConn,err:= net.ListenPacket(ip4:tcp,0.0.0.0)
if err!= nil {
panic(err)
}
_,err = ipConn.WriteTo(buf.Bytes(),&dstIPaddr)
if err!= nil {
panic(err)
}
log.Print (packet sent!\\\

}

然而运行这个程序doesn' t工作... SerializeLayer失败。
恐慌:
$ b


panic:无效src IP 127.0.0.1



goroutine 16 [running]:runtime.panic(0x5bb020,0xc2090723e0)
/home/human/golang-empire/go/src/pkg/runtime/panic.c:279+ 0xf5 main.main()
/home/human/golang-empire/gopkg/src/github.com/david415/HoneyBadger/packetSendTest.go:41 + 0x464


goroutine 19 [ finalizer wait]:runtime.park(0x413cc0,0x7bc6c0,
0x7bb189)
/home/human/golang-empire/go/src/pkg/runtime/proc.c:1369+x89 runtime.parkunlock( 0x7bc6c0,0x7bb189)
/home/human/golang-empire/go/src/pkg/runtime/proc.c:1385+ 0x3b runfinq()
/ home / human / golang-empire / go / src / pkg / runtime / mgc0.c:2644 + 0xcf runtime.goexit()
/home/human/golang-empire/go/src/pkg/runtime/proc.c:1445



解决方案

你的问题是craft custome [sic] TCP packets清除你还想制作自定义IP层3头,两者之间有区别。此外,您不提IPv4或IPv6,但您的代码似乎与IPv4相关。



考虑到您的示例代码,我假设您希望设置完整的IPv4 header。

从Go 1.3.3到即将发布的Go 1.4,你都无法用Core Go包做你想做的事。为了完成你的愿望,你需要做两件事:


  1. 你需要在Go中创建一个原始套接字。与此网站上的其他不正确答案相反,您可以使用 net.ListenPacket net.DialIP net.ListenIP

例如:

  conn,err:= net.ListenIP(ip4:tcp,netaddr)
if err!= nil {
log.Fatalf(ListenIP:%s \ n,err)
}

创建一个原始套接字。


  1. 如果您想设置自己的IPv4第3层标头,您需要设置一个套接字选项来启用功能。

你的问题没有说明你使用的是什么操作系统和架构。在运行Mac OS X的笔记本电脑上:

 %man ip 
。 。 。
除非已设置IP_HDRINCL选项,否则传出数据包会自动为它们添加一个IP标头
(基于目标地址和创建套接字的协议号)

IP_HDRINCL 也可在Linux上使用。不幸的是,Core Go没有办法设置 IP_HDRINCL 套接字选项,也没有办法设置其他IP套接字选项,比如 IP_TTL 。我有一组专用的补丁程序,可以使用Core Go的这种功能,但这对您无能为力。



我相信以下软件包具有您期望的所有功能 IPv4的。请注意,这是一个很大的包,我自己也没有用过。我做了grep,它在多个平台上支持 IP_HDRINCL 。你想调用 NewRawConn 创建一个原始连接,这个函数创建一个原始套接字并设置 IP_HDRINCL 套接字选项。

另见这里: raw-sockets-in-go 和他在这里写的代码延迟来感受一种更简单的方法,如果你只是想设置TCP头,可能会适合你的需求。但是,请注意,此代码不允许您在IPv4 IP标头中设置我怀疑您想要执行的IP地址。


I would like to craft custome TCP packets using gopacket and then send them using raw sockets.

Here is a short and readable example go program that demonstrates what I'd like to do:

package main

import (
    "code.google.com/p/gopacket"
    "code.google.com/p/gopacket/examples/util"
    "code.google.com/p/gopacket/layers"
    "log"
    "net"
)

func main() {
    defer util.Run()()

    // XXX create tcp/ip packet
    srcIP := net.ParseIP("127.0.0.1")
    dstIP := net.ParseIP("192.168.0.1")
    //srcIPaddr := net.IPAddr{
    //  IP: srcIP,
    //}
    dstIPaddr := net.IPAddr{
        IP: dstIP,
    }
    ipLayer := layers.IPv4{
        SrcIP:    srcIP,
        DstIP:    dstIP,
        Protocol: layers.IPProtocolTCP,
    }
    tcpLayer := layers.TCP{
        SrcPort: layers.TCPPort(666),
        DstPort: layers.TCPPort(22),
        SYN:     true,
    }
    tcpLayer.SetNetworkLayerForChecksum(&ipLayer)
    buf := gopacket.NewSerializeBuffer()
    opts := gopacket.SerializeOptions{
        FixLengths:       true,
        ComputeChecksums: true,
    }
    err := gopacket.SerializeLayers(buf, opts, &ipLayer, &tcpLayer)
    if err != nil {
        panic(err)
    }
    // XXX end of packet creation

    // XXX send packet
    ipConn, err := net.ListenPacket("ip4:tcp", "0.0.0.0")
    if err != nil {
        panic(err)
    }
    _, err = ipConn.WriteTo(buf.Bytes(), &dstIPaddr)
    if err != nil {
        panic(err)
    }
    log.Print("packet sent!\n")
}

However running this program doesn't work... the SerializeLayer fails. Here's the panic:

panic: invalid src IP 127.0.0.1

goroutine 16 [running]: runtime.panic(0x5bb020, 0xc2090723e0) /home/human/golang-empire/go/src/pkg/runtime/panic.c:279 +0xf5 main.main() /home/human/golang-empire/gopkg/src/github.com/david415/HoneyBadger/packetSendTest.go:41 +0x464

goroutine 19 [finalizer wait]: runtime.park(0x413cc0, 0x7bc6c0, 0x7bb189) /home/human/golang-empire/go/src/pkg/runtime/proc.c:1369 +0x89 runtime.parkunlock(0x7bc6c0, 0x7bb189) /home/human/golang-empire/go/src/pkg/runtime/proc.c:1385 +0x3b runfinq() /home/human/golang-empire/go/src/pkg/runtime/mgc0.c:2644 +0xcf runtime.goexit() /home/human/golang-empire/go/src/pkg/runtime/proc.c:1445

解决方案

You question says "craft custome[sic] TCP packets" but your code makes it clear you also want to craft custom IP layer 3 headers and there is a difference between the two. Also, you don't mention IPv4 vs IPv6, but again your code seems IPv4 specific.

Given your example code I'll assume you want to be set the full IPv4 header.

As of Go 1.3.3 and the soon to be released Go 1.4 you can't do what you want using the Core Go packages. To accomplish what you desire you need to do two things:

  1. You need to create a raw socket in Go. Contrary to other incorrect answers on this website you can create a raw socket in Go using one of net.ListenPacket, net.DialIP, or net.ListenIP.

For example:

conn, err := net.ListenIP("ip4:tcp", netaddr)
if err != nil {
    log.Fatalf("ListenIP: %s\n", err)
}

creates a raw socket.

  1. If you want to set your own IPv4 layer 3 header you will need to set a socket option to enable functionality.

Your question don't state what OS and architecture you are using. On my laptop running Mac OS X:

% man ip
. . .
Outgoing packets automatically have an IP header prepended to them
(based on the destination address and the protocol number the socket is created with),
unless the IP_HDRINCL option has been set.

IP_HDRINCL is also available on Linux. Unfortunately, Core Go does not have a way to set the IP_HDRINCL socket option nor does it have a way to set other IP socket options such as IP_TTL. I have a set of private patches that enable this functionality with Core Go but that won't help you.

I believe the following package has all the functionality you desire ipv4. Please note it's a large package and I haven't used it myself. I did grep and it supports IP_HDRINCL on multiple platforms. You want to call NewRawConn to create a raw connection and this function creates a raw socket and sets the IP_HDRINCL socket option.

See also here: raw-sockets-in-go and the code he wrote here latency to get a feel for a much simpler approach that might suit your needs if you just want to set TCP headers. However, please note this code doesn't let you set the IP addresses in the IPv4 IP header which I suspect you want to do.

这篇关于如何使用Golang编写原始TCP数据包(使用gopacket)并通过原始套接字发送的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆