Skip to content
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

Merged
merged 3 commits into from
Jan 9, 2020

Conversation

Ma27
Copy link
Contributor

@Ma27 Ma27 commented Jan 8, 2020

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.

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.
@Ma27
Copy link
Contributor Author

Ma27 commented Jan 8, 2020

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 :)

@zhangxp1998
Copy link
Collaborator

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?

@Ma27
Copy link
Contributor Author

Ma27 commented Jan 8, 2020

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).

@zhangxp1998
Copy link
Collaborator

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();
Copy link
Collaborator

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 => {
Copy link
Collaborator

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

@zhangxp1998
Copy link
Collaborator

Overall LGTM, the Travis CI failed though. But it seems to be some formatting issue. Please format the changed files with rustfmt and update this PR.

@Ma27
Copy link
Contributor Author

Ma27 commented Jan 9, 2020

Overall LGTM, the Travis CI failed though. But it seems to be some formatting issue. Please format the changed files with rustfmt and update this PR.

Fixed 👍

Will an Ipv4Packet struct return anything other than 4 for get_version() call?

Yes it does. You actually test IPv6 support in conjunction with my patches on https://github.com/Ma27/bandwhich/tree/ipv6-int-test

@zhangxp1998
Copy link
Collaborator

Thanks for a great PR!

@zhangxp1998 zhangxp1998 merged commit d3f6918 into imsnif:master Jan 9, 2020
@imsnif
Copy link
Owner

imsnif commented Jan 9, 2020

Hey, thanks for handling this @zhangxp1998 !
Sorry for jumping in late, but just one question: do you think we pay a performance cost for always trying to parse packets as L3 before falling back to L2?

@Ma27 Ma27 deleted the fix-network-gathering branch January 9, 2020 08:43
@Ma27
Copy link
Contributor Author

Ma27 commented Jan 9, 2020

Sorry for jumping in late, but just one question: do you think we pay a performance cost for always trying to parse packets as L3 before falling back to L2?

Using the change locally and didn't encounter a noticeable performance regression, but I'd be happy to investigate if people report something different :)

@imsnif
Copy link
Owner

imsnif commented Jan 9, 2020

Sounds good :) And thanks from me too!
On a different note, if you have access to ipv6 - maybe you can help @zhangxp1998 out with: #70?

@Ma27
Copy link
Contributor Author

Ma27 commented Jan 9, 2020

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 :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants