我正在尝试通过创建 TCP/IP 堆栈来学习 TCP 如何工作,正如标题所示,我正在 Rust 中以编程方式创建 TAP 设备,如下所示
pub struct Tap {
fd: i32,
}
#[repr(C)]
struct IFreq {
name: [c_char; IFNAMSIZ],
flags: c_short,
}
impl Tap {
pub fn new(name: &CStr) -> Result<Tap, TapError> {
let fd = unsafe {
let fd = libc::open(b"/dev/net/tun\0".as_ptr() as *const _, libc::O_RDWR);
if fd < 0 {
Err(TapError::OpenFD(std::io::Error::last_os_error()))
} else {
Ok(fd)
}
}?;
let mut ifr = IFreq {
name: [0; IFNAMSIZ],
flags: (libc::IFF_TAP | libc::IFF_NO_PI) as c_short,
};
for (dst, src) in ifr.name[0..IFNAMSIZ - 1]
.iter_mut()
.zip(name.to_bytes().iter())
{
*dst = *src as i8;
}
unsafe {
let err = libc::ioctl(fd, TUNSETIFF, &mut ifr as *mut _);
if err == -1 {
return Err(TapError::IOCTL(std::io::Error::last_os_error()));
}
}
Ok(Tap { fd })
}
}
然而,当我使用它ip link set dev <tap name> up
并开始读取以太网帧时,我似乎只获得 IPv6 帧(以太网类型为 0x86DD)。这是正常的吗?我该如何阻止这种情况发生?我目前只致力于实施 IPv4,不想处理 IPv6 流量。
答案1
然而,当我使用 ip link set dev up 启动并开始读取以太网帧时,我似乎只获得 IPv6 帧(以太网类型为 0x86DD)。这是正常的吗?我该如何阻止这种情况发生?我目前只致力于实施 IPv4,不想处理 IPv6 流量。
在支持 IPv6 的系统上,每个接口都会自动获得一个链接本地来自前缀的 IPv6 地址fe80::/64
。这主要用于基础设施目的,例如,它允许以常规方式发送 SLAAC 和 DHCPv6 数据包(分别是 ICMPv6 和 UDP),而不是像 DHCPv4 客户端那样诉诸原始套接字。
我怀疑,初始数据包是由操作系统分配链路本地地址而产生的“重复地址检测”数据包,也可能是启动 SLAAC 自动配置的“路由器请求”。
具体就您的情况而言,我不建议禁用此功能,因为这是网络堆栈需要处理的正常情况即使它不支持 IPv6。如果您正在为连接到真实以太网的真实设备实现 TCP/IP,您将无法选择其他设备向您发送的内容 – 您会接收各种奇怪的不需要的帧,而不仅仅是 IPv6(例如,这里的以太网有 LLDP、STP、RoMON、CTP,只是为了给出一个实际的示例)。
换句话说,尽管阻止操作系统在您的 Tap 接口上对话 IPv6可能的,这使得练习变得不切实际,并且通常是错误的方法。
相反,你的网络堆栈应该静静地忽略具有它无法识别的任何以太网类型的所有以太网帧,无论是 IPv6、DECnet 还是 IPX。 (也就是说,这里不需要特殊情况 0x86DD,可以安全地删除 0x0800/0x0806 以外的任何内容。)