restructured project

This commit is contained in:
Ishan Jain 2023-07-30 20:18:17 +05:30
parent ec8db9a658
commit 2c50a98e63
Signed by: ishan
GPG Key ID: 0506DB2A1CC75C27
7 changed files with 144 additions and 335 deletions

140
Cargo.lock generated
View File

@ -2,21 +2,6 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "addr2line"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3"
dependencies = [
"gimli",
]
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "aho-corasick"
version = "1.0.2"
@ -26,27 +11,6 @@ dependencies = [
"memchr",
]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "backtrace"
version = "0.3.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12"
dependencies = [
"addr2line",
"cc",
"cfg-if",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
]
[[package]]
name = "bitflags"
version = "1.3.2"
@ -161,12 +125,6 @@ dependencies = [
"libc",
]
[[package]]
name = "gimli"
version = "0.27.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e"
[[package]]
name = "hashbrown"
version = "0.14.0"
@ -230,26 +188,6 @@ version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "miniz_oxide"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
dependencies = [
"adler",
]
[[package]]
name = "mio"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
dependencies = [
"libc",
"wasi",
"windows-sys",
]
[[package]]
name = "multicast-socket"
version = "0.2.2"
@ -259,7 +197,7 @@ dependencies = [
"get_if_addrs",
"libc",
"nix",
"socket2 0.3.19",
"socket2",
"winapi 0.3.9",
]
@ -274,7 +212,6 @@ dependencies = [
"log",
"multicast-socket",
"serde",
"tokio",
"toml",
]
@ -290,31 +227,6 @@ dependencies = [
"libc",
]
[[package]]
name = "num_cpus"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
dependencies = [
"hermit-abi",
"libc",
]
[[package]]
name = "object"
version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1"
dependencies = [
"memchr",
]
[[package]]
name = "pin-project-lite"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57"
[[package]]
name = "proc-macro2"
version = "1.0.66"
@ -368,12 +280,6 @@ version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2"
[[package]]
name = "rustc-demangle"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "rustix"
version = "0.38.4"
@ -427,16 +333,6 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "socket2"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662"
dependencies = [
"libc",
"winapi 0.3.9",
]
[[package]]
name = "syn"
version = "2.0.27"
@ -457,34 +353,6 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "tokio"
version = "1.29.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da"
dependencies = [
"autocfg",
"backtrace",
"libc",
"mio",
"num_cpus",
"pin-project-lite",
"socket2 0.4.9",
"tokio-macros",
"windows-sys",
]
[[package]]
name = "tokio-macros"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "toml"
version = "0.7.6"
@ -525,12 +393,6 @@ version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "winapi"
version = "0.2.8"

View File

@ -11,5 +11,4 @@ libc = "0.2.147"
log = "0.4.18"
multicast-socket = "0.2.2"
serde = { version = "1.0.163", features = ["derive"] }
tokio = { version = "1.29.1", features = ["macros", "rt-multi-thread", "net"] }
toml = "0.7.4"

View File

@ -2,14 +2,15 @@
sources = ["eth70"]
destinations = ["eth10", "eth20", "eth30", "eth40"]
filters = [
"cups.local",
"_printer._tcp.local",
"_scanner._tcp.local",
"_ipp._tcp.local",
"_ipps._tcp.local",
"cups._ipps._tcp.local",
"lb._dns-sd._udp.local",
"EPSON1E715E.local",
"_pdl-datastream._tcp.local",
"EPSON M200 Series._pdl-datastream._tcp.local"
"cups.local",
"_printer._tcp.local",
"_scanner._tcp.local",
"_ipp._tcp.local",
"_ipps._tcp.local",
"cups._ipps._tcp.local",
"lb._dns-sd._udp.local",
"EPSON1E715E.local",
"_pdl-datastream._tcp.local",
"EPSON M200 Series._pdl-datastream._tcp.local",
"_ptp._tcp.local"
]

View File

