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

这是一个简短易读的示例go程序,
演示我想做什么:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
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!
")
}

但是,运行该程序不起作用... SerializeLayer失败。
这是恐慌:

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

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

您的问题是说"制作自定义TCP数据包",但是您的代码清楚地表明,您还希望制作自定义IP第3层标头,两者之间是有区别的。另外,您没有提到IPv4与IPv6,但是同样,您的代码似乎是IPv4特定的。

给定您的示例代码,我假设您想设置完整的IPv4标头。

从Go 1.3.3和即将发布的Go 1.4开始,您将无法使用Core Go软件包来完成您想做的事情。要实现您想要的目标,您需要做两件事:

  • 您需要在Go中创建一个原始套接字。与本网站上的其他错误答案相反,您可以使用net.ListenPacketnet.DialIPnet.ListenIP之一在Go中创建原始套接字。
  • 例如:

    1
    2
    3
    4
    5
    conn, err := net.ListenIP("ip4:tcp", netaddr)
    if err != nil {
        log.Fatalf("ListenIP: %s
    ", err)
    }

    创建一个原始套接字。

  • 如果要设置自己的IPv4第3层标头,则需要设置套接字选项以启用功能。
  • 您的问题没有说明您正在使用什么操作系统和体系结构。在运行Mac OS X的笔记本电脑上:

    1
    2
    3
    4
    5
    % 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在Linux上也可用。不幸的是,Core Go无法设置IP_HDRINCL套接字选项,也无法设置其他IP套接字选项(例如IP_TTL)。我有一组私人补丁程序,这些补丁程序可以通过Core Go启用此功能,但对您没有帮助。

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

    另请参见此处:原始套接字和他在此处编写的代码延迟,以感受一种更简单的方法,如果您只想设置TCP标头,它可能会满足您的需求。但是,请注意,此代码不允许您在IPv4 IP标头中设置IP地址,我怀疑您想这样做。

    • 谢谢! 是的。 在此提交中正常工作:github.com/david415/HoneyBadger/blob/
    • 这是您链接的博客文章的后续文章,该文章下至IP标头级别:darkcoding.net/software/raw-sockets-in-go-link-layer