Skip to content

Commit

Permalink
socket: add DNS
Browse files Browse the repository at this point in the history
  • Loading branch information
Dirbaio committed May 19, 2022
1 parent 72d66dd commit da1a2b2
Show file tree
Hide file tree
Showing 7 changed files with 571 additions and 5 deletions.
8 changes: 7 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ libc = { version = "0.2.18", optional = true }
bitflags = { version = "1.0", default-features = false }
defmt = { version = "0.3", optional = true }
cfg-if = "1.0.0"
heapless = "0.7.7"

[dev-dependencies]
env_logger = "0.9"
Expand Down Expand Up @@ -54,6 +55,7 @@ verbose = []
"socket-tcp" = ["socket"]
"socket-icmp" = ["socket"]
"socket-dhcpv4" = ["socket", "medium-ethernet", "proto-dhcpv4"]
"socket-dns" = ["socket", "proto-dns"]

"async" = []

Expand All @@ -62,7 +64,7 @@ default = [
"medium-ethernet", "medium-ip", "medium-ieee802154",
"phy-raw_socket", "phy-tuntap_interface",
"proto-ipv4", "proto-igmp", "proto-dhcpv4", "proto-ipv6", "proto-sixlowpan", "proto-dns",
"socket-raw", "socket-icmp", "socket-udp", "socket-tcp", "socket-dhcpv4",
"socket-raw", "socket-icmp", "socket-udp", "socket-tcp", "socket-dhcpv4", "socket-dns",
"async"
]

Expand Down Expand Up @@ -114,5 +116,9 @@ required-features = ["std", "medium-ethernet", "medium-ip", "phy-tuntap_interfac
name = "sixlowpan"
required-features = ["std", "medium-ieee802154", "phy-raw_socket", "proto-sixlowpan", "socket-udp"]

[[example]]
name = "dns"
required-features = ["std", "medium-ethernet", "medium-ip", "phy-tuntap_interface", "proto-ipv4", "socket-dns"]

[profile.release]
debug = 2
102 changes: 102 additions & 0 deletions examples/dns.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#[macro_use]
extern crate log;
extern crate byteorder;
extern crate env_logger;
extern crate getopts;
extern crate smoltcp;

mod utils;

use smoltcp::iface::{InterfaceBuilder, NeighborCache, Routes};
use smoltcp::phy::Device;
use smoltcp::phy::{wait as phy_wait, Medium};
use smoltcp::socket::DnsSocket;
use smoltcp::time::Instant;
use smoltcp::wire::{
EthernetAddress, HardwareAddress, IpAddress, IpCidr, Ipv4Address, Ipv6Address,
};
use smoltcp::Error;
use std::collections::BTreeMap;
use std::os::unix::io::AsRawFd;

fn main() {
utils::setup_logging("warn");

let (mut opts, mut free) = utils::create_options();
utils::add_tuntap_options(&mut opts, &mut free);
utils::add_middleware_options(&mut opts, &mut free);

let mut matches = utils::parse_options(&opts, free);
let device = utils::parse_tuntap_options(&mut matches);
let fd = device.as_raw_fd();
let device = utils::parse_middleware_options(&mut matches, device, /*loopback=*/ false);

let neighbor_cache = NeighborCache::new(BTreeMap::new());

let servers = vec![
Ipv4Address::new(8, 8, 4, 4).into(),
Ipv4Address::new(8, 8, 8, 8).into(),
];
let dns_socket = DnsSocket::new(servers, vec![]);

let ethernet_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x02]);
let src_ipv6 = IpAddress::v6(0xfdaa, 0, 0, 0, 0, 0, 0, 1);
let ip_addrs = [
IpCidr::new(IpAddress::v4(192, 168, 69, 1), 24),
IpCidr::new(src_ipv6, 64),
IpCidr::new(IpAddress::v6(0xfe80, 0, 0, 0, 0, 0, 0, 1), 64),
];
let default_v4_gw = Ipv4Address::new(192, 168, 69, 100);
let default_v6_gw = Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 0x100);
let mut routes_storage = [None; 2];
let mut routes = Routes::new(&mut routes_storage[..]);
routes.add_default_ipv4_route(default_v4_gw).unwrap();
routes.add_default_ipv6_route(default_v6_gw).unwrap();

let medium = device.capabilities().medium;
let mut builder = InterfaceBuilder::new(device, vec![])
.ip_addrs(ip_addrs)
.routes(routes);
if medium == Medium::Ethernet {
builder = builder
.hardware_addr(HardwareAddress::Ethernet(ethernet_addr))
.neighbor_cache(neighbor_cache);
}
let mut iface = builder.finalize();

let dns_handle = iface.add_socket(dns_socket);

//let name = b"\x08facebook\x03com\x00";
//let name = b"\x03www\x08facebook\x03com\x00";
//let name = b"\x06reddit\x03com\x00";
let name = b"\x09rust-lang\x03org\x00";

let (socket, cx) = iface.get_socket_and_context::<DnsSocket>(dns_handle);
let query = socket.start_query(cx, name).unwrap();

loop {
let timestamp = Instant::now();
debug!("timestamp {:?}", timestamp);

match iface.poll(timestamp) {
Ok(_) => {}
Err(e) => {
debug!("poll error: {}", e);
}
}

match iface
.get_socket::<DnsSocket>(dns_handle)
.get_query_result(query)
{
Ok(addrs) => {
println!("Query done: {:?}", addrs);
break;
}
Err(Error::Exhausted) => {} // not done yet
Err(e) => panic!("query failed: {:?}", e),
}

phy_wait(fd, iface.poll_delay(timestamp)).expect("wait error");
}
}
29 changes: 25 additions & 4 deletions src/iface/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ pub(crate) enum IpPacket<'a> {
Icmpv6((Ipv6Repr, Icmpv6Repr<'a>)),
#[cfg(feature = "socket-raw")]
Raw((IpRepr, &'a [u8])),
#[cfg(feature = "socket-udp")]
#[cfg(any(feature = "socket-udp", feature = "socket-dns"))]
Udp((IpRepr, UdpRepr, &'a [u8])),
#[cfg(feature = "socket-tcp")]
Tcp((IpRepr, TcpRepr<'a>)),
Expand Down Expand Up @@ -417,7 +417,7 @@ impl<'a> IpPacket<'a> {
),
#[cfg(feature = "socket-raw")]
IpPacket::Raw((_, raw_packet)) => payload.copy_from_slice(raw_packet),
#[cfg(feature = "socket-udp")]
#[cfg(any(feature = "socket-udp", feature = "socket-dns"))]
IpPacket::Udp((_, udp_repr, inner_payload)) => udp_repr.emit(
&mut UdpPacket::new_unchecked(payload),
&_ip_repr.src_addr(),
Expand Down Expand Up @@ -944,6 +944,10 @@ where
Socket::Dhcpv4(socket) => socket.dispatch(inner, |inner, response| {
respond!(inner, IpPacket::Dhcpv4(response))
}),
#[cfg(feature = "socket-dns")]
Socket::Dns(ref mut socket) => socket.dispatch(inner, |inner, response| {
respond!(inner, IpPacket::Udp(response))
}),
};

match (device_result, socket_result) {
Expand Down Expand Up @@ -1575,7 +1579,7 @@ impl<'a> InterfaceInner<'a> {
match nxt_hdr {
IpProtocol::Icmpv6 => self.process_icmpv6(sockets, ipv6_repr.into(), ip_payload),

#[cfg(feature = "socket-udp")]
#[cfg(any(feature = "socket-udp", feature = "socket-dns"))]
IpProtocol::Udp => {
self.process_udp(sockets, ipv6_repr.into(), handled_by_raw_socket, ip_payload)
}
Expand Down Expand Up @@ -2117,7 +2121,7 @@ impl<'a> InterfaceInner<'a> {
}
}

#[cfg(feature = "socket-udp")]
#[cfg(any(feature = "socket-udp", feature = "socket-dns"))]
fn process_udp<'frame>(
&mut self,
sockets: &mut SocketSet,
Expand Down Expand Up @@ -2146,6 +2150,23 @@ impl<'a> InterfaceInner<'a> {
}
}

#[cfg(feature = "socket-dns")]
for dns_socket in sockets
.iter_mut()
.filter_map(|i| DnsSocket::downcast(&mut i.socket))
{
if !dns_socket.accepts(&ip_repr, &udp_repr) {
continue;
}

match dns_socket.process(self, &ip_repr, &udp_repr, udp_payload) {
// The packet is valid and handled by socket.
Ok(()) => return Ok(None),
// The packet is malformed, or the socket buffer is full.
Err(e) => return Err(e),
}
}

// The packet wasn't handled by a socket, send an ICMP port unreachable packet.
match ip_repr {
#[cfg(feature = "proto-ipv4")]
Expand Down
14 changes: 14 additions & 0 deletions src/rand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,18 @@ impl Rand {
let shift = 29 - (s >> 61);
(s >> shift) as u32
}

pub(crate) fn rand_u16(&mut self) -> u16 {
let n = self.rand_u32();
(n ^ (n >> 16)) as u16
}

pub(crate) fn rand_source_port(&mut self) -> u16 {
loop {
let res = self.rand_u16();
if res > 1024 {
return res;
}
}
}
}
Loading

0 comments on commit da1a2b2

Please sign in to comment.