GithubHelp home page GithubHelp logo

nfq-rs's Introduction

nfq - NetFilter queue for Rust

nfq is Rust library for performing userspace handling of packets queued by the kernel packet packet filter chains.

License

In contrast to libnetfilter_queue which is licensed under GPL 2.0, which will require all binaries using that library to be bound by GPL, nfq is dual-licensed under MIT/Apache-2.0. nfq achieves this by communicates with kernel via NETLINK sockets directly.

Example

Here is an example which accepts all packets.

use nfq::{Queue, Verdict};

fn main() -> std::io::Result<()> {
   let mut queue = Queue::open()?; 
   queue.bind(0)?;
   loop {
       let mut msg = queue.recv()?;
       msg.set_verdict(Verdict::Accept);
       queue.verdict(msg)?;
   }
   Ok(())
}

nfq-rs's People

Contributors

nbdd0121 avatar steven-joruk avatar roshanr95 avatar daviessm avatar tjeukayim avatar iovxw avatar uvuarchftw avatar

Stargazers

Cheney avatar Vittorio Palmisano avatar Pavel Korotkov avatar Jiri Pospisil avatar ShellCode avatar Finn Bear avatar Enes ÖZTÜRK avatar Xiaobo Liu avatar Marius Ungureanu avatar Sandalots avatar Andrew Gunnerson avatar Piotr Rozentreter avatar  avatar  avatar Collin Zhang avatar  avatar Reed O'Brien avatar Oleg Solomko avatar FreshBird avatar Mitchel Humpherys avatar Massoud Asadi avatar  avatar  avatar  avatar Chris Lin avatar 寧靜 avatar

Watchers

Reed O'Brien avatar James Cloos avatar  avatar  avatar  avatar

nfq-rs's Issues

Async I/O for NetLink socket

This fork of nfq-rs implements async I/O for the NetLink socket with Tokio https://github.com/TjeuKayim/nfq-rs/tree/async. It is running fine, but I didn't stress test it yet. My work is based on https://github.com/little-dude/netlink/tree/master/netlink-sys/ (MIT license).

What would be the best approach to merge these changes into this project? The blocking and async implementations could be in different modules, depending on a module with shared code. A feature flag named tokio swaps the module for an async variant. I would like to hear your opinion.

Mock for `Message`

I am using nfq-rs and I was exploring a bug in my code and writing some tests. I found mocking Message quite difficult and I wrote the attached patch.

I don't think this is a good way, but I can imagine something like #[cfg(test)]impl Message { ::new_for_mock() } or other things working well. Basically I would like to create arbitrary Messages in order to test my queue processing code.

Maybe something like PacketBuilder in etherparse would also work. I'm happy to help on this but I don't want to head in a direction opposite of what is intended for your crate.

From cfb996543a257aa825db2159230059f1cb6e3bcd Mon Sep 17 00:00:00 2001
From: Issac Kelly <[email protected]>
Date: Tue, 18 Jul 2023 20:43:21 -0700
Subject: [PATCH] publish these private fields for debugging and testing in
 other applciations

---
 src/lib.rs | 44 ++++++++++++++++++++++----------------------
 1 file changed, 22 insertions(+), 22 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index 025e42d..d673d82 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -197,7 +197,7 @@ impl<'a> Nlmsg<'a> {
 }
 
 #[derive(Debug)]