@ -1,47 +0,0 @@
use log::{info, trace, warn};
use multicast_socket::{Message, MulticastOptions, MulticastSocket};
use std::{net::SocketAddrV4, sync::mpsc::Sender};
pub struct Communications {
tx_chan: Sender<Message>,
}
impl Communications {
pub fn new(tx_chan: Sender<Message>) -> Result<Self, String> {
Ok(Communications { tx_chan })
}
pub async fn start_listeners(&mut self) -> Result<(), String> {
info!("listener started");
let interfaces = get_if_addrs::get_if_addrs().unwrap();
trace!("Interfaces list: {:?}", interfaces);
// mdns
let mdns_address = SocketAddrV4::new([224, 0, 0, 251].into(), 5353);
let multicast_socket = MulticastSocket::with_options(
mdns_address,
multicast_socket::all_ipv4_interfaces().expect("could not fetch all interfaces"),
MulticastOptions {
loopback: false,
buffer_size: 4096,
..Default::default()
},
)
.expect("error in creating multicast socket");
loop {
match multicast_socket.receive() {
Ok(msg) => {
self.tx_chan
.send(msg)
.expect("error in sending to mpsc channel");
}
Err(e) if e.to_string().contains("EAGAIN") => continue,
Err(e) => {
warn!("error in reading from socket {:?} ", e);
}
};
}
}
}

View File

