我需要检查和修改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标头?
答案 0 :(得分:3)
与IPv4相比,具有IPv6的原始套接字不同。与您的案例相关的是RFC 3542。注意:
与IPv4原始套接字的另一个区别是无法使用IPv6原始套接字API发送或接收完整数据包(即带有扩展标头的IPv6数据包)。而是使用辅助数据对象传输扩展头和hoplimit信息,如第6节所述。如果应用程序需要访问完整的IPv6数据包,则必须使用其他一些技术,例如数据链路接口BPF或DLPI。 / p>
你可以自己找到它。通过在我的盒子上运行(和strace')我的每个数据包:
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 */
};
路由头选项,跳限制等存在类似选项。