diff --git a/src/main.rs b/src/main.rs index decd5b8..62dc629 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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? diff --git a/src/mdns/mod.rs b/src/mdns/mod.rs index 767fcac..4354171 100644 --- a/src/mdns/mod.rs +++ b/src/mdns/mod.rs @@ -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![]; diff --git a/src/parser/error.rs b/src/parser/error.rs index 93a4004..63f9106 100644 --- a/src/parser/error.rs +++ b/src/parser/error.rs @@ -10,4 +10,7 @@ pub enum ParserError { #[error("Label is not UTF-8")] LabelIsNotUTF8, + + #[error("Unknown rtype: {0}")] + UnknownRType(u16), } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 710aef4..77cf33d 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -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, pub answers: Vec, - // pub authority: Authority, - // pub additional: Additional, + pub authority: Vec, + pub additional: Vec, } impl DnsPacket { pub fn parse(data: &[u8]) -> Result { 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, 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, 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, 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()); } } } diff --git a/src/parser/qname.rs b/src/parser/qname.rs new file mode 100644 index 0000000..586a46a --- /dev/null +++ b/src/parser/qname.rs @@ -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 = 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]; + } + } + } + } +} diff --git a/src/parser/question.rs b/src/parser/question.rs index 195a55f..0b7d6de 100644 --- a/src/parser/question.rs +++ b/src/parser/question.rs @@ -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 = 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]; - } - } - } - } } diff --git a/src/parser/rdata/a.rs b/src/parser/rdata/a.rs new file mode 100644 index 0000000..77387c3 --- /dev/null +++ b/src/parser/rdata/a.rs @@ -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 { + let address = Ipv4Addr::from([data[0], data[1], data[2], data[3]]); + + Ok(Self { address }) + } +} diff --git a/src/parser/rdata/aaaa.rs b/src/parser/rdata/aaaa.rs new file mode 100644 index 0000000..d138c8a --- /dev/null +++ b/src/parser/rdata/aaaa.rs @@ -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 { + 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 }) + } +} diff --git a/src/parser/rdata/cname.rs b/src/parser/rdata/cname.rs new file mode 100644 index 0000000..d6d993e --- /dev/null +++ b/src/parser/rdata/cname.rs @@ -0,0 +1,10 @@ +use crate::ParserError; + +#[derive(Debug)] +pub struct Record {} + +impl Record { + pub fn parse(data: &[u8], original: &[u8]) -> Result { + Err(ParserError::UnexpectedEOP) + } +} diff --git a/src/parser/rdata/mod.rs b/src/parser/rdata/mod.rs new file mode 100644 index 0000000..717ca8d --- /dev/null +++ b/src/parser/rdata/mod.rs @@ -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), +} + +impl RData { + pub fn parse(rtype: Type, data: &[u8], original: &[u8]) -> Result { + 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!(), + } + } +} diff --git a/src/parser/rdata/nsec.rs b/src/parser/rdata/nsec.rs new file mode 100644 index 0000000..16598ca --- /dev/null +++ b/src/parser/rdata/nsec.rs @@ -0,0 +1,21 @@ +use crate::{ParserError, Qname}; + +#[derive(Debug)] +pub struct Record {} + +impl Record { + pub fn parse(data: &[u8], original: &[u8]) -> Result { + 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 {}) + } +} diff --git a/src/parser/rdata/ptr.rs b/src/parser/rdata/ptr.rs new file mode 100644 index 0000000..99f7a1c --- /dev/null +++ b/src/parser/rdata/ptr.rs @@ -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 { + let (domain_name, _) = Qname::read(data, original)?; + + Ok(Self { domain_name }) + } +} diff --git a/src/parser/rdata/srv.rs b/src/parser/rdata/srv.rs new file mode 100644 index 0000000..6fdb5d9 --- /dev/null +++ b/src/parser/rdata/srv.rs @@ -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 { + 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, + }) + } +} diff --git a/src/parser/rdata/txt.rs b/src/parser/rdata/txt.rs new file mode 100644 index 0000000..82a32bb --- /dev/null +++ b/src/parser/rdata/txt.rs @@ -0,0 +1,12 @@ +use crate::{ParserError, Qname}; + +#[derive(Debug)] +pub struct Record { + sets: Vec>, +} + +impl Record { + pub fn parse(data: &[u8], original: &[u8]) -> Result { + Ok(Self { sets: vec![] }) + } +} diff --git a/src/parser/resource_record.rs b/src/parser/resource_record.rs index 60a07ce..cd7549f 100644 --- a/src/parser/resource_record.rs +++ b/src/parser/resource_record.rs @@ -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 { + 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)), + } + } } diff --git a/src/socket.rs b/src/socket.rs index 6068333..3490d88 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -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>, - 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>, - multicast_group: MulticastGroup, + multicast_group: SocketAddrV4, ) -> Result { 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, - pub origin_address: Option, + pub origin_address: Option, 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 { 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 { - 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) { - println!("{}", std::any::type_name::()) -}