-
-
Notifications
You must be signed in to change notification settings - Fork 297
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix parsing of IP-Packets from Layer3 #98
Conversation
When using e.g. WireGuard (a VPN which completely acts on layer3), no packages will be matched as it's attempted to parse those as ethernet (=layer2) packets. This is a problem as all layer3-packets fail to get parsed properly (due to different offsets in the packet, wrong protocols will be determined for instance). This change inherits the basic idea from `<libpnet/examples/packetdump.rs>` to check if it's possible to parse version info using the IpPacket-parsers and if that fails, the sniffer will fall-back to the ethernet-based approach.
Btw in case someone else wants to test my change and IPv6 support at the same time, I created a temporary branch in my fork (https://github.com/Ma27/bandwhich/commits/ipv6-int-test) where I merged both changes and the latest master together :) |
I'm not super familiar with Wireguard, so correct me if I am wrong. From what I know, Wireguard create some virtual interfaces(such as wg0). When sending out packets, all packets will eventually go out through some physical interface(WiFi or ethernet), so we should be able to capture these packets when they go out on some physical interface? |
So Wireguard was just an example where you'd encounter this kind of issue. Several VPN technologies communicate using layer3 packets and in all of that cases you'd stumble upon this. When taking a look at libpnet, you'll see that it's theoretically possible to configure whether to parse layer2/3 packets (the API is pretty tied to layer2 stuff which is why I didn't use this), so that's actually a valid use-case. Finally, it's indeed possible to capture UDP packets from Wireguard on an uplink interface, but nothing more which isn't pretty helpful when you have an always-on VPN and you want to see which processes are doing networking (inside the VPN). |
Ah, thanks for clearing this up! I'll take a look at the code later |
let from = SocketAddr::new(IpAddr::V4(ip_packet.get_source()), source_port); | ||
let to = SocketAddr::new(IpAddr::V4(ip_packet.get_destination()), destination_port); | ||
let ip_packet = Ipv4Packet::new(&bytes)?; | ||
let version = ip_packet.get_version(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will an Ipv4Packet
struct return anything other than 4 for get_version()
call?
fn handle_v4(ip_packet: Ipv4Packet, network_interface: &NetworkInterface) -> Option<Segment> { | ||
let (protocol, source_port, destination_port, data_length) = | ||
match ip_packet.get_next_level_protocol() { | ||
IpNextHeaderProtocols::Tcp => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 Great that you changed this to IpNextHeaderProtocols::Tcp
instead of hard coded numbers
Overall LGTM, the Travis CI failed though. But it seems to be some formatting issue. Please format the changed files with |
Fixed 👍
Yes it does. You actually test IPv6 support in conjunction with my patches on https://github.com/Ma27/bandwhich/tree/ipv6-int-test |
Thanks for a great PR! |
Hey, thanks for handling this @zhangxp1998 ! |
Using the change locally and didn't encounter a noticeable performance regression, but I'd be happy to investigate if people report something different :) |
Sounds good :) And thanks from me too! |
Of course! IPv6 support is currerntly the last thing I'm missing. I actually use bandwhich with IPv6 support after merging all changes together on a temporary branch (https://github.com/Ma27/bandwhich/commits/ipv6-int-test). Will take a closer look at the current state of the PR later today :) |
When having layer3-packets on an interface (e.g. when using WireGuard), no results will be displayed as the sniffer tries to parse those as layer2/ethernet packets. This change uses a hack inspired by
<libpnet/examples/packetdump.rs>
which tries to parse the current frame as IP-Packet and if that doesn't work, the packet will be treated as ethernet packet.To reproduce this issue I'd recommend to create a VM with a WireGuard Interface and then try to capture packets from the interface with
bandwhich
.