我想使用 gopacket 制作自定义 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 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")
}
但是运行此程序不起作用...序列化层失败。这是恐慌:
紧急:源 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 [终结器等待]: 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
您的问题说"crafte[sic] TCP 数据包",但您的代码清楚地表明您还想制作自定义 IP 第 3 层标头,并且两者之间存在差异。另外,您没有提到IPv4与IPv6,但您的代码似乎特定于IPv4。
给定您的示例代码,我假设您希望设置完整的IPv4标头。
从Go 1.3.3和即将发布的Go 1.4开始,你不能使用Core Go软件包做你想做的事情。要实现你想要的,你需要做两件事:
- 您需要在 Go 中创建一个原始套接字。与本网站上的其他错误答案相反,您可以使用
net.ListenPacket
、net.DialIP
或net.ListenIP
之一在 Go 中创建原始套接字。
例如:
conn, err := net.ListenIP("ip4:tcp", netaddr)
if err != nil {
log.Fatalf("ListenIP: %sn", err)
}
创建原始套接字。
- 如果要设置自己的IPv4第3层标头,则需要设置套接字选项以启用功能。
您的问题没有说明您正在使用的操作系统和体系结构。在运行 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
也可以在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地址,我怀疑您要这样做。