eculocate

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit 0b4ea48d94cc7e0315d62b28603d57c10ff9df3f
parent 7225bb934de4c36fc2cf3cee63cde163afd2a7c4
Author: Daniel Barlow <dan@telent.net>
Date:   Fri, 12 Dec 2025 23:32:55 +0000

respond to mdns queries for our A with our A record

I'm not 100% this is technically correct, as wireshark doesn't
seem able to associate the response with the request. However,
I can't see anything wrong with what I'm sending, and wireshark
is unable to associate responses make by several other devices on the
LAN with their requests either, so this might not be a me problem

Diffstat:
Msrc/wifi.rs | 115+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
1 file changed, 75 insertions(+), 40 deletions(-)

diff --git a/src/wifi.rs b/src/wifi.rs @@ -55,6 +55,60 @@ const MDNS_IP: IpAddress = IpAddress::v4(224, 0, 0, 251); const MDNS_PORT: u16 = 5353; const MDNS_ENDPOINT: IpEndpoint = IpEndpoint::new(MDNS_IP, MDNS_PORT); +// RFC: "Multicast DNS responses MUST NOT contain any questions in the +// Question Section. ". However, responses to "legacy" queries (port != 5353) +// should have a question section just like traditional DNS + +async fn send_advert(sock: &UdpSocket<'_>, + id: u16, + endpoint: IpEndpoint, + question: Option<&Question<'_>>, + my_address: &[u8]) { + + let questions = match question { + Some(q) =>&mut [*q][..], + None => &mut [][..] + }; + + // FIXME for legacy unicast response max ttl is 10s + + let mut answer = [ + ResourceRecord::new( + "eculogical.local", + ResourceType::A, + 1 | (1<<15), // class = IN, flush cache + 120, // ttl + &my_address + ) + ]; + + let mut flags = Flags::new(); + flags.set_qr(MessageType::Reply); + flags.set_authoritative(true); + + let advert_message = Message::new( + id, + flags, + questions, + &mut answer, + &mut [], + &mut []); + + let mut data_buf = [0; 4096]; + // Serialize the message into the buffer + assert!(advert_message.space_needed() <= data_buf.len()); + + log::info!("ready to send to {:?}", endpoint); + + match advert_message.write(&mut data_buf) { + Result::Ok(len) => { + log::info!("sock.send: {:?}", sock.send_to(&data_buf[..len], endpoint).await); + }, + Result::Err(err) => { + log::error!("message.write {:?}", err); + } + } +} pub async fn start_wifi(spawner: &Spawner, wifi_peripheral: esp_hal::peripherals::WIFI<'static>) -> ! { @@ -121,54 +175,22 @@ pub async fn start_wifi(spawner: &Spawner, stack.join_multicast_group(MDNS_IP) ); - let mut answer = [ - ResourceRecord::new( - "eculogical.local", - ResourceType::A, - 1, // class - 60, // ttl - &my_address - ) - ]; - let mut flags = Flags::new(); - flags.set_qr(MessageType::Reply); - flags.set_authoritative(true); - - // RFC: Multicast DNS responses MUST NOT contain any questions in the - // RFC: Question Section. - - let message = Message::new((rng.random() as u16), - flags, - &mut [], - &mut answer, - &mut [], - &mut []); + let my_hostname = Label::from("eculogical.local"); + send_advert(&sock, rng.random() as u16, MDNS_ENDPOINT, None, &my_address).await; let mut data_buf = [0; 4096]; - // Serialize the message into the buffer - assert!(message.space_needed() <= data_buf.len()); loop { - match message.write(&mut data_buf) { - Result::Ok(len) => { - log::info!("sock.send: {:?}", sock.send_to(&data_buf[..len], MDNS_ENDPOINT).await); - }, - Result::Err(err) => { - log::error!("message.write {:?}", err); - } - } - if sock.may_recv() { - let mut questions = [Question::default(); 16]; let mut answers = [ResourceRecord::default(); 16]; let mut authorities = [ResourceRecord::default(); 16]; let mut addl = [ResourceRecord::default(); 16]; let res = sock.recv_from(&mut data_buf).await; - if let Ok((n, _endpoint)) = res { + if let Ok((n, meta)) = res { log::info!("received packet len {n}"); let message = Message::read( &data_buf[..n], @@ -177,16 +199,29 @@ pub async fn start_wifi(spawner: &Spawner, &mut authorities, &mut addl, ); + match message { Result::Ok(message) => { - log::info!("message receivefd"); + let q_id = message.id(); for q in message.questions() { - log::info!("question {:?}", q.name()); + log::info!("question {:?} {:?} {:?} flags {:?} from {:?}", + q.name(), q.ty(), q.class(), + message.flags().raw(), + meta.endpoint); + if q.name().eq(&my_hostname) { + if meta.endpoint.port == 5353 { + send_advert(&sock, q_id, MDNS_ENDPOINT, None, &my_address).await; + } else if (q.class() & 0x8000) != 0 { + log::info!("unicast"); + send_advert(&sock, q_id, meta.endpoint, None, &my_address).await; + } else { + // legacy unicast, send questions + send_advert(&sock, q_id, meta.endpoint, Some(q), &my_address).await; + } + log::info!("IT ME"); + } } - for q in message.answers() { - log::info!("answer {:?}", q.data()); - } }, Result::Err(err) => { log::error!("parsing dns message: {:?}", err);