@ -4,16 +4,11 @@
// Or a common listener/transmitter and then different modules to parse and transmit each type of
// traffic
use log::info;
use multicast_socket::Message;
use std::sync::mpsc::{self, Receiver, Sender};
use tokio::runtime::Runtime;
pub mod communications;
pub use communications::*;
pub mod config;
pub use config::*;
pub mod processor;
pub use processor::*;
pub mod mdns;
pub use mdns::*;
fn main() {
env_logger::init();
@ -24,24 +19,7 @@ fn main() {
println!("{:?}", config);
let rt = Runtime::new().expect("error in creating runtime");
let mdns_client = Mdns::new(config);
// This channel is used to send packets from this module to the processor
// TODO(ishan): Eventually, swap out std::mpsc for some thing faster
// or switch to a different model completely that doesn't use channels like this
let (tx, rx): (Sender<Message>, Receiver<Message>) = mpsc::channel();
// TODO(ishan): Start listeners and transmitters on v4 and v6 here
let mut comms = Communications::new(tx).expect("error in starting comms");
rt.spawn(async move {
comms
.start_listeners()
.await
.expect("error in comms listener");
});
let processor = Processor::new(rx, config).expect("error in starting processor");
processor.start_read_loop();
mdns_client.listener_loop();
}

128
src/mdns.rs Normal file
View File

@ -0,0 +1,128 @@
use crate::Config;
use dns_parser::Packet;
use log::{info, trace, warn};
use multicast_socket::{Interface as MulticastInterface, MulticastOptions, MulticastSocket};
use std::{ffi::CString, net::SocketAddrV4};
pub struct Mdns {
socket: MulticastSocket,
config: Config,
}
impl Mdns {
pub fn new(config: Config) -> Self {
// mdns
let mdns_address = SocketAddrV4::new([224, 0, 0, 251].into(), 5353);
let multicast_socket = MulticastSocket::with_options(
mdns_address,
// TODO(ishan): Listen on ALL Interfaces, including ipv6
multicast_socket::all_ipv4_interfaces().expect("could not fetch all interfaces"),
MulticastOptions {
loopback: false,
buffer_size: 4096,
..Default::default()
},
)
.expect("error in creating multicast socket");
Self {
socket: multicast_socket,
config,
}
}
pub fn listener_loop(&self) {
info!("listener started");
loop {
match self.socket.receive() {
Ok(msg) => self.process_packet(msg),
Err(e) if e.to_string().contains("EAGAIN") => continue,
Err(e) => {
warn!("error in reading from socket {:?} ", e);
}
};
}
}
pub fn process_packet(&self, msg: multicast_socket::Message) {
// TODO: Generalize this to parse any type of supported packet
let packet = Packet::parse(&msg.data).expect("failed to parse packet as a dns packet");
let src_ifname = if let MulticastInterface::Index(idx) = msg.interface {
ifidx_to_ifname(idx as u32)
} else {
"lo".to_string()
};
trace!(
"EVENT src-if = {} if-index {:?} address = {}, packet: {:?} answers = {:?}",
src_ifname,
msg.interface,
msg.origin_address,
packet.questions.iter().map(|q| q.qname).collect::<Vec<_>>(),
packet.answers.iter().map(|q| q.name).collect::<Vec<_>>()
);
let interfaces = get_if_addrs::get_if_addrs().unwrap();
trace!("Interfaces: {:?}", interfaces);
for conf in &self.config.mdns {
let mut dst_ifs = vec![];
for query in &packet.questions {
if conf.destinations.contains(&src_ifname)
&& (conf.filters.is_empty() || conf.filters.contains(&query.qname.to_string()))
{
dst_ifs.extend(
conf.sources
.iter()
.filter_map(|dst_if| interfaces.iter().find(|x| &x.name == dst_if)),
);
}
}
for answer in &packet.answers {
if conf.sources.contains(&src_ifname)
&& (conf.filters.is_empty() || conf.filters.contains(&answer.name.to_string()))
{
dst_ifs.extend(
conf.destinations
.iter()
.filter_map(|dst_if| interfaces.iter().find(|x| &x.name == dst_if)),
);
}
}
for dst_if in dst_ifs {
let dst_ifid = ifname_to_ifidx(dst_if.name.to_string());
info!(
"forwarding packet questions {:?} answers = {:?} from {} to {}",
packet.questions, packet.answers, src_ifname, dst_if.name
);
// TODO(ishan): Take a note of transaction id
// and avoid feedback loops
self.socket
.send(&msg.data, &MulticastInterface::Index(dst_ifid as i32))
.expect("error in sending mdns packet");
}
}
}
}
fn ifidx_to_ifname(idx: u32) -> String {
let out = CString::new("askdjhaskdjakdjadksa").unwrap();
unsafe {
let ptr = out.into_raw();
let response = libc::if_indextoname(idx, ptr);
CString::from_raw(response).into_string().unwrap()
}
}
fn ifname_to_ifidx(name: String) -> u32 {
let out = name.as_ptr() as *const _;
unsafe { libc::if_nametoindex(out) }
}

View File

@ -1,112 +0,0 @@
use crate::Config;
use dns_parser::Packet;
use log::{info, trace};
use multicast_socket::{Interface, Message, MulticastOptions, MulticastSocket};
use std::{ffi::CString, net::SocketAddrV4, sync::mpsc::Receiver};
pub struct Processor {
reader: Receiver<Message>,
config: Config,
}
impl Processor {
pub fn new(reader: Receiver<Message>, config: Config) -> Result<Self, String> {
Ok(Self { reader, config })
}
pub fn start_read_loop(self) {
// mdns
let mdns_address = SocketAddrV4::new([224, 0, 0, 251].into(), 5353);
let socket = MulticastSocket::with_options(
mdns_address,
multicast_socket::all_ipv4_interfaces().expect("could not fetch all interfaces"),
MulticastOptions {
loopback: false,
buffer_size: 4096,
..Default::default()
},
)
.expect("error in creating multicast socket");
for evt in self.reader {
// TODO: Generalize this to parse any type of supported packet
let packet = Packet::parse(&evt.data).expect("failed to parse packet as a dns packet");
let interfaces = get_if_addrs::get_if_addrs().unwrap();
let src_ifname = if let Interface::Index(idx) = evt.interface {
ifidx_to_ifname(idx as u32)
} else {
"lo".to_string()
};
trace!(
"EVENT src-if = {} if-index {:?} address = {}, packet: {:?} answers = {:?}",
src_ifname,
evt.interface,
evt.origin_address,
packet.questions.iter().map(|q| q.qname).collect::<Vec<_>>(),
packet.answers.iter().map(|q| q.name).collect::<Vec<_>>()
);
for conf in &self.config.mdns {
let mut dst_ifs = vec![];
for query in &packet.questions {
if conf.destinations.contains(&src_ifname)
&& (conf.filters.is_empty()
|| conf.filters.contains(&query.qname.to_string()))
{
dst_ifs.extend(
conf.sources
.iter()
.filter_map(|dst_if| interfaces.iter().find(|x| &x.name == dst_if)),
);
}
}
for answer in &packet.answers {
if conf.sources.contains(&src_ifname)
&& (conf.filters.is_empty()
|| conf.filters.contains(&answer.name.to_string()))
{
dst_ifs.extend(
conf.destinations
.iter()
.filter_map(|dst_if| interfaces.iter().find(|x| &x.name == dst_if)),
);
}
}
for dst_if in dst_ifs {
let dst_ifid = ifname_to_ifidx(dst_if.name.to_string());
info!(
"forwarding packet questions {:?} answers = {:?} from {} to {}",
packet.questions, packet.answers, src_ifname, dst_if.name
);
// TODO(ishan): Take a note of transaction id
// and avoid feedback loops
socket
.send(&evt.data, &Interface::Index(dst_ifid as i32))
.expect("error in sending mdns packet");
}
}
}
}
}
fn ifidx_to_ifname(idx: u32) -> String {
let out = CString::new("askdjhaskdjakdjadksa").unwrap();
unsafe {
let ptr = out.into_raw();
let response = libc::if_indextoname(idx, ptr);
CString::from_raw(response).into_string().unwrap()
}
}
fn ifname_to_ifidx(name: String) -> u32 {
let out = name.as_ptr() as *const _;
unsafe { libc::if_nametoindex(out) }
}