【发布时间】:2015-12-11 02:09:14
【问题描述】:
我正在尝试为我正在开发的测试工具做一些基本的数据包制作,但我似乎无法让数据包制作工作(我在 OSX 上使用 Go 1.5 并以 root 身份运行。)
我正在使用以下代码 (taken from here) 尝试创建 ICMP 数据包,但是当我尝试在 IP 标头中指定特定选项时,它似乎不起作用。此外,当我在 Wireshark 中查看此数据包时,它显示为协议 255(未知)。
我已经读过,在 Linux 系统上你可以使用 AF_PACKET,但在 OSX 系统上你需要使用 BPF,但是我发现的示例代码是使用“syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_RAW)”而且我不确定如何开始使用 BPF。我还看到有些人尝试使用 gopacket 而不是 x/net/ipv4 包。
package main
import (
"golang.org/x/net/ipv4"
"net"
"syscall"
)
func main() {
var err error
fd, _ := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_RAW)
addr := syscall.SockaddrInet4{
Port: 0,
Addr: [4]byte{127, 0, 0, 1},
}
p := pkt()
_ = syscall.Sendto(fd, p, 0, &addr)
}
func pkt() []byte {
h := ipv4.Header{
Version: 4,
Len: 20,
TOS: 0,
TotalLen: 85, // I can not seem to change this
ID: 2, // I can not seem to change this
TTL: 64, // I can not seem to change this
Protocol: 1, // ICMP, This does not seem to work
Dst: net.IPv4(127, 0, 0, 1),
}
icmp := []byte{
8, // type: echo request
0, // code: not used by echo request
0, // checksum (16 bit), we fill in below
0,
0, // identifier (16 bit). zero allowed.
0,
0, // sequence number (16 bit). zero allowed.
0,
0xC0, // Optional data. ping puts time packet sent here
0xDE,
}
cs := csum(icmp)
icmp[2] = byte(cs)
icmp[3] = byte(cs >> 8)
out, _ := h.Marshal()
return append(out, icmp...)
}
func csum(b []byte) uint16 {
var s uint32
for i := 0; i < len(b); i += 2 {
s += uint32(b[i+1])<<8 | uint32(b[i])
}
// add back the carry
s = s>>16 + s&0xffff
s = s + s>>16
return uint16(^s)
}
如果我在数据从 pkt() 返回后在 Main() 中打印出包含数据包数据的 p 变量,它看起来是正确的:
DEBUG: (decimal) [69 0 60 0 0 0 0 0 64 1 0 0 0 0 0 0 127 0 0 1 8 0 55 33 0 0 0 0 192 222]
DEBUG: (hex) 45 0 3c 0 0 0 0 0 40 1 0 0 0 0 0 0 7f 0 0 1 8 0 37 21 0 0 0 0 c0 de
您可以看到协议在第 10 个字节中设置为“1”。但是当我们在 Wireshark 中查看这个数据包时,它看起来像:
【问题讨论】:
-
在Linux上,你需要root才能做到这一点,也许在osx上也是如此?
-
感谢您发现遗漏,我已将其添加到文章中。是的,我以 root 身份运行,您必须具有 root 访问权限才能打开原始套接字。
-
请显示十六进制转储
-
添加了附加信息以显示 hexdumps
-
在 OSX 的“man socket”手册中,看起来有一个“PF_NDRV”的入口点可能会满足我的需要。看起来“AF_INET”确实适用于第 3 层以上的东西。但“PF_NDRV”似乎不是 Go syscall.Socket 库的一部分。还有其他想法吗?