即使使用原始套接字和 IPPROTO_RAW,操作系统也会附加 IP 标头

问题描述 投票:0回答:1

我有两个程序,一个发送者和一个接收者。发送方使用原始套接字向接收方发送 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

注意事项

  • 这里有一个观察结果,操作系统添加的 IP 标头的协议字段值为
    255
    ,即 Reserved。我不知道为什么会这样,是否有什么可以推断的。
  • 根据 man-7 页,当
    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 标头。我对原始套接字的理解有什么差距吗?

谢谢!

go sockets network-programming raw-sockets
1个回答
0
投票

它在我的机器上(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
。我们可能需要更多地了解您正在执行代码的机器。

© www.soinside.com 2019 - 2024. All rights reserved.