-enum PayloadState {
+pub enum PayloadState {
     Unmodified,
     Modified,
     Owned(Vec<u8>),
@@ -208,28 +208,28 @@ enum PayloadState {
 pub struct Message {
     // This is here for lifetime requirements, but we're not using it directly.
     #[allow(dead_code)]
-    buffer: Arc<Vec<u32>>,
-    id: u16,
-    nfmark: u32,
-    nfmark_dirty: bool,
-    indev: u32,
-    outdev: u32,
-    physindev: u32,
-    physoutdev: u32,
-    orig_len: u32,
-    skbinfo: u32,
-    secctx: *const libc::c_char,
-    uid: Option<u32>,
-    gid: Option<u32>,
-    timestamp: *const nfqnl_msg_packet_timestamp,
-    hwaddr: *const nfqnl_msg_packet_hw,
-    hdr: *const nfqnl_msg_packet_hdr,
+    pub buffer: Arc<Vec<u32>>,
+    pub id: u16,
+    pub nfmark: u32,
+    pub nfmark_dirty: bool,
+    pub indev: u32,
+    pub outdev: u32,
+    pub physindev: u32,
+    pub physoutdev: u32,
+    pub orig_len: u32,
+    pub skbinfo: u32,
+    pub secctx: *const libc::c_char,
+    pub uid: Option<u32>,
+    pub gid: Option<u32>,
+    pub timestamp: *const nfqnl_msg_packet_timestamp,
+    pub hwaddr: *const nfqnl_msg_packet_hw,
+    pub hdr: *const nfqnl_msg_packet_hdr,
     // conntrack data
-    ct: Option<Conntrack>,
+    pub ct: Option<Conntrack>,
     // The actual lifetime is 'buffer
-    payload: &'static mut [u8],
-    payload_state: PayloadState,
-    verdict: Verdict,
+    pub payload: &'static mut [u8],
+    pub payload_state: PayloadState,
+    pub verdict: Verdict,
 }
 
 unsafe impl Send for Message {}
@@ -585,7 +585,7 @@ unsafe fn parse_msg(nlh: *const nlmsghdr, queue: &mut Queue) {
 /// A NetFilter queue.
 pub struct Queue {
     /// NetLink socket
-    fd: RawFd,
+    pub fd: RawFd,
     /// Flag to send for recv operation. Decides whether or not the operation blocks until there is
     /// message from the kernel.
     recv_flag: libc::c_int,
-- 
GitLab

Questions / Feedback

Hey, thanks a lot for your work, this is awesome !

Not really an issue but I have a few questions if you don't mind...

  1. I was wondering why did you put the conntrack feature behind a ct feature flag and why is it hidden from the doc ? Is it not in a stable state ?
  2. The set_fail_open function made me wonder, what's the default behavior ? Does it depend on the chain policy ? I want the packets to be dropped if the queue is full, should I pass true or false ?

I think your project would benefit a lot from some documentation in the readme. When I stumbled across your library I didn't know the existence of the"queue" feature of netfilter, I had to go through your closed issues to figure it out.

Some ideas of things you could add to the readme:

  • Minimal nftables rules showing how to use the queue statement
  • Mention of the ct flag
  • Some pointers to nftables documentation that helped you building this lib and might help others understand what this lib is doing

It didn't work on ubuntu linux 5.15.0

I wrote a simple code to print msg without outputting content.

use nfq::{Queue, Verdict};

fn main() -> std::io::Result<()> {
    let mut queue = Queue::open()?;
    queue.bind(0)?;
    loop {
        let mut msg = queue.recv()?;
        println!("{:?}", msg);        // print msg
        msg.set_verdict(Verdict::Accept);
        queue.verdict(msg)?;
    }
}

The demo program runs as follows:

# cargo build
# ./target/debug/demo

Use curl to make requests on other machine:

% curl http://10.211.55.5:8000/ -v

The demo program does not produce any output.

The expectation is to be able to output msg content when requested. Did I use it wrong?

OS version:

$ uname -a
Linux 5.15.0-76-generic #83-Ubuntu SMP Thu Jun 15 19:21:56 UTC 2023 aarch64 aarch64 aarch64 GNU/Linux

First call of queue.recv()

I tried to use your library for mipsel-unknown-linux-musl target in some project, and I noticed a problem. Every time when I run my program, and it does first call of recv() method on Queue struct object it results with error:
Error: Os { code: 22, kind: InvalidInput, message: "Invalid argument" }
Every next call is valid.

That error is returned in 760 line of ./src/lib.rs file.

 if unsafe { (*nlh).nlmsg_flags } & NLM_F_DUMP_INTR as u16 != 0 {
                    return Err(std::io::Error::from_raw_os_error(EINTR));
                }

I checked what syscalls can return a error with strace, and i figured out this invalid syscall:

recvfrom(3, {{len=56, type=NLMSG_ERROR, flags=0, seq=0, pid=19762}, {error=-EOPNOTSUPP, msg={{len=36, type=0x302 /* NLMSG_??? */, flags=NLM_F_REQUEST, seq=0, pid=0}, "\x00\x00\x02\x31\x08\x00\x05\x00\x00\x00\x00\x02\x08\x00\x04\x00\x00\x00\x00\x02"}}}, 4224, MSG_TRUNC, NULL, NULL) = 56

A valid syscall should looks like that (I get its when I run my app on x86 target):

recvfrom(3,  {{len=284, type=NFNL_SUBSYS_QUEUE<<8|NFQNL_MSG_PACKET, flags=0, seq=0, pid=0}, "\x02\x00\x02\x31\x0b\x00\x01\x00\x00\x00\x00\x01\x08\x00\x03\x00\x08\x00\x06\x00\x00\x00\x00\x03\x94\x00\x0b\x80\x3c\x00\x01\x80"...}, 4224, MSG_TRUNC, NULL, NULL) = 284
write(1, "Accepted: saddr: 192.168.12.242 "..., 63Accepted: saddr: 192.168.12.242 daddr: 212.77.98.9 proto: Icmp
) = 63

That error occurs only on MIPS target, x86 was ok

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.