WIP: Working on config parser and a basic version which can receive multicast traffic
This commit is contained in:
parent
e2d443e6be
commit
46b21c2013
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1 +1,3 @@
|
|||
/target
|
||||
*.pcapng
|
||||
*.pcap
|
||||
|
|
270
Cargo.lock
generated
270
Cargo.lock
generated
|
@ -3,10 +3,83 @@
|
|||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "mdns-repeater"
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.144"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "multicaster"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"nix",
|
||||
"once_cell",
|
||||
"serde",
|
||||
"socket2",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.26.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"memoffset",
|
||||
"pin-utils",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -14,3 +87,198 @@ name = "once_cell"
|
|||
version = "1.17.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9670a07f94779e00908f3e686eab508878ebb390ba6e604d3a284c00e8d0487b"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.59"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.163"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.163"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6135d499e69981f9ff0ef2167955a5333c35e36f6937d382974566b3d5b94ec"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.19.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
|
|
@ -4,4 +4,8 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
nix = "0.26.2"
|
||||
once_cell = "1.17.2"
|
||||
serde = { version = "1.0.163", features = ["derive"] }
|
||||
socket2 = "0.5.3"
|
||||
toml = "0.7.4"
|
||||
|
|
14
README.md
Normal file
14
README.md
Normal file
|
@ -0,0 +1,14 @@
|
|||
# Multicaster
|
||||
|
||||
This is a software for routing multicast traffic across L2 networks.
|
||||
It'll allow you to be very specific about the exact traffic that is sent over.
|
||||
|
||||
|
||||
# Working Notes
|
||||
|
||||
1. It needs to listen on the specified port to receive multicast traffic.
|
||||
This causes problems if there are other softwares that are also listening without using `SO_ADDR_REUSE`.
|
||||
|
||||
For now, Disable those softwares when running this. A list of such softwares,
|
||||
|
||||
a. avahi-daemon
|
4
config.toml
Normal file
4
config.toml
Normal file
|
@ -0,0 +1,4 @@
|
|||
[config.mdns]
|
||||
port = 5353
|
||||
multicast_groups = ["224.0.0.251"]
|
||||
destinations = ["wlp6s0"]
|
34
src/config.rs
Normal file
34
src/config.rs
Normal file
|
@ -0,0 +1,34 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::{collections::HashMap, fs::File, io::Read, net::IpAddr};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Config {
|
||||
pub config: HashMap<String, Record>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Record {
|
||||
pub port: u16,
|
||||
pub multicast_groups: Vec<IpAddr>,
|
||||
pub destinations: Vec<String>,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
const FILENAME: &'static str = "config.toml";
|
||||
|
||||
pub fn parse(mut filename: &str) -> Result<Config, String> {
|
||||
if filename.is_empty() {
|
||||
filename = Config::FILENAME;
|
||||
}
|
||||
|
||||
let mut f = File::open(filename).map_err(|e| format!("error in opening file: {}", e))?;
|
||||
let mut contents = String::new();
|
||||
f.read_to_string(&mut contents)
|
||||
.map_err(|e| format!("error in reading file contents: {}", e))?;
|
||||
|
||||
let config: Config = toml::from_str(&contents)
|
||||
.map_err(|e| format!("error in parsing config: {}", e.message()))?;
|
||||
|
||||
Ok(config)
|
||||
}
|
||||
}
|
70
src/lib.rs
70
src/lib.rs
|
@ -1,6 +1,66 @@
|
|||
use once_cell::sync::Lazy;
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
||||
// TODO(ishan): Eventually we'll have a listener and transmitter module for every thing we want to
|
||||
// support. So, 1 for MDNS, another for WSDD?
|
||||
// Or a common listener/transmitter and then different modules to parse and transmit each type of
|
||||
// traffic
|
||||
pub mod config;
|
||||
pub use config::*;
|
||||
pub mod listener;
|
||||
|
||||
pub static IPv4: Lazy<IpAddr> = Lazy::new(|| Ipv4Addr::new(224, 0, 0, 123).into());
|
||||
pub static IPv6: Lazy<IpAddr> =
|
||||
Lazy::new(|| Ipv6Addr::new(0xff02, 0, 0, 0, 0, 0, 0, 0x0123).into());
|
||||
use crate::listener::{join_multicast, new_socket};
|
||||
use once_cell::sync::Lazy;
|
||||
use std::{
|
||||
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
|
||||
thread,
|
||||
};
|
||||
|
||||
pub static IPV4: Lazy<IpAddr> = Lazy::new(|| Ipv4Addr::new(0, 0, 0, 0).into());
|
||||
pub static IPV6: Lazy<IpAddr> = Lazy::new(|| {
|
||||
Ipv6Addr::new(0x2a0a, 0x6040, 0x4004, 0x10, 0xf1c6, 0xf2b0, 0x9f45, 0xb425).into()
|
||||
});
|
||||
|
||||
pub fn start(config: crate::Config) {
|
||||
// TODO(ishan): Start listeners and transmitters on v4 and v6 here
|
||||
|
||||
let mut handles = vec![];
|
||||
|
||||
for (_, v) in config.config {
|
||||
let handle = thread::spawn(move || {
|
||||
let mut ipv4_socket = new_socket(&SocketAddr::new(*IPV4, v.port))
|
||||
.expect("error in bind op on ipv4 address");
|
||||
|
||||
let mut ipv6_socket = new_socket(&SocketAddr::new(*IPV6, v.port))
|
||||
.expect("error in bind op on ipv6 address");
|
||||
|
||||
for group in v.multicast_groups {
|
||||
join_multicast(&mut ipv4_socket, &group)
|
||||
.expect("error in joining ipv4 multicast group");
|
||||
join_multicast(&mut ipv6_socket, &group)
|
||||
.expect("error in joining ipv6 multicast group");
|
||||
println!(
|
||||
"Listening for multicast packets on ipv4/ipv6 in group {}:{}",
|
||||
group, v.port
|
||||
);
|
||||
}
|
||||
let mut buf = [0u8; 64];
|
||||
match ipv4_socket.recv_from(&mut buf) {
|
||||
Ok((len, remote_addr)) => {
|
||||
let buf = &buf[..len];
|
||||
println!("received {}bytes response from {}", len, remote_addr);
|
||||
|
||||
let v = String::from_utf8_lossy(buf);
|
||||
|
||||
println!("output = {:?}", v);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("got an error: {}", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
handles.push(handle);
|
||||
}
|
||||
|
||||
for handle in handles {
|
||||
handle.join().unwrap()
|
||||
}
|
||||
}
|
||||
|
|
34
src/listener.rs
Normal file
34
src/listener.rs
Normal file
|
@ -0,0 +1,34 @@
|
|||
use std::{
|
||||
io::{Error, Result as IoResult},
|
||||
net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket},
|
||||
os::fd::AsRawFd,
|
||||
};
|
||||
|
||||
use nix::sys::socket::sockopt::ReuseAddr;
|
||||
|
||||
pub fn new_socket(addr: &SocketAddr) -> Result<UdpSocket, Error> {
|
||||
let socket = UdpSocket::bind(addr)?;
|
||||
|
||||
#[cfg(unix)]
|
||||
nix::sys::socket::setsockopt(socket.as_raw_fd(), ReuseAddr, &true)?;
|
||||
|
||||
// socket.set_read_timeout(Some(Duration::from_millis(100)))?;
|
||||
|
||||
Ok(socket)
|
||||
}
|
||||
|
||||
pub fn join_multicast(socket: &mut UdpSocket, group: &IpAddr) -> IoResult<()> {
|
||||
// TODO(ishan): Eventually, this should only listen on the
|
||||
// interfaces specified in config.toml
|
||||
match group {
|
||||
IpAddr::V4(ref mdns_v4) => {
|
||||
socket.multicast_loop_v4()?;
|
||||
socket.join_multicast_v4(mdns_v4, &Ipv4Addr::new(0, 0, 0, 0))
|
||||
}
|
||||
IpAddr::V6(ref mdns_v6) => {
|
||||
socket.multicast_loop_v6()?;
|
||||
|
||||
socket.join_multicast_v6(mdns_v6, 0)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +1,8 @@
|
|||
use multicaster::Config;
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
let config = Config::parse("config.toml").expect("error in parsing config");
|
||||
|
||||
println!("{:?}", config);
|
||||
|
||||
multicaster::start(config);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user