我有两个程序,一个发送者和一个接收者。发送方使用原始套接字向接收方发送 ICMP 回显请求数据包。在阅读了有关原始套接字的man-7页面和此博客之后,我的理解是,如果我使用
IPPROTO_RAW
,我将启用IP_HDRINCL
选项,这将告诉操作系统not添加任何发送方将提供 IP 标头。
但是,当我使用 tcpdump 捕获数据包时,我仍然看到添加了意外的 IP 标头。
➜ ~ tcpdump -nt -i lo0 not tcp -X
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on lo0, link-type NULL (BSD loopback), snapshot length 524288 bytes
IP 127.0.0.1 > 127.0.0.1: ip-proto-255 28
0x0000: 4500 0030 f9a2 0000 40ff 0000 7f00 0001 E..0....@.......
0x0010: 7f00 0001 4500 0000 0000 0000 4001 0000 ....E.......@...
0x0020: 0000 0000 7f00 0001 0800 f7ff 0000 0000 ................
为了清楚起见,
// the unexpected IP header
45 00 00 30 a8 d4 00 00 40 ff 00 00 7f 00 00 01 7f 00 00 01
// my IP header
45 00 00 00 00 00 00 00 40 01 00 00 00 00 00 00 7f 00 00 01
// my ICMP bytes
08 00 f7 ff 00 00 00 00
注意事项
255
,即 Reserved。我不知道为什么会这样,是否有什么可以推断的。IP_HDRINCL
启用时,操作系统将填写标识、源地址、校验和和总长度字段。因此,我在 IP 标头中将它们设置为零。这是我的发送程序
package main
import (
"fmt"
"log"
"syscall"
)
func main() {
fd, _ := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_RAW)
addr := syscall.SockaddrInet4{
Addr: [4]byte{127, 0, 0, 1},
}
// identification, src address, checksum, and total length will be set by the kernel since IP_HDRINCL is enabled.
ipHeader := []byte{
0x45, // VersionIHL
0x00, // ToS
0x00, 0x00, // total length
0x00, 0x00, // identification
0x00, 0x00, // flags and fragment offset
0x40, // ttl
0x01, // protocol is ICMP
0x00, 0x00, // checksum
0x00, 0x00, 0x00, 0x00, // src address
0x7f, 0x00, 0x00, 0x01, // dest address
}
p := append(ipHeader, 0x08, 0x00, 0xf7, 0xff, 0x00, 0x00, 0x00, 0x00)
err := syscall.Sendto(fd, p, 0, &addr)
if err != nil {
log.Fatal("send to error: ", err)
}
fmt.Printf("sent %d bytes\n", len(p))
}
我很好奇为什么操作系统要附加 IP 标头。我对原始套接字的理解有什么差距吗?
谢谢!
它在我的机器上(Ubuntu 6.8.0-35-generic)
lo
,我得到
# tcpdump -nt -i lo not tcp -X -vv
tcpdump: listening on lo, link-type EN10MB (Ethernet), snapshot length 262144 bytes
IP (tos 0x0, ttl 64, id 63468, offset 0, flags [none], proto ICMP (1), length 28)
127.0.0.1 > 127.0.0.1: ICMP echo request, id 0, seq 0, length 8
0x0000: 4500 001c f7ec 0000 4001 84f2 7f00 0001 E.......@.......
0x0010: 7f00 0001 0800 f7ff 0000 0000 ............
我想知道的是为什么你会得到链接类型
NULL
而我却得到ETHERNET
。我们可能需要更多地了解您正在执行代码的机器。