Search code examples
network-programmingrustdata-link-layer

Intercept packets at datalink layer


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.


Solution

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