rustchecksumipv4nftables

pnet Rust Checksum Calculation


I am using the nfq and pnet library to modify packets and redirect them (to another ip and port).

Modifying Udp and tcp ports i have already figured out and packets arrive at their newly set port. However, when changing the ip address the packets just vanish as far as I can tell.

I have created a rule to queue some packets to my user-space program:

sudo nft add table inet mangle
sudo nft add chain inet mangle prerouting { type filter hook prerouting priority mangle \; }
sudo nft add set inet mangle managed_services { type ipv4_addr . inet_service \; }
sudo nft add rule inet mangle prerouting ip daddr @managed_services queue num 0 bypass
sudo nft add element inet mangle managed_services { THIS_COMPUTER_IP . THIS_COMPUTER_PORT }

This works as expected and packages arrive in my program:

pub fn listen() -> Result<(), Error> {
    let mut queue = Queue::open()?;
    queue.bind(0)?;
    queue.set_recv_conntrack(0, true)?;

    loop {
        let msg = queue.recv()?;
        
        let mut payload = msg.get_payload().to_vec();
        println!("V {:?}", payload);

        let mut ipv4 = MutableIpv4Packet::new(&mut payload).unwrap();
        let source_ip = ipv4.get_source();
        let dest_ip = ipv4.get_destination();
        
        ipv4 = match ipv4.get_next_level_protocol() {
            IpNextHeaderProtocols::Tcp => { rewrite_tcp(ipv4) },
            IpNextHeaderProtocols::Udp => { rewrite_udp(ipv4) }
            proto => { warn!("Found packet with unhandled protocol: {}", proto); ipv4 } // Unhandled Protocols pass
        };

        ipv4.set_source(dest_ip);
        ipv4.set_destination(source_ip);
        ipv4.set_checksum(0);

        let checksum_ipv4 = checksum(&ipv4.to_immutable());

        ipv4.set_checksum(checksum_ipv4);

        let mut new = Message::from(msg);
        new.set_verdict(Verdict::Accept);

        new.set_payload(ipv4.packet());
        queue.verdict(new)?;
    }
}

I left out the udp / tcp methods as that parts works. It swaps out the port with 60535. However, when also using the part swapping source ip and destination ip packages just vanish after they are edited. I assume it is the checksum, since packets do not vanish when changing the port

Using tcpdump I can only see the incoming packets but afterwards nothing.

Any help what about my setup might be incorrect is highly appreciated.


Solution

  • I have figured it out. Since I have not found any tutorials on this I will leave some hints for people working on a similar problem.

    In my case the problem was the rp_filter. Packages are dropped if the source ip is not from reachable from the interface the package arrives from. Since Host IP is not reachable by sending the package to a NIC the packages where dropped.

    Another pitfall to consider is connection tracking. If you change the source and ip, the connection tracking entry might be invalid which can lead to dropped packets as well