You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Golang发送指定TCP数据包?Wireshark包转字节数组问题

解决方法

你捕获的是包含**以太网帧头、IP头、TCP头(带SYN标志)**的完整链路层数据包,不能通过net.Dial创建的TCP连接发送——因为这种连接是系统已经完成三次握手的传输层连接,会自动处理下层协议封装。要发送原始数据包,需要使用raw socket,并先把捕获的十六进制数据转换成字节数组。

步骤1:提取并转换十六进制数据

先把你提供的十六进制内容清理掉注释、地址前缀和空格,得到纯十六进制字符串,再用Go的encoding/hex包转成字节数组,最终实现发送:

package main

import (
	"encoding/hex"
	"fmt"
	"net"
	"syscall"
)

func main() {
	// 清理后的纯十六进制字符串(移除注释、地址标识和空格)
	hexStr := "5c647adfa951c87f5404ca0908004500003448494000800604a4c0a80068c0632c63f70b083aa055b59c000000008002faf071100000020405b40103030801010402"
	// 将十六进制字符串转换为字节数组
	packetBytes, err := hex.DecodeString(hexStr)
	if err != nil {
		fmt.Println("十六进制转字节数组失败:", err)
		return
	}

	// 创建raw socket,用于发送链路层原始数据包
	fd, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_RAW, syscall.HTONS(syscall.ETH_P_ALL))
	if err != nil {
		fmt.Println("创建raw socket失败:", err)
		return
	}
	defer syscall.Close(fd)

	// 指定发送数据包的网卡(替换为你机器的实际网卡名,比如eth0、en0)
	iface, err := net.InterfaceByName("en0")
	if err != nil {
		fmt.Println("获取网卡信息失败:", err)
		return
	}

	// 构造链路层地址结构体,绑定网卡和协议
	addr := syscall.SockaddrLinklayer{
		Ifindex:  iface.Index,
		Protocol: syscall.HTONS(syscall.ETH_P_ALL),
	}

	// 发送原始数据包
	err = syscall.Sendto(fd, packetBytes, 0, &addr)
	if err != nil {
		fmt.Println("发送数据包失败:", err)
		return
	}
	fmt.Println("数据包发送成功")
}

关键注意事项

  • 运行代码需要root/管理员权限,因为raw socket属于系统特权资源。
  • 必须替换代码中的网卡名称(如en0)为你当前机器的实际网卡名,可通过ifconfig或ip addr命令查看。
  • 捕获的数据包中的源MAC、源IP是你当时抓包时的机器地址,如果换了设备发送,需要修改十六进制字符串中对应字段:
    • 以太网帧头前6字节是目标MAC,接下来6字节是源MAC
    • IP头的第13-16字节是源IP,17-20字节是目标IP

对你原有代码的说明

你用net.Dial创建的是已建立的TCP连接,系统已经自动完成了TCP三次握手(包括发送SYN包),这种连接只能用于发送应用层数据,无法手动发送TCP握手阶段的原始SYN包。如果要模拟TCP连接建立过程,必须使用raw socket直接操作底层数据包。

内容的提问来源于stack exchange,提问作者Ming

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 12:17:46