【问题标题】:IPv6 packet header manipulationIPv6 数据包头操作
【发布时间】:2016-07-16 16:19:01
【问题描述】:

我需要检查和修改 IPv6 扩展标头。所以我设置了一个原始套接字来监听本地地址上的所有 IP 数据包。

package main

import (
    "log"
    "net"
)

func main() {
    c, err := net.ListenIP("ip6:tcp", &net.IPAddr{
        IP:   net.IPv6loopback,
        Zone: "",
    })
    if err != nil {
        panic(err)
    }

    buf := make([]byte, 1024)
    for {
        numRead, ipaddr, err := c.ReadFromIP(buf)
        log.Print(numRead, ipaddr, err)
        log.Printf("% X\n", buf[:numRead])
    }
}

我在连接上尝试了所有Read*() 方法,但似乎它们只是返回没有标头的有效负载。 所以我的问题是:如何访问数据包的 IPv6 标头?

【问题讨论】:

  • 需要注意的是,很少使用 IPv6 扩展标头,不幸的是,路径中的许多 ISP 会阻止或去除扩展标头,因为它们可用于攻击。

标签: sockets networking go ipv6


【解决方案1】:

IPv6 的原始套接字与 IPv4 不同。与您的案例相关的是RFC 3542。注意:

与 IPv4 原始套接字的另一个区别是无法使用 IPv6 原始套接字 API 发送或接收完整的数据包(即带有扩展标头的 IPv6 数据包)。相反,辅助数据对象用于传输扩展标头和跳数限制信息,如第 6 节所述。如果应用程序需要访问完整的 IPv6 数据包,则必须使用其他一些技术,例如数据链路接口 BPF 或 DLPI。


您可以自己找出答案。通过在我收到的每个数据包上运行(并跟踪)你的程序:

recvfrom(3, "\x45\x00\x00\x3c\x6a\x7d...
               ^^

这意味着 IP 版本 = 4,IHL = 5(20 字节)。

当我尝试使用 IPv6(即您的原始代码)做同样的事情时,每次都会得到不同的结果:

recvfrom(3, "\xc6\x22\x00\x50\x4d

在这种情况下,每次内核都返回直接以 TCP 开头的内容(在这种情况下,端口是50722,即0xC622)。

另一个有趣的部分应该在sources中注明:

switch sa := sa.(type) {
case *syscall.SockaddrInet4:
    addr = &IPAddr{IP: sa.Addr[0:]}
    n = stripIPv4Header(n, b)
case *syscall.SockaddrInet6:
    addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))}
}

对于 IPv4 手动剥离了标头,但对于 IPv6 则没有:对于 IPv6,无需删除任何内容。


请注意,有些机制会返回额外信息(但绝不是整个数据包)。例如,IPV6_RECVPKTINFO 套接字选项将允许您访问:

struct in6_pktinfo {
    struct in6_addr ipi6_addr;    /* src/dst IPv6 address */
    unsigned int    ipi6_ifindex; /* send/recv interface index */
};

路由标头选项、跳数限制等也存在类似选项。

【讨论】:

  • 感谢您的回答。我已经注意到源代码中标头被剥离但不知道原因的部分。所以我想这不可能与net 包有关?!
  • @fl0cke 我认为这里的 net 包是不够的。您可能会使用特定于 Linux 的 PF_PACKET 或 BPF(在许多 Unix 上可用)。
猜你喜欢
  • 2013-07-06
  • 2012-10-26
  • 1970-01-01
  • 2012-04-08
  • 2016-01-27
  • 1970-01-01
  • 1970-01-01
  • 2015-12-17
  • 2013-07-16
相关资源
最近更新 更多