WIP/parser: added parsers for some formats

This commit is contained in:
Ishan Jain 2023-11-22 02:08:45 +05:30
parent 55ee873280
commit df9e29c4a4
Signed by: ishan
GPG Key ID: 0506DB2A1CC75C27
16 changed files with 471 additions and 122 deletions

View File

@ -1,3 +1,4 @@
#![feature(ip_bits)]
#![feature(async_closure)]
// 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?

View File

@ -1,6 +1,4 @@
use crate::socket::{
Interface as MulticastInterface, MulticastGroup, MulticastOptions, MulticastSocket,
};
use crate::socket::{Interface as MulticastInterface, MulticastOptions, MulticastSocket};
use crate::Config;
use dns_parser::Packet;
use log::{info, trace, warn};
@ -19,10 +17,7 @@ impl Mdns {
let multicast_socket = MulticastSocket::new(
MulticastOptions::default(),
MulticastSocket::all_interfaces().unwrap(),
MulticastGroup {
ipv4: SocketAddrV4::new(Ipv4Addr::new(224, 0, 0, 251), 5353),
port: 5353,
},
SocketAddrV4::new(Ipv4Addr::new(224, 0, 0, 251), 5353),
)
.expect("error in creating multicast socket");
@ -55,12 +50,11 @@ impl Mdns {
pub fn process_packet(&self, msg: crate::socket::Message) {
// TODO: Generalize this to parse any type of supported packet
trace!("{:0x?}", msg.data);
let packet = Packet::parse(&msg.data).unwrap_or_else(|e| {
panic!(
"failed to parse packet as a dns packet: {:?} error = {:?}, loose_string = {}",
msg,
e,
String::from_utf8_lossy(&msg.data)
"failed to parse packet as a dns packet. origin = {:?} interface = {:?} error = {:?}, loose_string = {:02x?}",
msg.origin_address,msg.interface, e, msg.data,
)
});
@ -80,7 +74,6 @@ impl Mdns {
);
let interfaces = get_if_addrs::get_if_addrs().unwrap();
trace!("Interfaces: {:?}", interfaces);
for conf in &self.config.mdns {
let mut dst_ifs = vec![];

View File

@ -10,4 +10,7 @@ pub enum ParserError {
#[error("Label is not UTF-8")]
LabelIsNotUTF8,
#[error("Unknown rtype: {0}")]
UnknownRType(u16),
}

View File

@ -1,4 +1,8 @@
#![allow(unused)]
mod header;
use std::task::Wake;
pub use header::*;
mod error;
pub use error::*;
@ -6,29 +10,87 @@ mod question;
pub use question::*;
mod resource_record;
pub use resource_record::*;
mod qname;
pub use qname::*;
mod rdata;
pub use rdata::*;
#[derive(Debug, Default)]
pub struct DnsPacket {
pub header: Header,
pub questions: Vec<Question>,
pub answers: Vec<ResourceRecord>,
// pub authority: Authority,
// pub additional: Additional,
pub authority: Vec<ResourceRecord>,
pub additional: Vec<ResourceRecord>,
}
impl DnsPacket {
pub fn parse(data: &[u8]) -> Result<Self, ParserError> {
let header = Header::parse(data)?;
let (questions, read) = DnsPacket::parse_questions(&header, data)?;
let (answers, read) = DnsPacket::parse_answers(&header, data, read)?;
let (authority, read) = DnsPacket::parse_authority(&header, data, read)?;
let (additional, read) = DnsPacket::parse_additional(&header, data, read)?;
Ok(Self {
header,
questions,
..Default::default()
answers,
additional,
authority,
})
}
fn parse_additional(
header: &Header,
data: &[u8],
mut offset: usize,
) -> Result<(Vec<ResourceRecord>, usize), ParserError> {
let mut out = Vec::with_capacity(header.an_count as usize);
for _ in 0..header.ar_count {
let (q, read) = ResourceRecord::parse(&data[offset..], data)?;
offset += read;
out.push(q);
}
Ok((out, offset))
}
fn parse_authority(
header: &Header,
data: &[u8],
mut offset: usize,
) -> Result<(Vec<ResourceRecord>, usize), ParserError> {
let mut out = Vec::with_capacity(header.an_count as usize);
for _ in 0..header.ns_count {
let (q, read) = ResourceRecord::parse(&data[offset..], data)?;
offset += read;
out.push(q);
}
Ok((out, offset))
}
fn parse_answers(
header: &Header,
data: &[u8],
mut offset: usize,
) -> Result<(Vec<ResourceRecord>, usize), ParserError> {
let mut out = Vec::with_capacity(header.an_count as usize);
for _ in 0..header.an_count {
let (q, read) = ResourceRecord::parse(&data[offset..], data)?;
offset += read;
out.push(q);
}
Ok((out, offset))
}
fn parse_questions(
header: &Header,
data: &[u8],
@ -137,10 +199,64 @@ mod test {
0x00, 0x0c, 0x00, 0x01, 0x00, 0x00, 0x11, 0x93, 0x00, 0x11, 0x0e, 0x49, 0x73, 0x68,
0x61, 0x6e, 0xe2, 0x80, 0x99, 0x73, 0x20, 0x69, 0x50, 0x61, 0x64, 0xc0, 0x0c,
],
vec![
0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x05, 0x01, 0x44,
0x01, 0x33, 0x01, 0x42, 0x01, 0x39, 0x01, 0x45, 0x01, 0x44, 0x01, 0x45, 0x01, 0x35,
0x01, 0x32, 0x01, 0x36, 0x01, 0x36, 0x01, 0x46, 0x01, 0x37, 0x01, 0x36, 0x01, 0x43,
0x01, 0x31, 0x01, 0x30, 0x01, 0x30, 0x01, 0x30, 0x01, 0x30, 0x01, 0x30, 0x01, 0x30,
0x01, 0x30, 0x01, 0x30, 0x01, 0x30, 0x01, 0x30, 0x01, 0x30, 0x01, 0x30, 0x01, 0x30,
0x01, 0x38, 0x01, 0x45, 0x01, 0x46, 0x03, 0x69, 0x70, 0x36, 0x04, 0x61, 0x72, 0x70,
0x61, 0x00, 0x00, 0x0c, 0x80, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x13, 0x0b, 0x49,
0x73, 0x68, 0x61, 0x6e, 0x73, 0x2d, 0x69, 0x50, 0x61, 0x64, 0x05, 0x6c, 0x6f, 0x63,
0x61, 0x6c, 0x00, 0x01, 0x43, 0x01, 0x39, 0x01, 0x43, 0x01, 0x32, 0x01, 0x31, 0x01,
0x35, 0x01, 0x33, 0x01, 0x30, 0x01, 0x46, 0x01, 0x30, 0x01, 0x34, 0x01, 0x36, 0x01,
0x33, 0x01, 0x38, 0x01, 0x34, 0x01, 0x30, 0x01, 0x30, 0x01, 0x31, 0x01, 0x30, 0x01,
0x30, 0x01, 0x34, 0x01, 0x30, 0x01, 0x30, 0x01, 0x34, 0x01, 0x30, 0x01, 0x34, 0x01,
0x30, 0x01, 0x36, 0x01, 0x41, 0x01, 0x30, 0x01, 0x41, 0x01, 0x32, 0xc0, 0x4c, 0x00,
0x0c, 0x80, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x02, 0xc0, 0x60, 0x02, 0x35, 0x30,
0x02, 0x31, 0x30, 0x01, 0x30, 0x02, 0x31, 0x30, 0x07, 0x69, 0x6e, 0x2d, 0x61, 0x64,
0x64, 0x72, 0xc0, 0x50, 0x00, 0x0c, 0x80, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x02,
0xc0, 0x60, 0x0e, 0x49, 0x73, 0x68, 0x61, 0x6e, 0xe2, 0x80, 0x99, 0x73, 0x20, 0x69,
0x50, 0x61, 0x64, 0x0f, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x69, 0x6f, 0x6e,
0x2d, 0x6c, 0x69, 0x6e, 0x6b, 0x04, 0x5f, 0x74, 0x63, 0x70, 0xc0, 0x6c, 0x00, 0x10,
0x80, 0x01, 0x00, 0x00, 0x11, 0x94, 0x00, 0x82, 0x07, 0x72, 0x70, 0x4d, 0x61, 0x63,
0x3d, 0x30, 0x11, 0x72, 0x70, 0x48, 0x4e, 0x3d, 0x61, 0x37, 0x33, 0x33, 0x36, 0x31,
0x64, 0x61, 0x31, 0x32, 0x37, 0x63, 0x0c, 0x72, 0x70, 0x46, 0x6c, 0x3d, 0x30, 0x78,
0x33, 0x30, 0x30, 0x30, 0x30, 0x11, 0x72, 0x70, 0x48, 0x41, 0x3d, 0x35, 0x62, 0x32,
0x36, 0x39, 0x61, 0x65, 0x30, 0x35, 0x32, 0x32, 0x33, 0x0d, 0x72, 0x70, 0x56, 0x72,
0x3d, 0x35, 0x31, 0x30, 0x2e, 0x37, 0x31, 0x2e, 0x31, 0x11, 0x72, 0x70, 0x41, 0x44,
0x3d, 0x63, 0x30, 0x31, 0x66, 0x33, 0x61, 0x63, 0x39, 0x38, 0x66, 0x63, 0x38, 0x11,
0x72, 0x70, 0x48, 0x49, 0x3d, 0x35, 0x36, 0x34, 0x39, 0x31, 0x37, 0x31, 0x64, 0x33,
0x66, 0x61, 0x38, 0x16, 0x72, 0x70, 0x42, 0x41, 0x3d, 0x34, 0x45, 0x3a, 0x31, 0x46,
0x3a, 0x32, 0x33, 0x3a, 0x37, 0x44, 0x3a, 0x34, 0x46, 0x3a, 0x30, 0x33, 0x09, 0x5f,
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x07, 0x5f, 0x64, 0x6e, 0x73, 0x2d,
0x73, 0x64, 0x04, 0x5f, 0x75, 0x64, 0x70, 0xc0, 0x6c, 0x00, 0x0c, 0x00, 0x01, 0x00,
0x00, 0x11, 0x94, 0x00, 0x02, 0xc0, 0xf1, 0xc0, 0xf1, 0x00, 0x0c, 0x00, 0x01, 0x00,
0x00, 0x11, 0x94, 0x00, 0x02, 0xc0, 0xe2, 0x0e, 0x49, 0x73, 0x68, 0x61, 0x6e, 0xe2,
0x80, 0x99, 0x73, 0x20, 0x69, 0x50, 0x61, 0x64, 0x0c, 0x5f, 0x64, 0x65, 0x76, 0x69,
0x63, 0x65, 0x2d, 0x69, 0x6e, 0x66, 0x6f, 0xc1, 0x01, 0x00, 0x10, 0x00, 0x01, 0x00,
0x00, 0x11, 0x94, 0x00, 0x0d, 0x0c, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x3d, 0x4a, 0x35,
0x32, 0x32, 0x41, 0x50, 0xc0, 0xe2, 0x00, 0x21, 0x80, 0x01, 0x00, 0x00, 0x00, 0x78,
0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0xda, 0x42, 0xc0, 0x60, 0xc0, 0x60, 0x00, 0x1c,
0x80, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x10, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1c, 0x67, 0xf6, 0x62, 0x5e, 0xde, 0x9b, 0x3d, 0xc0, 0x60, 0x00, 0x1c,
0x80, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x10, 0x2a, 0x0a, 0x60, 0x40, 0x40, 0x04,
0x00, 0x10, 0x04, 0x83, 0x64, 0x0f, 0x03, 0x51, 0x2c, 0x9c, 0xc0, 0x60, 0x00, 0x01,
0x80, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x04, 0x0a, 0x00, 0x0a, 0x32, 0xc0, 0x0c,
0x00, 0x2f, 0x80, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x06, 0xc0, 0x0c, 0x00, 0x02,
0x00, 0x08, 0xc0, 0x73, 0x00, 0x2f, 0x80, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x06,
0xc0, 0x73, 0x00, 0x02, 0x00, 0x08, 0xc0, 0xc1, 0x00, 0x2f, 0x80, 0x01, 0x00, 0x00,
0x00, 0x78, 0x00, 0x06, 0xc0, 0xc1, 0x00, 0x02, 0x00, 0x08, 0xc0, 0xe2, 0x00, 0x2f,
0x80, 0x01, 0x00, 0x00, 0x11, 0x94, 0x00, 0x09, 0xc0, 0xe2, 0x00, 0x05, 0x00, 0x00,
0x80, 0x00, 0x40, 0xc0, 0x60, 0x00, 0x2f, 0x80, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00,
0x08, 0xc0, 0x60, 0x00, 0x04, 0x40, 0x00, 0x00, 0x08,
],
];
for input in inputs.iter() {
assert!(DnsPacket::parse(input).is_ok());
let output = DnsPacket::parse(input);
println!("{:#?}", output);
assert!(output.is_ok());
}
}
}

59
src/parser/qname.rs Normal file
View File

@ -0,0 +1,59 @@
use crate::ParserError;
#[derive(Debug, Default)]
pub struct Qname {}
impl Qname {
pub fn read(data: &[u8], original: &[u8]) -> Result<(String, usize), ParserError> {
let mut parse_data = data;
let mut out = Vec::new();
let mut offset = 0;
let mut byte = parse_data[offset];
let mut bytes_read = 1;
let mut return_pos: Option<usize> = None;
loop {
match byte {
0 => {
out.pop();
return Ok((
String::from_utf8(out).map_err(|_| ParserError::LabelIsNotUTF8)?,
if let Some(p) = return_pos {
p + 2
} else {
bytes_read
},
));
}
v if v & 0b1100_0000 == 0b1100_0000 => {
let nof = (((v & 0b0011_1111) as usize) << 8) | parse_data[offset + 1] as usize;
if nof >= original.len() {
return Err(ParserError::UnexpectedEOP);
}
if return_pos.is_none() {
return_pos = Some(offset);
}
offset = 0;
parse_data = &original[nof..];
byte = parse_data[0];
}
_ => {
out.extend(&parse_data[offset + 1..offset + 1 + byte as usize]);
out.push(b'.');
offset += byte as usize + 1;
bytes_read += byte as usize + 1;
byte = parse_data[offset];
}
}
}
}
}

View File

@ -1,4 +1,4 @@
use crate::ParserError;
use crate::{ParserError, Qname};
#[derive(Debug, Default)]
pub struct Question {
@ -10,7 +10,7 @@ pub struct Question {
impl Question {
pub fn parse(data: &[u8], original: &[u8]) -> Result<(Self, usize), ParserError> {
let (qname, mut read) = Self::read_label(data, original)?;
let (qname, mut read) = Qname::read(data, original)?;
let qtype = u16::from_be_bytes([data[read], data[read + 1]]);
read += 2;
@ -30,57 +30,4 @@ impl Question {
read,
))
}
fn read_label(data: &[u8], original: &[u8]) -> Result<(String, usize), ParserError> {
let mut parse_data = data;
let mut out = Vec::new();
let mut offset = 0;
let mut byte = parse_data[offset];
let mut bytes_read = 1;
let mut return_pos: Option<usize> = None;
loop {
match byte {
0 => {
out.pop();
return Ok((
String::from_utf8(out).map_err(|_| ParserError::LabelIsNotUTF8)?,
if let Some(p) = return_pos {
p + 2
} else {
bytes_read
},
));
}
0xc0 => {
let nof = parse_data[offset + 1] as usize;
if nof >= original.len() {
return Err(ParserError::UnexpectedEOP);
}
return_pos = match return_pos {
Some(x) => Some(std::cmp::max(x, offset)),
None => Some(offset),
};
offset = 0;
parse_data = &original[nof..];
byte = parse_data[0];
}
_ => {
out.extend(&parse_data[offset + 1..offset + 1 + byte as usize]);
out.push(b'.');
offset += byte as usize + 1;
bytes_read += byte as usize + 1;
byte = parse_data[offset];
}
}
}
}
}

15
src/parser/rdata/a.rs Normal file
View File

@ -0,0 +1,15 @@
use crate::ParserError;
use std::net::Ipv4Addr;
#[derive(Debug)]
pub struct Record {
pub address: Ipv4Addr,
}
impl Record {
pub fn parse(data: &[u8], original: &[u8]) -> Result<Self, ParserError> {
let address = Ipv4Addr::from([data[0], data[1], data[2], data[3]]);
Ok(Self { address })
}
}

18
src/parser/rdata/aaaa.rs Normal file
View File

@ -0,0 +1,18 @@
use crate::ParserError;
use std::net::Ipv6Addr;
#[derive(Debug)]
pub struct Record {
pub address: Ipv6Addr,
}
impl Record {
pub fn parse(mut data: &[u8], original: &[u8]) -> Result<Self, ParserError> {
let address = Ipv6Addr::from([
data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8],
data[9], data[10], data[11], data[12], data[13], data[14], data[15],
]);
Ok(Self { address })
}
}

10
src/parser/rdata/cname.rs Normal file
View File

@ -0,0 +1,10 @@
use crate::ParserError;
#[derive(Debug)]
pub struct Record {}
impl Record {
pub fn parse(data: &[u8], original: &[u8]) -> Result<Self, ParserError> {
Err(ParserError::UnexpectedEOP)
}
}

36
src/parser/rdata/mod.rs Normal file
View File

@ -0,0 +1,36 @@
mod a;
mod aaaa;
mod cname;
mod nsec;
mod ptr;
mod srv;
mod txt;
use crate::{ParserError, Type};
#[derive(Debug)]
pub enum RData {
A(a::Record),
Aaaa(aaaa::Record),
Cname(cname::Record),
Ptr(ptr::Record),
Txt(txt::Record),
Srv(srv::Record),
Nsec(nsec::Record),
Unknown(Type, Vec<u8>),
}
impl RData {
pub fn parse(rtype: Type, data: &[u8], original: &[u8]) -> Result<Self, ParserError> {
match rtype {
Type::A => Ok(RData::A(a::Record::parse(data, original)?)),
Type::Cname => Ok(RData::Cname(cname::Record::parse(data, original)?)),
Type::Ptr => Ok(RData::Ptr(ptr::Record::parse(data, original)?)),
Type::Txt => Ok(RData::Txt(txt::Record::parse(data, original)?)),
Type::Aaaa => Ok(RData::Aaaa(aaaa::Record::parse(data, original)?)),
Type::Srv => Ok(RData::Srv(srv::Record::parse(data, original)?)),
Type::Nsec => Ok(RData::Nsec(nsec::Record::parse(data, original)?)),
Type::Https => todo!(),
}
}
}

21
src/parser/rdata/nsec.rs Normal file
View File

@ -0,0 +1,21 @@
use crate::{ParserError, Qname};
#[derive(Debug)]
pub struct Record {}
impl Record {
pub fn parse(data: &[u8], original: &[u8]) -> Result<Self, ParserError> {
println!("{:02x?}", &data[..]);
let (domain_name, mut read) = Qname::read(data, original)?;
println!("{:02x?}", &data[read..]);
read += 1;
let rr_bitmap_len = data[read];
let rr_bitmap = u16::from_be_bytes([data[read], data[read + 1]]);
println!("{:0x}", rr_bitmap_len);
Ok(Self {})
}
}

14
src/parser/rdata/ptr.rs Normal file
View File

@ -0,0 +1,14 @@
use crate::{parser::qname, ParserError, Qname};
#[derive(Debug)]
pub struct Record {
domain_name: String,
}
impl Record {
pub fn parse(data: &[u8], original: &[u8]) -> Result<Self, ParserError> {
let (domain_name, _) = Qname::read(data, original)?;
Ok(Self { domain_name })
}
}

29
src/parser/rdata/srv.rs Normal file
View File

@ -0,0 +1,29 @@
use crate::{ParserError, Qname};
#[derive(Debug)]
pub struct Record {
priority: u16,
weight: u16,
port: u16,
target: String,
}
impl Record {
pub fn parse(mut data: &[u8], original: &[u8]) -> Result<Self, ParserError> {
let priority = u16::from_be_bytes([data[0], data[1]]);
data = &data[2..];
let weight = u16::from_be_bytes([data[0], data[1]]);
data = &data[2..];
let port = u16::from_be_bytes([data[0], data[1]]);
data = &data[2..];
let (target, _) = Qname::read(data, original)?;
Ok(Self {
priority,
weight,
port,
target,
})
}
}

12
src/parser/rdata/txt.rs Normal file
View File

@ -0,0 +1,12 @@
use crate::{ParserError, Qname};
#[derive(Debug)]
pub struct Record {
sets: Vec<Vec<u8>>,
}
impl Record {
pub fn parse(data: &[u8], original: &[u8]) -> Result<Self, ParserError> {
Ok(Self { sets: vec![] })
}
}

View File

@ -1,9 +1,86 @@
#[derive(Debug, Default)]
use crate::{ParserError, Qname, RData};
#[derive(Debug)]
pub struct ResourceRecord {
name: String,
rtype: u16,
class: u16,
ttl: u16,
rdlength: u16,
rdata: (),
pub name: String,
pub rtype: Type,
pub class: u16,
pub cache_flush: bool,
pub ttl: u32,
pub rdlength: u16,
pub rdata: RData,
}
impl ResourceRecord {
pub fn parse(data: &[u8], original: &[u8]) -> Result<(Self, usize), ParserError> {
let (name, mut read) = Qname::read(data, original)?;
if read + 10 > data.len() {
return Err(ParserError::UnexpectedEOP);
}
let rtype = Type::parse(u16::from_be_bytes([data[read], data[read + 1]]))?;
read += 2;
let (cache_flush, class) =
Self::parse_class(u16::from_be_bytes([data[read], data[read + 1]]));
read += 2;
let ttl = u32::from_be_bytes([data[read], data[read + 1], data[read + 2], data[read + 3]]);
read += 4;
let rdlength = u16::from_be_bytes([data[read], data[read + 1]]);
read += 2;
if read + rdlength as usize > data.len() {
return Err(ParserError::UnexpectedEOP);
}
let rdata = RData::parse(rtype, &data[read..read + rdlength as usize], original)?;
read += rdlength as usize;
Ok((
Self {
name,
rtype,
class,
cache_flush,
ttl,
rdlength,
rdata,
},
read,
))
}
fn parse_class(v: u16) -> (bool, u16) {
(((v >> 15) & 1) == 1, v & !(1 << 15))
}
}
#[derive(Debug, Copy, Clone)]
#[non_exhaustive]
pub enum Type {
A = 1,
Cname = 5,
Ptr = 12,
Txt = 16,
Aaaa = 28,
Srv = 33,
Nsec = 47,
Https = 65,
}
impl Type {
fn parse(v: u16) -> Result<Self, ParserError> {
use Type::*;
match v {
1 => Ok(A),
5 => Ok(Cname),
12 => Ok(Ptr),
16 => Ok(Txt),
28 => Ok(Aaaa),
33 => Ok(Srv),
47 => Ok(Nsec),
65 => Ok(Https),
v => Err(ParserError::UnknownRType(v)),
}
}
}

View File

@ -2,7 +2,10 @@
use log::trace;
// This code has been adapted from multicast_socket crate
use nix::sys::socket::{self as sock, AddressFamily, SockaddrIn, SockaddrLike, SockaddrStorage};
use nix::sys::{
self,
socket::{self as sock, AddressFamily, SockAddr, SockaddrIn, SockaddrLike, SockaddrStorage},
};
use serde::de::value;
use socket2::{Domain, Protocol, Socket, Type};
use std::{
@ -33,21 +36,15 @@ impl Default for MulticastOptions {
pub struct MulticastSocket {
socket: socket2::Socket,
interfaces: HashMap<String, Vec<IpAddr>>,
multicast_group: MulticastGroup,
multicast_group: SocketAddrV4,
buffer_size: usize,
}
#[derive(Debug, Clone)]
pub struct MulticastGroup {
pub ipv4: SocketAddrV4,
pub port: u16,
}
impl MulticastSocket {
pub fn new(
options: MulticastOptions,
interfaces: HashMap<String, Vec<IpAddr>>,
multicast_group: MulticastGroup,
multicast_group: SocketAddrV4,
) -> Result<Self, std::io::Error> {
let socket = Socket::new(Domain::IPV4, Type::DGRAM, Some(Protocol::UDP))?;
socket.set_read_timeout(Some(options.read_timeout))?;
@ -62,13 +59,7 @@ impl MulticastSocket {
.map_err(nix_to_io_error)?;
for (if_name, addresses) in interfaces.iter() {
trace!(
"joining groups = {:?} interface = {:?}",
multicast_group.ipv4.ip(),
Ipv4Addr::UNSPECIFIED
);
socket.join_multicast_v4(multicast_group.ipv4.ip(), &Ipv4Addr::UNSPECIFIED);
trace!("joining groups = {:?}", multicast_group);
for address in addresses {
if let IpAddr::V4(v4_addr) = address {
@ -76,11 +67,11 @@ impl MulticastSocket {
continue;
}
socket.join_multicast_v4(multicast_group.ipv4.ip(), v4_addr)?;
socket.join_multicast_v4(multicast_group.ip(), v4_addr)?;
trace!(
"joined ipv4 multicast group {} {}",
multicast_group.ipv4.ip(),
multicast_group.ip(),
v4_addr
);
}
@ -88,7 +79,7 @@ impl MulticastSocket {
}
socket.bind(
&SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), multicast_group.port).into(),
&SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), multicast_group.port()).into(),
)?;
Ok(MulticastSocket {
@ -121,7 +112,7 @@ impl MulticastSocket {
#[derive(Debug, Clone)]
pub struct Message {
pub data: Vec<u8>,
pub origin_address: Option<SocketAddr>,
pub origin_address: Option<SocketAddrV4>,
pub interface: Interface,
}
@ -129,7 +120,7 @@ pub struct Message {
pub enum Interface {
Default,
Index(i32),
IpAddr(Ipv6Addr),
IpAddr(IpAddr),
}
#[inline]
@ -145,7 +136,7 @@ fn nix_to_io_error(e: nix::Error) -> io::Error {
impl MulticastSocket {
pub fn receive(&self) -> IoResult<Message> {
let mut data_buffer = vec![0; self.buffer_size];
let mut control_buffer = nix::cmsg_space!(libc::in6_pktinfo, libc::in_pktinfo);
let mut control_buffer = nix::cmsg_space!(libc::in_pktinfo);
let (origin_address, interface, bytes_read) = {
let message = sock::recvmsg(
@ -156,28 +147,15 @@ impl MulticastSocket {
)
.map_err(nix_to_io_error)?;
let origin_address = match message.address {
//v4 @ Some(SockaddrIn) => v4,
Some(sock::SockAddr::Inet(inet)) => Some(inet.to_std()),
_ => None,
};
// let origin_address = match origin_address {
// Some(SocketAddr::V6(v6)) => v6,
// _ => SocketAddrV6::new(Ipv6Addr::UNSPECIFIED, 0, 0, 0),
// };
let origin_address = message.address.map(|x: sock::SockaddrIn| {
SocketAddrV4::new(Ipv4Addr::from_bits(x.ip()), x.port())
});
println!("{:?}", origin_address);
let mut interface = Interface::Default;
for cmsg in message.cmsgs() {
if let sock::ControlMessageOwned::Ipv6PacketInfo(pktinfo) = cmsg {
interface = Interface::Index(pktinfo.ipi6_ifindex as _);
trace!("control packet ipv6: {:?}", pktinfo);
}
if let sock::ControlMessageOwned::Ipv4PacketInfo(pktinfo) = cmsg {
interface = Interface::Index(pktinfo.ipi_ifindex as _);
trace!("control packet ipv4: {:?}", pktinfo);
}
}
@ -192,7 +170,31 @@ impl MulticastSocket {
}
pub fn send(&self, buf: &[u8], interface: &Interface) -> io::Result<usize> {
Ok(0)
let mut pkt_info: libc::in_pktinfo = unsafe { mem::zeroed() };
match interface {
Interface::Default => todo!(),
Interface::Index(i) => {
pkt_info.ipi_ifindex = *i as _;
}
Interface::IpAddr(IpAddr::V4(addr)) => {
pkt_info.ipi_spec_dst = libc::in_addr {
s_addr: (*addr).into(),
};
}
_ => unreachable!(),
}
sock::sendmsg(
self.socket.as_raw_fd(),
&[IoSlice::new(buf)],
&[sock::ControlMessage::Ipv4PacketInfo(&pkt_info)],
sock::MsgFlags::empty(),
Some(&SockaddrIn::from(self.multicast_group)),
)
.map_err(nix_to_io_error)
// match interface {
// Interface::Default => todo!(),
// Interface::Index(index) => {
@ -234,7 +236,3 @@ impl MulticastSocket {
// .map_err(nix_to_io_error)
}
}
fn print_type_of<T>(_: &T) {
println!("{}", std::any::type_name::<T>())
}