ICMP插座插座的问题
我已经写了一个申请,以发送和接收ICMP数据包(可以这么说)。
我已经在不同的计算机上对此进行了测试,发现代码仅在我的MacOS上运行。其他Linux机器(我在Linux的许多不同口味上进行了测试)给出了错误的结果,我什至不知道在哪里调试。
出现的内容
[2022-06-17T18:37:47Z INFO layer4_ip] Received 84 bytes from 142.250.69.206:0
[2022-06-17T18:37:47Z INFO layer4_ip] Received Ipv4Packet { version : 4, header_length : 5, dscp : 0, ecn : 0, total_length : 16384, identification : 0, flags : 0, fragment_offset : 0, ttl : 119, next_level_protocol : IpNextHeaderProtocol(1), checksum : 44214, source : 142.250.69.206, destination : 192.168.1.130, options : [], }
[2022-06-17T18:37:48Z INFO layer4_ip] Received 84 bytes from 142.250.69.206:0
[2022-06-17T18:37:48Z INFO layer4_ip] Received Ipv4Packet { version : 4, header_length : 5, dscp : 0, ecn : 0, total_length : 16384, identification : 0, flags : 0, fragment_offset : 0, ttl : 119, next_level_protocol : IpNextHeaderProtocol(1), checksum : 44214, source : 142.250.69.206, destination : 192.168.1.130, options : [], }
预期输出,这是我的Macos Linux输出(错误输出)
[2022-06-17T18:32:54Z INFO ping_playground] Received 64 bytes from 142.250.69.206:0
[2022-06-17T18:32:54Z INFO ping_playground] Received Ipv4Packet { version : 0, header_length : 0, dscp : 0, ecn : 0, total_length : 65454, identification : 80, flags : 0, fragment_offset : 1, ttl : 0, next_level_protocol : IpNextHeaderProtocol(0), checksum : 0, source : 0.0.0.0, destination : 0.0.0.0, options : [], }
[2022-06-17T18:32:55Z INFO ping_playground] Received 64 bytes from 142.250.69.206:0
[2022-06-17T18:32:55Z INFO ping_playground] Received Ipv4Packet { version : 0, header_length : 0, dscp : 0, ecn : 0, total_length : 65454, identification : 80, flags : 0, fragment_offset : 1, ttl : 0, next_level_protocol : IpNextHeaderProtocol(0), checksum : 0, source : 0.0.0.0, destination : 0.0.0.0, options : [], }
:不仅读取的字节数是不同的,而且解析是错误的。 在Wireshark中拦截表明我的MacOS和Linux机器上接收到的数据包确实相同。
这是提出问题的最小版本:
use std::{
net::{IpAddr, Ipv4Addr, SocketAddr},
os::unix::prelude::{AsRawFd, FromRawFd},
sync::Arc,
time::Duration,
};
use env_logger::Env;
use log::info;
use pnet_packet::{
icmp::{self},
Packet,
};
fn main() -> Result<(), Box<dyn std::error::Error>> {
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
// SOURCE IP ADDRESS
// let localhost = Ipv4Addr::LOCALHOST;
let localhost = Ipv4Addr::UNSPECIFIED;
let socket_ip_address = SocketAddr::new(IpAddr::V4(localhost), 80);
let socket2_ip_address = socket_ip_address.into();
// CREATE ICMP SOCKET
let socket2_ipv4_socket = socket2::Socket::new(
socket2::Domain::IPV4,
socket2::Type::DGRAM,
Some(socket2::Protocol::ICMPV4),
)
.unwrap();
// BIND TO LOCAL ADDRESS
socket2_ipv4_socket
.bind(&socket2_ip_address)
.expect(&format!(
"Failed binding to Ipv4 address {:?}",
&socket_ip_address
));
// CREATE STD SOCKET FROM SOCKET2 SOCKET
let raw_ipv4_socket = socket2_ipv4_socket.as_raw_fd();
let std_ipv4_socket = unsafe { std::net::UdpSocket::from_raw_fd(raw_ipv4_socket) };
std_ipv4_socket.set_read_timeout(Some(Duration::from_millis(100)))?;
let socket_arc = Arc::new(std_ipv4_socket);
let dest = "142.250.69.206:0";
let mut buffer = [0; 1024];
let socket_clone = Arc::clone(&socket_arc);
std::thread::spawn(move || {
let packet_slice = &mut [0; 56];
let mut buf = vec![0; 8 + 56]; // 8 bytes of header, then payload
let mut packet = icmp::echo_request::MutableEchoRequestPacket::new(&mut buf[..]).unwrap();
packet.set_icmp_type(icmp::IcmpTypes::EchoRequest);
packet.set_identifier(1);
packet.set_sequence_number(1);
packet.set_payload(packet_slice);
// Calculate and set the checksum
let icmp_packet = icmp::IcmpPacket::new(packet.packet()).unwrap();
let checksum = icmp::checksum(&icmp_packet);
packet.set_checksum(checksum);
loop {
socket_clone.send_to(&mut packet.packet(), dest).unwrap();
std::thread::sleep(Duration::from_millis(1000));
}
});
loop {
if let Ok((bytes_read, from)) = socket_arc.recv_from(&mut buffer) {
info!("Received {} bytes from {:?}", bytes_read, from);
let ipv4_packet = pnet_packet::ipv4::Ipv4Packet::new(&buffer).unwrap();
let _icmp_packet = pnet_packet::icmp::IcmpPacket::new(ipv4_packet.payload()).unwrap();
let _udp_packet = pnet_packet::udp::UdpPacket::new(&ipv4_packet.payload()).unwrap();
info!("Received {:?}", ipv4_packet);
}
}
}
这是货物的依赖部分
[dependencies]
pnet_packet = "0.29"
log = "0.4"
env_logger = "0.9"
socket2 = "0.4"
。 其次,我想帮助弄清楚什么问题。
谢谢
I've written an application to send and receive ICMP packets (a ping redo, so to speak).
I've tested this on different computers and found that the code only runs on my MacOS. Other linux machines (I tested on many different flavors of Linux) gave wrong results, and I don't even know where to debug anymore.
Expected output, this is what comes out of my MacOS
[2022-06-17T18:37:47Z INFO layer4_ip] Received 84 bytes from 142.250.69.206:0
[2022-06-17T18:37:47Z INFO layer4_ip] Received Ipv4Packet { version : 4, header_length : 5, dscp : 0, ecn : 0, total_length : 16384, identification : 0, flags : 0, fragment_offset : 0, ttl : 119, next_level_protocol : IpNextHeaderProtocol(1), checksum : 44214, source : 142.250.69.206, destination : 192.168.1.130, options : [], }
[2022-06-17T18:37:48Z INFO layer4_ip] Received 84 bytes from 142.250.69.206:0
[2022-06-17T18:37:48Z INFO layer4_ip] Received Ipv4Packet { version : 4, header_length : 5, dscp : 0, ecn : 0, total_length : 16384, identification : 0, flags : 0, fragment_offset : 0, ttl : 119, next_level_protocol : IpNextHeaderProtocol(1), checksum : 44214, source : 142.250.69.206, destination : 192.168.1.130, options : [], }
Linux output (wrong output):
[2022-06-17T18:32:54Z INFO ping_playground] Received 64 bytes from 142.250.69.206:0
[2022-06-17T18:32:54Z INFO ping_playground] Received Ipv4Packet { version : 0, header_length : 0, dscp : 0, ecn : 0, total_length : 65454, identification : 80, flags : 0, fragment_offset : 1, ttl : 0, next_level_protocol : IpNextHeaderProtocol(0), checksum : 0, source : 0.0.0.0, destination : 0.0.0.0, options : [], }
[2022-06-17T18:32:55Z INFO ping_playground] Received 64 bytes from 142.250.69.206:0
[2022-06-17T18:32:55Z INFO ping_playground] Received Ipv4Packet { version : 0, header_length : 0, dscp : 0, ecn : 0, total_length : 65454, identification : 80, flags : 0, fragment_offset : 1, ttl : 0, next_level_protocol : IpNextHeaderProtocol(0), checksum : 0, source : 0.0.0.0, destination : 0.0.0.0, options : [], }
Not only the number of bytes read is different, but the parsing is wrong.
Intercepting in wireshark shows that the packets that are received back are indeed the same on my MacOS and Linux machines.
Here's the minimal version that presents the problem:
use std::{
net::{IpAddr, Ipv4Addr, SocketAddr},
os::unix::prelude::{AsRawFd, FromRawFd},
sync::Arc,
time::Duration,
};
use env_logger::Env;
use log::info;
use pnet_packet::{
icmp::{self},
Packet,
};
fn main() -> Result<(), Box<dyn std::error::Error>> {
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
// SOURCE IP ADDRESS
// let localhost = Ipv4Addr::LOCALHOST;
let localhost = Ipv4Addr::UNSPECIFIED;
let socket_ip_address = SocketAddr::new(IpAddr::V4(localhost), 80);
let socket2_ip_address = socket_ip_address.into();
// CREATE ICMP SOCKET
let socket2_ipv4_socket = socket2::Socket::new(
socket2::Domain::IPV4,
socket2::Type::DGRAM,
Some(socket2::Protocol::ICMPV4),
)
.unwrap();
// BIND TO LOCAL ADDRESS
socket2_ipv4_socket
.bind(&socket2_ip_address)
.expect(&format!(
"Failed binding to Ipv4 address {:?}",
&socket_ip_address
));
// CREATE STD SOCKET FROM SOCKET2 SOCKET
let raw_ipv4_socket = socket2_ipv4_socket.as_raw_fd();
let std_ipv4_socket = unsafe { std::net::UdpSocket::from_raw_fd(raw_ipv4_socket) };
std_ipv4_socket.set_read_timeout(Some(Duration::from_millis(100)))?;
let socket_arc = Arc::new(std_ipv4_socket);
let dest = "142.250.69.206:0";
let mut buffer = [0; 1024];
let socket_clone = Arc::clone(&socket_arc);
std::thread::spawn(move || {
let packet_slice = &mut [0; 56];
let mut buf = vec![0; 8 + 56]; // 8 bytes of header, then payload
let mut packet = icmp::echo_request::MutableEchoRequestPacket::new(&mut buf[..]).unwrap();
packet.set_icmp_type(icmp::IcmpTypes::EchoRequest);
packet.set_identifier(1);
packet.set_sequence_number(1);
packet.set_payload(packet_slice);
// Calculate and set the checksum
let icmp_packet = icmp::IcmpPacket::new(packet.packet()).unwrap();
let checksum = icmp::checksum(&icmp_packet);
packet.set_checksum(checksum);
loop {
socket_clone.send_to(&mut packet.packet(), dest).unwrap();
std::thread::sleep(Duration::from_millis(1000));
}
});
loop {
if let Ok((bytes_read, from)) = socket_arc.recv_from(&mut buffer) {
info!("Received {} bytes from {:?}", bytes_read, from);
let ipv4_packet = pnet_packet::ipv4::Ipv4Packet::new(&buffer).unwrap();
let _icmp_packet = pnet_packet::icmp::IcmpPacket::new(ipv4_packet.payload()).unwrap();
let _udp_packet = pnet_packet::udp::UdpPacket::new(&ipv4_packet.payload()).unwrap();
info!("Received {:?}", ipv4_packet);
}
}
}
Here's the dependencies part of Cargo.toml:
[dependencies]
pnet_packet = "0.29"
log = "0.4"
env_logger = "0.9"
socket2 = "0.4"
First, I would like someone to confirm this behavior.
Second, I would like help in figuring out what's wrong.
Thank you
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我。
要接收IP标头,我必须使用原始插座,而不是Dgram。
将插座创建更改为:
您必须将正确的功能赋予二进制功能的警告。例如,这样的事情:
关闭问题。
Dummy me.
To receive the IP header I had to use a RAW socket and not the DGRAM.
Changing the socket creation to:
That comes with the caveat that you have to give the right capabilities to your binary. Something like this, for example:
Closing the question.