如何使用Golang编写原始TCP数据包(使用gopacket)并通过原始套接字发送

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!
")
}

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

dongzen7263
dongzen7263 此新提交通过将srcPort和dstPort与数据包分解后的预期值进行比较,证明了生成的TCP/IP数据包格式错误:github.com/david415/HoneyBadger/blob/…
5 年多之前 回复
dongle19863
dongle19863 目前,我的简单示例是发送精心制作的TCP/IP数据包...但是端口号和其他部分格式错误。也许TCP端口的“字节序”设置错误?这里有一个简单的例子:github.com/david415/HoneyBadger/blob/…
5 年多之前 回复
dqprf0976
dqprf0976 好的...我修复了“无效的srcip”错误...这是由于ParseIP返回了错误的类型...它需要使用.To4()方法进行转换;-)
5 年多之前 回复

1个回答

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
", 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.

doulao1966
doulao1966 这是您链接的博客文章的后续文章,该文章下至IP标头级别:darkcoding.net/software/raw-sockets-in-go-link-layer
4 年多之前 回复
duanshan1856
duanshan1856 谢谢! 是的。 在此提交中正常工作:github.com/david415/HoneyBadger/blob/…
5 年多之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问
相关内容推荐