1

I'm trying to intercept (i.e. consume, and not capture) packets at the data-link layer with the rust library pnet, however it doesn't seem to intercept them, just read them. I'm unsure whether it's my lack of understanding of networking or something else that is the cause

Here is the sample code:

use pnet::datalink::{self, NetworkInterface, Channel};
use pnet::datalink::Channel::Ethernet;
use pnet::packet::{Packet, MutablePacket};
use pnet::packet::ethernet::{EthernetPacket, MutableEthernetPacket};

use std::env;
use iovec::IoVec;

// Invoke as echo <interface name>
fn main() {
    let interface_name = env::args().nth(1).unwrap();
    let interface_names_match =
        |iface: &NetworkInterface| iface.name == interface_name;

    let interface = datalink::linux::interfaces().into_iter()
        .filter(interface_names_match)
        .next()
        .unwrap();

    let config = datalink::linux::Config::default();
    let channel = datalink::linux::channel(&interface, config).unwrap();



    let (tx, mut rx) = match channel {
        Ethernet(tx, rx) => {
            (tx, rx)
        }
        _ => {panic!("Could not create channel")}
    };

    let mut counter = 0;
    loop {
        match rx.next(){
            Ok(packet) => {
                counter += 1;

                if counter % 1000 == 0 {
                    println!("{}", counter);
                }
            },
            Err(_) => { panic!("Error occured") }
        }
    }
}

I am trying to intercept my wireless interface. What I would expect is that, when the program is running, if I try to connect to some website for example, there would be some network connection error, since the browser (or client) would never receive the packet.

Dominus
  • 808
  • 11
  • 25

1 Answers1

2

I'm afraid it does not depend on the programming language but on the operating system. As far as I know, packet-sockets can capture/emit frames but do not intercept them; this is the purpose of the firewall. A very long time ago, I used to experiment this; here is what I know about it.

It takes place in the firewall; you have to modprobe ip_queue then add a rule to send packets to that queue iptables -A OUTPUT -o eth1 -j QUEUE (adapt input/output/interface as needed).

Then you have to build and run in userspace a program which interacts with that queue and gives a verdict (ACCEPT/DROP) for every packet. This is done in C with <linux/netfilter.h> and -lipq; I don't know if you can easily do the equivalent in Rust.

By the way, maybe the best solution is not to rely on a userspace process giving the verdict but just on usual firewall rules (if the criterion for the verdict is not too complicated). There exist many modules and iptables options which enable many complex rules.

( https://linux.die.net/man/3/libipq )

prog-fh
  • 13,492
  • 1
  • 15
  • 30
  • Thank you for the answer, yes I was just sharing the code to check if someone saw something suspicious, the library (`pnet`) actually binds to a raw socket in the back, and I expected a raw socket to consume the interfacet. So, in the case of tun/tap devices, which do not have a "real" destination, how are packets consumed? Or is there some max buffer size so that the device doesn't start growing in memory? – Dominus Feb 01 '21 at 10:52
  • @Dominus As far as I know tun/tap devices exist only with a running process which emulates the physical layer by providing/consuming frames in software. If such a process does not consume the frames provided on this interface, I don't know if there is a kind of buffering, but it is probably pathological in the long run ;^) – prog-fh Feb 01 '21 at 11:07