234 lines
7.6 KiB
Rust
234 lines
7.6 KiB
Rust
#[allow(unused_imports)]
|
|
use lazy_static::lazy_static;
|
|
use nfq::{Queue, Verdict};
|
|
use pdu::{Gre, GrePdu, Icmp, IcmpPdu, Ip, Ipv4, Ipv4Pdu, Ipv6Pdu, Tcp, TcpPdu, Udp, UdpPdu};
|
|
#[allow(unused_imports)]
|
|
use regex::bytes::Regex;
|
|
|
|
fn main() {
|
|
let mut queue = Queue::open().expect("Could not open queue!");
|
|
queue.bind(0).expect("Could not bind to queue 0!");
|
|
loop {
|
|
let mut msg = queue.recv().expect("Could not receive message from queue!");
|
|
let packet = msg.get_payload();
|
|
|
|
let verdict = match Ip::new(packet) {
|
|
Ok(Ip::Ipv4(ipv4_pdu)) => {
|
|
print!("IPv4 -> ");
|
|
//print_ipv4(ipv4_pdu);
|
|
match ipv4_pdu.inner() {
|
|
#[allow(unused_variables)]
|
|
Ok(Ipv4::Raw(raw)) => {
|
|
print!("RAW");
|
|
Verdict::Accept
|
|
}
|
|
Ok(Ipv4::Tcp(tcp_pdu)) => {
|
|
print!("TCP -> ");
|
|
//print_tcp(tcp_pdu);
|
|
match tcp_pdu.inner() {
|
|
Ok(Tcp::Raw(raw)) => {
|
|
print!("RAW");
|
|
filter_ipv4_tcp_raw(ipv4_pdu, tcp_pdu, raw)
|
|
}
|
|
Err(e) => panic!("Could not get inner payload of TCP PDU: {}", e),
|
|
}
|
|
}
|
|
Ok(Ipv4::Udp(udp_pdu)) => {
|
|
print!("UDP -> ");
|
|
//print_udp(udp_pdu);
|
|
match udp_pdu.inner() {
|
|
#[allow(unused_variables)]
|
|
Ok(Udp::Raw(raw)) => {
|
|
print!("RAW");
|
|
}
|
|
Err(e) => panic!("Could not get inner payload of UDP PDU: {}", e),
|
|
}
|
|
Verdict::Accept
|
|
}
|
|
Ok(Ipv4::Icmp(icmp_pdu)) => {
|
|
print!("ICMP -> ");
|
|
//print_icmp(icmp_pdu);
|
|
match icmp_pdu.inner() {
|
|
#[allow(unused_variables)]
|
|
Ok(Icmp::Raw(raw)) => {
|
|
print!("RAW");
|
|
}
|
|
Err(e) => panic!("Could not get inner payload of ICMP PDU: {}", e),
|
|
}
|
|
Verdict::Accept
|
|
}
|
|
Ok(Ipv4::Gre(gre_pdu)) => {
|
|
print!("GRE -> ");
|
|
//print_gre(gre_pdu);
|
|
match gre_pdu.inner() {
|
|
#[allow(unused_variables)]
|
|
Ok(Gre::Raw(raw)) => {
|
|
print!("RAW");
|
|
}
|
|
Ok(_) => print!("Eth/Ipv4/Ipv6"),
|
|
Err(e) => panic!("Could not get inner payload of GRE PDU: {}", e),
|
|
}
|
|
Verdict::Accept
|
|
}
|
|
Err(e) => panic!("Could not decode inner packet: {}", e),
|
|
}
|
|
}
|
|
#[allow(unused_variables)]
|
|
Ok(Ip::Ipv6(ipv6_pdu)) => {
|
|
println!("IPv6!");
|
|
// TODO same as above
|
|
Verdict::Accept
|
|
}
|
|
Err(e) => panic!("Could not decode IP packet: {}", e),
|
|
};
|
|
println!();
|
|
|
|
msg.set_verdict(verdict);
|
|
queue
|
|
.verdict(msg)
|
|
.expect("Could not set verdict for message!");
|
|
}
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
fn print_gre(gre_pdu: GrePdu) {
|
|
print!(
|
|
"GRE {:10} {:3} {:5} {:5} {:5} {:5} {:?} {:?} {:?} {:?} ",
|
|
gre_pdu.computed_ihl(),
|
|
gre_pdu.version(),
|
|
gre_pdu.ethertype(),
|
|
gre_pdu.has_checksum(),
|
|
gre_pdu.has_key(),
|
|
gre_pdu.has_sequence_number(),
|
|
gre_pdu.checksum(),
|
|
gre_pdu.computed_checksum(),
|
|
gre_pdu.key(),
|
|
gre_pdu.sequence_number()
|
|
);
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
fn print_icmp(icmp_pdu: IcmpPdu) {
|
|
print!(
|
|
"ICMP {:3} {:3} {:5} {:10}",
|
|
icmp_pdu.message_type(),
|
|
icmp_pdu.message_code(),
|
|
icmp_pdu.checksum(),
|
|
//icmp_pdu.computed_checksum(ip: &crate::Ip)
|
|
icmp_pdu.computed_data_offset()
|
|
);
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
fn print_ipv4(ipv4_pdu: Ipv4Pdu) {
|
|
let sa = ipv4_pdu.source_address();
|
|
let da = ipv4_pdu.destination_address();
|
|
print!(
|
|
"IPv4 {} {} {} {:2} {} {:4} {:5} {:5} {:5} {} {} {:3} {:2} {:5} {:5} {:03}:{:03}:{:03}:{:03} {:03}:{:03}:{:03}:{:03} ",
|
|
ipv4_pdu.version(),
|
|
ipv4_pdu.ihl(),
|
|
ipv4_pdu.computed_ihl(),
|
|
ipv4_pdu.dscp(),
|
|
ipv4_pdu.ecn(),
|
|
ipv4_pdu.total_length(),
|
|
ipv4_pdu.identification(),
|
|
ipv4_pdu.dont_fragment(),
|
|
ipv4_pdu.more_fragments(),
|
|
ipv4_pdu.fragment_offset(),
|
|
ipv4_pdu.computed_fragment_offset(),
|
|
ipv4_pdu.ttl(),
|
|
ipv4_pdu.protocol(),
|
|
ipv4_pdu.checksum(),
|
|
ipv4_pdu.computed_checksum(),
|
|
//ipv4_pdu.source_address(),
|
|
sa[0],
|
|
sa[1],
|
|
sa[2],
|
|
sa[3],
|
|
//ipv4_pdu.destination_address(),
|
|
da[0],
|
|
da[1],
|
|
da[2],
|
|
da[3]
|
|
//ipv4_pdu.options()
|
|
);
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
fn print_ipv6(ipv6_pdu: Ipv6Pdu) {
|
|
print!(
|
|
"IPv {:3} {:3} {:3} {:10} {:5} {:3} {:10} {:3} {:?} {:?} {:?} {:3} {:?} {:?}",
|
|
// the {:10} could maybe be shorter
|
|
// {:?} should be replaced with "proper" hexdecoding, aka a lib to do the displaying
|
|
ipv6_pdu.version(),
|
|
ipv6_pdu.dscp(),
|
|
ipv6_pdu.ecn(),
|
|
ipv6_pdu.flow_label(),
|
|
ipv6_pdu.payload_length(),
|
|
ipv6_pdu.next_header(),
|
|
ipv6_pdu.computed_ihl(),
|
|
ipv6_pdu.computed_protocol(),
|
|
ipv6_pdu.computed_identification(),
|
|
ipv6_pdu.computed_more_fragments(),
|
|
ipv6_pdu.computed_fragment_offset(),
|
|
ipv6_pdu.hop_limit(),
|
|
ipv6_pdu.source_address(),
|
|
ipv6_pdu.destination_address(),
|
|
//ipv6_pdu.extension_headers()
|
|
);
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
fn print_tcp(tcp_pdu: TcpPdu) {
|
|
print!(
|
|
"TCP {:5} {:5} {:10} {:10} {:2} {:2} {:2} {:5} {:5} {:5} {:5} {:5} {:5} {:5} {:5} {:5} {} {} ",
|
|
tcp_pdu.source_port(),
|
|
tcp_pdu.destination_port(),
|
|
tcp_pdu.sequence_number(),
|
|
tcp_pdu.acknowledgement_number(),
|
|
tcp_pdu.data_offset(),
|
|
tcp_pdu.computed_data_offset(),
|
|
tcp_pdu.flags(),
|
|
tcp_pdu.fin(),
|
|
tcp_pdu.syn(),
|
|
tcp_pdu.rst(),
|
|
tcp_pdu.psh(),
|
|
tcp_pdu.ack(),
|
|
tcp_pdu.urg(),
|
|
tcp_pdu.ecn(),
|
|
tcp_pdu.cwr(),
|
|
tcp_pdu.window_size(),
|
|
//tcp_pdu.computed_window_size(shift: u8),
|
|
tcp_pdu.checksum(),
|
|
//tcp_pdu.computed_checksum(ip: &crate::Ip),
|
|
tcp_pdu.urgent_pointer(),
|
|
//tcp_pdu.options(),
|
|
);
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
fn print_udp(udp_pdu: UdpPdu) {
|
|
print!(
|
|
"UDP {:5} {:5} {:5} {:5} {} ",
|
|
udp_pdu.source_port(),
|
|
udp_pdu.destination_port(),
|
|
udp_pdu.length(),
|
|
udp_pdu.checksum(),
|
|
//udp_pdu.computed_checksum(ip: &crate::Ip),
|
|
udp_pdu.computed_data_offset()
|
|
);
|
|
}
|
|
|
|
#[allow(unused_variables)]
|
|
fn filter_ipv4_tcp_raw(ipv4_pdu: Ipv4Pdu, tcp_pdu: TcpPdu, raw: &[u8]) -> Verdict {
|
|
// example filter that drops GET requests to /secret
|
|
lazy_static! {
|
|
static ref RE: Regex = Regex::new("^GET /secret ").expect("Could not compile Regex!");
|
|
}
|
|
if RE.is_match(raw) {
|
|
Verdict::Drop
|
|
} else {
|
|
Verdict::Accept
|
|
}
|
|
}
|